1 /* === S Y N F I G ========================================================= */
2 /*! \file dock_navigator.cpp
3 ** \brief Dock Nagivator File
5 ** $Id: dock_navigator.cpp,v 1.3 2005/01/12 00:31:11 darco Exp $
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
10 ** This package is free software; you can redistribute it and/or
11 ** modify it under the terms of the GNU General Public License as
12 ** published by the Free Software Foundation; either version 2 of
13 ** the License, or (at your option) any later version.
15 ** This package is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ** General Public License for more details.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
32 #include "dock_navigator.h"
33 #include "canvasview.h"
37 #include <synfig/canvas.h>
38 #include <synfig/context.h>
39 #include <synfig/target_scanline.h>
40 #include <synfig/surface.h>
42 #include <gtkmm/separator.h>
44 #include "asyncrenderer.h"
48 /* === U S I N G =========================================================== */
52 using namespace synfig;
54 /* === M A C R O S ========================================================= */
56 const double log_10_2 = log(2.0);
58 /* === G L O B A L S ======================================================= */
60 /* === P R O C E D U R E S ================================================= */
62 /* === M E T H O D S ======================================================= */
64 /* === E N T R Y P O I N T ================================================= */
65 studio::Widget_NavView::Widget_NavView(CanvasView::LooseHandle cv)
68 surface(new synfig::Surface)
70 attach(drawto,0,4,0,1);
72 attach(*manage(new Gtk::HSeparator),0,4,1,2,Gtk::SHRINK|Gtk::FILL,Gtk::SHRINK|Gtk::FILL);
75 attach(zoom_print,0,1,2,3,Gtk::SHRINK|Gtk::FILL,Gtk::SHRINK|Gtk::FILL);
76 zoom_print.set_size_request(40,-1);
78 Gtk::HScale *s = manage(new Gtk::HScale(adj_zoom));
79 s->set_draw_value(false);
80 //s->set_update_policy(Gtk::UPDATE_DELAYED);
81 //s->signal_event().connect(sigc::mem_fun(*this,&Dock_Navigator::on_scroll_event));
82 attach(*s,1,4,2,3,Gtk::EXPAND|Gtk::FILL,Gtk::SHRINK|Gtk::FILL);
86 adj_zoom.signal_value_changed().connect(sigc::mem_fun(*this,&Widget_NavView::on_number_modify));
90 drawto.signal_expose_event().connect(sigc::mem_fun(*this,&Widget_NavView::on_expose_draw));
91 drawto.signal_event().connect(sigc::mem_fun(*this,&Widget_NavView::on_mouse_event));
93 drawto.add_events(Gdk::BUTTON_MOTION_MASK|Gdk::BUTTON_PRESS_MASK);
95 //get_canvas_view()->canvas_interface()->signal_dirty_preview()
96 // .connect(sigc::mem_fun(*this,&Widget_NavView::on_dirty_preview));
97 get_canvas_view()->work_area->signal_rendering()
98 .connect(sigc::mem_fun(*this,&Widget_NavView::on_dirty_preview));
100 get_canvas_view()->work_area->signal_view_window_changed()
101 .connect(sigc::mem_fun(*this,&Widget_NavView::on_workarea_view_change));
103 //update with this canvas' view
104 on_workarea_view_change();
110 adj_zoom.set_value(0);
113 studio::Widget_NavView::~Widget_NavView()
118 static void freegu8(const guint8 *p)
123 void studio::Widget_NavView::on_start_render()
127 //synfig::warning("Nav: Starting render");
128 //synfig::warning("Nav: Rendering canvas");
129 etl::handle<Target_Scanline> targ = surface_target(surface.get());
131 targ->set_canvas(get_canvas_view()->get_canvas());
132 targ->set_remove_alpha();
133 targ->set_avoid_time_sync();
134 targ->set_quality(get_canvas_view()->get_work_area()->get_quality());
135 //synfig::info("Set the quality level to: %d", get_canvas_view()->get_work_area()->get_quality());
137 //this should set it to render a single frame
138 RendDesc r = get_canvas_view()->get_canvas()->rend_desc();
139 r.set_time(get_canvas_view()->canvas_interface()->get_time());
141 //this changes the size of the canvas to the closest thing we can find
142 int sw = r.get_w(), sh = r.get_h();
144 //synfig::warning("Nav: source image is %d x %d", sw,sh);
146 //resize so largest dimension is 128
147 int dw = sw > sh ? 128 : sw*128/sh,
148 dh = sh > sw ? 128 : sh*128/sw;
150 //synfig::warning("Nav: dest image is %d x %d", dw,dh);
156 //float pw = r.get_pw();
157 //float ph = r.get_ph();
159 //synfig::warning("Nav: pixel size is %f x %f", pw,ph);
161 //this renders that single frame
162 targ->set_rend_desc(&r);
164 //synfig::warning("Nav: Building async renderer and starting it...");
166 renderer = new AsyncRenderer(targ);
167 renderer->signal_success().connect(sigc::mem_fun(*this,&Widget_NavView::on_finish_render));
173 void studio::Widget_NavView::on_finish_render()
175 //convert it into our pixmap
176 PixelFormat pf(PF_RGB);
178 //synfig::warning("Nav: It hath succeeded!!!");
180 //assert(renderer && renderer->has_success());
182 //synfig::warning("Nav: now we know it really succeeded");
185 synfig::warning("dock_navigator: Bad surface");
190 int dw = surface->get_w();
191 int dh = surface->get_h();
195 w = prev->get_width();
196 h = prev->get_height();
199 if(w != dw || h != dh || !prev)
201 const int total_bytes(dw*dh*synfig::channels(pf));
203 //synfig::warning("Nav: Updating the pixbuf to be the right size, etc. (%d bytes)", total_bytes);
206 guint8 *bytes = new guint8[total_bytes]; //24 bits per pixel
208 //convert into our buffered dataS
209 //synfig::warning("Nav: converting color format into buffer");
210 convert_color_format((unsigned char *)bytes, (*surface)[0], dw*dh, pf, App::gamma);
213 Gdk::Pixbuf::create_from_data(
214 bytes, // pointer to the data
215 Gdk::COLORSPACE_RGB, // the colorspace
216 ((pf&PF_A)==PF_A), // has alpha?
217 8, // bits per sample
220 dw*synfig::channels(pf), // stride (pitch)
226 //synfig::warning("Nav: Don't need to resize");
227 //convert into our buffered dataS
228 //synfig::warning("Nav: converting color format into buffer");
229 if(prev) //just in case we're stupid
231 convert_color_format((unsigned char *)prev->get_pixels(), (*surface)[0], dw*dh, pf, App::gamma);
237 /* zoom slider is on exponential scale
239 map: -4,4 -> small number,1600 with 100 at 0
244 static double unit_to_zoom(double f)
249 static double zoom_to_unit(double f)
253 return log(f) / log_10_2;
254 }else return -999999.0;
257 bool studio::Widget_NavView::on_expose_draw(GdkEventExpose *exp)
261 //zoom_print.set_text(strprintf("%.1f%%",100*unit_to_zoom(adj_zoom.get_value())));
263 //draw the good stuff
266 //if we've got a preview etc. display it...
267 if(get_canvas_view() && prev)
269 //axis transform from units to pixel coords
270 float xaxis = 0, yaxis = 0;
272 int canvw = get_canvas_view()->get_canvas()->rend_desc().get_w();
273 //int canvh = get_canvas_view()->get_canvas()->rend_desc().get_h();
275 float pw = get_canvas_view()->get_canvas()->rend_desc().get_pw();
276 float ph = get_canvas_view()->get_canvas()->rend_desc().get_ph();
278 int w = prev->get_width();
279 int h = prev->get_height();
281 //scale up/down to the nearest pixel ratio...
282 //and center in center
288 sx = drawto.get_width() / (float)w;
289 sy = drawto.get_height() / (float)h;
291 //synfig::warning("Nav redraw: now to scale the bitmap: %.3f x %.3f",sx,sy);
293 //round to smallest scale (fit entire thing in window without distortion)
298 // the point to navpixel space conversion should be:
299 // (navpixels / canvpixels) * (canvpixels / canvsize)
300 // or (navpixels / prevpixels) * (prevpixels / navpixels)
301 xaxis = sx * w / (float)canvw;
305 //scale to a new pixmap and then copy over to the window
309 //must now center to be cool
310 offx = (drawto.get_width() - nw)/2;
311 offy = (drawto.get_height() - nh)/2;
314 if(nw == 0 || nh == 0)return true;
316 //draw to drawing area
317 Glib::RefPtr<Gdk::GC> gc = Gdk::GC::create(drawto.get_window());
319 //synfig::warning("Nav: Scaling pixmap to off (%d,%d) with size (%d,%d)", offx,offy,nw, nh);
320 Glib::RefPtr<Gdk::Pixbuf> scalepx = prev->scale_simple(nw,nh,Gdk::INTERP_NEAREST);
322 //synfig::warning("Nav: Drawing scaled bitmap");
323 drawto.get_window()->draw_pixbuf(
326 0, 0, // Source X and Y
327 offx, offy, // Dest X and Y
328 -1,-1, // Width and Height
329 Gdk::RGB_DITHER_MAX, // RgbDither
330 2, 2 // Dither offset X and Y
333 //draw fancy red rectangle around focus point
334 const Point &wtl = get_canvas_view()->work_area->get_window_tl(),
335 &wbr = get_canvas_view()->work_area->get_window_br();
337 gc->set_rgb_fg_color(Gdk::Color("#ff0000"));
338 gc->set_line_attributes(2,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER);
340 //it must be clamped to the drawing area though
341 int l=0,rw=0,t=0,rh=0;
342 const Point fp = -get_canvas_view()->work_area->get_focus_point();
344 //get focus point in normal space
345 rw = (int)(abs((wtl[0]-wbr[0])*xaxis));
346 rh = (int)(abs((wtl[1]-wbr[1])*yaxis));
348 //transform into pixel space
349 l = (int)(drawto.get_width()/2 + fp[0]*xaxis - rw/2);
350 t = (int)(drawto.get_height()/2 + fp[1]*yaxis - rh/2);
354 // axis multipliers = xaxis,yaxis
355 //synfig::warning("Nav: tl (%f,%f), br (%f,%f)", wtl[0],wtl[1],wbr[0],wbr[1]);
356 //synfig::warning("Nav: tl (%f,%f), br (%f,%f)", wtl[0],wtl[1],wbr[0],wbr[1]);
357 //synfig::warning("Nav: Drawing Rectangle (%d,%d) with dim (%d,%d)", l,t,rw,rh);
358 drawto.get_window()->draw_rectangle(gc,false,l,t,rw,rh);
361 return false; //draw everything else too
364 void studio::Widget_NavView::on_dirty_preview()
370 bool studio::Widget_NavView::on_scroll_event(GdkEvent *event)
372 if(get_canvas_view() && get_canvas_view()->get_work_area())
374 double z = unit_to_zoom(adj_zoom.get_value());
378 case GDK_BUTTON_PRESS:
380 if(event->button.button == 1)
383 get_canvas_view()->get_work_area()->set_zoom(z);
389 case GDK_MOTION_NOTIFY:
391 if(Gdk::ModifierType(event->motion.state) & Gdk::BUTTON1_MASK)
394 get_canvas_view()->get_work_area()->set_zoom(z);
408 void studio::Widget_NavView::on_number_modify()
410 double z = unit_to_zoom(adj_zoom.get_value());
411 zoom_print.set_text(strprintf("%.1f%%",z*100.0));
412 //synfig::warning("Updating zoom to %f",adj_zoom.get_value());
414 if(get_canvas_view() && z != get_canvas_view()->get_work_area()->get_zoom())
417 get_canvas_view()->get_work_area()->set_zoom(z);
422 void studio::Widget_NavView::on_workarea_view_change()
424 double wz = get_canvas_view()->get_work_area()->get_zoom();
425 double z = zoom_to_unit(wz);
427 //synfig::warning("Updating zoom to %f -> %f",wz,z);
428 if(!scrolling && z != adj_zoom.get_value())
430 adj_zoom.set_value(z);
431 //adj_zoom.value_changed();
436 bool studio::Widget_NavView::on_mouse_event(GdkEvent * e)
441 if(e->type == GDK_BUTTON_PRESS && e->button.button == 1)
443 p[0] = e->button.x - drawto.get_width()/2;
444 p[1] = e->button.y - drawto.get_height()/2;
449 if(e->type == GDK_MOTION_NOTIFY && (Gdk::ModifierType(e->motion.state) & Gdk::BUTTON1_MASK))
451 p[0] = e->motion.x - drawto.get_width()/2;
452 p[1] = e->motion.y - drawto.get_height()/2;
457 if(setpos && prev && get_canvas_view())
459 const Point &tl = get_canvas_view()->get_canvas()->rend_desc().get_tl();
460 const Point &br = get_canvas_view()->get_canvas()->rend_desc().get_br();
462 float max = abs((br[0]-tl[0]) / drawto.get_width());
464 if((prev->get_width() / drawto.get_width()) < (prev->get_height() / drawto.get_height()))
465 max = abs((br[1]-tl[1]) / drawto.get_height());
467 float signx = (br[0]-tl[0]) < 0 ? -1 : 1;
468 float signy = (br[1]-tl[1]) < 0 ? -1 : 1;
472 pos[0] = p[0] * max * signx;
473 pos[1] = p[1] * max * signy;
475 get_canvas_view()->get_work_area()->set_focus_point(-pos);
483 //Navigator Dock Definitions
485 studio::Dock_Navigator::Dock_Navigator()
486 :Dock_CanvasSpecific("navigator",_("Navigator"),Gtk::StockID("synfig-navigator"))
491 studio::Dock_Navigator::~Dock_Navigator()
495 void studio::Dock_Navigator::changed_canvas_view_vfunc(etl::loose_handle<CanvasView> canvas_view)
499 Widget *v = canvas_view->get_ext_widget("navview");
503 v = new Widget_NavView(canvas_view);
504 canvas_view->set_ext_widget("navview",v);