X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=synfig-studio%2Ftrunk%2Fsrc%2Fgtkmm%2Fworkarea.cpp;h=8f7360402f789e4d6ee479a15df61440169d694c;hb=63e709f66d50c124cc0ece2325f4773ac4ae7b20;hp=740f791e0792d1872cd263e6fde77ed6fdeea416;hpb=3a3c4bca3a17137bec5d7960560934b91ef4146e;p=synfig.git diff --git a/synfig-studio/trunk/src/gtkmm/workarea.cpp b/synfig-studio/trunk/src/gtkmm/workarea.cpp index 740f791..8f73604 100644 --- a/synfig-studio/trunk/src/gtkmm/workarea.cpp +++ b/synfig-studio/trunk/src/gtkmm/workarea.cpp @@ -1,20 +1,23 @@ -/* === S I N F G =========================================================== */ +/* === S Y N F I G ========================================================= */ /*! \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 Robert B. Quattlebaum Jr. +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright 2006 Yue Shi Lai +** Copyright (c) 2007 Chris Moore ** -** This software and associated documentation -** are CONFIDENTIAL and PROPRIETARY property of -** the above-mentioned copyright holder. +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. ** -** You may not copy, print, publish, or in any -** other way distribute this software without -** a prior written agreement with -** the copyright holder. +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. ** \endlegal */ /* ========================================================================= */ @@ -46,14 +49,15 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "event_mouse.h" #include "event_layerclick.h" #include "widget_color.h" -#include +#include #include "workarearenderer.h" #include "renderer_canvas.h" @@ -66,7 +70,9 @@ #include "asyncrenderer.h" #include -#include +#include + +#include "general.h" #endif @@ -74,7 +80,7 @@ using namespace std; using namespace etl; -using namespace sinfg; +using namespace synfig; using namespace studio; /* === M A C R O S ========================================================= */ @@ -91,7 +97,7 @@ using namespace studio; /* === C L A S S E S ======================================================= */ -class WorkAreaTarget : public sinfg::Target_Tile +class studio::WorkAreaTarget : public synfig::Target_Tile { public: WorkArea *workarea; @@ -102,25 +108,25 @@ public: int twindow_start, twindow_width, twindow_height, twindow_pad; int refresh_id; - + bool onionskin; bool onion_first_tile; int onion_layers; - std::list onion_skin_queue; + std::list onion_skin_queue; - sinfg::Mutex mutex; + synfig::Mutex mutex; 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( @@ -131,7 +137,7 @@ public: } catch(...) { } - + try { onion_skin_queue.push_back( @@ -142,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()), @@ -176,13 +182,13 @@ public: set_canvas(workarea->get_canvas()); set_quality(workarea->get_quality()); } - + ~WorkAreaTarget() { workarea->queue_draw(); } - virtual bool set_rend_desc(sinfg::RendDesc *newdesc) + virtual bool set_rend_desc(synfig::RendDesc *newdesc) { assert(workarea); newdesc->set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN); @@ -195,7 +201,7 @@ public: workarea->get_w()!=w || workarea->get_h()!=h ) workarea->set_wh(w,h,4); - + workarea->full_frame=false; desc=*newdesc; @@ -213,13 +219,13 @@ public: virtual int next_frame(Time& time) { - sinfg::Mutex::Lock lock(mutex); - + synfig::Mutex::Lock lock(mutex); + if(!onionskin) - return sinfg::Target_Tile::next_frame(time); - + 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(); @@ -227,25 +233,25 @@ public: } else return 0; - + return onion_skin_queue.size()+1; } virtual int next_tile(int& x, int& y) { - sinfg::Mutex::Lock lock(mutex); + 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(); @@ -258,10 +264,10 @@ public: return total_tiles()-curr_tile+1; } - - virtual bool start_frame(sinfg::ProgressCallback *cb) + + virtual bool start_frame(synfig::ProgressCallback */*cb*/) { - sinfg::Mutex::Lock lock(mutex); + synfig::Mutex::Lock lock(mutex); int tw(rend_desc().get_w()/get_tile_w()); if(rend_desc().get_w()%get_tile_w()!=0)tw++; @@ -277,17 +283,17 @@ 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 sinfg::Surface &surface, int x, int y) + + virtual bool add_tile(const synfig::Surface &surface, int x, int y) { - sinfg::Mutex::Lock lock(mutex); + synfig::Mutex::Lock lock(mutex); assert(surface); - + PixelFormat pf(PF_RGB); - - const int total_bytes(get_tile_w()*get_tile_h()*sinfg::channels(pf)); + + const int total_bytes(get_tile_w()*get_tile_h()*synfig::channels(pf)); unsigned char *buffer((unsigned char*)malloc(total_bytes)); @@ -324,7 +330,7 @@ public: return false; Glib::RefPtr pixbuf; - + pixbuf=Gdk::Pixbuf::create_from_data( buffer, // pointer to the data Gdk::COLORSPACE_RGB, // the colorspace @@ -332,9 +338,9 @@ public: 8, // bits per sample surface.get_w(), // width surface.get_h(), // height - surface.get_w()*sinfg::channels(pf), // stride (pitch) + surface.get_w()*synfig::channels(pf), // stride (pitch) sigc::ptr_fun(&WorkAreaTarget::free_buff) - ); + ); if(low_res) { @@ -345,9 +351,9 @@ public: Gdk::INTERP_NEAREST ); } - + if(!onionskin || onion_first_tile || !workarea->tile_book[index].first) - { + { workarea->tile_book[index].first=pixbuf; } else @@ -366,9 +372,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; } @@ -380,7 +386,7 @@ public: }; -class WorkAreaTarget_Full : public sinfg::Target_Scanline +class studio::WorkAreaTarget_Full : public synfig::Target_Scanline { public: WorkArea *workarea; @@ -391,27 +397,27 @@ public: int twindow_start, twindow_width, twindow_height, twindow_pad; int refresh_id; - + bool onionskin; bool onion_first_tile; int onion_layers; Surface surface; - std::list onion_skin_queue; + std::list onion_skin_queue; 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( @@ -422,7 +428,7 @@ public: } catch(...) { } - + try { onion_skin_queue.push_back( @@ -433,13 +439,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()), @@ -452,12 +458,12 @@ public: set_canvas(workarea->get_canvas()); set_quality(workarea->get_quality()); } - + ~WorkAreaTarget_Full() { } - virtual bool set_rend_desc(sinfg::RendDesc *newdesc) + virtual bool set_rend_desc(synfig::RendDesc *newdesc) { assert(workarea); newdesc->set_flags(RendDesc::PX_ASPECT|RendDesc::IM_SPAN); @@ -470,7 +476,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; @@ -488,22 +494,22 @@ public: workarea->tile_book[0].second=refresh_id; if(!onionskin) - return sinfg::Target_Scanline::next_frame(time); - + 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(sinfg::ProgressCallback *cb) + + virtual bool start_frame(synfig::ProgressCallback */*cb*/) { return true; } @@ -519,14 +525,14 @@ 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()*sinfg::channels(pf)); + + const int total_bytes(surface.get_w()*surface.get_h()*synfig::channels(pf)); unsigned char *buffer((unsigned char*)malloc(total_bytes)); @@ -562,7 +568,7 @@ public: } Glib::RefPtr pixbuf; - + pixbuf=Gdk::Pixbuf::create_from_data( buffer, // pointer to the data Gdk::COLORSPACE_RGB, // the colorspace @@ -570,9 +576,9 @@ public: 8, // bits per sample surface.get_w(), // width surface.get_h(), // height - surface.get_w()*sinfg::channels(pf), // stride (pitch) + surface.get_w()*synfig::channels(pf), // stride (pitch) sigc::ptr_fun(&WorkAreaTarget::free_buff) - ); + ); if(low_res) { @@ -583,11 +589,11 @@ public: Gdk::INTERP_NEAREST ); } - + int index=0; - + if(!onionskin || onion_first_tile || !workarea->tile_book[index].first) - { + { workarea->tile_book[index].first=pixbuf; } else @@ -606,8 +612,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); } }; @@ -618,18 +624,23 @@ public: /* === M E T H O D S ======================================================= */ -WorkArea::WorkArea(etl::loose_handle canvas_interface): +WorkArea::WorkArea(etl::loose_handle canvas_interface): Gtk::Table(4+RULER_FIX, 3, false), canvas_interface(canvas_interface), 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), + last_event_time(0), progresscallback(0), dragging(DRAG_NONE), show_grid(false), tile_w(128), - tile_h(128) -{ + tile_h(128), + timecode_width(0), + timecode_height(0) +{ show_guides=true; curr_input_device=0; full_frame=false; @@ -638,7 +649,7 @@ WorkArea::WorkArea(etl::loose_handle canvas_interface render_idle_func_id=0; zoom=prev_zoom=1.0; quality=10; - rendering=false; + rendering=false; canceled_=false; low_resolution=true; pw=0.001; @@ -648,7 +659,7 @@ WorkArea::WorkArea(etl::loose_handle canvas_interface queued=false; dirty_trap_enabled=false; solid_lines=true; - + dirty_trap_queued=0; meta_data_lock=false; @@ -669,7 +680,7 @@ WorkArea::WorkArea(etl::loose_handle canvas_interface // 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); @@ -691,12 +702,12 @@ WorkArea::WorkArea(etl::loose_handle canvas_interface 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("sinfg-small_icon"); + Gtk::IconSize iconsize=Gtk::IconSize::from_name("synfig-small_icon"); // Create the vertical and horizontal rulers @@ -721,7 +732,7 @@ WorkArea::WorkArea(etl::loose_handle canvas_interface 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())); @@ -742,15 +753,15 @@ WorkArea::WorkArea(etl::loose_handle canvas_interface 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)); @@ -774,14 +785,14 @@ WorkArea::WorkArea(etl::loose_handle canvas_interface 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)); } } @@ -794,6 +805,24 @@ WorkArea::WorkArea(etl::loose_handle canvas_interface 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; +} + +bool +WorkArea::get_updating()const +{ + return App::single_threaded && async_renderer && async_renderer->updating; +} + +void +WorkArea::stop_updating(bool cancel) +{ + async_renderer->stop(); + if (cancel) canceled_=true; } void @@ -821,7 +850,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) { @@ -832,7 +861,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())) @@ -850,7 +879,7 @@ WorkArea::load_meta_data() if(meta_data_lock) return; meta_data_lock=true; - + String data; data=canvas->get_meta_data("grid_size"); @@ -859,11 +888,11 @@ 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); - + if(iter==data.end()) tmp.clear(); else @@ -871,11 +900,11 @@ WorkArea::load_meta_data() if(!tmp.empty()) gy=stratof(tmp); - + set_grid_size(Vector(gx,gy)); } else - sinfg::error("WorkArea::load_meta_data(): Unable to parse data for \"grid_size\", which was \"%s\"",data.c_str()); + 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')) @@ -912,34 +941,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 @@ -976,7 +1005,7 @@ WorkArea::enable_grid() queue_draw(); } -void +void WorkArea::disable_grid() { show_grid=false; @@ -1023,7 +1052,7 @@ WorkArea::popup_menu() } void -WorkArea::set_grid_size(const sinfg::Vector &s) +WorkArea::set_grid_size(const synfig::Vector &s) { Duckmatic::set_grid_size(s); save_meta_data(); @@ -1031,32 +1060,32 @@ WorkArea::set_grid_size(const sinfg::Vector &s) } void -WorkArea::set_focus_point(const sinfg::Point &point) +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 sinfg::Point& adjusted(point); - - sinfg::RendDesc &rend_desc(get_canvas()->rend_desc()); + 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); } -sinfg::Point +synfig::Point WorkArea::get_focus_point()const { - sinfg::RendDesc &rend_desc(get_canvas()->rend_desc()); + 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 sinfg::Point(get_scrollx_adjustment()->get_value()*x_factor, get_scrolly_adjustment()->get_value()*y_factor); + + return synfig::Point(get_scrollx_adjustment()->get_value()*x_factor, get_scrolly_adjustment()->get_value()*y_factor); } bool @@ -1069,11 +1098,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; @@ -1082,7 +1111,7 @@ WorkArea::set_wh(int W, int H,int CHAN) refresh_dimension_info(); tile_book.clear(); - + return true; } @@ -1093,10 +1122,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) { @@ -1116,15 +1145,15 @@ WorkArea::on_key_press_event(GdkEventKey* event) return false; break; } - - sinfgapp::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(); @@ -1137,23 +1166,23 @@ WorkArea::on_key_press_event(GdkEventKey* event) set_grid_snap(grid_snap_holder); set_guide_snap(guide_snap_holder); - + return true; } bool WorkArea::on_drawing_area_event(GdkEvent *event) { - sinfg::Point mouse_pos; + synfig::Point mouse_pos; float bezier_click_pos; const float radius((abs(pw)+abs(ph))*4); int button_pressed(0); 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 || @@ -1174,8 +1203,8 @@ WorkArea::on_drawing_area_event(GdkEvent *event) device=event->button.device; modifier=Gdk::ModifierType(event->button.state); } - - // Make sure we recognise the device + + // Make sure we recognize the device if(curr_input_device) { if(curr_input_device!=device) @@ -1184,21 +1213,21 @@ 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 if(!event->button.axes) { - mouse_pos=sinfg::Point(screen_to_comp_coords(sinfg::Point(event->button.x,event->button.y))); + mouse_pos=synfig::Point(screen_to_comp_coords(synfig::Point(event->button.x,event->button.y))); button_pressed=event->button.button; pressure=1.0f; is_mouse=true; @@ -1213,32 +1242,42 @@ WorkArea::on_drawing_area_event(GdkEvent *event) return false; pressure=event->button.axes[2]; - //sinfg::info("pressure=%f",pressure); + //synfig::info("pressure=%f",pressure); pressure-=0.04f; pressure/=1.0f-0.04f; - - + + assert(!isnan(pressure)); - - mouse_pos=sinfg::Point(screen_to_comp_coords(sinfg::Point(x,y))); - + + 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) pressure=0; //if(event->any.type==GDK_BUTTON_PRESS && button_pressed) - // sinfg::info("Button pressed on input device = %d",event->button.button); - + // 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 interpret mouse + // scrolling events are: scroll.state, scroll.x/scroll.y, and + // scroll.direction. The value of scroll.direction will be + // obtained later. + modifier=Gdk::ModifierType(event->scroll.state); + mouse_pos=synfig::Point(screen_to_comp_coords(synfig::Point(event->scroll.x,event->scroll.y))); + } // Handle the renderables { @@ -1262,49 +1301,70 @@ 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()) { //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()))) + { + 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 { + // 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(); @@ -1314,7 +1374,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 @@ -1332,7 +1392,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()) { @@ -1380,33 +1440,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) { @@ -1436,16 +1492,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; @@ -1461,7 +1517,7 @@ WorkArea::on_drawing_area_event(GdkEvent *event) } } - + if(dragging==DRAG_DUCK) { if(canvas_view->get_cancel_status()) @@ -1479,20 +1535,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) @@ -1501,30 +1559,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 sinfg::Point point(mouse_pos); + 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); @@ -1537,12 +1599,12 @@ WorkArea::on_drawing_area_event(GdkEvent *event) } else if(dragging==DRAG_DUCK) - { - sinfgapp::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; @@ -1550,37 +1612,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) { - //sinfg::info("DUCK_DRAG_RELEASE: SHIFT-MASK ON!"); - if(clicked_duck) - { - //sinfg::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) - { - //sinfg::info("DUCK_DRAG_RELEASE: CONTROL-MASK ON!"); - if(clicked_duck) - { - //sinfg::info("DUCK_DRAG_RELEASE: CLICKED DUCK!"); - unselect_duck(clicked_duck); - } - } - else - { - //sinfg::info("DUCK_DRAG_RELEASE: NO MASK!"); - if(clicked_duck) + else { - //sinfg::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 { @@ -1599,28 +1644,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; } @@ -1631,15 +1685,120 @@ 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; + case GDK_SCROLL: + { + // Handle a mouse scrolling event like Xara Xtreme and + // Inkscape: + + // Scroll up/down: scroll up/down + // Shift + scroll up/down: scroll left/right + // Control + scroll up/down: zoom in/out + + if(modifier&GDK_CONTROL_MASK) + { + + // The zoom is performed while preserving the pointer + // position as a fixed point (similarly to Xara Xtreme and + // Inkscape). + + // The strategy used below is to scroll to the updated + // position, then zoom. This is easy to implement within + // the present architecture, but has the disadvantage of + // triggering multiple visible refreshes. Note: 1.25 is + // the hard wired ratio in zoom_in()/zoom_out(). The + // variable "drift" compensates additional inaccuracies in + // the zoom. There is also an additional minus sign for + // the inverted y coordinates. + + // FIXME: One might want to figure out where in the code + // this empirical drift is been introduced. + + const synfig::Point scroll_point(get_scrollx_adjustment()->get_value(),get_scrolly_adjustment()->get_value()); + const double drift = 0.052; + + 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(); + break; + default: + break; + } + } + else if(modifier&GDK_SHIFT_MASK) + { + // Scroll in either direction by 20 pixels. Ideally, the + // amount of pixels per scrolling event should be + // configurable. Xara Xtreme currently uses an (hard + // wired) amount 20 pixel, Inkscape defaults to 40 pixels. + + const int scroll_pixel = 20; + + switch(event->scroll.direction) + { + case GDK_SCROLL_UP: + get_scrollx_adjustment()->set_value(get_scrollx_adjustment()->get_value()-scroll_pixel*pw); + break; + 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 + // wired) amount 20 pixel, Inkscape defaults to 40 pixels. + + const int scroll_pixel = 20; + + switch(event->scroll.direction) + { + case GDK_SCROLL_UP: + get_scrolly_adjustment()->set_value(get_scrolly_adjustment()->get_value()+scroll_pixel*ph); + break; + 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; + } + } + } + break; default: break; } @@ -1647,7 +1806,7 @@ WorkArea::on_drawing_area_event(GdkEvent *event) } bool -WorkArea::on_hruler_event(GdkEvent *event) +WorkArea::on_hruler_event(GdkEvent */*event*/) { /* switch(event->type) @@ -1677,17 +1836,17 @@ WorkArea::on_hruler_event(GdkEvent *event) x=event->button.x; y=event->button.y; } - + if(isnan(y) || isnan(x)) - return false; - - *curr_guide=sinfg::Point(screen_to_comp_coords(sinfg::Point(x,y)))[1]; + 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) { @@ -1704,16 +1863,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; @@ -1721,10 +1878,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); } @@ -1741,13 +1896,13 @@ WorkArea::on_vruler_event(GdkEvent *event) void WorkArea::refresh_dimension_info() { - sinfg::RendDesc &rend_desc(get_canvas()->rend_desc()); + synfig::RendDesc &rend_desc(get_canvas()->rend_desc()); canvaswidth=rend_desc.get_br()[0]-rend_desc.get_tl()[0]; 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)); @@ -1759,20 +1914,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 sinfg::Point focus_point(get_focus_point()); - const sinfg::Real x(focus_point[0]/pw+drawing_area->get_width()/2-w/2); - const sinfg::Real y(focus_point[1]/ph+drawing_area->get_height()/2-h/2); - + + 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); @@ -1782,26 +1937,26 @@ WorkArea::refresh_dimension_info() } -sinfg::Point -WorkArea::screen_to_comp_coords(sinfg::Point pos)const +synfig::Point +WorkArea::screen_to_comp_coords(synfig::Point pos)const { - sinfg::RendDesc &rend_desc(get_canvas()->rend_desc()); - //sinfg::Vector::value_type canvaswidth=rend_desc.get_br()[0]-rend_desc.get_tl()[0]; - //sinfg::Vector::value_type canvasheight=rend_desc.get_br()[1]-rend_desc.get_tl()[1]; - //sinfg::Vector::value_type pw=canvaswidth/w; - //sinfg::Vector::value_type ph=canvasheight/h; + synfig::RendDesc &rend_desc(get_canvas()->rend_desc()); + //synfig::Vector::value_type canvaswidth=rend_desc.get_br()[0]-rend_desc.get_tl()[0]; + //synfig::Vector::value_type canvasheight=rend_desc.get_br()[1]-rend_desc.get_tl()[1]; + //synfig::Vector::value_type pw=canvaswidth/w; + //synfig::Vector::value_type ph=canvasheight/h; Vector focus_point=get_focus_point(); - sinfg::Vector::value_type x=focus_point[0]/pw+drawing_area->get_width()/2-w/2; - sinfg::Vector::value_type y=focus_point[1]/ph+drawing_area->get_height()/2-h/2; + synfig::Vector::value_type x=focus_point[0]/pw+drawing_area->get_width()/2-w/2; + synfig::Vector::value_type y=focus_point[1]/ph+drawing_area->get_height()/2-h/2; - return rend_desc.get_tl()-sinfg::Point(pw*x,ph*y)+sinfg::Point(pw*pos[0],ph*pos[1]); + return rend_desc.get_tl()-synfig::Point(pw*x,ph*y)+synfig::Point(pw*pos[0],ph*pos[1]); } -sinfg::Point -WorkArea::comp_to_screen_coords(sinfg::Point pos)const +synfig::Point +WorkArea::comp_to_screen_coords(synfig::Point /*pos*/)const { - sinfg::warning("WorkArea::comp_to_screen_coords: Not yet implemented"); - return sinfg::Point(); + synfig::warning("WorkArea::comp_to_screen_coords: Not yet implemented"); + return synfig::Point(); } int @@ -1811,33 +1966,33 @@ WorkArea::next_unrendered_tile(int refreshes)const if(tile_book.empty()) return -1; - //const sinfg::RendDesc &rend_desc(get_canvas()->rend_desc()); - - const sinfg::Vector focus_point(get_focus_point()); - + //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 sinfg::Vector::value_type + 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)); 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); } }; @@ -1893,14 +2048,14 @@ WorkArea::refresh(GdkEventExpose*event) assert(get_canvas()); drawing_area->get_window()->clear(); - - //const sinfg::RendDesc &rend_desc(get_canvas()->rend_desc()); - - const sinfg::Vector focus_point(get_focus_point()); - + + //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; @@ -1913,44 +2068,47 @@ WorkArea::refresh(GdkEventExpose*event) ); } } - - + // Calculate the window coordinates of the top-left // corner of the canvas. - //const sinfg::Vector::value_type + //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 sinfg::Vector::value_type window_startx(window_tl[0]); - //const sinfg::Vector::value_type window_endx(window_br[0]); - //const sinfg::Vector::value_type window_starty(window_tl[1]); - //const sinfg::Vector::value_type window_endy(window_br[1]); - - Glib::RefPtr gc=Gdk::GC::create(drawing_area->get_window()); - + //const synfig::Vector::value_type window_startx(window_tl[0]); + //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()); // If we are in animate mode, draw a red border around the screen - if(canvas_interface->get_mode()&sinfgapp::MODE_ANIMATE) + 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); +#endif - - - previous_focus=get_focus_point(); + previous_focus=get_focus_point(); return true; } @@ -1985,7 +2143,9 @@ WorkArea::set_quality(int x) } -class WorkAreaProgress : public sinfg::ProgressCallback +namespace studio +{ +class WorkAreaProgress : public synfig::ProgressCallback { WorkArea *work_area; ProgressCallback *cb; @@ -2022,10 +2182,18 @@ public: return cb->amount_complete(current,total); } }; +} bool studio::WorkArea::async_update_preview() { + if (get_updating()) + { + stop_updating(); + queue_render_preview(); + return false; + } + async_renderer=0; queued=false; @@ -2035,43 +2203,46 @@ 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()); - //sinfg::ProgressCallback *cb=&callback; + //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); - + // 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 + if(w*h>(low_resolution?480*270:480*270/2) && + !getenv("SYNFIG_DISABLE_TILE_RENDER")) { + // do a tile render handle trgt(new class WorkAreaTarget(this,w,h)); trgt->set_rend_desc(&desc); @@ -2080,18 +2251,19 @@ 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. // UPDATE: This is kind of needless with - // the way that time is handled now in SINFG. + // the way that time is handled now in SYNFIG. //target->set_avoid_time_sync(true); async_renderer=new AsyncRenderer(target); async_renderer->signal_finished().connect( @@ -2101,37 +2273,37 @@ studio::WorkArea::async_update_preview() rendering=true; async_renderer->start(); - sinfg::ProgressCallback *cb=get_canvas_view()->get_ui_interface().get(); + 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() { - sinfg::ProgressCallback *cb=get_canvas_view()->get_ui_interface().get(); + synfig::ProgressCallback *cb=get_canvas_view()->get_ui_interface().get(); rendering=false; 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(); @@ -2151,10 +2323,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()); - sinfg::ProgressCallback *cb=&callback; - + synfig::ProgressCallback *cb=&callback; + // We don't want to render if we are already rendering if(rendering) { @@ -2163,36 +2335,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 @@ -2204,12 +2375,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; @@ -2218,21 +2389,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) { @@ -2247,7 +2418,7 @@ again: } void -studio::WorkArea::async_render_preview(Time time) +studio::WorkArea::async_render_preview(synfig::Time time) { cur_time=time; //tile_book.clear(); @@ -2255,7 +2426,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()(); @@ -2268,7 +2439,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(); @@ -2292,15 +2463,15 @@ WorkArea::sync_render_preview_hook() void WorkArea::queue_scroll() { -// const sinfg::RendDesc &rend_desc(get_canvas()->rend_desc()); - - const sinfg::Point focus_point(get_focus_point()); - - const sinfg::Real +// 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); - const sinfg::Real + const synfig::Real old_x(last_focus_point[0]/pw+drawing_area->get_width()/2-w/2), old_y(last_focus_point[1]/ph+drawing_area->get_height()/2-h/2); @@ -2309,18 +2480,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; } @@ -2358,9 +2557,11 @@ studio::WorkArea::zoom_norm() 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()); @@ -2370,12 +2571,12 @@ studio::WorkArea::__render_preview(gpointer data) void studio::WorkArea::queue_render_preview() { - //sinfg::info("queue_render_preview(): called for %s", get_canvas_view()->get_time().get_string().c_str()); + //synfig::info("queue_render_preview(): called for %s", get_canvas_view()->get_time().get_string().c_str()); if(queued==true) { return; - //sinfg::info("queue_render_preview(): already queued, unqueuing"); + //synfig::info("queue_render_preview(): already queued, unqueuing"); /* if(render_idle_func_id) g_source_remove(render_idle_func_id); render_idle_func_id=0; @@ -2383,24 +2584,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) { - //sinfg::info("queue_render_preview(): (re)queuing..."); + //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) @@ -2415,7 +2621,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; } @@ -2443,12 +2649,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 @@ -2477,7 +2683,7 @@ studio::WorkArea::set_zoom(float z) } void -WorkArea::set_selected_value_node(etl::loose_handle x) +WorkArea::set_selected_value_node(etl::loose_handle x) { if(x!=selected_value_node_) {