9d0a10ced567bb381e179282370c092e033f3fb1
[synfig.git] / synfig-studio / src / gui / states / state_bline.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file state_bline.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 **
11 **      This package is free software; you can redistribute it and/or
12 **      modify it under the terms of the GNU General Public License as
13 **      published by the Free Software Foundation; either version 2 of
14 **      the License, or (at your option) any later version.
15 **
16 **      This package is distributed in the hope that it will be useful,
17 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **      General Public License for more details.
20 **      \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #ifdef USING_PCH
27 #       include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 #       include <config.h>
31 #endif
32
33 #include <gtkmm/dialog.h>
34 #include <gtkmm/entry.h>
35
36 #include <synfig/valuenode_dynamiclist.h>
37
38 #include "state_bline.h"
39 #include "state_normal.h"
40 #include "canvasview.h"
41 #include "workarea.h"
42 #include "app.h"
43 #include <synfig/valuenode_bline.h>
44 #include <ETL/hermite>
45 #include <ETL/calculus>
46 #include <utility>
47 #include "event_mouse.h"
48 #include "event_layerclick.h"
49 #include "toolbox.h"
50 #include "docks/dialog_tooloptions.h"
51 #include <gtkmm/spinbutton.h>
52 #include <synfig/transform.h>
53 #include <synfigapp/main.h>
54
55 #include "general.h"
56
57 #endif
58
59 /* === U S I N G =========================================================== */
60
61 using namespace std;
62 using namespace etl;
63 using namespace synfig;
64 using namespace studio;
65
66 /* === M A C R O S ========================================================= */
67
68 // if defined, show the first duck as green while drawing
69 #define DISTINGUISH_FIRST_DUCK
70
71 /* === G L O B A L S ======================================================= */
72
73 StateBLine studio::state_bline;
74
75 /* === C L A S S E S & S T R U C T S ======================================= */
76
77 class studio::StateBLine_Context : public sigc::trackable
78 {
79         etl::handle<CanvasView> canvas_view_;
80         CanvasView::IsWorking is_working;
81
82         bool prev_table_status;
83         bool loop_;
84         bool prev_workarea_layer_status_;
85
86         int depth;
87         Canvas::Handle canvas;
88
89         Gtk::Menu menu;
90
91         Duckmatic::Push duckmatic_push;
92
93         etl::handle<Duck> curr_duck;
94
95         etl::handle<Duck> next_duck;
96
97         std::list<synfig::ValueNode_Const::Handle> bline_point_list;
98         synfigapp::Settings& settings;
99
100         bool on_vertex_change(const synfig::Point &point, synfig::ValueNode_Const::Handle value_node);
101         bool on_tangent1_change(const synfig::Point &point, synfig::ValueNode_Const::Handle value_node);
102         bool on_tangent2_change(const synfig::Point &point, synfig::ValueNode_Const::Handle value_node);
103
104
105         void popup_handle_menu(synfig::ValueNode_Const::Handle value_node);
106         void popup_vertex_menu(synfig::ValueNode_Const::Handle value_node);
107         void popup_bezier_menu(float location, synfig::ValueNode_Const::Handle value_node);
108
109         void bline_detach_handle(synfig::ValueNode_Const::Handle value_node);
110         void bline_attach_handle(synfig::ValueNode_Const::Handle value_node);
111         void bline_delete_vertex(synfig::ValueNode_Const::Handle value_node);
112         void bline_insert_vertex(synfig::ValueNode_Const::Handle value_node,float origin=0.5);
113         void loop_bline();
114         void unloop_bline();
115
116         void refresh_ducks(bool x=true);
117
118         Gtk::Table options_table;
119         Gtk::Entry entry_id;
120         Gtk::CheckButton checkbutton_layer_region;
121         Gtk::CheckButton checkbutton_layer_outline;
122         Gtk::CheckButton checkbutton_layer_curve_gradient;
123         Gtk::CheckButton checkbutton_layer_plant;
124         Gtk::CheckButton checkbutton_layer_link_origins;
125         Gtk::CheckButton checkbutton_auto_export;
126         Gtk::Button button_make;
127         Gtk::Button button_clear;
128         Gtk::Adjustment  adj_feather;
129         Gtk::SpinButton  spin_feather;
130
131
132
133 public:
134
135         int layers_to_create()const
136         {
137                 return
138                         get_layer_region_flag() +
139                         get_layer_outline_flag() +
140                         get_layer_curve_gradient_flag() +
141                         get_layer_plant_flag();
142         }
143
144         void sanity_check()
145         {
146                 if(layers_to_create()==0)
147                         set_layer_region_flag(true);
148         }
149
150         bool get_auto_export_flag()const { return checkbutton_auto_export.get_active(); }
151         void set_auto_export_flag(bool x) { return checkbutton_auto_export.set_active(x); }
152
153         bool get_layer_region_flag()const { return checkbutton_layer_region.get_active(); }
154         void set_layer_region_flag(bool x) { return checkbutton_layer_region.set_active(x); }
155
156         bool get_layer_outline_flag()const { return checkbutton_layer_outline.get_active(); }
157         void set_layer_outline_flag(bool x) { return checkbutton_layer_outline.set_active(x); }
158
159         bool get_layer_curve_gradient_flag()const { return checkbutton_layer_curve_gradient.get_active(); }
160         void set_layer_curve_gradient_flag(bool x) { return checkbutton_layer_curve_gradient.set_active(x); }
161
162         bool get_layer_plant_flag()const { return checkbutton_layer_plant.get_active(); }
163         void set_layer_plant_flag(bool x) { return checkbutton_layer_plant.set_active(x); }
164
165         bool get_layer_link_origins_flag()const { return checkbutton_layer_link_origins.get_active(); }
166         void set_layer_link_origins_flag(bool x) { return checkbutton_layer_link_origins.set_active(x); }
167
168         Real get_feather() const { return adj_feather.get_value(); }
169         void set_feather(Real x) { return adj_feather.set_value(x); }
170         synfig::String get_id()const { return entry_id.get_text(); }
171         void set_id(const synfig::String& x) { return entry_id.set_text(x); }
172
173         Smach::event_result event_stop_handler(const Smach::event& x);
174
175         Smach::event_result event_refresh_handler(const Smach::event& x);
176
177         Smach::event_result event_mouse_click_handler(const Smach::event& x);
178         Smach::event_result event_mouse_release_handler(const Smach::event& x);
179         Smach::event_result event_mouse_motion_handler(const Smach::event& x);
180         Smach::event_result event_refresh_tool_options(const Smach::event& x);
181
182         Smach::event_result event_hijack(const Smach::event& /*x*/) { return Smach::RESULT_ACCEPT; }
183
184         void refresh_tool_options();
185
186         StateBLine_Context(CanvasView* canvas_view);
187
188         ~StateBLine_Context();
189
190         const etl::handle<CanvasView>& get_canvas_view()const{return canvas_view_;}
191         etl::handle<synfigapp::CanvasInterface> get_canvas_interface()const{return canvas_view_->canvas_interface();}
192         synfig::Canvas::Handle get_canvas()const{return canvas_view_->get_canvas();}
193         WorkArea * get_work_area()const{return canvas_view_->get_work_area();}
194         const synfig::TransformStack& get_transform_stack()const { return canvas_view_->get_curr_transform_stack(); }
195
196         void load_settings();
197         void save_settings();
198         void reset();
199         void increment_id();
200         //void on_user_click(synfig::Point point);
201
202         bool run_();
203         bool run();
204
205         bool egress_on_selection_change;
206         Smach::event_result event_layer_selection_changed_handler(const Smach::event& /*x*/)
207         {
208                 if(egress_on_selection_change)
209                         throw &state_normal; //throw Smach::egress_exception();
210                 return Smach::RESULT_OK;
211         }
212
213 };      // END of class StateBLine_Context
214
215
216 /* === M E T H O D S ======================================================= */
217
218 StateBLine::StateBLine():
219         Smach::state<StateBLine_Context>("bline")
220 {
221         insert(event_def(EVENT_LAYER_SELECTION_CHANGED,         &StateBLine_Context::event_layer_selection_changed_handler));
222         insert(event_def(EVENT_STOP,                                            &StateBLine_Context::event_stop_handler));
223         insert(event_def(EVENT_REFRESH,                                         &StateBLine_Context::event_refresh_handler));
224         insert(event_def(EVENT_REFRESH_DUCKS,                           &StateBLine_Context::event_hijack));
225         insert(event_def(EVENT_WORKAREA_MOUSE_BUTTON_DOWN,      &StateBLine_Context::event_mouse_click_handler));
226         insert(event_def(EVENT_WORKAREA_MOUSE_BUTTON_UP,        &StateBLine_Context::event_mouse_release_handler));
227         insert(event_def(EVENT_WORKAREA_MOUSE_MOTION,           &StateBLine_Context::event_mouse_motion_handler));
228         insert(event_def(EVENT_WORKAREA_MOUSE_BUTTON_DRAG,      &StateBLine_Context::event_mouse_motion_handler));
229         insert(event_def(EVENT_REFRESH_TOOL_OPTIONS,            &StateBLine_Context::event_refresh_tool_options));
230 }
231
232 StateBLine::~StateBLine()
233 {
234 }
235
236 void
237 StateBLine_Context::load_settings()
238 {
239         try
240         {
241                 SETTINGS_LOCALE_SAFE_AND_BACKUP
242                 String value;
243
244                 if(settings.get_value("bline.layer_region",value) && value=="0")
245                         set_layer_region_flag(false);
246                 else
247                         set_layer_region_flag(true);
248
249                 if(settings.get_value("bline.layer_outline",value) && value=="0")
250                         set_layer_outline_flag(false);
251                 else
252                         set_layer_outline_flag(true);
253
254                 if(settings.get_value("bline.layer_curve_gradient",value) && value=="1")
255                         set_layer_curve_gradient_flag(true);
256                 else
257                         set_layer_curve_gradient_flag(false);
258
259                 if(settings.get_value("bline.layer_plant",value) && value=="1")
260                         set_layer_plant_flag(true);
261                 else
262                         set_layer_plant_flag(false);
263
264                 if(settings.get_value("bline.layer_link_origins",value) && value=="0")
265                         set_layer_link_origins_flag(false);
266                 else
267                         set_layer_link_origins_flag(true);
268
269                 if(settings.get_value("bline.auto_export",value) && value=="1")
270                         set_auto_export_flag(true);
271                 else
272                         set_auto_export_flag(false);
273
274                 if(settings.get_value("bline.id",value))
275                         set_id(value);
276                 else
277                         set_id("NewBLine");
278
279                 if(settings.get_value("bline.feather",value))
280                 {
281                         Real n = atof(value.c_str());
282                         set_feather(n);
283                 }
284
285                 sanity_check();
286                 SETTINGS_LOCALE_RESTORE
287         }
288         catch(...)
289         {
290                 synfig::warning("State BLine: Caught exception when attempting to load settings.");
291         }
292 }
293
294 void
295 StateBLine_Context::save_settings()
296 {
297         try
298         {
299                 SETTINGS_LOCALE_SAFE_AND_BACKUP
300                 sanity_check();
301                 settings.set_value("bline.layer_outline",get_layer_outline_flag()?"1":"0");
302                 settings.set_value("bline.layer_region",get_layer_region_flag()?"1":"0");
303                 settings.set_value("bline.layer_curve_gradient",get_layer_curve_gradient_flag()?"1":"0");
304                 settings.set_value("bline.layer_plant",get_layer_plant_flag()?"1":"0");
305                 settings.set_value("bline.layer_link_origins",get_layer_link_origins_flag()?"1":"0");
306                 settings.set_value("bline.auto_export",get_auto_export_flag()?"1":"0");
307                 settings.set_value("bline.id",get_id().c_str());
308                 settings.set_value("bline.feather",strprintf("%f",get_feather()));
309                 SETTINGS_LOCALE_RESTORE
310         }
311         catch(...)
312         {
313                 synfig::warning("State BLine : Caught exception when attempting to save settings.");
314         }
315 }
316
317 void
318 StateBLine_Context::reset()
319 {
320         loop_=false;
321         bline_point_list.clear();
322         refresh_ducks();
323 }
324
325 void
326 StateBLine_Context::increment_id()
327 {
328         String id(get_id());
329         int number=1;
330         int digits=0;
331
332         if(id.empty())
333                 id="NewBLine";
334
335         // If there is a number
336         // already at the end of the
337         // id, then remove it.
338         if(id[id.size()-1]<='9' && id[id.size()-1]>='0')
339         {
340                 // figure out how many digits it is
341                 for (digits = 0;
342                          (int)id.size()-1 >= digits && id[id.size()-1-digits] <= '9' && id[id.size()-1-digits] >= '0';
343                          digits++)
344                         ;
345
346                 String str_number;
347                 str_number=String(id,id.size()-digits,id.size());
348                 id=String(id,0,id.size()-digits);
349                 // synfig::info("---------------- \"%s\"",str_number.c_str());
350
351                 number=atoi(str_number.c_str());
352         }
353         else
354         {
355                 number=1;
356                 digits=3;
357         }
358
359         number++;
360
361         // Add the number back onto the id
362         {
363                 const String format(strprintf("%%0%dd",digits));
364                 id+=strprintf(format.c_str(),number);
365         }
366
367         // Set the ID
368         set_id(id);
369 }
370
371
372 StateBLine_Context::StateBLine_Context(CanvasView* canvas_view):
373         canvas_view_(canvas_view),
374         is_working(*canvas_view),
375         loop_(false),
376         prev_workarea_layer_status_(get_work_area()->get_allow_layer_clicks()),
377         duckmatic_push(get_work_area()),
378         settings(synfigapp::Main::get_selected_input_device()->settings()),
379         entry_id(),
380         checkbutton_layer_region(_("Create Region BLine")),
381         checkbutton_layer_outline(_("Create Outline BLine")),
382         checkbutton_layer_curve_gradient(_("Create Curve Gradient BLine")),
383         checkbutton_layer_plant(_("Create Plant BLine")),
384         checkbutton_layer_link_origins(_("Link Origins")),
385         checkbutton_auto_export(_("Auto Export")),
386         button_make(_("Make")),
387         button_clear(_("Clear")),
388         adj_feather(0,0,10000,0.01,0.1),
389         spin_feather(adj_feather,0.01,4)
390 {
391         depth=-1;
392         egress_on_selection_change=true;
393         load_settings();
394
395         // Set up the tool options dialog
396         options_table.attach(*manage(new Gtk::Label(_("BLine Tool"))),  0, 2,  0,  1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
397         options_table.attach(entry_id,                                                                  0, 2,  1,  2, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
398         options_table.attach(checkbutton_layer_outline,                                 0, 2,  2,  3, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
399         options_table.attach(checkbutton_layer_region,                                  0, 2,  3,  4, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
400         options_table.attach(checkbutton_layer_plant,                                   0, 2,  4,  5, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
401         options_table.attach(checkbutton_layer_curve_gradient,                  0, 2,  5,  6, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
402         options_table.attach(checkbutton_layer_link_origins,                    0, 2,  6,  7, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
403         options_table.attach(checkbutton_auto_export,                                   0, 2,  7,  8, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
404         options_table.attach(*manage(new Gtk::Label(_("Feather"))),     0, 1, 10, 11, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
405         options_table.attach(spin_feather,                                                              1, 2, 10, 11, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
406         //options_table.attach(button_make, 0, 2, 5, 6, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
407         //button_make.signal_pressed().connect(sigc::mem_fun(*this,&StateBLine_Context::run));
408         options_table.show_all();
409         refresh_tool_options();
410         App::dialog_tool_options->present();
411
412         // Turn off layer clicking
413         get_work_area()->set_allow_layer_clicks(false);
414
415         // clear out the ducks
416         get_work_area()->clear_ducks();
417
418         // Refresh the work area
419         get_work_area()->queue_draw();
420
421         // Hide the tables if they are showing
422         prev_table_status=get_canvas_view()->tables_are_visible();
423         if(prev_table_status)get_canvas_view()->hide_tables();
424
425         // Disable the time bar
426         get_canvas_view()->set_sensitive_timebar(false);
427
428         // Connect a signal
429         //get_work_area()->signal_user_click().connect(sigc::mem_fun(*this,&studio::StateBLine_Context::on_user_click));
430         get_work_area()->set_cursor(Gdk::CROSSHAIR);
431
432         App::toolbox->refresh();
433 }
434
435 void
436 StateBLine_Context::refresh_tool_options()
437 {
438         App::dialog_tool_options->clear();
439         App::dialog_tool_options->set_widget(options_table);
440         App::dialog_tool_options->set_local_name(_("BLine Tool"));
441         App::dialog_tool_options->set_name("bline");
442
443         App::dialog_tool_options->add_button(
444                 Gtk::StockID("gtk-execute"),
445                 _("Make BLine and/or Region")
446         )->signal_clicked().connect(
447                 sigc::hide_return(sigc::mem_fun(
448                         *this,
449                         &StateBLine_Context::run
450                 ))
451         );
452
453         App::dialog_tool_options->add_button(
454                 Gtk::StockID("gtk-clear"),
455                 _("Clear current BLine")
456         )->signal_clicked().connect(
457                 sigc::mem_fun(
458                         *this,
459                         &StateBLine_Context::reset
460                 )
461         );
462 }
463
464 Smach::event_result
465 StateBLine_Context::event_refresh_tool_options(const Smach::event& /*x*/)
466 {
467         refresh_tool_options();
468         return Smach::RESULT_ACCEPT;
469 }
470
471 StateBLine_Context::~StateBLine_Context()
472 {
473         run();
474
475         save_settings();
476         App::dialog_tool_options->clear();
477
478         get_work_area()->reset_cursor();
479
480         // Restore layer clicking
481         get_work_area()->set_allow_layer_clicks(prev_workarea_layer_status_);
482
483         // Enable the time bar
484         get_canvas_view()->set_sensitive_timebar(true);
485
486         // Bring back the tables if they were out before
487         if(prev_table_status)get_canvas_view()->show_tables();
488
489 //      get_canvas_view()->get_smach().process_event(EVENT_REFRESH_DUCKS);
490
491         // Refresh the work area
492         get_work_area()->queue_draw();
493
494         App::toolbox->refresh();
495 }
496
497 Smach::event_result
498 StateBLine_Context::event_stop_handler(const Smach::event& /*x*/)
499 {
500 //      synfig::info("STATE RotoBLine: Received Stop Event");
501 //      run();
502         reset();
503 //      throw Smach::egress_exception();
504 //      get_canvas_view()->get_smach().pop_state();
505         return Smach::RESULT_ACCEPT;
506 }
507
508 Smach::event_result
509 StateBLine_Context::event_refresh_handler(const Smach::event& /*x*/)
510 {
511 //      synfig::info("STATE RotoBLine: Received Refresh Event");
512         refresh_ducks();
513         return Smach::RESULT_ACCEPT;
514 }
515
516 bool
517 StateBLine_Context::run()
518 {
519         sanity_check();
520
521         String err;
522         bool success(false);
523         for(int i=5;i>0 && !success;i--)try
524         {
525                 success=run_();
526         }
527         catch(String s)
528         {
529                 err=s;
530         }
531         if(!success && !err.empty())
532         {
533                 get_canvas_view()->get_ui_interface()->error(err);
534         }
535         return success;
536 }
537
538 bool
539 StateBLine_Context::run_()
540 {
541         curr_duck=0;
542         next_duck=0;
543
544         // Now we need to generate it
545
546         if(bline_point_list.empty())
547         {
548                 return false;
549         }
550         if(bline_point_list.size()<2)
551         {
552                 //get_canvas_view()->get_ui_interface()->error(_("You need at least two (2) points to create a BLine"));
553                 return false;
554         }
555
556         do
557         {
558
559                 // Create the action group
560                 synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("New BLine"));
561
562                 std::vector<BLinePoint> new_list;
563                 std::list<synfig::ValueNode_Const::Handle>::iterator iter;
564                 const synfig::TransformStack& transform(get_transform_stack());
565
566                 for(iter=bline_point_list.begin();iter!=bline_point_list.end();++iter)
567                 {
568                         BLinePoint bline_point((*iter)->get_value().get(BLinePoint()));
569                         Point new_vertex(transform.unperform(bline_point.get_vertex()));
570
571                         bline_point.set_tangent1(
572                                 transform.unperform(
573                                         bline_point.get_tangent1()+bline_point.get_vertex()
574                                 ) -new_vertex
575                         );
576
577                         bline_point.set_tangent2(
578                                 transform.unperform(
579                                         bline_point.get_tangent2()+bline_point.get_vertex()
580                                 ) -new_vertex
581                         );
582
583                         bline_point.set_vertex(new_vertex);
584
585                         new_list.push_back(bline_point);
586                 }
587
588                 ValueNode_BLine::Handle value_node_bline(ValueNode_BLine::create(new_list));
589                 assert(value_node_bline);
590
591                 ValueNode_Const::Handle value_node_origin(ValueNode_Const::create(Vector()));
592                 assert(value_node_origin);
593
594                 // Set the looping flag
595                 value_node_bline->set_loop(loop_);
596
597                 // Add the BLine to the canvas
598                 if(get_auto_export_flag() && !get_canvas_interface()->add_value_node(value_node_bline,get_id()))
599                 {
600                         //get_canvas_view()->get_ui_interface()->error(_("Unable to add value node"));
601                         group.cancel();
602                         increment_id();
603                         throw String(_("Unable to add value node"));
604                         return false;
605                 }
606
607                 Layer::Handle layer;
608
609                 // we are temporarily using the layer to hold something
610                 layer=get_canvas_view()->get_selection_manager()->get_selected_layer();
611
612                 if(layer)
613                 {
614                         if(depth<0)
615                                 depth=layer->get_depth();
616                         if(!canvas)
617                                 canvas=layer->get_canvas();
618                 }
619                 else
620                         depth=0;
621
622                 if(!canvas)
623                         canvas=get_canvas_view()->get_canvas();
624
625                 value_node_bline->set_member_canvas(canvas);
626
627                 synfigapp::SelectionManager::LayerList layer_selection;
628                 if (!getenv("SYNFIG_TOOLS_CLEAR_SELECTION"))
629                         layer_selection = get_canvas_view()->get_selection_manager()->get_selected_layers();
630
631                 // count how many layers we're going to be creating
632                 int layers_to_create = this->layers_to_create();
633
634                 ///////////////////////////////////////////////////////////////////////////
635                 //   C U R V E   G R A D I E N T
636                 ///////////////////////////////////////////////////////////////////////////
637
638                 if(get_layer_curve_gradient_flag())
639                 {
640                         synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);
641
642                         Layer::Handle layer(get_canvas_interface()->add_layer_to("curve_gradient",canvas,depth));
643                         if (!layer)
644                         {
645                                 group.cancel();
646                                 throw String(_("Unable to create layer"));
647                         }
648                         layer_selection.push_back(layer);
649                         layer->set_description(get_id()+_(" Gradient"));
650                         get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());
651
652                         {
653                                 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
654                                 assert(action);
655
656                                 action->set_param("canvas",get_canvas());
657                                 action->set_param("canvas_interface",get_canvas_interface());
658                                 action->set_param("layer",layer);
659                                 if(!action->set_param("param",String("bline")))
660                                         synfig::error("LayerParamConnect didn't like \"param\"");
661                                 if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
662                                         synfig::error("LayerParamConnect didn't like \"value_node\"");
663
664                                 if(!get_canvas_interface()->get_instance()->perform_action(action))
665                                 {
666                                         //get_canvas_view()->get_ui_interface()->error(_("Unable to create BLine layer"));
667                                         group.cancel();
668                                         throw String(_("Unable to create Gradient layer"));
669                                         return false;
670                                 }
671                         }
672
673                         // only link the curve gradient's origin parameter if the option is selected and we're creating more than one layer
674                         if (get_layer_link_origins_flag() && layers_to_create > 1)
675                         {
676                                 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
677                                 assert(action);
678
679                                 action->set_param("canvas",get_canvas());
680                                 action->set_param("canvas_interface",get_canvas_interface());
681                                 action->set_param("layer",layer);
682                                 if(!action->set_param("param",String("origin")))
683                                         synfig::error("LayerParamConnect didn't like \"param\"");
684                                 if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
685                                         synfig::error("LayerParamConnect didn't like \"value_node\"");
686
687                                 if(!get_canvas_interface()->get_instance()->perform_action(action))
688                                 {
689                                         //get_canvas_view()->get_ui_interface()->error(_("Unable to create BLine layer"));
690                                         group.cancel();
691                                         throw String(_("Unable to create Gradient layer"));
692                                         return false;
693                                 }
694                         }
695                 }
696
697                 ///////////////////////////////////////////////////////////////////////////
698                 //   P L A N T
699                 ///////////////////////////////////////////////////////////////////////////
700
701                 if(get_layer_plant_flag())
702                 {
703                         synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);
704
705                         Layer::Handle layer(get_canvas_interface()->add_layer_to("plant",canvas,depth));
706                         if (!layer)
707                         {
708                                 group.cancel();
709                                 throw String(_("Unable to create layer"));
710                         }
711                         layer_selection.push_back(layer);
712                         layer->set_description(get_id()+_(" Plant"));
713                         get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());
714
715                         {
716                                 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
717                                 assert(action);
718
719                                 action->set_param("canvas",get_canvas());
720                                 action->set_param("canvas_interface",get_canvas_interface());
721                                 action->set_param("layer",layer);
722                                 if(!action->set_param("param",String("bline")))
723                                         synfig::error("LayerParamConnect didn't like \"param\"");
724                                 if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
725                                         synfig::error("LayerParamConnect didn't like \"value_node\"");
726
727                                 if(!get_canvas_interface()->get_instance()->perform_action(action))
728                                 {
729                                         //get_canvas_view()->get_ui_interface()->error(_("Unable to create BLine layer"));
730                                         group.cancel();
731                                         throw String(_("Unable to create Plant layer"));
732                                         return false;
733                                 }
734                         }
735
736                         // only link the plant's origin parameter if the option is selected and we're creating more than one layer
737                         if (get_layer_link_origins_flag() && layers_to_create > 1)
738                         {
739                                 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
740                                 assert(action);
741
742                                 action->set_param("canvas",get_canvas());
743                                 action->set_param("canvas_interface",get_canvas_interface());
744                                 action->set_param("layer",layer);
745                                 if(!action->set_param("param",String("origin")))
746                                         synfig::error("LayerParamConnect didn't like \"param\"");
747                                 if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
748                                         synfig::error("LayerParamConnect didn't like \"value_node\"");
749
750                                 if(!get_canvas_interface()->get_instance()->perform_action(action))
751                                 {
752                                         //get_canvas_view()->get_ui_interface()->error(_("Unable to create BLine layer"));
753                                         group.cancel();
754                                         throw String(_("Unable to create Plant layer"));
755                                         return false;
756                                 }
757                         }
758                 }
759
760                 ///////////////////////////////////////////////////////////////////////////
761                 //   R E G I O N
762                 ///////////////////////////////////////////////////////////////////////////
763
764                 if(get_layer_region_flag())
765                 {
766                         synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);
767
768                         Layer::Handle layer(get_canvas_interface()->add_layer_to("region",canvas,depth));
769                         if (!layer)
770                         {
771                                 group.cancel();
772                                 throw String(_("Unable to create layer"));
773                         }
774                         layer_selection.push_back(layer);
775                         layer->set_description(get_id()+_(" Region"));
776                         get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());
777
778                         if(get_feather())
779                         {
780                                 layer->set_param("feather",get_feather());
781                                 get_canvas_interface()->signal_layer_param_changed()(layer,"feather");
782                         }
783
784                         // I don't know if it's safe to reuse the same LayerParamConnect action, so I'm
785                         // using 2 separate ones.
786                         {
787                                 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
788                                 assert(action);
789
790                                 action->set_param("canvas",get_canvas());
791                                 action->set_param("canvas_interface",get_canvas_interface());
792                                 action->set_param("layer",layer);
793                                 if(!action->set_param("param",String("bline")))
794                                         synfig::error("LayerParamConnect didn't like \"param\"");
795                                 if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
796                                         synfig::error("LayerParamConnect didn't like \"value_node\"");
797
798                                 if(!get_canvas_interface()->get_instance()->perform_action(action))
799                                 {
800                                         //get_canvas_view()->get_ui_interface()->error(_("Unable to create Region layer"));
801                                         group.cancel();
802                                         throw String(_("Unable to create Region layer"));
803                                         return false;
804                                 }
805                         }
806
807                         // only link the region's origin parameter if the option is selected and we're creating more than one layer
808                         if (get_layer_link_origins_flag() && layers_to_create > 1)
809                         {
810                                 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
811                                 assert(action);
812
813                                 action->set_param("canvas",get_canvas());
814                                 action->set_param("canvas_interface",get_canvas_interface());
815                                 action->set_param("layer",layer);
816                                 if(!action->set_param("param",String("origin")))
817                                         synfig::error("LayerParamConnect didn't like \"param\"");
818                                 if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
819                                         synfig::error("LayerParamConnect didn't like \"value_node\"");
820
821                                 if(!get_canvas_interface()->get_instance()->perform_action(action))
822                                 {
823                                         //get_canvas_view()->get_ui_interface()->error(_("Unable to create Region layer"));
824                                         group.cancel();
825                                         throw String(_("Unable to create Region layer"));
826                                         return false;
827                                 }
828                         }
829                 }
830
831                 ///////////////////////////////////////////////////////////////////////////
832                 //   O U T L I N E
833                 ///////////////////////////////////////////////////////////////////////////
834
835                 if(get_layer_outline_flag())
836                 {
837                         synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);
838
839                         Layer::Handle layer(get_canvas_interface()->add_layer_to("outline",canvas,depth));
840                         if (!layer)
841                         {
842                                 group.cancel();
843                                 throw String(_("Unable to create layer"));
844                         }
845                         layer_selection.push_back(layer);
846                         layer->set_description(get_id()+_(" Outline"));
847                         get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());
848                         if(get_feather())
849                         {
850                                 layer->set_param("feather",get_feather());
851                                 get_canvas_interface()->signal_layer_param_changed()(layer,"feather");
852                         }
853
854                         {
855                                 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
856                                 assert(action);
857
858                                 action->set_param("canvas",get_canvas());
859                                 action->set_param("canvas_interface",get_canvas_interface());
860                                 action->set_param("layer",layer);
861                                 if(!action->set_param("param",String("bline")))
862                                         synfig::error("LayerParamConnect didn't like \"param\"");
863                                 if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
864                                         synfig::error("LayerParamConnect didn't like \"value_node\"");
865
866                                 if(!get_canvas_interface()->get_instance()->perform_action(action))
867                                 {
868                                         //get_canvas_view()->get_ui_interface()->error(_("Unable to create BLine layer"));
869                                         group.cancel();
870                                         throw String(_("Unable to create Outline layer"));
871                                         return false;
872                                 }
873                         }
874
875                         // only link the outline's origin parameter if the option is selected and we're creating more than one layer
876                         if (get_layer_link_origins_flag() && layers_to_create > 1)
877                         {
878                                 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
879                                 assert(action);
880
881                                 action->set_param("canvas",get_canvas());
882                                 action->set_param("canvas_interface",get_canvas_interface());
883                                 action->set_param("layer",layer);
884                                 if(!action->set_param("param",String("origin")))
885                                         synfig::error("LayerParamConnect didn't like \"param\"");
886                                 if(!action->set_param("value_node",ValueNode::Handle(value_node_origin)))
887                                         synfig::error("LayerParamConnect didn't like \"value_node\"");
888
889                                 if(!get_canvas_interface()->get_instance()->perform_action(action))
890                                 {
891                                         //get_canvas_view()->get_ui_interface()->error(_("Unable to create BLine layer"));
892                                         group.cancel();
893                                         throw String(_("Unable to create Outline layer"));
894                                         return false;
895                                 }
896                         }
897                 }
898
899                 egress_on_selection_change=false;
900                 get_canvas_interface()->get_selection_manager()->clear_selected_layers();
901                 get_canvas_interface()->get_selection_manager()->set_selected_layers(layer_selection);
902                 egress_on_selection_change=true;
903
904                 //if(finish_bline_dialog.get_region_flag() || finish_bline_dialog.get_bline_flag())
905                 //      get_canvas_interface()->signal_dirty_preview()();
906
907         } while(0);
908
909         reset();
910         increment_id();
911         return true;
912 }
913
914 Smach::event_result
915 StateBLine_Context::event_mouse_motion_handler(const Smach::event& x)
916 {
917         const EventMouse& event(*reinterpret_cast<const EventMouse*>(&x));
918
919         if(curr_duck)
920         {
921                 //synfig::info("Moved Duck");
922                 Point p(get_work_area()->snap_point_to_grid(event.pos));
923                 curr_duck->set_trans_point(p);
924                 if(next_duck)
925                         next_duck->set_trans_point(p);
926                 get_work_area()->queue_draw();
927                 return Smach::RESULT_ACCEPT;
928         }
929
930         return Smach::RESULT_OK;
931 }
932
933 Smach::event_result
934 StateBLine_Context::event_mouse_release_handler(const Smach::event& /*x*/)
935 {
936         if(curr_duck)
937         {
938                 //synfig::info("Released current duck");
939                 curr_duck->signal_edited()(curr_duck->get_point());
940                 if(next_duck)
941                 {
942                         //synfig::info("grabbing next duck");
943                         curr_duck=next_duck;
944                         next_duck=0;
945                 }
946                 return Smach::RESULT_ACCEPT;
947         }
948         return Smach::RESULT_OK;
949 }
950
951 Smach::event_result
952 StateBLine_Context::event_mouse_click_handler(const Smach::event& x)
953 {
954         // synfig::info("STATE BLINE: Received mouse button down Event");
955         const EventMouse& event(*reinterpret_cast<const EventMouse*>(&x));
956         switch(event.button)
957         {
958         case BUTTON_LEFT:
959                 {
960                         // If we are already looped up, then don't try to add anything else
961                         if(loop_)
962                                 return Smach::RESULT_OK;
963
964                         BLinePoint bline_point;
965
966                         bline_point.set_vertex(get_work_area()->snap_point_to_grid(event.pos));
967                         //bline_point.set_width(synfigapp::Main::get_bline_width());
968                         bline_point.set_width(1.0f);
969                         bline_point.set_origin(0.5f);
970                         bline_point.set_split_tangent_flag(false);
971                         bline_point.set_tangent1(Vector(0,0));
972
973                         // set the tangent
974                         /*
975                         if(bline_point_list.empty())
976                         {
977                                 bline_point.set_tangent1(Vector(1,1));
978                         }
979                         else
980                         {
981                                 const Vector t(event.pos-bline_point_list.back()->get_value().get(BLinePoint()).get_vertex());
982                                 bline_point.set_tangent1(t);
983                         }
984
985                         if(bline_point_list.size()>1)
986                         {
987                                 std::list<synfig::ValueNode_Const::Handle>::iterator iter;
988                                 iter=bline_point_list.end();
989                                 iter--;iter--;
990                                 BLinePoint prev(bline_point_list.back()->get_value().get(BLinePoint()));
991                                 prev.set_tangent1(event.pos-(*iter)->get_value().get(BLinePoint()).get_vertex());
992                                 bline_point_list.back()->set_value(prev);
993                         };
994                         */
995
996                         bline_point_list.push_back(ValueNode_Const::create(bline_point));
997
998                         refresh_ducks();
999                         return Smach::RESULT_ACCEPT;
1000                 }
1001
1002         default:
1003                 return Smach::RESULT_OK;
1004         }
1005 }
1006
1007 void
1008 StateBLine_Context::refresh_ducks(bool button_down)
1009 {
1010         get_work_area()->clear_ducks();
1011         get_work_area()->queue_draw();
1012
1013         if(bline_point_list.empty())
1014                 return;
1015
1016         list<ValueNode_Const::Handle>::iterator iter;
1017
1018         handle<WorkArea::Bezier> bezier;
1019         handle<WorkArea::Duck> duck,tduck;
1020         BLinePoint bline_point;
1021
1022         for(iter=bline_point_list.begin();iter!=bline_point_list.end();++iter)
1023         {
1024                 ValueNode_Const::Handle value_node(*iter);
1025                 bline_point=(value_node->get_value().get(BLinePoint()));
1026                 assert(value_node);
1027
1028
1029                 // First add the duck associated with this vertex
1030                 duck=new WorkArea::Duck(bline_point.get_vertex());
1031                 duck->set_editable(true);
1032 #ifdef DISTINGUISH_FIRST_DUCK
1033                 if (iter!=bline_point_list.begin())
1034                         duck->set_type(Duck::TYPE_VERTEX);
1035 #else
1036                 duck->set_type(Duck::TYPE_VERTEX);
1037 #endif
1038                 duck->set_name(strprintf("%x-vertex",value_node.get()));
1039                 duck->signal_edited().connect(
1040                         sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::on_vertex_change),value_node)
1041                 );
1042                 duck->signal_user_click(2).connect(
1043                         sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::popup_vertex_menu),value_node)
1044                 );
1045                 duck->set_guid(value_node->get_guid()^synfig::GUID::hasher(0));
1046
1047                 get_work_area()->add_duck(duck);
1048
1049                 // Add the tangent1 duck
1050                 tduck=new WorkArea::Duck(bline_point.get_tangent1());
1051                 tduck->set_editable(true);
1052                 tduck->set_name(strprintf("%x-tangent1",value_node.get()));
1053                 tduck->set_origin(duck);
1054                 tduck->set_scalar(-0.33333333333333333);
1055                 tduck->set_tangent(true);
1056                 tduck->set_guid(value_node->get_guid()^synfig::GUID::hasher(3));
1057                 tduck->signal_edited().connect(
1058                         sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::on_tangent1_change),value_node)
1059                 );
1060                 tduck->signal_user_click(2).connect(
1061                         sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::popup_handle_menu),value_node)
1062                 );
1063
1064                 // See if we need to add that duck to the previous bezier
1065                 if(bezier)
1066                 {
1067                         get_work_area()->add_duck(tduck);
1068                         bezier->p2=duck;
1069                         bezier->c2=tduck;
1070
1071                         bezier->signal_user_click(2).connect(
1072                                 sigc::bind(
1073                                         sigc::mem_fun(
1074                                                 *this,
1075                                                 &studio::StateBLine_Context::popup_bezier_menu
1076                                         ),
1077                                         value_node
1078                                 )
1079                         );
1080
1081                         //get_work_area()->add_duck(bezier->c1);
1082                         //get_work_area()->add_duck(bezier->c2);
1083                         get_work_area()->add_bezier(bezier);
1084
1085                         bezier=0;
1086                 }
1087
1088                 // Now we see if we need to create a bezier
1089                 list<ValueNode_Const::Handle>::iterator next(iter);
1090                 next++;
1091
1092                 // If our next iterator is the end, then we don't need
1093                 // to add a bezier.
1094                 //if(next==bline_point_list.end() && !loop_)
1095                 //      continue;
1096
1097                 bezier=new WorkArea::Bezier();
1098
1099                 // Add the tangent2 duck
1100                 tduck=new WorkArea::Duck(bline_point.get_tangent2());
1101                 tduck->set_editable(true);
1102                 tduck->set_origin(duck);
1103                 tduck->set_scalar(0.33333333333333333);
1104                 tduck->set_tangent(true);
1105                 if(bline_point.get_split_tangent_flag())
1106                 {
1107                         tduck->set_name(strprintf("%x-tangent2",value_node.get()));
1108                         tduck->signal_edited().connect(
1109                                 sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::on_tangent2_change),value_node)
1110                         );
1111                 }
1112                 else
1113                 {
1114                         tduck->set_name(strprintf("%x-tangent1",value_node.get()));
1115                         tduck->signal_edited().connect(
1116                                 sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::on_tangent1_change),value_node)
1117                         );
1118                 }
1119                 tduck->set_guid(value_node->get_guid()^synfig::GUID::hasher(4));
1120                 tduck->signal_user_click(2).connect(
1121                         sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::popup_handle_menu),value_node)
1122                 );
1123
1124                 // Setup the next bezier
1125                 bezier->p1=duck;
1126                 bezier->c1=tduck;
1127
1128                 get_work_area()->add_duck(tduck);
1129                 curr_duck=tduck;
1130         }
1131
1132         // Add the loop, if requested
1133         if(bezier && loop_)
1134         {
1135                 curr_duck=0;
1136                 BLinePoint bline_point(bline_point_list.front()->get_value().get(BLinePoint()));
1137
1138                 duck=new WorkArea::Duck(bline_point.get_vertex());
1139                 duck->set_editable(true);
1140 #ifndef DISTINGUISH_FIRST_DUCK
1141                 duck->set_type(Duck::TYPE_VERTEX);
1142 #endif
1143                 duck->set_name(strprintf("%x-vertex",bline_point_list.front().get()));
1144                 duck->signal_edited().connect(
1145                         sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::on_vertex_change),bline_point_list.front())
1146                 );
1147                 duck->signal_user_click(2).connect(
1148                         sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::popup_vertex_menu),bline_point_list.front())
1149                 );
1150                 get_work_area()->add_duck(duck);
1151
1152                 // Add the tangent1 duck
1153                 tduck=new WorkArea::Duck(bline_point.get_tangent1());
1154                 tduck->set_editable(true);
1155                 tduck->set_name(strprintf("%x-tangent1",bline_point_list.front().get()));
1156                 tduck->set_origin(duck);
1157                 tduck->set_scalar(-0.33333333333333333);
1158                 tduck->set_tangent(true);
1159                 tduck->signal_edited().connect(
1160                         sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::on_tangent1_change),bline_point_list.front())
1161                 );
1162                 tduck->signal_user_click(2).connect(
1163                         sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::popup_handle_menu),bline_point_list.front())
1164                 );
1165                 get_work_area()->add_duck(tduck);
1166
1167                 bezier->p2=duck;
1168                 bezier->c2=tduck;
1169
1170                 bezier->signal_user_click(2).connect(
1171                         sigc::bind(
1172                                 sigc::mem_fun(
1173                                         *this,
1174                                         &studio::StateBLine_Context::popup_bezier_menu
1175                                 ),
1176                                 bline_point_list.front()
1177                         )
1178                 );
1179
1180                 //get_work_area()->add_duck(bezier->c1);
1181                 get_work_area()->add_bezier(bezier);
1182         }
1183         if(bezier && !loop_)
1184         {
1185                 duck=new WorkArea::Duck(bline_point.get_vertex());
1186                 duck->set_ignore(true);
1187                 duck->set_name("temp");
1188
1189                 // Add the tangent1 duck
1190                 tduck=new WorkArea::Duck(Vector(0,0));
1191                 tduck->set_ignore(true);
1192                 tduck->set_name("ttemp");
1193                 tduck->set_origin(duck);
1194                 tduck->set_scalar(-0.33333333333333333);
1195
1196                 tduck->set_tangent(true);
1197                 bezier->p2=duck;
1198                 bezier->c2=tduck;
1199
1200                 get_work_area()->add_duck(bezier->p2);
1201                 //get_work_area()->add_duck(bezier->c2);
1202                 get_work_area()->add_bezier(bezier);
1203
1204                 duck->set_guid(synfig::GUID());
1205                 tduck->set_guid(synfig::GUID());
1206
1207                 next_duck=duck;
1208         }
1209
1210         if(!button_down)
1211         {
1212                 if(curr_duck)
1213                 {
1214                         if(next_duck)
1215                         {
1216                                 curr_duck=next_duck;
1217                                 next_duck=0;
1218                         }
1219                 }
1220         }
1221         get_work_area()->queue_draw();
1222 }
1223
1224
1225 bool
1226 StateBLine_Context::on_vertex_change(const synfig::Point &point, synfig::ValueNode_Const::Handle value_node)
1227 {
1228         BLinePoint bline_point(value_node->get_value().get(BLinePoint()));
1229         bline_point.set_vertex(point);
1230         value_node->set_value(bline_point);
1231         //refresh_ducks();
1232         return true;
1233 }
1234
1235 bool
1236 StateBLine_Context::on_tangent1_change(const synfig::Point &point, synfig::ValueNode_Const::Handle value_node)
1237 {
1238         BLinePoint bline_point(value_node->get_value().get(BLinePoint()));
1239         bline_point.set_tangent1(point);
1240         value_node->set_value(bline_point);
1241         //refresh_ducks();
1242         return true;
1243 }
1244
1245 bool
1246 StateBLine_Context::on_tangent2_change(const synfig::Point &point, synfig::ValueNode_Const::Handle value_node)
1247 {
1248         BLinePoint bline_point(value_node->get_value().get(BLinePoint()));
1249         bline_point.set_tangent2(point);
1250         value_node->set_value(bline_point);
1251         //refresh_ducks();
1252         return true;
1253 }
1254
1255 void
1256 StateBLine_Context::loop_bline()
1257 {
1258         loop_=true;
1259
1260         refresh_ducks(false);
1261 }
1262
1263 void
1264 StateBLine_Context::unloop_bline()
1265 {
1266         loop_=false;
1267
1268         refresh_ducks(false);
1269 }
1270
1271 void
1272 StateBLine_Context::popup_vertex_menu(synfig::ValueNode_Const::Handle value_node)
1273 {
1274         menu.items().clear();
1275
1276         if(loop_)
1277         {
1278                 menu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Unloop BLine"),
1279                                 sigc::mem_fun(*this,&studio::StateBLine_Context::unloop_bline)
1280                 ));
1281         } else {
1282                 menu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Loop BLine"),
1283                                 sigc::mem_fun(*this,&studio::StateBLine_Context::loop_bline)
1284                 ));
1285         }
1286
1287         menu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Delete Vertex"),
1288                 sigc::bind(
1289                         sigc::mem_fun(*this,&studio::StateBLine_Context::bline_delete_vertex),
1290                         value_node
1291                 )
1292         ));
1293
1294         menu.popup(0,0);
1295 }
1296
1297 void
1298 StateBLine_Context::popup_bezier_menu(float location, synfig::ValueNode_Const::Handle value_node)
1299 {
1300         menu.items().clear();
1301
1302         menu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Insert Vertex"),
1303                 sigc::bind(
1304                         sigc::bind(
1305                                 sigc::mem_fun(*this,&studio::StateBLine_Context::bline_insert_vertex),
1306                                 location
1307                         ),
1308                         value_node
1309                 )
1310         ));
1311
1312         menu.popup(0,0);
1313 }
1314
1315 void
1316 StateBLine_Context::bline_insert_vertex(synfig::ValueNode_Const::Handle value_node, float origin)
1317 {
1318         list<ValueNode_Const::Handle>::iterator iter;
1319
1320         for(iter=bline_point_list.begin();iter!=bline_point_list.end();++iter)
1321                 if(*iter==value_node)
1322                 {
1323                         BLinePoint bline_point;
1324                         BLinePoint next_bline_point((*iter)->get_value().get(BLinePoint()));
1325                         BLinePoint prev_bline_point;
1326
1327                         list<ValueNode_Const::Handle>::iterator prev(iter);
1328                         if(iter==bline_point_list.begin())
1329                         {
1330                                 assert(loop_);
1331                                 prev = bline_point_list.end();
1332                         }
1333                         prev--;
1334
1335                         prev_bline_point=(*prev)->get_value().get(BLinePoint());
1336
1337                         etl::hermite<Vector> curve(prev_bline_point.get_vertex(),
1338                                                                            next_bline_point.get_vertex(),
1339                                                                            prev_bline_point.get_tangent2(),
1340                                                                            next_bline_point.get_tangent1());
1341                         etl::derivative< etl::hermite<Vector> > deriv(curve);
1342
1343                         bline_point.set_vertex(curve(origin));
1344                         bline_point.set_width((next_bline_point.get_width()-prev_bline_point.get_width())*origin+prev_bline_point.get_width());
1345                         bline_point.set_tangent1(deriv(origin)*std::min(1.0f-origin,origin));
1346                         bline_point.set_tangent2(bline_point.get_tangent1());
1347                         bline_point.set_split_tangent_flag(false);
1348                         bline_point.set_origin(origin);
1349
1350 /*
1351                         bline_point.set_vertex((next_bline_point.get_vertex()+prev_bline_point.get_vertex())*0.5);
1352                         bline_point.set_width((next_bline_point.get_width()+prev_bline_point.get_width())*0.5);
1353                         bline_point.set_origin(origin);
1354                         bline_point.set_split_tangent_flag(false);
1355                         bline_point.set_tangent1((next_bline_point.get_vertex()-prev_bline_point.get_vertex())*0.5);
1356 */
1357
1358                         bline_point_list.insert(iter,ValueNode_Const::create(bline_point));
1359                         break;
1360                 }
1361
1362         if(iter==bline_point_list.end())
1363         {
1364                 get_canvas_view()->get_ui_interface()->error(_("Unable to find where to insert vertex, internal error, please report this bug"));
1365         }
1366
1367         refresh_ducks(false);
1368 }
1369
1370 void
1371 StateBLine_Context::bline_delete_vertex(synfig::ValueNode_Const::Handle value_node)
1372 {
1373         list<ValueNode_Const::Handle>::iterator iter;
1374
1375         for(iter=bline_point_list.begin();iter!=bline_point_list.end();++iter)
1376                 if(*iter==value_node)
1377                 {
1378                         bline_point_list.erase(iter);
1379                         break;
1380                 }
1381         if(iter==bline_point_list.end())
1382         {
1383                 get_canvas_view()->get_ui_interface()->error(_("Unable to remove vertex, internal error, please report this bug"));
1384         }
1385
1386         refresh_ducks(false);
1387 }
1388
1389 void
1390 StateBLine_Context::popup_handle_menu(synfig::ValueNode_Const::Handle value_node)
1391 {
1392         menu.items().clear();
1393
1394         BLinePoint bline_point(value_node->get_value().get(BLinePoint()));
1395
1396         if(bline_point.get_split_tangent_flag())
1397                 menu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Merge Tangents"),
1398                         sigc::bind(
1399                                 sigc::mem_fun(*this,&studio::StateBLine_Context::bline_attach_handle),
1400                                 value_node
1401                         )
1402                 ));
1403         else
1404                 menu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Split Tangents"),
1405                         sigc::bind(
1406                                 sigc::mem_fun(*this,&studio::StateBLine_Context::bline_detach_handle),
1407                                 value_node
1408                         )
1409                 ));
1410
1411         menu.popup(0,0);
1412 }
1413
1414 void
1415 StateBLine_Context::bline_detach_handle(synfig::ValueNode_Const::Handle value_node)
1416 {
1417         BLinePoint bline_point(value_node->get_value().get(BLinePoint()));
1418         bline_point.set_split_tangent_flag(true);
1419         bline_point.set_tangent2(bline_point.get_tangent1());
1420         value_node->set_value(bline_point);
1421         refresh_ducks(false);
1422 }
1423
1424 void
1425 StateBLine_Context::bline_attach_handle(synfig::ValueNode_Const::Handle value_node)
1426 {
1427         BLinePoint bline_point(value_node->get_value().get(BLinePoint()));
1428         bline_point.set_tangent1((bline_point.get_tangent1()+bline_point.get_tangent2())*0.5);
1429         bline_point.set_split_tangent_flag(false);
1430         value_node->set_value(bline_point);
1431         refresh_ducks(false);
1432 }