X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-studio%2Ftrunk%2Fsrc%2Fgtkmm%2Fworkarea.cpp;h=9038bb1e90d16c161547553c721123e6f0765a27;hb=4ba22fb51d97f1ecce04dcc5e40569a4354c1bae;hp=e22108a1424c3f3bc5aa92bba808bcc9ab974545;hpb=ddfac3f719741977d49b3a84fcefe13e9e65b03a;p=synfig.git diff --git a/synfig-studio/trunk/src/gtkmm/workarea.cpp b/synfig-studio/trunk/src/gtkmm/workarea.cpp index e22108a..9038bb1 100644 --- a/synfig-studio/trunk/src/gtkmm/workarea.cpp +++ b/synfig-studio/trunk/src/gtkmm/workarea.cpp @@ -2,11 +2,12 @@ /*! \file workarea.cpp ** \brief Template Header ** -** $Id: workarea.cpp,v 1.3 2005/01/16 19:55:57 darco Exp $ +** $Id$ ** ** \legal ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright 2006 Yue Shi Lai +** Copyright (c) 2006 Yue Shi Lai +** Copyright (c) 2007, 2008 Chris Moore ** ** This package is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License as @@ -51,6 +52,7 @@ #include #include #include +#include #include #include "event_mouse.h" #include "event_layerclick.h" @@ -70,6 +72,8 @@ #include +#include "general.h" + #endif /* === U S I N G =========================================================== */ @@ -104,7 +108,7 @@ public: int twindow_start, twindow_width, twindow_height, twindow_pad; int refresh_id; - + bool onionskin; bool onion_first_tile; int onion_layers; @@ -116,13 +120,13 @@ public: void set_onion_skin(bool x) { onionskin=x; - + Time time(rend_desc().get_time_start()); - + onion_skin_queue.push_back(time); //onion_skin_queue.push_back(time-1); //onion_skin_queue.push_back(time+1); - + try { onion_skin_queue.push_back( @@ -133,7 +137,7 @@ public: } catch(...) { } - + try { onion_skin_queue.push_back( @@ -144,13 +148,13 @@ public: } catch(...) { } - + onion_layers=onion_skin_queue.size(); - + onion_first_tile=false; } public: - + WorkAreaTarget(WorkArea *workarea,int w, int h): workarea(workarea), low_res(workarea->get_low_resolution_flag()), @@ -167,8 +171,9 @@ public: set_clipping(true); if(low_res) { - set_tile_w(workarea->tile_w/2); - set_tile_h(workarea->tile_h/2); + int div = workarea->get_low_res_pixel_size(); + set_tile_w(workarea->tile_w/div); + set_tile_h(workarea->tile_h/div); } else { @@ -178,7 +183,7 @@ public: set_canvas(workarea->get_canvas()); set_quality(workarea->get_quality()); } - + ~WorkAreaTarget() { workarea->queue_draw(); @@ -188,8 +193,10 @@ public: { assert(workarea); newdesc->set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN); - if(low_res) - newdesc->set_wh(w/2,h/2); + if(low_res) { + int div = workarea->get_low_res_pixel_size(); + newdesc->set_wh(w/div,h/div); + } else newdesc->set_wh(w,h); @@ -197,7 +204,7 @@ public: workarea->get_w()!=w || workarea->get_h()!=h ) workarea->set_wh(w,h,4); - + workarea->full_frame=false; desc=*newdesc; @@ -216,12 +223,12 @@ public: virtual int next_frame(Time& time) { synfig::Mutex::Lock lock(mutex); - + if(!onionskin) return synfig::Target_Tile::next_frame(time); - + onion_first_tile=(onion_layers==(signed)onion_skin_queue.size()); - + if(!onion_skin_queue.empty()) { time=onion_skin_queue.front(); @@ -229,7 +236,7 @@ public: } else return 0; - + return onion_skin_queue.size()+1; } @@ -237,17 +244,17 @@ public: { synfig::Mutex::Lock lock(mutex); //if(workarea->tile_queue.empty()) return 0; - + //int curr_tile(workarea->tile_queue.front()); //workarea->tile_queue.pop_front(); int curr_tile(workarea->next_unrendered_tile(refresh_id-onion_skin_queue.size())); if(curr_tile<0) return 0; - + // Width of the image(in tiles) int tw(rend_desc().get_w()/get_tile_w()); if(rend_desc().get_w()%get_tile_w()!=0)tw++; - + y=(curr_tile/tw)*get_tile_w(); x=(curr_tile%tw)*get_tile_h(); @@ -260,8 +267,8 @@ public: return total_tiles()-curr_tile+1; } - - virtual bool start_frame(synfig::ProgressCallback *cb) + + virtual bool start_frame(synfig::ProgressCallback */*cb*/) { synfig::Mutex::Lock lock(mutex); @@ -279,16 +286,16 @@ public: //tile_iter=workarea->tile_book.begin()+twindow_start; return true; } - + static void free_buff(const guint8 *x) { free(const_cast(x)); } - + virtual bool add_tile(const synfig::Surface &surface, int x, int y) { synfig::Mutex::Lock lock(mutex); assert(surface); - + PixelFormat pf(PF_RGB); - + const int total_bytes(get_tile_w()*get_tile_h()*synfig::channels(pf)); unsigned char *buffer((unsigned char*)malloc(total_bytes)); @@ -301,7 +308,10 @@ public: int w(get_tile_w()); int h(get_tile_h()); int x(surface.get_w()*surface.get_h()); - //if(low_res) { w/=2,h/=2; } + //if(low_res) { + // int div = workarea->get_low_res_pixel_size(); + // w/=div,h/=div; + //} Color dark(0.6,0.6,0.6); Color lite(0.8,0.8,0.8); for(int i=0;i pixbuf; - + pixbuf=Gdk::Pixbuf::create_from_data( buffer, // pointer to the data Gdk::COLORSPACE_RGB, // the colorspace @@ -336,20 +346,21 @@ public: surface.get_h(), // height surface.get_w()*synfig::channels(pf), // stride (pitch) sigc::ptr_fun(&WorkAreaTarget::free_buff) - ); + ); if(low_res) { // We need to scale up + int div = workarea->get_low_res_pixel_size(); pixbuf=pixbuf->scale_simple( - surface.get_w()*2, - surface.get_h()*2, + surface.get_w()*div, + surface.get_h()*div, Gdk::INTERP_NEAREST ); } - + if(!onionskin || onion_first_tile || !workarea->tile_book[index].first) - { + { workarea->tile_book[index].first=pixbuf; } else @@ -368,9 +379,9 @@ public: 255/(onion_layers-onion_skin_queue.size()+1) //int overall_alpha ); } - + //if(index%2) - workarea->queue_draw(); + workarea->queue_draw(); assert(workarea->tile_book[index].first); return true; } @@ -393,7 +404,7 @@ public: int twindow_start, twindow_width, twindow_height, twindow_pad; int refresh_id; - + bool onionskin; bool onion_first_tile; int onion_layers; @@ -405,15 +416,15 @@ public: void set_onion_skin(bool x) { onionskin=x; - + Time time(rend_desc().get_time_start()); - + onion_skin_queue.push_back(time); //onion_skin_queue.push_back(time-1); //onion_skin_queue.push_back(time+1); if(!onionskin) return; - + try { onion_skin_queue.push_back( @@ -424,7 +435,7 @@ public: } catch(...) { } - + try { onion_skin_queue.push_back( @@ -435,13 +446,13 @@ public: } catch(...) { } - + onion_layers=onion_skin_queue.size(); - + onion_first_tile=false; } public: - + WorkAreaTarget_Full(WorkArea *workarea,int w, int h): workarea(workarea), low_res(workarea->get_low_resolution_flag()), @@ -454,7 +465,7 @@ public: set_canvas(workarea->get_canvas()); set_quality(workarea->get_quality()); } - + ~WorkAreaTarget_Full() { } @@ -464,7 +475,10 @@ public: assert(workarea); newdesc->set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN); if(low_res) - newdesc->set_wh(w/2,h/2); + { + int div = workarea->get_low_res_pixel_size(); + newdesc->set_wh(w/div,h/div); + } else newdesc->set_wh(w,h); @@ -472,7 +486,7 @@ public: workarea->get_w()!=w || workarea->get_h()!=h ) workarea->set_wh(w,h,4); - + surface.set_wh(newdesc->get_w(),newdesc->get_h()); desc=*newdesc; @@ -491,21 +505,21 @@ public: if(!onionskin) return synfig::Target_Scanline::next_frame(time); - + onion_first_tile=(onion_layers==(signed)onion_skin_queue.size()); - + if(!onion_skin_queue.empty()) { time=onion_skin_queue.front(); onion_skin_queue.pop_front(); } else - return 0; + return 0; return onion_skin_queue.size()+1; } - - virtual bool start_frame(synfig::ProgressCallback *cb) + + virtual bool start_frame(synfig::ProgressCallback */*cb*/) { return true; } @@ -521,13 +535,13 @@ public: } static void free_buff(const guint8 *x) { free(const_cast(x)); } - + virtual void end_frame() { assert(surface); - + PixelFormat pf(PF_RGB); - + const int total_bytes(surface.get_w()*surface.get_h()*synfig::channels(pf)); unsigned char *buffer((unsigned char*)malloc(total_bytes)); @@ -540,15 +554,19 @@ public: int w(surface.get_w()); //int h(surface.get_h()); int x(surface.get_w()*surface.get_h()); - //if(low_res) { w/=2,h/=2; } + //if(low_res) { + // int div = workarea->get_low_res_pixel_size(); + // w/=div,h/=div; + //} Color dark(0.6,0.6,0.6); Color lite(0.8,0.8,0.8); int tw=workarea->tile_w; int th=workarea->tile_h; if(low_res) { - tw/=2; - th/=2; + int div = workarea->get_low_res_pixel_size(); + tw/=div; + th/=div; } for(int i=0;i pixbuf; - + pixbuf=Gdk::Pixbuf::create_from_data( buffer, // pointer to the data Gdk::COLORSPACE_RGB, // the colorspace @@ -574,22 +592,23 @@ public: surface.get_h(), // height surface.get_w()*synfig::channels(pf), // stride (pitch) sigc::ptr_fun(&WorkAreaTarget::free_buff) - ); + ); if(low_res) { // We need to scale up + int div = workarea->get_low_res_pixel_size(); pixbuf=pixbuf->scale_simple( - surface.get_w()*2, - surface.get_h()*2, + surface.get_w()*div, + surface.get_h()*div, Gdk::INTERP_NEAREST ); } - + int index=0; - + if(!onionskin || onion_first_tile || !workarea->tile_book[index].first) - { + { workarea->tile_book[index].first=pixbuf; } else @@ -608,8 +627,8 @@ public: 255/(onion_layers-onion_skin_queue.size()+1) //int overall_alpha ); } - - workarea->queue_draw(); + + workarea->queue_draw(); assert(workarea->tile_book[index].first); } }; @@ -626,15 +645,17 @@ WorkArea::WorkArea(etl::loose_handle canvas_interfac canvas(canvas_interface->get_canvas()), scrollx_adjustment(0,-4,4,0.01,0.1), scrolly_adjustment(0,-4,4,0.01,0.1), - w(128), - h(128), + w(TILE_SIZE), + h(TILE_SIZE), last_event_time(0), progresscallback(0), dragging(DRAG_NONE), show_grid(false), - tile_w(128), - tile_h(128) -{ + tile_w(TILE_SIZE), + tile_h(TILE_SIZE), + timecode_width(0), + timecode_height(0) +{ show_guides=true; curr_input_device=0; full_frame=false; @@ -643,7 +664,8 @@ WorkArea::WorkArea(etl::loose_handle canvas_interfac render_idle_func_id=0; zoom=prev_zoom=1.0; quality=10; - rendering=false; + low_res_pixel_size=2; + rendering=false; canceled_=false; low_resolution=true; pw=0.001; @@ -653,7 +675,7 @@ WorkArea::WorkArea(etl::loose_handle canvas_interfac queued=false; dirty_trap_enabled=false; solid_lines=true; - + dirty_trap_queued=0; meta_data_lock=false; @@ -674,7 +696,7 @@ WorkArea::WorkArea(etl::loose_handle canvas_interfac // Not that it really makes a difference... (setting this to zero, that is) refreshes=0; - + drawing_area=manage(new class Gtk::DrawingArea()); drawing_area->show(); drawing_area->set_extension_events(Gdk::EXTENSION_EVENTS_ALL); @@ -696,9 +718,9 @@ WorkArea::WorkArea(etl::loose_handle canvas_interfac drawing_frame->modify_bg(Gtk::STATE_SELECTED,Gdk::Color("#00ff00")); */ //drawing_frame->set_state(Gtk::STATE_NORMAL); - + drawing_frame->show(); - + attach(*drawing_frame, 1, 3+RULER_FIX, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0); Gtk::IconSize iconsize=Gtk::IconSize::from_name("synfig-small_icon"); @@ -726,7 +748,7 @@ WorkArea::WorkArea(etl::loose_handle canvas_interfac menubutton->signal_pressed().connect(sigc::mem_fun(*this, &WorkArea::popup_menu)); attach(*menubutton, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0); - + Gtk::VScrollbar *vscrollbar1 = manage(new class Gtk::VScrollbar(*get_scrolly_adjustment())); Gtk::HScrollbar *hscrollbar1 = manage(new class Gtk::HScrollbar(*get_scrollx_adjustment())); @@ -747,15 +769,15 @@ WorkArea::WorkArea(etl::loose_handle canvas_interfac add_events(Gdk::KEY_PRESS_MASK); drawing_area->add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); drawing_area->add_events(Gdk::BUTTON1_MOTION_MASK | Gdk::BUTTON2_MOTION_MASK |Gdk::POINTER_MOTION_MASK); - + // ----------------- Attach signals - + drawing_area->signal_expose_event().connect(sigc::mem_fun(*this, &WorkArea::refresh)); drawing_area->signal_event().connect(sigc::mem_fun(*this, &WorkArea::on_drawing_area_event)); drawing_area->signal_size_allocate().connect(sigc::hide(sigc::mem_fun(*this, &WorkArea::refresh_dimension_info))); - + canvas_interface->signal_rend_desc_changed().connect(sigc::mem_fun(*this, &WorkArea::refresh_dimension_info)); // When either of the scrolling adjustments change, then redraw. get_scrollx_adjustment()->signal_value_changed().connect(sigc::mem_fun(*this, &WorkArea::queue_scroll)); @@ -779,14 +801,14 @@ WorkArea::WorkArea(etl::loose_handle canvas_interfac set_focus_point(Point(0,0)); - load_meta_data(); + load_meta_data(); // Load sketch { String data(canvas->get_meta_data("sketch")); if(!data.empty()) { if(!load_sketch(data)) - load_sketch(dirname(canvas->get_file_name())+ETL_DIRECTORY_SEPERATOR+basename(data)); + load_sketch(dirname(canvas->get_file_name())+ETL_DIRECTORY_SEPARATOR+basename(data)); } } @@ -799,7 +821,29 @@ WorkArea::WorkArea(etl::loose_handle canvas_interfac WorkArea::~WorkArea() { // delete [] buffer; + + // don't leave the render function queued if we are about to vanish; + // that causes crashes + if(render_idle_func_id) + render_idle_func_id=0; +} + +#ifdef SINGLE_THREADED +bool +WorkArea::get_updating()const +{ + return App::single_threaded && async_renderer && async_renderer->updating; +} +#endif + +#ifdef SINGLE_THREADED +void +WorkArea::stop_updating(bool cancel) +{ + async_renderer->stop(); + if (cancel) canceled_=true; } +#endif void WorkArea::save_meta_data() @@ -826,7 +870,7 @@ WorkArea::save_meta_data() } if(!data.empty()) canvas_interface->set_meta_data("guide_x",data); - + data.clear(); for(iter=get_guide_list_y().begin();iter!=get_guide_list_y().end();++iter) { @@ -837,7 +881,7 @@ WorkArea::save_meta_data() if(!data.empty()) canvas_interface->set_meta_data("guide_y",data); } - + if(get_sketch_filename().size()) { if(dirname(canvas->get_file_name())==dirname(get_sketch_filename())) @@ -855,7 +899,7 @@ WorkArea::load_meta_data() if(meta_data_lock) return; meta_data_lock=true; - + String data; data=canvas->get_meta_data("grid_size"); @@ -864,11 +908,13 @@ WorkArea::load_meta_data() float gx(get_grid_size()[0]),gy(get_grid_size()[1]); String::iterator iter(find(data.begin(),data.end(),' ')); - String tmp(data.begin(),iter); - + String tmp(data.begin(),iter); + if(!tmp.empty()) gx=stratof(tmp); - + else + synfig::error("WorkArea::load_meta_data(): Unable to parse data for \"grid_size\", which was \"%s\"",data.c_str()); + if(iter==data.end()) tmp.clear(); else @@ -876,11 +922,11 @@ WorkArea::load_meta_data() if(!tmp.empty()) gy=stratof(tmp); - + else + synfig::error("WorkArea::load_meta_data(): Unable to parse data for \"grid_size\", which was \"%s\"",data.c_str()); + set_grid_size(Vector(gx,gy)); } - else - synfig::error("WorkArea::load_meta_data(): Unable to parse data for \"grid_size\", which was \"%s\"",data.c_str()); data=canvas->get_meta_data("grid_show"); if(data.size() && (data=="1" || data[0]=='t' || data[0]=='T')) @@ -917,34 +963,34 @@ WorkArea::load_meta_data() set_onion_skin(true); if(data.size() && (data=="0" || data[0]=='f' || data[0]=='F')) set_onion_skin(false); - + data=canvas->get_meta_data("guide_x"); get_guide_list_x().clear(); while(!data.empty()) { String::iterator iter(find(data.begin(),data.end(),' ')); - String guide(data.begin(),iter); + String guide(data.begin(),iter); if(!guide.empty()) get_guide_list_x().push_back(stratof(guide)); - + if(iter==data.end()) data.clear(); else data=String(iter+1,data.end()); } //sort(get_guide_list_x()); - + data=canvas->get_meta_data("guide_y"); get_guide_list_y().clear(); while(!data.empty()) { String::iterator iter(find(data.begin(),data.end(),' ')); - String guide(data.begin(),iter); + String guide(data.begin(),iter); if(!guide.empty()) get_guide_list_y().push_back(stratof(guide)); - + if(iter==data.end()) data.clear(); else @@ -981,7 +1027,7 @@ WorkArea::enable_grid() queue_draw(); } -void +void WorkArea::disable_grid() { show_grid=false; @@ -1039,19 +1085,19 @@ void WorkArea::set_focus_point(const synfig::Point &point) { // These next three lines try to ensure that we place the - // focus on a pixel boundry + // focus on a pixel boundary /*Point adjusted(point[0]/abs(get_pw()),point[1]/abs(get_ph())); adjusted[0]=(abs(adjusted[0]-floor(adjusted[0]))<0.5)?floor(adjusted[0])*abs(get_pw()):ceil(adjusted[0])*abs(get_ph()); adjusted[1]=(abs(adjusted[1]-floor(adjusted[1]))<0.5)?floor(adjusted[1])*abs(get_ph()):ceil(adjusted[1])*abs(get_ph()); */ const synfig::Point& adjusted(point); - + synfig::RendDesc &rend_desc(get_canvas()->rend_desc()); Real x_factor=(rend_desc.get_br()[0]-rend_desc.get_tl()[0]>0)?-1:1; Real y_factor=(rend_desc.get_br()[1]-rend_desc.get_tl()[1]>0)?-1:1; get_scrollx_adjustment()->set_value(adjusted[0]*x_factor); - get_scrolly_adjustment()->set_value(adjusted[1]*y_factor); + get_scrolly_adjustment()->set_value(adjusted[1]*y_factor); } synfig::Point @@ -1060,7 +1106,7 @@ WorkArea::get_focus_point()const synfig::RendDesc &rend_desc(get_canvas()->rend_desc()); Real x_factor=(rend_desc.get_br()[0]-rend_desc.get_tl()[0]>0)?-1:1; Real y_factor=(rend_desc.get_br()[1]-rend_desc.get_tl()[1]>0)?-1:1; - + return synfig::Point(get_scrollx_adjustment()->get_value()*x_factor, get_scrolly_adjustment()->get_value()*y_factor); } @@ -1074,11 +1120,11 @@ WorkArea::set_wh(int W, int H,int CHAN) } if(W<=0 || H<=0 || CHAN<=0) return false; - + assert(W>0); assert(H>0); assert(CHAN>0); - + // Set all of the parameters w=W; h=H; @@ -1087,7 +1133,7 @@ WorkArea::set_wh(int W, int H,int CHAN) refresh_dimension_info(); tile_book.clear(); - + return true; } @@ -1098,10 +1144,10 @@ WorkArea::on_key_press_event(GdkEventKey* event) return false; Real multiplier(1.0); - + if(Gdk::ModifierType(event->state)&GDK_SHIFT_MASK) multiplier=10.0; - + Vector nudge; switch(event->keyval) { @@ -1121,15 +1167,15 @@ WorkArea::on_key_press_event(GdkEventKey* event) return false; break; } - - synfigapp::Action::PassiveGrouper grouper(instance.get(),"Nudge"); - + + synfigapp::Action::PassiveGrouper grouper(instance.get(),_("Nudge")); + // Grid snap does not apply to nudging bool grid_snap_holder(get_grid_snap()); bool guide_snap_holder(get_guide_snap()); set_grid_snap(false); - try { + try { start_duck_drag(get_selected_duck()->get_trans_point()); translate_selected_ducks(get_selected_duck()->get_trans_point()+nudge*multiplier); end_duck_drag(); @@ -1142,7 +1188,7 @@ WorkArea::on_key_press_event(GdkEventKey* event) set_grid_snap(grid_snap_holder); set_guide_snap(guide_snap_holder); - + return true; } @@ -1156,9 +1202,7 @@ WorkArea::on_drawing_area_event(GdkEvent *event) float pressure(0); bool is_mouse(false); Gdk::ModifierType modifier(Gdk::ModifierType(0)); - - drawing_area->grab_focus(); - + // Handle input stuff if( event->any.type==GDK_MOTION_NOTIFY || @@ -1178,9 +1222,10 @@ WorkArea::on_drawing_area_event(GdkEvent *event) { device=event->button.device; modifier=Gdk::ModifierType(event->button.state); + drawing_area->grab_focus(); } - - // Make sure we recognise the device + + // Make sure we recognize the device if(curr_input_device) { if(curr_input_device!=device) @@ -1189,15 +1234,15 @@ WorkArea::on_drawing_area_event(GdkEvent *event) curr_input_device=device; signal_input_device_changed()(curr_input_device); } - } + } else if(device) { curr_input_device=device; signal_input_device_changed()(curr_input_device); - } + } assert(curr_input_device); - + // Calculate the position of the // input device in canvas coordinates // and the buttons @@ -1221,14 +1266,14 @@ WorkArea::on_drawing_area_event(GdkEvent *event) //synfig::info("pressure=%f",pressure); pressure-=0.04f; pressure/=1.0f-0.04f; - - + + assert(!isnan(pressure)); - + mouse_pos=synfig::Point(screen_to_comp_coords(synfig::Point(x,y))); - + button_pressed=event->button.button; - + if(button_pressed==1 && pressure<0 && (event->any.type!=GDK_BUTTON_RELEASE && event->any.type!=GDK_BUTTON_PRESS)) button_pressed=0; if(pressure<0) @@ -1236,17 +1281,17 @@ WorkArea::on_drawing_area_event(GdkEvent *event) //if(event->any.type==GDK_BUTTON_PRESS && button_pressed) // synfig::info("Button pressed on input device = %d",event->button.button); - + //if(event->button.axes[2]>0.1) // button_pressed=1; //else - // button_pressed=0; + // button_pressed=0; } } // GDK mouse scrolling events else if(event->any.type==GDK_SCROLL) { - // GDK information needed to properly interprete mouse + // GDK information needed to properly interpret mouse // scrolling events are: scroll.state, scroll.x/scroll.y, and // scroll.direction. The value of scroll.direction will be // obtained later. @@ -1277,49 +1322,77 @@ WorkArea::on_drawing_area_event(GdkEvent *event) switch(button_pressed) { case 1: // Attempt to click on a duck - { + { etl::handle duck; dragging=DRAG_NONE; - + if(allow_duck_clicks) { duck=find_duck(mouse_pos,radius); - + if(duck) { - clicked_duck=0; + // make a note of whether the duck we click on was selected or not if(duck_is_selected(duck)) - { clicked_duck=duck; - } else { - if(modifier&GDK_SHIFT_MASK) - { - select_duck(duck); - } - else if(modifier&GDK_CONTROL_MASK) - { - select_duck(duck); - } - else - { + clicked_duck=0; + // if CTRL isn't pressed, clicking an unselected duck will unselect all other ducks + if(!(modifier&GDK_CONTROL_MASK)) clear_selected_ducks(); - select_duck(duck); - } + select_duck(duck); } } } //else // clear_selected_ducks(); - - - + + + selected_bezier=find_bezier(mouse_pos,radius,&bezier_click_pos); - if(duck && duck->get_editable()) + if(duck) { + if (!duck->get_editable()) + return true; + //get_selected_duck()->signal_user_click(0)(); //if(clicked_duck)clicked_duck->signal_user_click(0)(); + + // if the user is holding shift while clicking on a tangent duck, consider splitting the tangent + if (event->motion.state&GDK_SHIFT_MASK && duck->get_type() == Duck::TYPE_TANGENT) + { + synfigapp::ValueDesc value_desc = duck->get_value_desc(); + + // we have the tangent, but need the vertex - that's the parent + if (value_desc.parent_is_value_node()) { + ValueNode_Composite::Handle parent_value_node = value_desc.get_parent_value_node(); + + // if the tangent isn't split, then split it + if (!((*(parent_value_node->get_link("split")))(get_time()).get(bool()))) + { + if (get_canvas_view()->canvas_interface()-> + change_value(synfigapp::ValueDesc(parent_value_node, + parent_value_node->get_link_index_from_name("split")), + true)) + { + // rebuild the ducks from scratch, so the tangents ducks aren't connected + get_canvas_view()->rebuild_ducks(); + + // reprocess the mouse click + return on_drawing_area_event(event); + } + else + return true; + } + } else { + // I don't know how to access the vertex from the tangent duck when originally drawing the bline in the bline tool + + // synfig::ValueNode::Handle vn = value_desc.get_value_node(); + synfig::info("parent isn't value node? shift-drag-tangent doesn't work in bline tool yet..."); + } + } + dragging=DRAG_DUCK; drag_point=mouse_pos; //drawing_area->queue_draw(); @@ -1329,7 +1402,7 @@ WorkArea::on_drawing_area_event(GdkEvent *event) } // I commented out this section because // it was causing issues when rotoscoping. -// At the moment, we don't need it, so +// At the moment, we don't need it, so // this was the easiest way to fix the problem. /* else @@ -1347,7 +1420,7 @@ WorkArea::on_drawing_area_event(GdkEvent *event) { // Check for a guide click GuideList::iterator iter; - + iter=find_guide_x(mouse_pos,radius); if(iter==get_guide_list_x().end()) { @@ -1395,33 +1468,29 @@ WorkArea::on_drawing_area_event(GdkEvent *event) { etl::handle duck=find_duck(mouse_pos,radius); etl::handle bezier=find_bezier(mouse_pos,radius,&bezier_click_pos); - + Layer::Handle layer(get_canvas()->find_layer(mouse_pos)); if(duck) { if(get_selected_ducks().size()<=1) duck->signal_user_click(2)(); else - { canvas_view->get_smach().process_event(EventMouse(EVENT_WORKAREA_MULTIPLE_DUCKS_CLICKED,BUTTON_RIGHT,mouse_pos,pressure,modifier)); - } return true; } - else - if(bezier) + else if(bezier) { bezier->signal_user_click(2)(bezier_click_pos); return true; } - else - if(layer) + else if (layer) { - if(canvas_view->get_smach().process_event(EventLayerClick(layer,BUTTON_RIGHT,mouse_pos))==Smach::RESULT_OK) + if(canvas_view->get_smach().process_event(EventLayerClick(layer,BUTTON_RIGHT,mouse_pos))==Smach::RESULT_OK) return false; return true; } else - canvas_view->get_smach().process_event(EventMouse(EVENT_WORKAREA_MOUSE_BUTTON_DOWN,BUTTON_RIGHT,mouse_pos,pressure,modifier)); + canvas_view->get_smach().process_event(EventMouse(EVENT_WORKAREA_MOUSE_BUTTON_DOWN,BUTTON_RIGHT,mouse_pos,pressure,modifier)); /* if(canvas_view->get_smach().process_event(EventMouse(EVENT_WORKAREA_MOUSE_BUTTON_DOWN,BUTTON_RIGHT,mouse_pos,pressure,modifier))==Smach::RESULT_OK) { @@ -1451,16 +1520,16 @@ WorkArea::on_drawing_area_event(GdkEvent *event) last_event_time=event->motion.time; signal_cursor_moved_(); - - // Guide/Duck hilights on hover + + // Guide/Duck highlights on hover if(dragging==DRAG_NONE) { GuideList::iterator iter; - + iter=find_guide_x(mouse_pos,radius); if(iter==get_guide_list_x().end()) iter=find_guide_y(mouse_pos,radius); - + if(iter!=curr_guide) { curr_guide=iter; @@ -1476,7 +1545,7 @@ WorkArea::on_drawing_area_event(GdkEvent *event) } } - + if(dragging==DRAG_DUCK) { if(canvas_view->get_cancel_status()) @@ -1494,20 +1563,22 @@ WorkArea::on_drawing_area_event(GdkEvent *event) } selected_duck->set_point(point); */ - + //Point p(mouse_pos); - + set_axis_lock(event->motion.state&GDK_SHIFT_MASK); - + translate_selected_ducks(mouse_pos); - + drawing_area->queue_draw(); } + if(dragging==DRAG_BOX) { curr_point=mouse_pos; drawing_area->queue_draw(); } + if(dragging==DRAG_GUIDE) { if(curr_guide_is_x) @@ -1516,30 +1587,34 @@ WorkArea::on_drawing_area_event(GdkEvent *event) *curr_guide=mouse_pos[1]; drawing_area->queue_draw(); } + if(dragging!=DRAG_WINDOW) { // Update those triangle things on the rulers const synfig::Point point(mouse_pos); hruler->property_position()=Distance(point[0],Distance::SYSTEM_UNITS).get(App::distance_system,get_canvas()->rend_desc()); vruler->property_position()=Distance(point[1],Distance::SYSTEM_UNITS).get(App::distance_system,get_canvas()->rend_desc()); } - if(dragging==DRAG_WINDOW) - { - set_focus_point(get_focus_point()+mouse_pos-drag_point); - } - else - if(event->motion.state&GDK_BUTTON1_MASK && canvas_view->get_smach().process_event(EventMouse(EVENT_WORKAREA_MOUSE_BUTTON_DRAG,BUTTON_LEFT,mouse_pos,pressure,modifier))==Smach::RESULT_ACCEPT) + + if(dragging == DRAG_WINDOW) + set_focus_point(get_focus_point() + mouse_pos-drag_point); + else if (event->motion.state & GDK_BUTTON1_MASK && + canvas_view->get_smach().process_event(EventMouse(EVENT_WORKAREA_MOUSE_BUTTON_DRAG, BUTTON_LEFT, + mouse_pos,pressure,modifier)) == Smach::RESULT_ACCEPT) return true; - else - if(event->motion.state&GDK_BUTTON2_MASK && canvas_view->get_smach().process_event(EventMouse(EVENT_WORKAREA_MOUSE_BUTTON_DRAG,BUTTON_MIDDLE,mouse_pos,pressure,modifier))==Smach::RESULT_ACCEPT) + else if (event->motion.state & GDK_BUTTON2_MASK && + canvas_view->get_smach().process_event(EventMouse(EVENT_WORKAREA_MOUSE_BUTTON_DRAG, BUTTON_MIDDLE, + mouse_pos, pressure, modifier)) == Smach::RESULT_ACCEPT) return true; - else - if(event->motion.state&GDK_BUTTON3_MASK && canvas_view->get_smach().process_event(EventMouse(EVENT_WORKAREA_MOUSE_BUTTON_DRAG,BUTTON_RIGHT,mouse_pos,pressure,modifier))==Smach::RESULT_ACCEPT) + else if (event->motion.state & GDK_BUTTON3_MASK && + canvas_view->get_smach().process_event(EventMouse(EVENT_WORKAREA_MOUSE_BUTTON_DRAG, BUTTON_RIGHT, + mouse_pos, pressure, modifier)) == Smach::RESULT_ACCEPT) return true; - else - if(canvas_view->get_smach().process_event(EventMouse(EVENT_WORKAREA_MOUSE_MOTION,BUTTON_NONE,mouse_pos,pressure,modifier))==Smach::RESULT_ACCEPT) + else if(canvas_view->get_smach().process_event(EventMouse(EVENT_WORKAREA_MOUSE_MOTION, BUTTON_NONE, + mouse_pos, pressure,modifier)) == Smach::RESULT_ACCEPT) return true; break; + case GDK_BUTTON_RELEASE: { bool ret(false); @@ -1552,12 +1627,12 @@ WorkArea::on_drawing_area_event(GdkEvent *event) } else if(dragging==DRAG_DUCK) - { - synfigapp::Action::PassiveGrouper grouper(instance.get(),"Move"); + { + synfigapp::Action::PassiveGrouper grouper(instance.get(),_("Move")); dragging=DRAG_NONE; //translate_selected_ducks(mouse_pos); set_axis_lock(false); - + try{ get_canvas_view()->duck_refresh_flag=false; get_canvas_view()->duck_refresh_needed=false; @@ -1565,37 +1640,20 @@ WorkArea::on_drawing_area_event(GdkEvent *event) get_canvas_view()->duck_refresh_flag=true; if(!drag_did_anything) { - //etl::handle duck=find_duck(mouse_pos,radius); - - if(modifier&GDK_SHIFT_MASK) + // if we originally clicked on a selected duck ... + if(clicked_duck) { - //synfig::info("DUCK_DRAG_RELEASE: SHIFT-MASK ON!"); - if(clicked_duck) - { - //synfig::info("DUCK_DRAG_RELEASE: CLICKED DUCK!"); + // ... and CTRL is pressed, then just toggle the clicked duck + // otherwise make the clicked duck the only selected duck + if(modifier&GDK_CONTROL_MASK) unselect_duck(clicked_duck); - } - } - else if(modifier&GDK_CONTROL_MASK) - { - //synfig::info("DUCK_DRAG_RELEASE: CONTROL-MASK ON!"); - if(clicked_duck) - { - //synfig::info("DUCK_DRAG_RELEASE: CLICKED DUCK!"); - unselect_duck(clicked_duck); - } - } - else - { - //synfig::info("DUCK_DRAG_RELEASE: NO MASK!"); - if(clicked_duck) + else { - //synfig::info("DUCK_DRAG_RELEASE: CLICKED DUCK!"); clear_selected_ducks(); select_duck(clicked_duck); } - } - if(clicked_duck)clicked_duck->signal_user_click(0)(); + clicked_duck->signal_user_click(0)(); + } } else { @@ -1614,28 +1672,37 @@ WorkArea::on_drawing_area_event(GdkEvent *event) ret=true; } - + if(dragging==DRAG_BOX) - { + { dragging=DRAG_NONE; if((drag_point-mouse_pos).mag()>radius/2.0f) { if(canvas_view->get_smach().process_event(EventBox(drag_point,mouse_pos,MouseButton(event->button.button),modifier))==Smach::RESULT_ACCEPT) return true; - if(!(modifier&GDK_CONTROL_MASK) && !(modifier&GDK_SHIFT_MASK)) + // when dragging a box around some ducks: + // SHIFT selects; CTRL toggles; SHIFT+CTRL unselects; clears all then selects + if(modifier&GDK_SHIFT_MASK) + select_ducks_in_box(drag_point,mouse_pos); + + if(modifier&GDK_CONTROL_MASK) + toggle_select_ducks_in_box(drag_point,mouse_pos); + else if(!(modifier&GDK_SHIFT_MASK)) + { clear_selected_ducks(); - select_ducks_in_box(drag_point,mouse_pos); + select_ducks_in_box(drag_point,mouse_pos); + } ret=true; } else - { + { if(allow_layer_clicks) { Layer::Handle layer(get_canvas()->find_layer(drag_point)); //if(layer) { - if(canvas_view->get_smach().process_event(EventLayerClick(layer,BUTTON_LEFT,mouse_pos,modifier))==Smach::RESULT_OK) + if(canvas_view->get_smach().process_event(EventLayerClick(layer,BUTTON_LEFT,mouse_pos,modifier))==Smach::RESULT_OK) signal_layer_selected_(layer); ret=true; } @@ -1646,12 +1713,12 @@ WorkArea::on_drawing_area_event(GdkEvent *event) } } } - + dragging=DRAG_NONE; if(canvas_view->get_smach().process_event(EventMouse(EVENT_WORKAREA_MOUSE_BUTTON_UP,MouseButton(event->button.button),mouse_pos,pressure,modifier))==Smach::RESULT_ACCEPT) ret=true; - + return ret; } break; @@ -1666,7 +1733,7 @@ WorkArea::on_drawing_area_event(GdkEvent *event) if(modifier&GDK_CONTROL_MASK) { - + // The zoom is performed while preserving the pointer // position as a fixed point (similarly to Xara Xtreme and // Inkscape). @@ -1689,11 +1756,13 @@ WorkArea::on_drawing_area_event(GdkEvent *event) switch(event->scroll.direction) { case GDK_SCROLL_UP: + case GDK_SCROLL_RIGHT: get_scrollx_adjustment()->set_value(scroll_point[0]+(mouse_pos[0]-scroll_point[0])*(1.25-(1+drift))); get_scrolly_adjustment()->set_value(scroll_point[1]-(mouse_pos[1]+scroll_point[1])*(1.25-(1+drift))); zoom_in(); break; case GDK_SCROLL_DOWN: + case GDK_SCROLL_LEFT: get_scrollx_adjustment()->set_value(scroll_point[0]+(mouse_pos[0]-scroll_point[0])*(1/1.25-(1+drift))); get_scrolly_adjustment()->set_value(scroll_point[1]-(mouse_pos[1]+scroll_point[1])*(1/1.25-(1+drift))); zoom_out(); @@ -1719,12 +1788,18 @@ WorkArea::on_drawing_area_event(GdkEvent *event) case GDK_SCROLL_DOWN: get_scrollx_adjustment()->set_value(get_scrollx_adjustment()->get_value()+scroll_pixel*pw); break; + case GDK_SCROLL_LEFT: + get_scrolly_adjustment()->set_value(get_scrolly_adjustment()->get_value()+scroll_pixel*ph); + break; + case GDK_SCROLL_RIGHT: + get_scrolly_adjustment()->set_value(get_scrolly_adjustment()->get_value()-scroll_pixel*ph); + break; default: break; } } else - { + { // Scroll in either direction by 20 pixels. Ideally, the // amount of pixels per scrolling event should be // configurable. Xara Xtreme currently uses an (hard @@ -1740,6 +1815,12 @@ WorkArea::on_drawing_area_event(GdkEvent *event) case GDK_SCROLL_DOWN: get_scrolly_adjustment()->set_value(get_scrolly_adjustment()->get_value()-scroll_pixel*ph); break; + case GDK_SCROLL_LEFT: + get_scrollx_adjustment()->set_value(get_scrollx_adjustment()->get_value()-scroll_pixel*pw); + break; + case GDK_SCROLL_RIGHT: + get_scrollx_adjustment()->set_value(get_scrollx_adjustment()->get_value()+scroll_pixel*pw); + break; default: break; } @@ -1753,7 +1834,7 @@ WorkArea::on_drawing_area_event(GdkEvent *event) } bool -WorkArea::on_hruler_event(GdkEvent *event) +WorkArea::on_hruler_event(GdkEvent */*event*/) { /* switch(event->type) @@ -1783,17 +1864,17 @@ WorkArea::on_hruler_event(GdkEvent *event) x=event->button.x; y=event->button.y; } - + if(isnan(y) || isnan(x)) - return false; - + return false; + *curr_guide=synfig::Point(screen_to_comp_coords(synfig::Point(x,y)))[1]; queue_draw(); } return true; break; - + case GDK_BUTTON_RELEASE: if(dragging==DRAG_GUIDE && curr_guide_is_x==false) { @@ -1810,16 +1891,14 @@ WorkArea::on_hruler_event(GdkEvent *event) } bool -WorkArea::on_vruler_event(GdkEvent *event) +WorkArea::on_vruler_event(GdkEvent */*event*/) { /* switch(event->type) { case GDK_BUTTON_PRESS: - DEBUGPOINT(); if(dragging==DRAG_NONE) { - DEBUGPOINT(); dragging=DRAG_GUIDE; curr_guide=get_guide_list_x().insert(get_guide_list_x().begin()); curr_guide_is_x=true; @@ -1827,10 +1906,8 @@ WorkArea::on_vruler_event(GdkEvent *event) return true; break; case GDK_BUTTON_RELEASE: - DEBUGPOINT(); if(dragging==DRAG_GUIDE && curr_guide_is_x==true) { - DEBUGPOINT(); dragging=DRAG_NONE; get_guide_list_x().erase(curr_guide); } @@ -1853,7 +1930,7 @@ WorkArea::refresh_dimension_info() canvasheight=rend_desc.get_br()[1]-rend_desc.get_tl()[1]; pw=canvaswidth/w; - ph=canvasheight/h; + ph=canvasheight/h; scrollx_adjustment.set_page_increment(abs(get_grid_size()[0])); scrollx_adjustment.set_step_increment(abs(pw)); @@ -1865,20 +1942,20 @@ WorkArea::refresh_dimension_info() scrolly_adjustment.set_page_increment(abs(get_grid_size()[1])); - + if(drawing_area->get_width()<=0 || drawing_area->get_height()<=0 || w==0 || h==0) return; - + const synfig::Point focus_point(get_focus_point()); const synfig::Real x(focus_point[0]/pw+drawing_area->get_width()/2-w/2); const synfig::Real y(focus_point[1]/ph+drawing_area->get_height()/2-h/2); - + window_tl[0]=rend_desc.get_tl()[0]-pw*x; window_br[0]=rend_desc.get_br()[0]+pw*(drawing_area->get_width()-x-w); window_tl[1]=rend_desc.get_tl()[1]-ph*y; window_br[1]=rend_desc.get_br()[1]+ph*(drawing_area->get_height()-y-h); - + hruler->property_lower()=Distance(window_tl[0],Distance::SYSTEM_UNITS).get(App::distance_system,rend_desc); hruler->property_upper()=Distance(window_br[0],Distance::SYSTEM_UNITS).get(App::distance_system,rend_desc); vruler->property_lower()=Distance(window_tl[1],Distance::SYSTEM_UNITS).get(App::distance_system,rend_desc); @@ -1904,7 +1981,7 @@ WorkArea::screen_to_comp_coords(synfig::Point pos)const } synfig::Point -WorkArea::comp_to_screen_coords(synfig::Point pos)const +WorkArea::comp_to_screen_coords(synfig::Point /*pos*/)const { synfig::warning("WorkArea::comp_to_screen_coords: Not yet implemented"); return synfig::Point(); @@ -1918,32 +1995,33 @@ WorkArea::next_unrendered_tile(int refreshes)const return -1; //const synfig::RendDesc &rend_desc(get_canvas()->rend_desc()); - + const synfig::Vector focus_point(get_focus_point()); - + // Calculate the window coordinates of the top-left // corner of the canvas. const synfig::Vector::value_type x(focus_point[0]/pw+drawing_area->get_width()/2-w/2), y(focus_point[1]/ph+drawing_area->get_height()/2-h/2); - - const int width_in_tiles(w/tile_w+(w%tile_w?1:0)); + + int div = low_res_pixel_size; + const int width_in_tiles(w/tile_w+((low_resolution?((w/div)%(tile_w/div)):(w%tile_w))?1:0)); const int height_in_tiles(h/tile_h+(h%tile_h?1:0)); - + int u(0),v(0), u1(int(-x/tile_w)), v1(int(-y/tile_h)), u2(int((-x+drawing_area->get_width())/tile_w+1)), v2(int((-y+drawing_area->get_height())/tile_h+1)); - + if(u2>width_in_tiles)u2=width_in_tiles; if(v2>height_in_tiles)v2=height_in_tiles; if(u1<0)u1=0; if(v1<0)v1=0; - + int last_good_tile(-1); - + for(v=v1;v x) { return func(*x); } }; @@ -1999,14 +2077,14 @@ WorkArea::refresh(GdkEventExpose*event) assert(get_canvas()); drawing_area->get_window()->clear(); - + //const synfig::RendDesc &rend_desc(get_canvas()->rend_desc()); - + const synfig::Vector focus_point(get_focus_point()); - + // Update the old focus point last_focus_point=focus_point; - + // Draw out the renderables { std::set >::iterator iter; @@ -2019,8 +2097,7 @@ WorkArea::refresh(GdkEventExpose*event) ); } } - - + // Calculate the window coordinates of the top-left // corner of the canvas. //const synfig::Vector::value_type @@ -2031,32 +2108,34 @@ WorkArea::refresh(GdkEventExpose*event) //const synfig::Vector::value_type window_endx(window_br[0]); //const synfig::Vector::value_type window_starty(window_tl[1]); //const synfig::Vector::value_type window_endy(window_br[1]); - - Glib::RefPtr gc=Gdk::GC::create(drawing_area->get_window()); - + Glib::RefPtr gc=Gdk::GC::create(drawing_area->get_window()); // If we are in animate mode, draw a red border around the screen if(canvas_interface->get_mode()&synfigapp::MODE_ANIMATE) { - /*gc->set_rgb_fg_color(Gdk::Color("#FF0000")); - gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER); +// #define USE_FRAME_BACKGROUND_TO_SHOW_EDIT_MODE +#ifdef USE_FRAME_BACKGROUND_TO_SHOW_EDIT_MODE + // This method of drawing the red border doesn't work on any + // Gtk theme which uses the crux-engine, hcengine, industrial, + // mist, or ubuntulooks engine, such as the default ubuntu + // 'Human' theme. + drawing_frame->modify_bg(Gtk::STATE_NORMAL,Gdk::Color("#FF0000")); +#else + // So let's do it in a more primitive fashion. + gc->set_rgb_fg_color(Gdk::Color("#FF0000")); + gc->set_line_attributes(1,Gdk::LINE_SOLID,Gdk::CAP_BUTT,Gdk::JOIN_MITER); drawing_area->get_window()->draw_rectangle( gc, false, // Fill? 0,0, // x,y - drawing_area->get_width()-1,drawing_area->get_height()-1 //w,h - ); - */ - drawing_frame->modify_bg(Gtk::STATE_NORMAL,Gdk::Color("#FF0000")); - //get_window()->set_background(Gdk::Color("#FF0000")); + drawing_area->get_width()-1,drawing_area->get_height()-1); // w,h +#endif } +#ifdef USE_FRAME_BACKGROUND_TO_SHOW_EDIT_MODE else drawing_frame->unset_bg(Gtk::STATE_NORMAL); - - - - previous_focus=get_focus_point(); +#endif return true; } @@ -2090,7 +2169,17 @@ WorkArea::set_quality(int x) queue_render_preview(); } +void +WorkArea::set_low_res_pixel_size(int x) +{ + if(x==low_res_pixel_size) + return; + low_res_pixel_size=x; + queue_render_preview(); +} +namespace studio +{ class WorkAreaProgress : public synfig::ProgressCallback { WorkArea *work_area; @@ -2128,10 +2217,20 @@ public: return cb->amount_complete(current,total); } }; +} bool studio::WorkArea::async_update_preview() { +#ifdef SINGLE_THREADED + if (get_updating()) + { + stop_updating(); + queue_render_preview(); + return false; + } +#endif + async_renderer=0; queued=false; @@ -2141,43 +2240,52 @@ studio::WorkArea::async_update_preview() // This object will mark us as busy until // we are done. //studio::App::Busy busy; - + //WorkAreaProgress callback(this,get_canvas_view()->get_ui_interface().get()); //synfig::ProgressCallback *cb=&callback; if(!is_visible())return false; - + /* // If we are queued to render the scene at the next idle - // go ahead and de-queue it. + // go ahead and de-queue it. if(render_idle_func_id) { - g_source_remove(render_idle_func_id); + g_source_remove(render_idle_func_id); //queued=false; render_idle_func_id=0; } */ - + dirty=false; get_canvas_view()->reset_cancel_status(); - + //bool ret=false; RendDesc desc=get_canvas()->rend_desc(); - + int w=(int)(desc.get_w()*zoom); int h=(int)(desc.get_h()*zoom); - + + // ensure that the size we draw is at least one pixel in each dimension + int min_size = low_resolution ? low_res_pixel_size : 1; + if (w < min_size) w = min_size; + if (h < min_size) h = min_size; + // Setup the description parameters - desc.set_antialias(1); + desc.set_antialias(1); desc.set_time(cur_time); - + set_rend_desc(desc); // Create the render target handle target; - - if(w*h>(low_resolution?480*270:480*270/2)) + + // if we have lots of pixels to render and the tile renderer isn't disabled, use it + int div; + div = low_resolution ? low_res_pixel_size : 1; + if ((w*h > 240*div*135*div && !getenv("SYNFIG_DISABLE_TILE_RENDER")) || getenv("SYNFIG_FORCE_TILE_RENDER")) { + // do a tile render handle trgt(new class WorkAreaTarget(this,w,h)); trgt->set_rend_desc(&desc); @@ -2186,13 +2294,14 @@ studio::WorkArea::async_update_preview() } else { + // do a scanline render handle trgt(new class WorkAreaTarget_Full(this,w,h)); trgt->set_rend_desc(&desc); trgt->set_onion_skin(get_onion_skin()); target=trgt; } - + // We can rest assured that our time has already // been set, so there is no need to have to // recalculate that over again. @@ -2210,13 +2319,13 @@ studio::WorkArea::async_update_preview() synfig::ProgressCallback *cb=get_canvas_view()->get_ui_interface().get(); rendering=true; - cb->task("Rendering..."); + cb->task(_("Rendering...")); rendering=true; - + return true; } -void +void studio::WorkArea::async_update_finished() { synfig::ProgressCallback *cb=get_canvas_view()->get_ui_interface().get(); @@ -2225,19 +2334,19 @@ studio::WorkArea::async_update_finished() if(!async_renderer) return; - - // If we completed successfuly, then + + // If we completed successfully, then // we aren't dirty anymore if(async_renderer->has_success()) { dirty=false; //queued=false; - cb->task("Idle"); + cb->task(_("Idle")); } else { dirty=true; - cb->task("Render Failed"); + cb->task(_("Render Failed")); } //get_canvas_view()->reset_cancel_status(); done_rendering(); @@ -2257,10 +2366,10 @@ again: // This object will mark us as busy until // we are done. studio::App::Busy busy; - + WorkAreaProgress callback(this,get_canvas_view()->get_ui_interface().get()); synfig::ProgressCallback *cb=&callback; - + // We don't want to render if we are already rendering if(rendering) { @@ -2269,36 +2378,35 @@ again: } if(!is_visible())return false; - get_canvas()->set_time(get_time()); + get_canvas()->set_time(get_time()); get_canvas_view()->get_smach().process_event(EVENT_REFRESH_DUCKS); signal_rendering()(); - + // If we are queued to render the scene at the next idle - // go ahead and de-queue it. + // go ahead and de-queue it. if(render_idle_func_id) { - g_source_remove(render_idle_func_id); + g_source_remove(render_idle_func_id); //queued=false; render_idle_func_id=0; } // Start rendering rendering=true; - + dirty=false; get_canvas_view()->reset_cancel_status(); - - bool ret=false; + RendDesc desc=get_canvas()->rend_desc(); //newdesc->set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN); - + int w=(int)(desc.get_w()*zoom); int h=(int)(desc.get_h()*zoom); - + // Setup the description parameters - desc.set_antialias(1); + desc.set_antialias(1); desc.set_time(cur_time); //desc.set_wh(w,h); - + set_rend_desc(desc); // Create the render target @@ -2310,12 +2418,12 @@ again: // been set, so there is no need to have to // recalculate that over again. target->set_avoid_time_sync(true); - + if(cb) - cb->task(strprintf("Rendering canvas %s...",get_canvas()->get_name().c_str())); + cb->task(strprintf(_("Rendering canvas %s..."),get_canvas()->get_name().c_str())); + + bool ret = target->render(cb); - target->render(cb); - if(!ret && !get_canvas_view()->get_cancel_status() && dirty) { rendering=false; @@ -2324,21 +2432,21 @@ again: } if(get_canvas_view()->get_cancel_status()) canceled_=true; - + if(cb) { if(ret) - cb->task("Idle"); + cb->task(_("Idle")); else - cb->task("Render Failed"); - cb->amount_complete(0,1); + cb->task(_("Render Failed")); + cb->amount_complete(0,1); } // Refresh the work area to make sure that // it is being displayed correctly drawing_area->queue_draw(); - - // If we completed successfuly, then + + // If we completed successfully, then // we aren't dirty anymore if(ret) { @@ -2353,7 +2461,7 @@ again: } void -studio::WorkArea::async_render_preview(Time time) +studio::WorkArea::async_render_preview(synfig::Time time) { cur_time=time; //tile_book.clear(); @@ -2361,7 +2469,7 @@ studio::WorkArea::async_render_preview(Time time) refreshes+=5; if(!is_visible())return; - get_canvas()->set_time(get_time()); + get_canvas()->set_time(get_time()); get_canvas_view()->get_smach().process_event(EVENT_REFRESH_DUCKS); signal_rendering()(); @@ -2374,7 +2482,7 @@ WorkArea::async_render_preview() } bool -studio::WorkArea::sync_render_preview(Time time) +studio::WorkArea::sync_render_preview(synfig::Time time) { cur_time=time; //tile_book.clear(); @@ -2399,9 +2507,9 @@ void WorkArea::queue_scroll() { // const synfig::RendDesc &rend_desc(get_canvas()->rend_desc()); - + const synfig::Point focus_point(get_focus_point()); - + const synfig::Real new_x(focus_point[0]/pw+drawing_area->get_width()/2-w/2), new_y(focus_point[1]/ph+drawing_area->get_height()/2-h/2); @@ -2415,18 +2523,46 @@ WorkArea::queue_scroll() return; const int - dx(round_to_int(old_x)-round_to_int(new_x)), + dx(round_to_int(old_x)-round_to_int(new_x)), dy(round_to_int(old_y)-round_to_int(new_y)); - + drawing_area->get_window()->scroll(-dx,-dy); - /*drawing_area->queue_draw_area( - 0, - 0, - 128, - 64 - ); - */ + if (timecode_width && timecode_height) + { + drawing_area->queue_draw_area(4, 4, 4+timecode_width, 4+timecode_height); + drawing_area->queue_draw_area(4-dx, 4-dy, 4-dx+timecode_width, 4-dy+timecode_height); + } + +#ifndef USE_FRAME_BACKGROUND_TO_SHOW_EDIT_MODE + if(canvas_interface->get_mode()&synfigapp::MODE_ANIMATE) + { + int maxx = drawing_area->get_width()-1; + int maxy = drawing_area->get_height()-1; + + if (dx > 0) + { + drawing_area->queue_draw_area( 0, 0, 1, maxy); + drawing_area->queue_draw_area(maxx-dx, 0, maxx-dx, maxy); + } + else if (dx < 0) + { + drawing_area->queue_draw_area( maxx, 0, maxx, maxy); + drawing_area->queue_draw_area( -dx, 0, -dx, maxy); + } + if (dy > 0) + { + drawing_area->queue_draw_area(0, 0, maxx, 1); + drawing_area->queue_draw_area(0, maxy-dy, maxx, maxy-dy); + } + else if (dy < 0) + { + drawing_area->queue_draw_area(0, maxy, maxx, maxy); + drawing_area->queue_draw_area(0, -dy, maxx, -dy); + } + } +#endif // USE_FRAME_BACKGROUND_TO_SHOW_EDIT_MODE + last_focus_point=focus_point; } @@ -2445,28 +2581,35 @@ studio::WorkArea::zoom_out() void studio::WorkArea::zoom_fit() { - // This really doesn't zoom to fit. Bug. - zoom_norm(); + float new_zoom(min(drawing_area->get_width() * zoom / w, + drawing_area->get_height() * zoom / h) * 0.995); + if (zoom / new_zoom > 0.995 && new_zoom / zoom > 0.995) + { + set_zoom(prev_zoom); + return set_focus_point(previous_focus); + } + previous_focus = get_focus_point(); + prev_zoom = zoom; + set_zoom(new_zoom); + set_focus_point(Point(0,0)); } void studio::WorkArea::zoom_norm() { - if(zoom==1.0) - set_zoom(prev_zoom); - else - { - prev_zoom=zoom; - set_zoom(1.0f); - } + if (zoom == 1.0) return set_zoom(prev_zoom); + prev_zoom = zoom; + set_zoom(1.0f); } gboolean studio::WorkArea::__render_preview(gpointer data) { - WorkArea *work_area(static_cast(data)); + // there's no point anyone trying to cancel the timer now - it's gone off already + work_area->render_idle_func_id = 0; + work_area->queued=false; work_area->async_render_preview(work_area->get_canvas_view()->get_time()); @@ -2489,24 +2632,29 @@ studio::WorkArea::queue_render_preview() */ //async_renderer=0; } - + if(dirty_trap_enabled) { dirty_trap_queued++; return; } - + int queue_time=50; - + if(rendering) queue_time+=250; - + if(queued==false) { //synfig::info("queue_render_preview(): (re)queuing..."); //render_idle_func_id=g_idle_add_full(G_PRIORITY_DEFAULT,__render_preview,this,NULL); - render_idle_func_id=g_timeout_add_full(G_PRIORITY_DEFAULT,queue_time,__render_preview,this,NULL); + render_idle_func_id=g_timeout_add_full( + G_PRIORITY_DEFAULT, // priority - + queue_time, // interval - the time between calls to the function, in milliseconds (1/1000ths of a second) + __render_preview, // function - function to call + this, // data - data to pass to function + NULL); // notify - function to call when the idle is removed, or NULL queued=true; } /* else if(rendering) @@ -2521,7 +2669,7 @@ studio::WorkArea::queue_render_preview() DirtyTrap::DirtyTrap(WorkArea *work_area):work_area(work_area) { work_area->dirty_trap_enabled=true; - + work_area->dirty_trap_queued=0; } @@ -2549,12 +2697,12 @@ studio::WorkArea::set_cursor(Gdk::CursorType x) drawing_area->get_window()->set_cursor(Gdk::Cursor(x)); } -#include "iconcontroler.h" +#include "iconcontroller.h" void studio::WorkArea::refresh_cursor() { -// set_cursor(IconControler::get_tool_cursor(canvas_view->get_smach().get_state_name(),drawing_area->get_window())); +// set_cursor(IconController::get_tool_cursor(canvas_view->get_smach().get_state_name(),drawing_area->get_window())); } void