66c7453e43d7e51d921d20f353b34f5638e9f0a7
[synfig.git] / synfig-studio / src / gtkmm / state_normal.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file state_normal.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007, 2008 Chris Moore
10 **      Copyright (c) 2009 Nikita Kitaev
11 **
12 **      This package is free software; you can redistribute it and/or
13 **      modify it under the terms of the GNU General Public License as
14 **      published by the Free Software Foundation; either version 2 of
15 **      the License, or (at your option) any later version.
16 **
17 **      This package is distributed in the hope that it will be useful,
18 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
19 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 **      General Public License for more details.
21 **      \endlegal
22 */
23 /* ========================================================================= */
24
25 /* === H E A D E R S ======================================================= */
26
27 #ifdef USING_PCH
28 #       include "pch.h"
29 #else
30 #ifdef HAVE_CONFIG_H
31 #       include <config.h>
32 #endif
33
34 #include <gtkmm/dialog.h>
35 #include <gtkmm/entry.h>
36
37 #include <synfig/valuenode_animated.h>
38 #include <synfig/valuenode_blinecalcvertex.h>
39 #include <synfig/valuenode_composite.h>
40 #include <synfig/valuenode_const.h>
41 #include <synfig/valuenode_dynamiclist.h>
42 #include <synfigapp/action_system.h>
43
44 #include "state_normal.h"
45 #include "canvasview.h"
46 #include "workarea.h"
47 #include "app.h"
48
49 #include <synfigapp/action.h>
50 #include "event_mouse.h"
51 #include "event_layerclick.h"
52 #include "toolbox.h"
53 #include "dialog_tooloptions.h"
54 #include <gtkmm/optionmenu.h>
55 #include "duck.h"
56 #include <synfig/angle.h>
57 #include <synfigapp/main.h>
58
59 #include "general.h"
60 #endif
61
62 /* === U S I N G =========================================================== */
63
64 using namespace std;
65 using namespace etl;
66 using namespace synfig;
67 using namespace studio;
68
69 /* === M A C R O S ========================================================= */
70
71 #ifndef EPSILON
72 #define EPSILON 0.0000001
73 #endif
74
75 /* === G L O B A L S ======================================================= */
76
77 StateNormal studio::state_normal;
78
79 /* === C L A S S E S & S T R U C T S ======================================= */
80
81 class DuckDrag_Combo : public DuckDrag_Base
82 {
83         synfig::Vector last_move;
84         synfig::Vector drag_offset;
85         synfig::Vector center;
86         synfig::Vector snap;
87
88         synfig::Angle original_angle;
89         synfig::Real original_mag;
90
91         std::vector<synfig::Vector> last_;
92         std::vector<synfig::Vector> positions;
93
94
95         bool bad_drag;
96         bool move_only;
97
98 public:
99         CanvasView* canvas_view_;
100         bool scale;
101         bool rotate;
102         bool constrain;
103         DuckDrag_Combo();
104         void begin_duck_drag(Duckmatic* duckmatic, const synfig::Vector& begin);
105         bool end_duck_drag(Duckmatic* duckmatic);
106         void duck_drag(Duckmatic* duckmatic, const synfig::Vector& vector);
107
108         etl::handle<synfigapp::CanvasInterface> get_canvas_interface()const{return canvas_view_->canvas_interface();}
109 };
110
111
112 class studio::StateNormal_Context : public sigc::trackable
113 {
114         CanvasView* canvas_view_;
115
116         synfigapp::Settings& settings;
117
118         sigc::connection keypress_connect;
119         sigc::connection keyrelease_connect;
120
121         etl::handle<DuckDrag_Combo> duck_dragger_;
122
123         Gtk::Table options_table;
124
125         Gtk::CheckButton checkbutton_rotate;
126         Gtk::CheckButton checkbutton_scale;
127         Gtk::CheckButton checkbutton_constrain;
128
129 public:
130
131         bool get_rotate_flag()const { return checkbutton_rotate.get_active(); }
132         void set_rotate_flag(bool x) { checkbutton_rotate.set_active(x); refresh_rotate_flag(); }
133         void refresh_rotate_flag() { if(duck_dragger_)duck_dragger_->rotate=get_rotate_flag(); }
134
135         bool get_scale_flag()const { return checkbutton_scale.get_active(); }
136         void set_scale_flag(bool x) { checkbutton_scale.set_active(x); refresh_scale_flag(); }
137         void refresh_scale_flag() { if(duck_dragger_)duck_dragger_->scale=get_scale_flag(); }
138
139         bool get_constrain_flag()const { return checkbutton_constrain.get_active(); }
140         void set_constrain_flag(bool x) { checkbutton_constrain.set_active(x); refresh_constrain_flag(); }
141         void refresh_constrain_flag() { if(duck_dragger_)duck_dragger_->constrain=get_constrain_flag(); }
142         void refresh_cursor();
143
144         StateNormal_Context(CanvasView* canvas_view);
145
146         ~StateNormal_Context();
147
148         CanvasView* get_canvas_view()const{return canvas_view_;}
149         etl::handle<synfigapp::CanvasInterface> get_canvas_interface()const{return canvas_view_->canvas_interface();}
150         synfig::Canvas::Handle get_canvas()const{return canvas_view_->get_canvas();}
151         WorkArea * get_work_area()const{return canvas_view_->get_work_area();}
152
153         void load_settings();
154         void save_settings();
155
156         bool key_pressed(GdkEventKey *event);
157         bool key_released(GdkEventKey *event);
158
159         Smach::event_result event_stop_handler(const Smach::event& x);
160         Smach::event_result event_refresh_handler(const Smach::event& x);
161         Smach::event_result event_refresh_ducks_handler(const Smach::event& x);
162         Smach::event_result event_undo_handler(const Smach::event& x);
163         Smach::event_result event_redo_handler(const Smach::event& x);
164         Smach::event_result event_mouse_button_down_handler(const Smach::event& x);
165         Smach::event_result event_multiple_ducks_clicked_handler(const Smach::event& x);
166         Smach::event_result event_refresh_tool_options(const Smach::event& x);
167         void refresh_tool_options();
168         Smach::event_result event_layer_click(const Smach::event& x);
169
170
171 };      // END of class StateNormal_Context
172
173 /* === M E T H O D S ======================================================= */
174
175 StateNormal::StateNormal():
176         Smach::state<StateNormal_Context>("normal")
177 {
178         insert(event_def(EVENT_STOP,&StateNormal_Context::event_stop_handler));
179         insert(event_def(EVENT_REFRESH,&StateNormal_Context::event_refresh_handler));
180         insert(event_def(EVENT_REFRESH_DUCKS,&StateNormal_Context::event_refresh_ducks_handler));
181         insert(event_def(EVENT_UNDO,&StateNormal_Context::event_undo_handler));
182         insert(event_def(EVENT_REDO,&StateNormal_Context::event_redo_handler));
183         insert(event_def(EVENT_WORKAREA_MOUSE_BUTTON_DOWN,&StateNormal_Context::event_mouse_button_down_handler));
184         insert(event_def(EVENT_WORKAREA_MULTIPLE_DUCKS_CLICKED,&StateNormal_Context::event_multiple_ducks_clicked_handler));
185         insert(event_def(EVENT_REFRESH_TOOL_OPTIONS,&StateNormal_Context::event_refresh_tool_options));
186         insert(event_def(EVENT_WORKAREA_LAYER_CLICKED,&StateNormal_Context::event_layer_click));
187
188 }
189
190 StateNormal::~StateNormal()
191 {
192 }
193
194 void StateNormal_Context::refresh_cursor()
195 {
196         // Check the current state and return when applicable
197         synfig::String sname;
198         sname=get_canvas_view()->get_smach().get_state_name();
199         if (sname=="smooth_move"||sname=="zoom"||sname=="width" ||
200                 sname=="text"||sname=="stroke"||sname=="star"||sname=="sketch"||
201                 sname=="scale"||sname=="zoom"||sname=="rotate"||sname=="rectangle"||
202                 sname=="polygon"||sname=="gradient"||sname=="fill"||sname=="draw"||
203                 sname=="circle")
204                         return;
205
206         // Change the cursor based on key flags
207         if(get_rotate_flag() && !get_scale_flag())
208         {
209                 get_work_area()->set_cursor(Gdk::EXCHANGE);
210                 return;
211         }
212         if(!get_rotate_flag() && get_scale_flag())
213         {
214                 get_work_area()->set_cursor(Gdk::SIZING);
215                 return;
216         }
217         if(get_rotate_flag() && get_scale_flag())
218         {
219                 get_work_area()->set_cursor(Gdk::CROSSHAIR);
220                 return;
221         }
222         // If we are in BLine state and there is not key pressed return to
223         // the bline cursor.
224         if (sname=="bline")
225         {
226                 get_work_area()->set_cursor(Gdk::CROSSHAIR);
227                 return;
228         }
229         // Default cursor for Transform tool
230         get_work_area()->set_cursor(Gdk::ARROW);
231
232 }
233
234 void
235 StateNormal_Context::load_settings()
236 {
237         String value;
238
239         if(settings.get_value("normal.rotate",value) && value=="1")
240                 set_rotate_flag(true);
241         else
242                 set_rotate_flag(false);
243
244         if(settings.get_value("normal.scale",value) && value=="1")
245                 set_scale_flag(true);
246         else
247                 set_scale_flag(false);
248
249         if(settings.get_value("normal.constrain",value) && value=="1")
250                 set_constrain_flag(true);
251         else
252                 set_constrain_flag(false);
253
254 }
255
256 void
257 StateNormal_Context::save_settings()
258 {
259         settings.set_value("normal.rotate",get_rotate_flag()?"1":"0");
260         settings.set_value("normal.scale",get_scale_flag()?"1":"0");
261         settings.set_value("normal.constrain",get_constrain_flag()?"1":"0");
262 }
263
264 StateNormal_Context::StateNormal_Context(CanvasView* canvas_view):
265         canvas_view_(canvas_view),
266         settings(synfigapp::Main::get_selected_input_device()->settings()),
267         duck_dragger_(new DuckDrag_Combo()),
268         checkbutton_rotate(_("Rotate (Ctrl)")),
269         checkbutton_scale(_("Scale (Alt)")),
270         checkbutton_constrain(_("Constrain (Shift)"))
271 {
272         duck_dragger_->canvas_view_=get_canvas_view();
273
274         // Set up the tool options dialog
275         options_table.attach(*manage(new Gtk::Label(_("Transform Tool"))),      0, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
276         options_table.attach(checkbutton_rotate,                                                        0, 2, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
277         options_table.attach(checkbutton_scale,                                                 0, 2, 2, 3, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
278         options_table.attach(checkbutton_constrain,                                                     0, 2, 3, 4, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
279
280         checkbutton_rotate.signal_toggled().connect(sigc::mem_fun(*this,&StateNormal_Context::refresh_rotate_flag));
281         checkbutton_scale.signal_toggled().connect(sigc::mem_fun(*this,&StateNormal_Context::refresh_scale_flag));
282         checkbutton_constrain.signal_toggled().connect(sigc::mem_fun(*this,&StateNormal_Context::refresh_constrain_flag));
283
284
285         options_table.show_all();
286         refresh_tool_options();
287         //App::dialog_tool_options->set_widget(options_table);
288         //App::dialog_tool_options->present();
289
290         get_work_area()->set_allow_layer_clicks(true);
291         get_work_area()->set_duck_dragger(duck_dragger_);
292
293         keypress_connect=get_work_area()->signal_key_press_event().connect(sigc::mem_fun(*this,&StateNormal_Context::key_pressed),false);
294         keyrelease_connect=get_work_area()->signal_key_release_event().connect(sigc::mem_fun(*this,&StateNormal_Context::key_released),false);
295
296         //these will segfault
297 //      get_work_area()->set_cursor(Gdk::CROSSHAIR);
298 //      get_work_area()->reset_cursor();
299
300         App::toolbox->refresh();
301
302         load_settings();
303         refresh_scale_flag();
304 }
305
306 bool
307 StateNormal_Context::key_pressed(GdkEventKey *event)
308 {
309         switch(event->keyval)
310         {
311                 case GDK_Control_L:
312                 case GDK_Control_R:
313                         set_rotate_flag(true);
314                         break;
315                 case GDK_Alt_L:
316                 case GDK_Alt_R:
317                         set_scale_flag(true);
318                         break;
319                 case GDK_Shift_L:
320                 case GDK_Shift_R:
321                         set_constrain_flag(true);
322                         break;
323                 default:
324                         break;
325         }
326         refresh_cursor();
327         return false; //Pass on the event to other handlers, just in case
328 }
329
330 bool
331 StateNormal_Context::key_released(GdkEventKey *event)
332 {
333         switch(event->keyval)
334         {
335                 case GDK_Control_L:
336                 case GDK_Control_R:
337                         set_rotate_flag(false);
338                         break;
339                 case GDK_Alt_L:
340                 case GDK_Alt_R:
341                         set_scale_flag(false);
342                         break;
343                 case GDK_Shift_L:
344                 case GDK_Shift_R:
345                         set_constrain_flag(false);
346                         break;
347                 default:
348                         break;
349         }
350         refresh_cursor();
351         return false; //Pass on the event to other handlers
352 }
353
354 void
355 StateNormal_Context::refresh_tool_options()
356 {
357         App::dialog_tool_options->clear();
358         App::dialog_tool_options->set_widget(options_table);
359         App::dialog_tool_options->set_local_name(_("Transform Tool"));
360         App::dialog_tool_options->set_name("normal");
361 }
362
363
364
365 StateNormal_Context::~StateNormal_Context()
366 {
367         save_settings();
368
369         get_work_area()->clear_duck_dragger();
370         get_work_area()->reset_cursor();
371
372         keypress_connect.disconnect();
373         keyrelease_connect.disconnect();
374
375         App::dialog_tool_options->clear();
376
377         App::toolbox->refresh();
378 }
379
380 DuckDrag_Combo::DuckDrag_Combo():
381         scale(false),
382         rotate(false),
383         constrain(false) // Lock aspect for scale; smooth move for translate
384 {
385 }
386
387 void
388 DuckDrag_Combo::begin_duck_drag(Duckmatic* duckmatic, const synfig::Vector& offset)
389 {
390         last_move=Vector(1,1);
391
392         const DuckList selected_ducks(duckmatic->get_selected_ducks());
393         DuckList::const_iterator iter;
394
395         bad_drag=false;
396
397                 drag_offset=duckmatic->find_duck(offset)->get_trans_point();
398
399                 //snap=drag_offset-duckmatic->snap_point_to_grid(drag_offset);
400                 //snap=offset-drag_offset_;
401                 snap=Vector(0,0);
402
403         // Calculate center
404         Point vmin(100000000,100000000);
405         Point vmax(-100000000,-100000000);
406         //std::set<etl::handle<Duck> >::iterator iter;
407         positions.clear();
408         int i;
409         for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
410         {
411                 Point p((*iter)->get_trans_point());
412                 vmin[0]=min(vmin[0],p[0]);
413                 vmin[1]=min(vmin[1],p[1]);
414                 vmax[0]=max(vmax[0],p[0]);
415                 vmax[1]=max(vmax[1],p[1]);
416                 positions.push_back(p);
417         }
418         center=(vmin+vmax)*0.5;
419         if((vmin-vmax).mag()<=EPSILON)
420                 move_only=true;
421         else
422                 move_only=false;
423
424
425         synfig::Vector vect(offset-center);
426         original_angle=Angle::tan(vect[1],vect[0]);
427         original_mag=vect.mag();
428 }
429
430
431 void
432 DuckDrag_Combo::duck_drag(Duckmatic* duckmatic, const synfig::Vector& vector)
433 {
434         if (!duckmatic) return;
435
436         if(bad_drag)
437                 return;
438
439         //Override axis lock set in workarea when holding down the shift key
440         if (!move_only && (scale || rotate))
441                 duckmatic->set_axis_lock(false);
442
443         synfig::Vector vect;
444         if (move_only || (!scale && !rotate))
445                 vect= duckmatic->snap_point_to_grid(vector)-drag_offset+snap;
446         else
447                 vect= duckmatic->snap_point_to_grid(vector)-center+snap;
448
449         last_move=vect;
450
451         const DuckList selected_ducks(duckmatic->get_selected_ducks());
452         DuckList::const_iterator iter;
453
454         Time time(duckmatic->get_time());
455
456         int i;
457         if( move_only || (!scale && !rotate) )
458         {
459                 for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
460                 {
461                         if((*iter)->get_type()==Duck::TYPE_VERTEX || (*iter)->get_type()==Duck::TYPE_POSITION)
462                                 (*iter)->set_trans_point(positions[i]+vect, time);
463                 }
464                 for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
465                 {
466                         if((*iter)->get_type()!=Duck::TYPE_VERTEX&&(*iter)->get_type()!=Duck::TYPE_POSITION)
467                                 (*iter)->set_trans_point(positions[i]+vect, time);
468                 }
469         }
470
471         if (rotate)
472         {
473                 Angle::deg angle(Angle::tan(vect[1],vect[0]));
474                 angle=original_angle-angle;
475                 if (constrain)
476                 {
477                         float degrees = angle.get()/15;
478                         angle= Angle::deg (degrees>0?std::floor(degrees)*15:std::ceil(degrees)*15);
479                 }
480                 Real mag(vect.mag()/original_mag);
481                 Real sine(Angle::sin(angle).get());
482                 Real cosine(Angle::cos(angle).get());
483
484                 for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
485                 {
486                         if((*iter)->get_type()!=Duck::TYPE_VERTEX&&(*iter)->get_type()!=Duck::TYPE_POSITION)continue;
487
488                         Vector x(positions[i]-center),p;
489
490                         p[0]=cosine*x[0]+sine*x[1];
491                         p[1]=-sine*x[0]+cosine*x[1];
492                         if(scale)p*=mag;
493                         p+=center;
494                         (*iter)->set_trans_point(p, time);
495                 }
496                 for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
497                 {
498                         if(!((*iter)->get_type()!=Duck::TYPE_VERTEX&&(*iter)->get_type()!=Duck::TYPE_POSITION))continue;
499
500                         Vector x(positions[i]-center),p;
501
502                         p[0]=cosine*x[0]+sine*x[1];
503                         p[1]=-sine*x[0]+cosine*x[1];
504                         if(scale)p*=mag;
505                         p+=center;
506                         (*iter)->set_trans_point(p, time);
507                 }
508         } else if (scale)
509         {
510                 if(!constrain)
511                 {
512                         if(abs(drag_offset[0]-center[0])>EPSILON)
513                                 vect[0]/=drag_offset[0]-center[0];
514                         else
515                                 vect[0]=1;
516                         if(abs(drag_offset[1]-center[1])>EPSILON)
517                                 vect[1]/=drag_offset[1]-center[1];
518                         else
519                                 vect[1]=1;
520                         }
521                 else
522                 {
523                         //vect[0]=vect[1]=vect.mag()*0.707106781;
524                         Real amount(vect.mag()/(drag_offset-center).mag());
525                         vect[0]=vect[1]=amount;
526                 }
527
528                 if(vect[0]<EPSILON && vect[0]>-EPSILON)
529                         vect[0]=1;
530                 if(vect[1]<EPSILON && vect[1]>-EPSILON)
531                         vect[1]=1;
532
533                 for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
534                 {
535                         if(((*iter)->get_type()!=Duck::TYPE_VERTEX&&(*iter)->get_type()!=Duck::TYPE_POSITION))continue;
536
537                         Vector p(positions[i]-center);
538
539                         p[0]*=vect[0];
540                         p[1]*=vect[1];
541                         p+=center;
542                         (*iter)->set_trans_point(p, time);
543                 }
544                 for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
545                 {
546                         if(!((*iter)->get_type()!=Duck::TYPE_VERTEX&&(*iter)->get_type()!=Duck::TYPE_POSITION))continue;
547
548                         Vector p(positions[i]-center);
549
550                         p[0]*=vect[0];
551                         p[1]*=vect[1];
552                         p+=center;
553                         (*iter)->set_trans_point(p, time);
554                 }
555         }
556
557         // then patch up the tangents for the vertices we've moved
558         duckmatic->update_ducks();
559
560         last_move=vect;
561 }
562
563 bool
564 DuckDrag_Combo::end_duck_drag(Duckmatic* duckmatic)
565 {
566         if(bad_drag)return false;
567
568         //synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Rotate Ducks"));
569
570         if((last_move-Vector(1,1)).mag()>0.0001)
571         {
572                 duckmatic->signal_edited_selected_ducks();
573                 return true;
574         }
575         else
576         {
577                 duckmatic->signal_user_click_selected_ducks(0);
578                 return false;
579         }
580 }
581
582 Smach::event_result
583 StateNormal_Context::event_refresh_tool_options(const Smach::event& /*x*/)
584 {
585         refresh_tool_options();
586         return Smach::RESULT_ACCEPT;
587 }
588
589 Smach::event_result
590 StateNormal_Context::event_stop_handler(const Smach::event& /*x*/)
591 {
592         // synfig::info("STATE NORMAL: Received Stop Event");
593         canvas_view_->stop();
594         return Smach::RESULT_ACCEPT;
595 }
596
597 Smach::event_result
598 StateNormal_Context::event_refresh_handler(const Smach::event& /*x*/)
599 {
600         // synfig::info("STATE NORMAL: Received Refresh Event");
601         canvas_view_->rebuild_tables();
602         canvas_view_->work_area->queue_render_preview();
603         return Smach::RESULT_ACCEPT;
604 }
605
606 Smach::event_result
607 StateNormal_Context::event_refresh_ducks_handler(const Smach::event& /*x*/)
608 {
609         // synfig::info("STATE NORMAL: Received Refresh Ducks");
610         canvas_view_->queue_rebuild_ducks();
611         return Smach::RESULT_ACCEPT;
612 }
613
614 Smach::event_result
615 StateNormal_Context::event_undo_handler(const Smach::event& /*x*/)
616 {
617         // synfig::info("STATE NORMAL: Received Undo Event");
618         canvas_view_->get_instance()->undo();
619         return Smach::RESULT_ACCEPT;
620 }
621
622 Smach::event_result
623 StateNormal_Context::event_redo_handler(const Smach::event& /*x*/)
624 {
625         // synfig::info("STATE NORMAL: Received Redo Event");
626         canvas_view_->get_instance()->redo();
627         return Smach::RESULT_ACCEPT;
628 }
629
630 Smach::event_result
631 StateNormal_Context::event_mouse_button_down_handler(const Smach::event& x)
632 {
633         // synfig::info("STATE NORMAL: Received mouse button down Event");
634
635         const EventMouse& event(*reinterpret_cast<const EventMouse*>(&x));
636
637         switch(event.button)
638         {
639         case BUTTON_RIGHT:
640                 canvas_view_->popup_main_menu();
641                 return Smach::RESULT_ACCEPT;
642         default:
643                 return Smach::RESULT_OK;
644         }
645 }
646
647 Smach::event_result
648 StateNormal_Context::event_layer_click(const Smach::event& x)
649 {
650         const EventLayerClick& event(*reinterpret_cast<const EventLayerClick*>(&x));
651
652         if(event.layer)
653         {
654                 // synfig::info("STATE NORMAL: Received layer click Event, \"%s\"",event.layer->get_name().c_str());
655         }
656         else
657         {
658                 // synfig::info("STATE NORMAL: Received layer click Event with an empty layer.");
659         }
660
661         switch(event.button)
662         {
663         case BUTTON_LEFT:
664                 if(!(event.modifier&Gdk::CONTROL_MASK))
665                         canvas_view_->get_selection_manager()->clear_selected_layers();
666                 if(event.layer)
667                 {
668                         std::list<Layer::Handle> layer_list(canvas_view_->get_selection_manager()->get_selected_layers());
669                         std::set<Layer::Handle> layers(layer_list.begin(),layer_list.end());
670                         if(layers.count(event.layer))
671                         {
672                                 layers.erase(event.layer);
673                                 layer_list=std::list<Layer::Handle>(layers.begin(),layers.end());
674                                 canvas_view_->get_selection_manager()->clear_selected_layers();
675                                 canvas_view_->get_selection_manager()->set_selected_layers(layer_list);
676                         }
677                         else
678                         {
679                                 canvas_view_->get_selection_manager()->set_selected_layer(event.layer);
680                         }
681                 }
682                 return Smach::RESULT_ACCEPT;
683         case BUTTON_RIGHT:
684                 canvas_view_->popup_layer_menu(event.layer);
685                 return Smach::RESULT_ACCEPT;
686         default:
687                 return Smach::RESULT_OK;
688         }
689 }
690
691 /*
692 void
693 StateNormal_Context::edit_several_waypoints(std::list<synfigapp::ValueDesc> value_desc_list)
694 {
695         Gtk::Dialog dialog(
696                 "Edit Multiple Waypoints",              // Title
697                 true,           // Modal
698                 true            // use_separator
699         );
700
701         Widget_WaypointModel widget_waypoint_model;
702         widget_waypoint_model.show();
703
704         dialog.get_vbox()->pack_start(widget_waypoint_model);
705
706
707         dialog.add_button(Gtk::StockID("gtk-apply"),1);
708         dialog.add_button(Gtk::StockID("gtk-cancel"),0);
709         dialog.show();
710
711         if(dialog.run()==0)
712                 return;
713         synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Set Waypoints"));
714
715         std::list<synfigapp::ValueDesc>::iterator iter;
716         for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
717         {
718                 synfigapp::ValueDesc value_desc(*iter);
719
720                 if(!value_desc.is_valid())
721                         continue;
722
723                 ValueNode_Animated::Handle value_node;
724
725                 // If this value isn't a ValueNode_Animated, but
726                 // it is somewhat constant, then go ahead and convert
727                 // it to a ValueNode_Animated.
728                 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
729                 {
730                         ValueBase value;
731                         if(value_desc.is_value_node())
732                                 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
733                         else
734                                 value=value_desc.get_value();
735
736                         value_node=ValueNode_Animated::create(value,get_canvas()->get_time());
737
738                         synfigapp::Action::Handle action;
739
740                         if(!value_desc.is_value_node())
741                         {
742                                 action=synfigapp::Action::create("ValueDescConnect");
743                                 action->set_param("dest",value_desc);
744                                 action->set_param("src",ValueNode::Handle(value_node));
745                         }
746                         else
747                         {
748                                 action=synfigapp::Action::create("ValueNodeReplace");
749                                 action->set_param("dest",value_desc.get_value_node());
750                                 action->set_param("src",ValueNode::Handle(value_node));
751                         }
752
753                         action->set_param("canvas",get_canvas());
754                         action->set_param("canvas_interface",get_canvas_interface());
755
756
757                         if(!get_canvas_interface()->get_instance()->perform_action(action))
758                         {
759                                 get_canvas_view()->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
760                                 group.cancel();
761                                 return;
762                         }
763                 }
764                 else
765                 {
766                         if(value_desc.is_value_node())
767                                 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
768                 }
769
770
771                 if(value_node)
772                 {
773
774                         synfigapp::Action::Handle action(synfigapp::Action::create("WaypointSetSmart"));
775
776                         if(!action)
777                         {
778                                 get_canvas_view()->get_ui_interface()->error(_("Unable to find WaypointSetSmart action"));
779                                 group.cancel();
780                                 return;
781                         }
782
783
784                         action->set_param("canvas",get_canvas());
785                         action->set_param("canvas_interface",get_canvas_interface());
786                         action->set_param("value_node",ValueNode::Handle(value_node));
787                         action->set_param("time",get_canvas()->get_time());
788                         action->set_param("model",widget_waypoint_model.get_waypoint_model());
789
790                         if(!get_canvas_interface()->get_instance()->perform_action(action))
791                         {
792                                 get_canvas_view()->get_ui_interface()->error(_("Unable to set a specific waypoint"));
793                                 group.cancel();
794                                 return;
795                         }
796                 }
797                 else
798                 {
799                         //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
800                         //group.cancel();
801                         //return;
802                 }
803
804         }
805 }
806 */
807
808 Smach::event_result
809 StateNormal_Context::event_multiple_ducks_clicked_handler(const Smach::event& /*x*/)
810 {
811         // synfig::info("STATE NORMAL: Received multiple duck click event");
812
813         //const EventMouse& event(*reinterpret_cast<const EventMouse*>(&x));
814
815         std::list<synfigapp::ValueDesc> value_desc_list;
816
817         // Create a list of value_descs associated with selection
818         const DuckList selected_ducks(get_work_area()->get_selected_ducks());
819         DuckList::const_iterator iter;
820         for(iter=selected_ducks.begin();iter!=selected_ducks.end();++iter)
821         {
822                 synfigapp::ValueDesc value_desc((*iter)->get_value_desc());
823
824                 if(!value_desc.is_valid())
825                         continue;
826
827                 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
828                 {
829                         value_desc_list.push_back(
830                                 synfigapp::ValueDesc(
831                                         ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
832                                         ,ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
833                                                                ->get_link_index_from_name("point")
834                                 )
835                         );
836                 }
837                 else
838                         value_desc_list.push_back(value_desc);
839         }
840
841         Gtk::Menu *menu=manage(new Gtk::Menu());
842         menu->signal_hide().connect(sigc::bind(sigc::ptr_fun(&delete_widget), menu));
843
844         canvas_view_->get_instance()->make_param_menu(menu,canvas_view_->get_canvas(),value_desc_list);
845
846         /*
847         synfigapp::Action::ParamList param_list;
848         param_list=get_canvas_interface()->generate_param_list(value_desc_list);
849
850         canvas_view_->add_actions_to_menu(menu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
851
852         menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
853                 sigc::bind(
854                         sigc::mem_fun(
855                                 *this,
856                                 &studio::StateNormal_Context::edit_several_waypoints
857                         ),
858                         value_desc_list
859                 )
860         ));
861         */
862         menu->popup(3,gtk_get_current_event_time());
863
864         return Smach::RESULT_ACCEPT;
865 }
866
867