1 /* === S Y N F I G ========================================================= */
2 /*! \file state_bline.cpp
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
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.
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.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
33 #include <gtkmm/dialog.h>
34 #include <gtkmm/entry.h>
36 #include <synfig/valuenode_dynamiclist.h>
38 #include "state_bline.h"
39 #include "state_normal.h"
40 #include "canvasview.h"
43 #include <synfig/valuenode_bline.h>
44 #include <ETL/hermite>
45 #include <ETL/calculus>
47 #include "event_mouse.h"
48 #include "event_layerclick.h"
50 #include "docks/dialog_tooloptions.h"
51 #include <gtkmm/spinbutton.h>
52 #include <synfig/transform.h>
53 #include <synfigapp/main.h>
59 /* === U S I N G =========================================================== */
63 using namespace synfig;
64 using namespace studio;
66 /* === M A C R O S ========================================================= */
68 // if defined, show the first duck as green while drawing
69 #define DISTINGUISH_FIRST_DUCK
71 /* === G L O B A L S ======================================================= */
73 StateBLine studio::state_bline;
75 /* === C L A S S E S & S T R U C T S ======================================= */
77 class studio::StateBLine_Context : public sigc::trackable
79 etl::handle<CanvasView> canvas_view_;
80 CanvasView::IsWorking is_working;
82 bool prev_table_status;
84 bool prev_workarea_layer_status_;
87 Canvas::Handle canvas;
91 Duckmatic::Push duckmatic_push;
93 etl::handle<Duck> curr_duck;
95 etl::handle<Duck> next_duck;
97 std::list<synfig::ValueNode_Const::Handle> bline_point_list;
98 synfigapp::Settings& settings;
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);
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);
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);
116 void refresh_ducks(bool x=true);
118 Gtk::Table options_table;
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;
135 int layers_to_create()const
138 get_layer_region_flag() +
139 get_layer_outline_flag() +
140 get_layer_curve_gradient_flag() +
141 get_layer_plant_flag();
146 if(layers_to_create()==0)
147 set_layer_region_flag(true);
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); }
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); }
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); }
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); }
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); }
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); }
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); }
173 Smach::event_result event_stop_handler(const Smach::event& x);
175 Smach::event_result event_refresh_handler(const Smach::event& x);
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);
182 Smach::event_result event_hijack(const Smach::event& /*x*/) { return Smach::RESULT_ACCEPT; }
184 void refresh_tool_options();
186 StateBLine_Context(CanvasView* canvas_view);
188 ~StateBLine_Context();
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(); }
196 void load_settings();
197 void save_settings();
200 //void on_user_click(synfig::Point point);
205 bool egress_on_selection_change;
206 Smach::event_result event_layer_selection_changed_handler(const Smach::event& /*x*/)
208 if(egress_on_selection_change)
209 throw &state_normal; //throw Smach::egress_exception();
210 return Smach::RESULT_OK;
213 }; // END of class StateBLine_Context
216 /* === M E T H O D S ======================================================= */
218 StateBLine::StateBLine():
219 Smach::state<StateBLine_Context>("bline")
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));
232 StateBLine::~StateBLine()
237 StateBLine_Context::load_settings()
241 SETTINGS_LOCALE_SAFE_AND_BACKUP
244 if(settings.get_value("bline.layer_region",value) && value=="0")
245 set_layer_region_flag(false);
247 set_layer_region_flag(true);
249 if(settings.get_value("bline.layer_outline",value) && value=="0")
250 set_layer_outline_flag(false);
252 set_layer_outline_flag(true);
254 if(settings.get_value("bline.layer_curve_gradient",value) && value=="1")
255 set_layer_curve_gradient_flag(true);
257 set_layer_curve_gradient_flag(false);
259 if(settings.get_value("bline.layer_plant",value) && value=="1")
260 set_layer_plant_flag(true);
262 set_layer_plant_flag(false);
264 if(settings.get_value("bline.layer_link_origins",value) && value=="0")
265 set_layer_link_origins_flag(false);
267 set_layer_link_origins_flag(true);
269 if(settings.get_value("bline.auto_export",value) && value=="1")
270 set_auto_export_flag(true);
272 set_auto_export_flag(false);
274 if(settings.get_value("bline.id",value))
279 if(settings.get_value("bline.feather",value))
281 Real n = atof(value.c_str());
286 SETTINGS_LOCALE_RESTORE
290 synfig::warning("State BLine: Caught exception when attempting to load settings.");
295 StateBLine_Context::save_settings()
299 SETTINGS_LOCALE_SAFE_AND_BACKUP
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
313 synfig::warning("State BLine : Caught exception when attempting to save settings.");
318 StateBLine_Context::reset()
321 bline_point_list.clear();
326 StateBLine_Context::increment_id()
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')
340 // figure out how many digits it is
342 (int)id.size()-1 >= digits && id[id.size()-1-digits] <= '9' && id[id.size()-1-digits] >= '0';
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());
351 number=atoi(str_number.c_str());
361 // Add the number back onto the id
363 const String format(strprintf("%%0%dd",digits));
364 id+=strprintf(format.c_str(),number);
372 StateBLine_Context::StateBLine_Context(CanvasView* canvas_view):
373 canvas_view_(canvas_view),
374 is_working(*canvas_view),
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()),
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)
392 egress_on_selection_change=true;
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();
412 // Turn off layer clicking
413 get_work_area()->set_allow_layer_clicks(false);
415 // clear out the ducks
416 get_work_area()->clear_ducks();
418 // Refresh the work area
419 get_work_area()->queue_draw();
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();
425 // Disable the time bar
426 get_canvas_view()->set_sensitive_timebar(false);
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);
432 App::toolbox->refresh();
436 StateBLine_Context::refresh_tool_options()
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");
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(
449 &StateBLine_Context::run
453 App::dialog_tool_options->add_button(
454 Gtk::StockID("gtk-clear"),
455 _("Clear current BLine")
456 )->signal_clicked().connect(
459 &StateBLine_Context::reset
465 StateBLine_Context::event_refresh_tool_options(const Smach::event& /*x*/)
467 refresh_tool_options();
468 return Smach::RESULT_ACCEPT;
471 StateBLine_Context::~StateBLine_Context()
476 App::dialog_tool_options->clear();
478 get_work_area()->reset_cursor();
480 // Restore layer clicking
481 get_work_area()->set_allow_layer_clicks(prev_workarea_layer_status_);
483 // Enable the time bar
484 get_canvas_view()->set_sensitive_timebar(true);
486 // Bring back the tables if they were out before
487 if(prev_table_status)get_canvas_view()->show_tables();
489 // get_canvas_view()->get_smach().process_event(EVENT_REFRESH_DUCKS);
491 // Refresh the work area
492 get_work_area()->queue_draw();
494 App::toolbox->refresh();
498 StateBLine_Context::event_stop_handler(const Smach::event& /*x*/)
500 // synfig::info("STATE RotoBLine: Received Stop Event");
503 // throw Smach::egress_exception();
504 // get_canvas_view()->get_smach().pop_state();
505 return Smach::RESULT_ACCEPT;
509 StateBLine_Context::event_refresh_handler(const Smach::event& /*x*/)
511 // synfig::info("STATE RotoBLine: Received Refresh Event");
513 return Smach::RESULT_ACCEPT;
517 StateBLine_Context::run()
523 for(int i=5;i>0 && !success;i--)try
531 if(!success && !err.empty())
533 get_canvas_view()->get_ui_interface()->error(err);
539 StateBLine_Context::run_()
544 // Now we need to generate it
546 if(bline_point_list.empty())
550 if(bline_point_list.size()<2)
552 //get_canvas_view()->get_ui_interface()->error(_("You need at least two (2) points to create a BLine"));
559 // Create the action group
560 synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("New BLine"));
562 std::vector<BLinePoint> new_list;
563 std::list<synfig::ValueNode_Const::Handle>::iterator iter;
564 const synfig::TransformStack& transform(get_transform_stack());
566 for(iter=bline_point_list.begin();iter!=bline_point_list.end();++iter)
568 BLinePoint bline_point((*iter)->get_value().get(BLinePoint()));
569 Point new_vertex(transform.unperform(bline_point.get_vertex()));
571 bline_point.set_tangent1(
573 bline_point.get_tangent1()+bline_point.get_vertex()
577 bline_point.set_tangent2(
579 bline_point.get_tangent2()+bline_point.get_vertex()
583 bline_point.set_vertex(new_vertex);
585 new_list.push_back(bline_point);
588 ValueNode_BLine::Handle value_node_bline(ValueNode_BLine::create(new_list));
589 assert(value_node_bline);
591 ValueNode_Const::Handle value_node_origin(ValueNode_Const::create(Vector()));
592 assert(value_node_origin);
594 // Set the looping flag
595 value_node_bline->set_loop(loop_);
597 // Add the BLine to the canvas
598 if(get_auto_export_flag() && !get_canvas_interface()->add_value_node(value_node_bline,get_id()))
600 //get_canvas_view()->get_ui_interface()->error(_("Unable to add value node"));
603 throw String(_("Unable to add value node"));
609 // we are temporarily using the layer to hold something
610 layer=get_canvas_view()->get_selection_manager()->get_selected_layer();
615 depth=layer->get_depth();
617 canvas=layer->get_canvas();
623 canvas=get_canvas_view()->get_canvas();
625 value_node_bline->set_member_canvas(canvas);
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();
631 // count how many layers we're going to be creating
632 int layers_to_create = this->layers_to_create();
634 ///////////////////////////////////////////////////////////////////////////
635 // C U R V E G R A D I E N T
636 ///////////////////////////////////////////////////////////////////////////
638 if(get_layer_curve_gradient_flag())
640 synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);
642 Layer::Handle layer(get_canvas_interface()->add_layer_to("curve_gradient",canvas,depth));
646 throw String(_("Unable to create layer"));
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());
653 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
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\"");
664 if(!get_canvas_interface()->get_instance()->perform_action(action))
666 //get_canvas_view()->get_ui_interface()->error(_("Unable to create BLine layer"));
668 throw String(_("Unable to create Gradient layer"));
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)
676 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
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\"");
687 if(!get_canvas_interface()->get_instance()->perform_action(action))
689 //get_canvas_view()->get_ui_interface()->error(_("Unable to create BLine layer"));
691 throw String(_("Unable to create Gradient layer"));
697 ///////////////////////////////////////////////////////////////////////////
699 ///////////////////////////////////////////////////////////////////////////
701 if(get_layer_plant_flag())
703 synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);
705 Layer::Handle layer(get_canvas_interface()->add_layer_to("plant",canvas,depth));
709 throw String(_("Unable to create layer"));
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());
716 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
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\"");
727 if(!get_canvas_interface()->get_instance()->perform_action(action))
729 //get_canvas_view()->get_ui_interface()->error(_("Unable to create BLine layer"));
731 throw String(_("Unable to create Plant layer"));
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)
739 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
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\"");
750 if(!get_canvas_interface()->get_instance()->perform_action(action))
752 //get_canvas_view()->get_ui_interface()->error(_("Unable to create BLine layer"));
754 throw String(_("Unable to create Plant layer"));
760 ///////////////////////////////////////////////////////////////////////////
762 ///////////////////////////////////////////////////////////////////////////
764 if(get_layer_region_flag())
766 synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);
768 Layer::Handle layer(get_canvas_interface()->add_layer_to("region",canvas,depth));
772 throw String(_("Unable to create layer"));
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());
780 layer->set_param("feather",get_feather());
781 get_canvas_interface()->signal_layer_param_changed()(layer,"feather");
784 // I don't know if it's safe to reuse the same LayerParamConnect action, so I'm
785 // using 2 separate ones.
787 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
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\"");
798 if(!get_canvas_interface()->get_instance()->perform_action(action))
800 //get_canvas_view()->get_ui_interface()->error(_("Unable to create Region layer"));
802 throw String(_("Unable to create Region layer"));
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)
810 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
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\"");
821 if(!get_canvas_interface()->get_instance()->perform_action(action))
823 //get_canvas_view()->get_ui_interface()->error(_("Unable to create Region layer"));
825 throw String(_("Unable to create Region layer"));
831 ///////////////////////////////////////////////////////////////////////////
833 ///////////////////////////////////////////////////////////////////////////
835 if(get_layer_outline_flag())
837 synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);
839 Layer::Handle layer(get_canvas_interface()->add_layer_to("outline",canvas,depth));
843 throw String(_("Unable to create layer"));
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());
850 layer->set_param("feather",get_feather());
851 get_canvas_interface()->signal_layer_param_changed()(layer,"feather");
855 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
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\"");
866 if(!get_canvas_interface()->get_instance()->perform_action(action))
868 //get_canvas_view()->get_ui_interface()->error(_("Unable to create BLine layer"));
870 throw String(_("Unable to create Outline layer"));
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)
878 synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
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\"");
889 if(!get_canvas_interface()->get_instance()->perform_action(action))
891 //get_canvas_view()->get_ui_interface()->error(_("Unable to create BLine layer"));
893 throw String(_("Unable to create Outline layer"));
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;
904 //if(finish_bline_dialog.get_region_flag() || finish_bline_dialog.get_bline_flag())
905 // get_canvas_interface()->signal_dirty_preview()();
915 StateBLine_Context::event_mouse_motion_handler(const Smach::event& x)
917 const EventMouse& event(*reinterpret_cast<const EventMouse*>(&x));
921 //synfig::info("Moved Duck");
922 Point p(get_work_area()->snap_point_to_grid(event.pos));
923 curr_duck->set_trans_point(p);
925 next_duck->set_trans_point(p);
926 get_work_area()->queue_draw();
927 return Smach::RESULT_ACCEPT;
930 return Smach::RESULT_OK;
934 StateBLine_Context::event_mouse_release_handler(const Smach::event& /*x*/)
938 //synfig::info("Released current duck");
939 curr_duck->signal_edited()(curr_duck->get_point());
942 //synfig::info("grabbing next duck");
946 return Smach::RESULT_ACCEPT;
948 return Smach::RESULT_OK;
952 StateBLine_Context::event_mouse_click_handler(const Smach::event& x)
954 // synfig::info("STATE BLINE: Received mouse button down Event");
955 const EventMouse& event(*reinterpret_cast<const EventMouse*>(&x));
960 // If we are already looped up, then don't try to add anything else
962 return Smach::RESULT_OK;
964 BLinePoint bline_point;
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));
975 if(bline_point_list.empty())
977 bline_point.set_tangent1(Vector(1,1));
981 const Vector t(event.pos-bline_point_list.back()->get_value().get(BLinePoint()).get_vertex());
982 bline_point.set_tangent1(t);
985 if(bline_point_list.size()>1)
987 std::list<synfig::ValueNode_Const::Handle>::iterator iter;
988 iter=bline_point_list.end();
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);
996 bline_point_list.push_back(ValueNode_Const::create(bline_point));
999 return Smach::RESULT_ACCEPT;
1003 return Smach::RESULT_OK;
1008 StateBLine_Context::refresh_ducks(bool button_down)
1010 get_work_area()->clear_ducks();
1011 get_work_area()->queue_draw();
1013 if(bline_point_list.empty())
1016 list<ValueNode_Const::Handle>::iterator iter;
1018 handle<WorkArea::Bezier> bezier;
1019 handle<WorkArea::Duck> duck,tduck;
1020 BLinePoint bline_point;
1022 for(iter=bline_point_list.begin();iter!=bline_point_list.end();++iter)
1024 ValueNode_Const::Handle value_node(*iter);
1025 bline_point=(value_node->get_value().get(BLinePoint()));
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);
1036 duck->set_type(Duck::TYPE_VERTEX);
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)
1042 duck->signal_user_click(2).connect(
1043 sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::popup_vertex_menu),value_node)
1045 duck->set_guid(value_node->get_guid()^synfig::GUID::hasher(0));
1047 get_work_area()->add_duck(duck);
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)
1060 tduck->signal_user_click(2).connect(
1061 sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::popup_handle_menu),value_node)
1064 // See if we need to add that duck to the previous bezier
1067 get_work_area()->add_duck(tduck);
1071 bezier->signal_user_click(2).connect(
1075 &studio::StateBLine_Context::popup_bezier_menu
1081 //get_work_area()->add_duck(bezier->c1);
1082 //get_work_area()->add_duck(bezier->c2);
1083 get_work_area()->add_bezier(bezier);
1088 // Now we see if we need to create a bezier
1089 list<ValueNode_Const::Handle>::iterator next(iter);
1092 // If our next iterator is the end, then we don't need
1094 //if(next==bline_point_list.end() && !loop_)
1097 bezier=new WorkArea::Bezier();
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())
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)
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)
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)
1124 // Setup the next bezier
1128 get_work_area()->add_duck(tduck);
1132 // Add the loop, if requested
1136 BLinePoint bline_point(bline_point_list.front()->get_value().get(BLinePoint()));
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);
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())
1147 duck->signal_user_click(2).connect(
1148 sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::popup_vertex_menu),bline_point_list.front())
1150 get_work_area()->add_duck(duck);
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())
1162 tduck->signal_user_click(2).connect(
1163 sigc::bind(sigc::mem_fun(*this,&studio::StateBLine_Context::popup_handle_menu),bline_point_list.front())
1165 get_work_area()->add_duck(tduck);
1170 bezier->signal_user_click(2).connect(
1174 &studio::StateBLine_Context::popup_bezier_menu
1176 bline_point_list.front()
1180 //get_work_area()->add_duck(bezier->c1);
1181 get_work_area()->add_bezier(bezier);
1183 if(bezier && !loop_)
1185 duck=new WorkArea::Duck(bline_point.get_vertex());
1186 duck->set_ignore(true);
1187 duck->set_name("temp");
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);
1196 tduck->set_tangent(true);
1200 get_work_area()->add_duck(bezier->p2);
1201 //get_work_area()->add_duck(bezier->c2);
1202 get_work_area()->add_bezier(bezier);
1204 duck->set_guid(synfig::GUID());
1205 tduck->set_guid(synfig::GUID());
1216 curr_duck=next_duck;
1221 get_work_area()->queue_draw();
1226 StateBLine_Context::on_vertex_change(const synfig::Point &point, synfig::ValueNode_Const::Handle value_node)
1228 BLinePoint bline_point(value_node->get_value().get(BLinePoint()));
1229 bline_point.set_vertex(point);
1230 value_node->set_value(bline_point);
1236 StateBLine_Context::on_tangent1_change(const synfig::Point &point, synfig::ValueNode_Const::Handle value_node)
1238 BLinePoint bline_point(value_node->get_value().get(BLinePoint()));
1239 bline_point.set_tangent1(point);
1240 value_node->set_value(bline_point);
1246 StateBLine_Context::on_tangent2_change(const synfig::Point &point, synfig::ValueNode_Const::Handle value_node)
1248 BLinePoint bline_point(value_node->get_value().get(BLinePoint()));
1249 bline_point.set_tangent2(point);
1250 value_node->set_value(bline_point);
1256 StateBLine_Context::loop_bline()
1260 refresh_ducks(false);
1264 StateBLine_Context::unloop_bline()
1268 refresh_ducks(false);
1272 StateBLine_Context::popup_vertex_menu(synfig::ValueNode_Const::Handle value_node)
1274 menu.items().clear();
1278 menu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Unloop BLine"),
1279 sigc::mem_fun(*this,&studio::StateBLine_Context::unloop_bline)
1282 menu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Loop BLine"),
1283 sigc::mem_fun(*this,&studio::StateBLine_Context::loop_bline)
1287 menu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Delete Vertex"),
1289 sigc::mem_fun(*this,&studio::StateBLine_Context::bline_delete_vertex),
1298 StateBLine_Context::popup_bezier_menu(float location, synfig::ValueNode_Const::Handle value_node)
1300 menu.items().clear();
1302 menu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Insert Vertex"),
1305 sigc::mem_fun(*this,&studio::StateBLine_Context::bline_insert_vertex),
1316 StateBLine_Context::bline_insert_vertex(synfig::ValueNode_Const::Handle value_node, float origin)
1318 list<ValueNode_Const::Handle>::iterator iter;
1320 for(iter=bline_point_list.begin();iter!=bline_point_list.end();++iter)
1321 if(*iter==value_node)
1323 BLinePoint bline_point;
1324 BLinePoint next_bline_point((*iter)->get_value().get(BLinePoint()));
1325 BLinePoint prev_bline_point;
1327 list<ValueNode_Const::Handle>::iterator prev(iter);
1328 if(iter==bline_point_list.begin())
1331 prev = bline_point_list.end();
1335 prev_bline_point=(*prev)->get_value().get(BLinePoint());
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);
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);
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);
1358 bline_point_list.insert(iter,ValueNode_Const::create(bline_point));
1362 if(iter==bline_point_list.end())
1364 get_canvas_view()->get_ui_interface()->error(_("Unable to find where to insert vertex, internal error, please report this bug"));
1367 refresh_ducks(false);
1371 StateBLine_Context::bline_delete_vertex(synfig::ValueNode_Const::Handle value_node)
1373 list<ValueNode_Const::Handle>::iterator iter;
1375 for(iter=bline_point_list.begin();iter!=bline_point_list.end();++iter)
1376 if(*iter==value_node)
1378 bline_point_list.erase(iter);
1381 if(iter==bline_point_list.end())
1383 get_canvas_view()->get_ui_interface()->error(_("Unable to remove vertex, internal error, please report this bug"));
1386 refresh_ducks(false);
1390 StateBLine_Context::popup_handle_menu(synfig::ValueNode_Const::Handle value_node)
1392 menu.items().clear();
1394 BLinePoint bline_point(value_node->get_value().get(BLinePoint()));
1396 if(bline_point.get_split_tangent_flag())
1397 menu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Merge Tangents"),
1399 sigc::mem_fun(*this,&studio::StateBLine_Context::bline_attach_handle),
1404 menu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Split Tangents"),
1406 sigc::mem_fun(*this,&studio::StateBLine_Context::bline_detach_handle),
1415 StateBLine_Context::bline_detach_handle(synfig::ValueNode_Const::Handle value_node)
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);
1425 StateBLine_Context::bline_attach_handle(synfig::ValueNode_Const::Handle value_node)
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);