source: synfigstudio/trunk/fuentes/.pc/c++11.patch/src/gui/states/state_draw.cpp @ 481

Last change on this file since 481 was 481, checked in by jrpelegrina, 4 years ago

First release to xenial

File size: 96.1 KB
Line 
1/* === S Y N F I G ========================================================= */
2/*!     \file state_draw.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 Chris Moore
10**      Copyright (c) 2009 Nikita Kitaev
11**  Copyright (c) 2010 Carlos López
12**
13**      This package is free software; you can redistribute it and/or
14**      modify it under the terms of the GNU General Public License as
15**      published by the Free Software Foundation; either version 2 of
16**      the License, or (at your option) any later version.
17**
18**      This package is distributed in the hope that it will be useful,
19**      but WITHOUT ANY WARRANTY; without even the implied warranty of
20**      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21**      General Public License for more details.
22**      \endlegal
23*/
24/* ========================================================================= */
25
26/* === H E A D E R S ======================================================= */
27
28#ifdef USING_PCH
29#       include "pch.h"
30#else
31#ifdef HAVE_CONFIG_H
32#       include <config.h>
33#endif
34
35#include <ETL/hermite>
36#include <ETL/calculus>
37#include <ETL/gaussian>
38
39#include <synfig/valuenodes/valuenode_bline.h>
40#include <synfig/valuenodes/valuenode_wplist.h>
41#include <synfig/valuenodes/valuenode_composite.h>
42#include <synfig/valuenodes/valuenode_dynamiclist.h>
43
44#include <synfigapp/blineconvert.h>
45#include <synfigapp/wplistconverter.h>
46#include <synfigapp/main.h>
47
48#include "widgets/widget_distance.h"
49#include "widgets/widget_enum.h"
50
51#include "event_mouse.h"
52#include "event_layerclick.h"
53#include "docks/dock_toolbox.h"
54#include "docks/dialog_tooloptions.h"
55#include "state_draw.h"
56#include "state_stroke.h"
57#include "state_normal.h"
58#include "canvasview.h"
59#include "workarea.h"
60#include "app.h"
61
62#include <utility>
63#include <sigc++/connection.h>
64
65#include <gtkmm/radiobutton.h>
66#include <gtkmm/radiobuttongroup.h>
67
68#include "general.h"
69
70#endif
71
72/* === U S I N G =========================================================== */
73
74using namespace std;
75using namespace etl;
76using namespace synfig;
77using namespace studio;
78
79/* === M A C R O S ========================================================= */
80
81#ifndef LAYER_CREATION
82#define LAYER_CREATION(button, stockid, tooltip)        \
83        { \
84                Gtk::Image *icon = manage(new Gtk::Image(Gtk::StockID(stockid), \
85                        Gtk::ICON_SIZE_SMALL_TOOLBAR)); \
86                button.add(*icon); \
87        } \
88        button.set_relief(Gtk::RELIEF_NONE); \
89        button.set_tooltip_text(tooltip); \
90        button.signal_toggled().connect(sigc::mem_fun(*this, \
91                &studio::StateDraw_Context::toggle_layer_creation))
92#endif
93
94// indentation for options layout
95#ifndef SPACING
96#define SPACING(name, px) \
97        Gtk::Alignment *name = Gtk::manage(new Gtk::Alignment()); \
98        name->set_size_request(px)
99#endif
100
101#define GAP     (3)
102#define INDENTATION (6)
103
104/* === G L O B A L S ======================================================= */
105
106StateDraw studio::state_draw;
107
108/* === C L A S S E S & S T R U C T S ======================================= */
109
110class studio::StateDraw_Context : public sigc::trackable
111{
112        typedef etl::smart_ptr<std::list<synfig::Point> > StrokeData;
113        typedef etl::smart_ptr<std::list<synfig::Real> > WidthData;
114
115        typedef list< pair<StrokeData,WidthData> > StrokeQueue;
116
117        StrokeQueue stroke_queue;
118
119
120        etl::handle<CanvasView> canvas_view_;
121        CanvasView::IsWorking is_working;
122
123        WorkArea::PushState push_state;
124
125        bool prev_table_status;
126        bool loop_;
127
128        int nested;
129        sigc::connection process_queue_connection;
130
131        ValueNode_BLine::Handle last_stroke;
132        synfig::String last_stroke_id;
133
134        Gtk::Menu menu;
135
136        std::list< etl::smart_ptr<std::list<synfig::Point> > > stroke_list;
137
138        void refresh_ducks();
139
140        void fill_last_stroke();
141        Smach::event_result fill_last_stroke_and_unselect_other_layers();
142
143        Smach::event_result new_bline(std::list<synfig::BLinePoint> bline, std::list<synfig::WidthPoint> wplist, bool loop_bline_flag,float radius);
144        Smach::event_result new_region(std::list<synfig::BLinePoint> bline,synfig::Real radius);
145
146        Smach::event_result extend_bline_from_begin(ValueNode_BLine::Handle value_node,std::list<synfig::BLinePoint> bline,std::list<synfig::WidthPoint> wplist,bool complete_loop);
147        Smach::event_result extend_bline_from_end(ValueNode_BLine::Handle value_node,std::list<synfig::BLinePoint> bline,std::list<synfig::WidthPoint> wplist,bool complete_loop);
148        void reverse_bline(std::list<synfig::BLinePoint> &bline);
149        void reverse_wplist(std::list<synfig::WidthPoint> &wplist);
150
151        //Toolbox settings
152        synfigapp::Settings& settings;
153
154        // holder of options
155        Gtk::Table options_table;
156
157        // title
158        Gtk::Label title_label;
159
160        // layer name:
161        Gtk::Label id_label;
162        Gtk::HBox id_box;
163        Gtk::Entry id_entry;
164
165        // layer types to create:
166        Gtk::Label layer_types_label;
167        Gtk::ToggleButton layer_region_togglebutton;
168        Gtk::ToggleButton layer_outline_togglebutton;
169        Gtk::ToggleButton layer_advanced_outline_togglebutton;
170        Gtk::HBox layer_types_box;
171
172        // blend method
173        Gtk::Label blend_label;
174        Gtk::HBox blend_box;
175        Widget_Enum blend_enum;
176
177        // opacity
178        Gtk::Label opacity_label;
179        Gtk::HScale opacity_hscl;
180
181        // brush size
182        Gtk::Label bline_width_label;
183        Widget_Distance bline_width_dist;
184
185        // pressure width
186        Gtk::Label pressure_width_label;
187        Gtk::CheckButton pressure_width_checkbutton;
188        Gtk::HBox pressure_width_box;
189
190        // min pressure, sub option of pressure width
191        Gtk::Label min_pressure_label;
192        Gtk::HBox min_pressure_label_box;
193
194        Gtk::CheckButton min_pressure_checkbutton;
195        Glib::RefPtr<Gtk::Adjustment> min_pressure_adj;
196        Gtk::SpinButton  min_pressure_spin;
197        Gtk::HBox min_pressure_box;
198
199        // smoothness
200        Gtk::Label smoothness_label;
201        Gtk::RadioButton::Group smoothness_group;
202
203        // local threshold
204        Gtk::RadioButton localthres_radiobutton;
205        Glib::RefPtr<Gtk::Adjustment> localthres_adj;
206        Gtk::SpinButton localthres_spin;
207        Gtk::HBox localthres_box;
208
209        // golbal threshold
210        Gtk::RadioButton globalthres_radiobutton;
211        Glib::RefPtr<Gtk::Adjustment> globalthres_adj;
212        Gtk::SpinButton globalthres_spin;
213        Gtk::HBox globalthres_box;
214
215        // width max error advanced outline layer
216        Gtk::Label width_max_error_label;
217        Gtk::HBox width_max_error_box;
218        Glib::RefPtr<Gtk::Adjustment> width_max_error_adj;
219        Gtk::SpinButton width_max_error_spin;
220
221        // constructing control
222        // round ends
223        Gtk::Label round_ends_label;
224        Gtk::CheckButton round_ends_checkbutton;
225        Gtk::HBox round_ends_box;
226
227        // whether to loop new strokes which start and end in the same place
228        Gtk::Label auto_loop_label;
229        Gtk::CheckButton auto_loop_checkbutton;
230        Gtk::HBox auto_loop_box;
231
232        // whether to extend existing lines
233        Gtk::Label auto_extend_label;
234        Gtk::CheckButton auto_extend_checkbutton;
235        Gtk::HBox auto_extend_box;
236
237        // whether to link new ducks to existing ducks
238        Gtk::Label auto_link_label;
239        Gtk::CheckButton auto_link_checkbutton;
240        Gtk::HBox auto_link_box;
241
242        // feather size
243        Gtk::Label feather_label;
244        Widget_Distance feather_dist;
245
246        // auto export
247        Gtk::Label auto_export_label;
248        Gtk::CheckButton auto_export_checkbutton;
249        Gtk::HBox auto_export_box;
250
251        // toolbar buttons
252        Gtk::Button fill_last_stroke_button;
253
254
255        void UpdateUsePressure();
256        void UpdateCreateAdvancedOutline();
257        void UpdateSmoothness();
258
259        //Added by Adrian - data drive HOOOOO
260        synfigapp::BLineConverter blineconv;
261        synfigapp::WPListConverter wplistconv;
262
263public:
264        synfig::String get_id()const { return id_entry.get_text(); }
265        void set_id(const synfig::String& x) { return id_entry.set_text(x); }
266
267        int get_blend()const { return blend_enum.get_value(); }
268        void set_blend(int x) { return blend_enum.set_value(x); }
269
270        Real get_opacity()const { return opacity_hscl.get_value(); }
271        void set_opacity(Real x) { opacity_hscl.set_value(x); }
272
273        Real get_bline_width() const {
274                return bline_width_dist.get_value().get(
275                        Distance::SYSTEM_UNITS,
276                        get_canvas_view()->get_canvas()->rend_desc()
277                );
278        }
279        void set_bline_width(Distance x) { return bline_width_dist.set_value(x);}
280
281        bool get_pressure_width_flag()const { return pressure_width_checkbutton.get_active(); }
282        void set_pressure_width_flag(bool x) { return pressure_width_checkbutton.set_active(x); }
283
284        bool get_auto_loop_flag()const { return auto_loop_checkbutton.get_active(); }
285        void set_auto_loop_flag(bool x) { return auto_loop_checkbutton.set_active(x); }
286
287        bool get_auto_extend_flag()const { return auto_extend_checkbutton.get_active(); }
288        void set_auto_extend_flag(bool x) { return auto_extend_checkbutton.set_active(x); }
289
290        bool get_auto_link_flag()const { return auto_link_checkbutton.get_active(); }
291        void set_auto_link_flag(bool x) { return auto_link_checkbutton.set_active(x); }
292
293        bool get_layer_region_flag()const { return layer_region_togglebutton.get_active(); }
294        void set_layer_region_flag(bool x) { return layer_region_togglebutton.set_active(x); }
295
296        bool get_layer_outline_flag()const { return layer_outline_togglebutton.get_active(); }
297        void set_layer_outline_flag(bool x) { return layer_outline_togglebutton.set_active(x); }
298
299        bool get_layer_advanced_outline_flag()const { return layer_advanced_outline_togglebutton.get_active(); }
300        void set_layer_advanced_outline_flag(bool x) { return layer_advanced_outline_togglebutton.set_active(x); }
301
302        bool get_auto_export_flag()const { return auto_export_checkbutton.get_active(); }
303        void set_auto_export_flag(bool x) { return auto_export_checkbutton.set_active(x); }
304
305        Real get_min_pressure() const { return min_pressure_adj->get_value(); }
306        void set_min_pressure(Real x) { return min_pressure_adj->set_value(x); }
307
308        Real get_feather_size() const {
309                return feather_dist.get_value().get(Distance::SYSTEM_UNITS,
310                get_canvas_view()->get_canvas()->rend_desc());
311        }
312        void set_feather_size(Distance x) { return feather_dist.set_value(x); }
313
314        Real get_gthres() const { return globalthres_adj->get_value(); }
315        void set_gthres(Real x) { return globalthres_adj->set_value(x); }
316
317        Real get_lthres() const { return localthres_adj->get_value(); }
318        void set_lthres(Real x) { return localthres_adj->set_value(x); }
319
320        Real get_width_max_error() const { return width_max_error_adj->get_value(); }
321        void set_width_max_error(Real x) { return width_max_error_adj->set_value(x); }
322
323        bool get_local_threshold_flag() const { return localthres_radiobutton.get_active(); }
324        void set_local_threshold_flag(bool x) { localthres_radiobutton.set_active(x); }
325
326        bool get_global_threshold_flag() const { return globalthres_radiobutton.get_active(); }
327        void set_global_threshold_flag(bool x) { globalthres_radiobutton.set_active(x); }
328
329        bool get_min_pressure_flag()const { return min_pressure_checkbutton.get_active(); }
330        void set_min_pressure_flag(bool x) { min_pressure_checkbutton.set_active(x); }
331
332        bool get_round_ends_flag()const { return round_ends_checkbutton.get_active();}
333        void set_round_ends_flag(bool x) {round_ends_checkbutton.set_active(x);}
334
335  bool layer_region_flag;
336  bool layer_outline_flag;
337  bool layer_advanced_outline_flag;
338
339        void load_settings();
340        void save_settings();
341        void increment_id();
342
343        Smach::event_result event_stop_handler(const Smach::event& x);
344
345        Smach::event_result event_refresh_handler(const Smach::event& x);
346
347        Smach::event_result event_mouse_down_handler(const Smach::event& x);
348
349        Smach::event_result event_stroke(const Smach::event& x);
350        Smach::event_result event_refresh_tool_options(const Smach::event& x);
351        void refresh_tool_options();
352
353        Smach::event_result process_stroke(StrokeData stroke_data, WidthData width_data, bool region_flag=false);
354
355        bool process_queue();
356
357
358        StateDraw_Context(CanvasView* canvas_view);
359
360        ~StateDraw_Context();
361
362        const etl::handle<CanvasView>& get_canvas_view()const{return canvas_view_;}
363        etl::handle<synfigapp::CanvasInterface> get_canvas_interface()const{return canvas_view_->canvas_interface();}
364        synfig::Time get_time()const { return get_canvas_interface()->get_time(); }
365        synfig::Canvas::Handle get_canvas()const{return canvas_view_->get_canvas();}
366        WorkArea * get_work_area()const{return canvas_view_->get_work_area();}
367
368        //void on_user_click(synfig::Point point);
369
370//      bool run();
371
372        void toggle_layer_creation();
373
374};      // END of class StateDraw_Context
375
376
377/* === M E T H O D S ======================================================= */
378
379StateDraw::StateDraw():
380        Smach::state<StateDraw_Context>("draw")
381{
382        insert(event_def(EVENT_STOP,&StateDraw_Context::event_stop_handler));
383        insert(event_def(EVENT_REFRESH,&StateDraw_Context::event_refresh_handler));
384        insert(event_def(EVENT_WORKAREA_MOUSE_BUTTON_DOWN,&StateDraw_Context::event_mouse_down_handler));
385        insert(event_def(EVENT_WORKAREA_STROKE,&StateDraw_Context::event_stroke));
386        insert(event_def(EVENT_REFRESH_TOOL_OPTIONS,&StateDraw_Context::event_refresh_tool_options));
387}
388
389StateDraw::~StateDraw()
390{
391}
392
393
394void
395StateDraw_Context::load_settings()
396{
397        try
398        {
399                synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
400                String value;
401
402                if(settings.get_value("draw.id",value))
403                        set_id(value);
404                else
405                        set_id("NewDrawing");
406
407                if(settings.get_value("draw.blend",value) && value != "")
408                        set_blend(atoi(value.c_str()));
409                else
410                        set_blend(0);//(int)Color::BLEND_COMPOSITE); //0 should be blend composites value
411
412                if(settings.get_value("draw.opacity",value))
413                        set_opacity(atof(value.c_str()));
414                else
415                        set_opacity(1);
416
417                if(settings.get_value("draw.bline_width",value) && value != "")
418                        set_bline_width(Distance(atof(value.c_str()), App::distance_system));
419                else
420                        set_bline_width(Distance(1, App::distance_system)); // default width
421
422                if(settings.get_value("draw.pressure_width",value) && value=="0")
423                        set_pressure_width_flag(false);
424                else
425                        set_pressure_width_flag(true);
426
427                if(settings.get_value("draw.auto_loop",value) && value=="0")
428                        set_auto_loop_flag(false);
429                else
430                        set_auto_loop_flag(true);
431
432                if(settings.get_value("draw.auto_extend",value) && value=="0")
433                        set_auto_extend_flag(false);
434                else
435                        set_auto_extend_flag(true);
436
437                if(settings.get_value("draw.auto_link",value) && value=="0")
438                        set_auto_link_flag(false);
439                else
440                        set_auto_link_flag(true);
441
442                if(settings.get_value("draw.region",value) && value=="0")
443                        set_layer_region_flag(false);
444                else
445                        set_layer_region_flag(true);
446
447                if(settings.get_value("draw.outline",value) && value=="0")
448                        set_layer_outline_flag(false);
449                else
450                        set_layer_outline_flag(true);
451
452                if(settings.get_value("draw.advanced_outline",value) && value=="0")
453                        set_layer_advanced_outline_flag(false);
454                else
455                        set_layer_advanced_outline_flag(true);
456
457                if(settings.get_value("draw.auto_export",value) && value=="1")
458                        set_auto_export_flag(true);
459                else
460                        set_auto_export_flag(false);
461
462                if(settings.get_value("draw.min_pressure_on",value) && value=="0")
463                        set_min_pressure_flag(false);
464                else
465                        set_min_pressure_flag(true);
466
467                if(settings.get_value("draw.min_pressure",value))
468                {
469                        Real n = atof(value.c_str());
470                        set_min_pressure(n);
471                }else
472                        set_min_pressure(0);
473
474                if(settings.get_value("draw.feather",value))
475                        set_feather_size(Distance(atof(value.c_str()), App::distance_system));
476                else
477                        set_feather_size(Distance(0, App::distance_system));
478
479                if(settings.get_value("draw.gthreshold",value))
480                {
481                        Real n = atof(value.c_str());
482                        set_gthres(n);
483                }
484
485                if(settings.get_value("draw.widthmaxerror",value))
486                {
487                        Real n = atof(value.c_str());
488                        set_width_max_error(n);
489                }
490
491                if(settings.get_value("draw.lthreshold",value))
492                {
493                        Real n = atof(value.c_str());
494                        set_lthres(n);
495                }
496
497                if(settings.get_value("draw.localize",value) && value == "1")
498                        //set_local_error_flag(true);
499                        set_local_threshold_flag(true);
500                else
501                        //set_local_error_flag(false);
502                        //set_local_threshold_flag(false);
503                        set_global_threshold_flag(true);
504
505                if(settings.get_value("draw.round_ends", value) && value == "1")
506                        set_round_ends_flag(true);
507                else
508                        set_round_ends_flag(false);
509
510          // determine layer flags
511          layer_region_flag = get_layer_region_flag();
512          layer_outline_flag = get_layer_outline_flag();
513          layer_advanced_outline_flag = get_layer_advanced_outline_flag();
514        }
515        catch(...)
516        {
517                synfig::warning("State Draw: Caught exception when attempting to load settings.");
518        }
519}
520
521void
522StateDraw_Context::save_settings()
523{
524        try
525        {
526                synfig::ChangeLocale change_locale(LC_NUMERIC, "C");
527                settings.set_value("draw.id",get_id().c_str());
528                settings.set_value("draw.blend",strprintf("%d",get_blend()));
529                settings.set_value("draw.opacity",strprintf("%f",(float)get_opacity()));
530                settings.set_value("draw.bline_width", bline_width_dist.get_value().get_string());
531                settings.set_value("draw.pressure_width",get_pressure_width_flag()?"1":"0");
532                settings.set_value("draw.auto_loop",get_auto_loop_flag()?"1":"0");
533                settings.set_value("draw.auto_extend",get_auto_extend_flag()?"1":"0");
534                settings.set_value("draw.auto_link",get_auto_link_flag()?"1":"0");
535                settings.set_value("draw.region",get_layer_region_flag()?"1":"0");
536                settings.set_value("draw.outline",get_layer_outline_flag()?"1":"0");
537                settings.set_value("draw.advanced_outline",get_layer_advanced_outline_flag()?"1":"0");
538                settings.set_value("draw.auto_export",get_auto_export_flag()?"1":"0");
539                settings.set_value("draw.min_pressure",strprintf("%f",get_min_pressure()));
540                settings.set_value("draw.feather",feather_dist.get_value().get_string());
541                settings.set_value("draw.min_pressure_on",get_min_pressure_flag()?"1":"0");
542                settings.set_value("draw.gthreshold",strprintf("%f",get_gthres()));
543                settings.set_value("draw.widthmaxerror",strprintf("%f",get_width_max_error()));
544                settings.set_value("draw.lthreshold",strprintf("%f",get_lthres()));
545                settings.set_value("draw.localize",get_local_threshold_flag()?"1":"0");
546                settings.set_value("draw.round_ends", get_round_ends_flag()?"1":"0");
547        }
548        catch(...)
549        {
550                synfig::warning("State Draw: Caught exception when attempting to save settings.");
551        }
552}
553
554void
555StateDraw_Context::increment_id()
556{
557        String id(get_id());
558        int number=1;
559        int digits=0;
560
561        if(id.empty())
562                id="Drawing";
563
564        // If there is a number
565        // already at the end of the
566        // id, then remove it.
567        if(id[id.size()-1]<='9' && id[id.size()-1]>='0')
568        {
569                // figure out how many digits it is
570                for (digits = 0;
571                         (int)id.size()-1 >= digits && id[id.size()-1-digits] <= '9' && id[id.size()-1-digits] >= '0';
572                         digits++)
573                        ;
574
575                String str_number;
576                str_number=String(id,id.size()-digits,id.size());
577                id=String(id,0,id.size()-digits);
578                // synfig::info("---------------- \"%s\"",str_number.c_str());
579
580                number=atoi(str_number.c_str());
581        }
582        else
583        {
584                number=1;
585                digits=3;
586        }
587
588        number++;
589
590        // Add the number back onto the id
591        {
592                const String format(strprintf("%%0%dd",digits));
593                id+=strprintf(format.c_str(),number);
594        }
595
596        // Set the ID
597        set_id(id);
598}
599
600StateDraw_Context::StateDraw_Context(CanvasView* canvas_view):
601        canvas_view_(canvas_view),
602        is_working(*canvas_view),
603        push_state(get_work_area()),
604        loop_(false),
605        settings(synfigapp::Main::get_selected_input_device()->settings()),
606        opacity_hscl(0.0f, 1.01f, 0.01f),
607        min_pressure_adj(Gtk::Adjustment::create(0,0,1,0.01,0.1)),
608        min_pressure_spin(min_pressure_adj,0.1,3),
609        localthres_adj(Gtk::Adjustment::create(20, 1, 100000, 0.1, 1)),
610        localthres_spin(localthres_adj, 0.1, 1),
611        globalthres_adj(Gtk::Adjustment::create(0.70f, 0.01, 10000, 0.01, 0.1)),
612        globalthres_spin(globalthres_adj, 0.01, 3),
613        width_max_error_adj(Gtk::Adjustment::create(1.0f, 0.01, 100.0, 0.1,1)),
614        width_max_error_spin(width_max_error_adj, 0.01, 2),
615        fill_last_stroke_button(_("Fill Last Stroke"))
616{
617        /* Set up the tool options dialog */
618
619        // 0, title
620        title_label.set_label(_("Drawing"));
621        Pango::AttrList list;
622        Pango::AttrInt attr = Pango::Attribute::create_attr_weight(Pango::WEIGHT_BOLD);
623        list.insert(attr);
624        title_label.set_attributes(list);
625        title_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
626
627        // 1, layer name label and entry
628        id_label.set_label(_("Name:"));
629        id_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
630        SPACING(id_gap, GAP);
631        id_box.pack_start(id_label, Gtk::PACK_SHRINK);
632        id_box.pack_start(*id_gap, Gtk::PACK_SHRINK);
633
634        id_box.pack_start(id_entry);
635
636        // 2, layer types creation
637        layer_types_label.set_label(_("Layer Type:"));
638        layer_types_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
639
640        LAYER_CREATION(layer_region_togglebutton,
641                ("synfig-layer_geometry_region"), _("Create a region layer"));
642
643        LAYER_CREATION(layer_outline_togglebutton,
644                ("synfig-layer_geometry_outline"), _("Create a outline layer"));
645
646        LAYER_CREATION(layer_advanced_outline_togglebutton,
647                ("synfig-layer_geometry_advanced_outline"), _("Create a advanced outline layer"));
648
649        SPACING(layer_types_indent, INDENTATION);
650
651        layer_types_box.pack_start(*layer_types_indent, Gtk::PACK_SHRINK);
652        layer_types_box.pack_start(layer_region_togglebutton, Gtk::PACK_SHRINK);
653        layer_types_box.pack_start(layer_outline_togglebutton, Gtk::PACK_SHRINK);
654        layer_types_box.pack_start(layer_advanced_outline_togglebutton, Gtk::PACK_SHRINK);
655
656        // 3, blend method label and dropdown list
657        blend_label.set_label(_("Blend Method:"));
658        blend_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
659        SPACING(blend_gap, GAP);
660        blend_box.pack_start(blend_label, Gtk::PACK_SHRINK);
661        blend_box.pack_start(*blend_gap, Gtk::PACK_SHRINK);
662
663        blend_enum.set_param_desc(ParamDesc(Color::BLEND_COMPOSITE,"blend_method")
664                .set_local_name(_("Blend Method"))
665                .set_description(_("Defines the blend method to be used for draws")));
666
667        // 4, opacity label and slider
668        opacity_label.set_label(_("Opacity:"));
669        opacity_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
670
671        opacity_hscl.set_digits(2);
672        opacity_hscl.set_value_pos(Gtk::POS_LEFT);
673        opacity_hscl.set_tooltip_text(_("Opacity"));
674
675        // 5, brush size
676        bline_width_label.set_label(_("Brush Size:"));
677        bline_width_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
678
679        bline_width_dist.set_digits(2);
680        bline_width_dist.set_range(0,10000000);
681
682        // 6, pressure width
683        pressure_width_label.set_label(_("Pressure Sensitive"));
684        pressure_width_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
685
686        pressure_width_box.pack_start(pressure_width_label, Gtk::PACK_SHRINK);
687        pressure_width_box.pack_end(pressure_width_checkbutton, Gtk::PACK_SHRINK);
688
689        // 7, min pressure, sub option of pressure width
690        SPACING(min_pressure_indent, INDENTATION);
691        SPACING(min_pressure_gap, GAP);
692        min_pressure_label.set_label(_("Min Width:"));
693        min_pressure_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
694        min_pressure_label_box.pack_start(*min_pressure_indent, Gtk::PACK_SHRINK);
695        min_pressure_label_box.pack_start(min_pressure_label, Gtk::PACK_SHRINK);
696
697        min_pressure_box.pack_end(min_pressure_checkbutton, Gtk::PACK_SHRINK);
698        min_pressure_box.pack_end(*min_pressure_gap, Gtk::PACK_SHRINK);
699        min_pressure_box.pack_end(min_pressure_spin);
700
701        // 8, Smoothness
702        smoothness_label.set_label(_("Smoothness"));
703        smoothness_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
704
705        // 9, local threshold
706        SPACING(localthres_indent, INDENTATION);
707        localthres_box.pack_start(*localthres_indent, Gtk::PACK_SHRINK);
708        localthres_box.pack_start(localthres_radiobutton, Gtk::PACK_SHRINK);
709        localthres_radiobutton.set_label("Local:");
710
711        // 10, global threshold
712        SPACING(globalthres_indent, INDENTATION);
713        globalthres_box.pack_start(*globalthres_indent, Gtk::PACK_SHRINK);
714        globalthres_box.pack_start(globalthres_radiobutton, Gtk::PACK_SHRINK);
715        globalthres_radiobutton.set_label("Global:");
716
717        smoothness_group = localthres_radiobutton.get_group();
718        globalthres_radiobutton.set_group(smoothness_group);
719
720        // 11, width max error of advanced outline layer
721        width_max_error_label.set_label(_("Width Max Error:"));
722        SPACING(width_max_error_gap, GAP);
723        width_max_error_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
724        width_max_error_box.pack_start(width_max_error_label, Gtk::PACK_SHRINK);
725        width_max_error_box.pack_start(*width_max_error_gap, Gtk::PACK_SHRINK);
726
727        // 12, round ends
728        round_ends_label.set_label(_("Round Ends"));
729        round_ends_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
730
731        round_ends_box.pack_start(round_ends_label, Gtk::PACK_SHRINK);
732        round_ends_box.pack_end(round_ends_checkbutton, Gtk::PACK_SHRINK);
733
734        // 13, auto loop
735        auto_loop_label.set_label(_("Auto Loop"));
736        auto_loop_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
737
738        auto_loop_box.pack_start(auto_loop_label, Gtk::PACK_SHRINK);
739        auto_loop_box.pack_end(auto_loop_checkbutton, Gtk::PACK_SHRINK);
740
741        // 14, auto extend
742        auto_extend_label.set_label(_("Auto Extend"));
743        auto_extend_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
744
745        auto_extend_box.pack_start(auto_extend_label, Gtk::PACK_SHRINK);
746        auto_extend_box.pack_end(auto_extend_checkbutton, Gtk::PACK_SHRINK);
747
748        // 15, auto link
749        auto_link_label.set_label(_("Auto Link"));
750        auto_link_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
751
752        auto_link_box.pack_start(auto_link_label, Gtk::PACK_SHRINK);
753        auto_link_box.pack_end(auto_link_checkbutton, Gtk::PACK_SHRINK);
754
755        // 16, feather
756        feather_label.set_label(_("Feather:"));
757        feather_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
758
759        feather_dist.set_digits(2);
760        feather_dist.set_range(0,10000000);
761
762        // 17, auto export
763        auto_export_label.set_label(_("Auto Export"));
764        auto_export_label.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
765
766        auto_export_box.pack_start(auto_export_label, Gtk::PACK_SHRINK);
767        auto_export_box.pack_end(auto_export_checkbutton, Gtk::PACK_SHRINK);
768
769
770        nested=0;
771        load_settings();
772
773        UpdateUsePressure();
774        UpdateCreateAdvancedOutline();
775        UpdateSmoothness();
776
777
778        // pack all options to the options_table
779
780        // 0, title
781        options_table.attach(title_label,
782                0, 2, 0, 1, Gtk::FILL, Gtk::FILL, 0, 0
783                );
784        // 1, name
785        options_table.attach(id_box,
786                0, 2, 1, 2, Gtk::FILL, Gtk::FILL, 0, 0
787                );
788        // 2, layer types creation
789        options_table.attach(layer_types_label,
790                0, 2, 2, 3, Gtk::FILL, Gtk::FILL, 0, 0
791                );
792        options_table.attach(layer_types_box,
793                0, 2, 3, 4, Gtk::FILL, Gtk::FILL, 0, 0
794                );
795        // 3, blend method
796        options_table.attach(blend_box,
797                0, 1, 4, 5, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
798                );
799        options_table.attach(blend_enum,
800                1, 2, 4, 5, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
801                );
802        // 4, opacity
803        options_table.attach(opacity_label,
804                0, 1, 5, 6, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
805                );
806        options_table.attach(opacity_hscl,
807                1, 2, 5, 6, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
808                );
809        // 5, brush size
810        options_table.attach(bline_width_label,
811                0, 1, 6, 7, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
812                );
813        options_table.attach(bline_width_dist,
814                1, 2, 6, 7, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
815                );
816        // 6, pressure width
817        options_table.attach(pressure_width_box,
818                0, 2, 7, 8, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
819                );
820        // 7, min pressure, sub-option of pressure width
821        options_table.attach(min_pressure_label_box,
822                0, 1, 8, 9, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
823                );
824        options_table.attach(min_pressure_box,
825                1, 2, 8, 9, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
826                );
827        // 8, smoothness
828        options_table.attach(smoothness_label,
829                0, 2, 9, 10, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
830                );
831        // 9, local threshold
832        options_table.attach(localthres_box,
833                0, 1, 10, 11, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
834                );
835        options_table.attach(localthres_spin,
836                1, 2, 10, 11, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
837                );
838        // 10, global threshold
839        options_table.attach(globalthres_box,
840                0, 1, 11, 12, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
841                );
842        options_table.attach(globalthres_spin,
843                1, 2, 11, 12, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
844                );
845        // 11, width max error of advanced outline layer
846        options_table.attach(width_max_error_box,
847                0, 1, 12, 13, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
848                );
849        options_table.attach(width_max_error_spin,
850                1, 2, 12, 13, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
851                );
852        // 12, round ends
853        options_table.attach(round_ends_box,
854                0, 2, 13, 14, Gtk::FILL, Gtk::FILL, 0, 0
855                );
856        // 13, auto loop
857        options_table.attach(auto_loop_box,
858                0, 2, 14, 15, Gtk::FILL, Gtk::FILL, 0, 0
859                );
860        // 14, auto extend
861        options_table.attach(auto_extend_box,
862                0, 2, 15, 16, Gtk::FILL, Gtk::FILL, 0, 0
863                );
864        // 15, auto link
865        options_table.attach(auto_link_box,
866                0, 2, 16, 17, Gtk::FILL, Gtk::FILL, 0, 0
867                );
868        // 16, feather
869        options_table.attach(feather_label,
870                0, 1, 17, 18, Gtk::FILL, Gtk::FILL, 0, 0
871                );
872        options_table.attach(feather_dist,
873                1, 2, 17, 18, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 0, 0
874                );
875        // 17, auto export
876        options_table.attach(auto_export_box,
877                0, 2, 18, 19, Gtk::FILL, Gtk::FILL, 0, 0
878                );
879
880        // fine-tune options layout
881        options_table.set_border_width(GAP*2); // border width
882        options_table.set_row_spacings(GAP); // row gap
883        options_table.set_row_spacing(0, GAP*2); // the gap between first and second row.
884        options_table.set_row_spacing(2, 1); // row gap between label and icon of layer type
885        options_table.set_row_spacing(19, 0); // the final row using border width of table
886
887        options_table.show_all();
888
889
890        fill_last_stroke_button.signal_pressed().connect(
891                sigc::mem_fun(*this, &StateDraw_Context::fill_last_stroke));
892        pressure_width_checkbutton.signal_toggled().connect(
893                sigc::mem_fun(*this, &StateDraw_Context::UpdateUsePressure));
894        layer_advanced_outline_togglebutton.signal_toggled().connect(
895                sigc::mem_fun(*this, &StateDraw_Context::UpdateCreateAdvancedOutline));
896        localthres_spin.signal_value_changed().connect(sigc::mem_fun(*this,
897                &StateDraw_Context::UpdateSmoothness));
898        globalthres_spin.signal_value_changed().connect(sigc::mem_fun(*this,
899                &StateDraw_Context::UpdateSmoothness));
900
901
902        refresh_tool_options();
903        App::dialog_tool_options->present();
904
905        // Hide all tangent and width ducks
906        get_work_area()->set_type_mask(get_work_area()->get_type_mask()-Duck::TYPE_TANGENT-Duck::TYPE_WIDTH);
907        get_canvas_view()->toggle_duck_mask(Duck::TYPE_NONE);
908
909        // Turn off layer clicking
910        get_work_area()->set_allow_layer_clicks(false);
911
912        // Turn off duck clicking
913        get_work_area()->set_allow_duck_clicks(false);
914
915        // Hide the tables if they are showing
916        prev_table_status=get_canvas_view()->tables_are_visible();
917        //if(prev_table_status)get_canvas_view()->hide_tables();
918
919        // Disable the time bar
920        get_canvas_view()->set_sensitive_timebar(false);
921
922        // Connect a signal
923        //get_work_area()->signal_user_click().connect(sigc::mem_fun(*this,&studio::StateDraw_Context::on_user_click));
924
925        get_work_area()->set_cursor(Gdk::PENCIL);
926
927        App::dock_toolbox->refresh();
928
929        refresh_ducks();
930}
931
932
933void
934StateDraw_Context::UpdateUsePressure()
935{
936        bool status(get_pressure_width_flag());
937        min_pressure_label.set_sensitive(status);
938        min_pressure_checkbutton.set_sensitive(status);
939        min_pressure_spin.set_sensitive(status);
940}
941
942void
943StateDraw_Context::UpdateCreateAdvancedOutline()
944{
945        width_max_error_label.set_sensitive(get_layer_advanced_outline_flag());
946        width_max_error_spin.set_sensitive(get_layer_advanced_outline_flag());
947}
948
949
950void
951StateDraw_Context::UpdateSmoothness()
952{
953        localthres_radiobutton.set_active(localthres_spin.is_focus());
954        globalthres_radiobutton.set_active(globalthres_spin.is_focus());
955}
956
957
958void
959StateDraw_Context::refresh_tool_options()
960{
961        App::dialog_tool_options->clear();
962        App::dialog_tool_options->set_widget(options_table);
963        App::dialog_tool_options->set_local_name(_("Draw Tool"));
964        App::dialog_tool_options->set_name("draw");
965
966        App::dialog_tool_options->add_button(
967                Gtk::StockID("synfig-fill"),
968                _("Fill Last Stroke")
969        )->signal_clicked().connect(
970                sigc::mem_fun(
971                        *this,
972                        &StateDraw_Context::fill_last_stroke));
973}
974
975Smach::event_result
976StateDraw_Context::event_refresh_tool_options(const Smach::event& /*x*/)
977{
978        refresh_tool_options();
979        return Smach::RESULT_ACCEPT;
980}
981
982StateDraw_Context::~StateDraw_Context()
983{
984        save_settings();
985
986        App::dialog_tool_options->clear();
987
988        get_work_area()->reset_cursor();
989
990        // Enable the time bar
991        get_canvas_view()->set_sensitive_timebar(true);
992
993        // Bring back the tables if they were out before
994        if(prev_table_status)get_canvas_view()->show_tables();
995
996        // Refresh the work area
997        get_work_area()->queue_draw();
998
999        App::dock_toolbox->refresh();
1000}
1001
1002Smach::event_result
1003StateDraw_Context::event_stop_handler(const Smach::event& /*x*/)
1004{
1005        //throw Smach::egress_exception();
1006        throw &state_normal;
1007        return Smach::RESULT_OK;
1008}
1009
1010Smach::event_result
1011StateDraw_Context::event_refresh_handler(const Smach::event& /*x*/)
1012{
1013        refresh_ducks();
1014        return Smach::RESULT_ACCEPT;
1015}
1016
1017Smach::event_result
1018StateDraw_Context::event_mouse_down_handler(const Smach::event& x)
1019{
1020        const EventMouse& event(*reinterpret_cast<const EventMouse*>(&x));
1021        switch(event.button)
1022        {
1023        case BUTTON_LEFT:
1024                {
1025                        // Enter the stroke state to get the stroke
1026                        get_canvas_view()->get_smach().push_state(&state_stroke);
1027                        return Smach::RESULT_ACCEPT;
1028                }
1029
1030        default:
1031                return Smach::RESULT_OK;
1032        }
1033}
1034
1035#define SIMILAR_TANGENT_THRESHOLD       (0.2)
1036
1037struct debugclass
1038{
1039        synfig::String x;
1040        debugclass(const synfig::String &x):x(x)
1041        {
1042//              synfig::warning(">>>>>>>>>>>>>>>>>>> "+x);
1043        }
1044        ~debugclass()
1045        {
1046//              synfig::warning("<<<<<<<<<<<<<<<<<<< "+x);
1047        }
1048};
1049
1050struct DepthCounter
1051{
1052        int &i;
1053        DepthCounter(int &i):i(i) { i++; }
1054        ~DepthCounter() { i--; }
1055};
1056
1057Smach::event_result
1058StateDraw_Context::event_stroke(const Smach::event& x)
1059{
1060//      debugclass debugger("StateDraw_Context::event_stroke(const Smach::event& x)");
1061
1062        const EventStroke& event(*reinterpret_cast<const EventStroke*>(&x));
1063
1064        assert(event.stroke_data);
1065
1066        get_work_area()->add_stroke(event.stroke_data,synfigapp::Main::get_outline_color());
1067
1068        if(nested==0)
1069        {
1070                DirtyTrap dirty_trap(get_work_area());
1071                Smach::event_result result;
1072                result = process_stroke(event.stroke_data, event.width_data, (event.modifier&Gdk::CONTROL_MASK) || (event.modifier&Gdk::BUTTON2_MASK));
1073                process_queue();
1074                return result;
1075        }
1076
1077        stroke_queue.push_back(pair<StrokeData,WidthData>(event.stroke_data,event.width_data));
1078
1079        return Smach::RESULT_ACCEPT;
1080}
1081
1082bool
1083StateDraw_Context::process_queue()
1084{
1085//      debugclass debugger("StateDraw_Context::process_queue()");
1086        if(nested)
1087                return true;
1088        DepthCounter depth_counter(nested);
1089        while(!stroke_queue.empty())
1090        {
1091                pair<StrokeData,WidthData> front(stroke_queue.front());
1092                process_stroke(front.first,front.second);
1093                stroke_queue.pop_front();
1094        }
1095        return false;
1096}
1097
1098Smach::event_result
1099StateDraw_Context::process_stroke(StrokeData stroke_data, WidthData width_data, bool region_flag)
1100{
1101//      debugclass debugger("StateDraw_Context::process_stroke");
1102        DepthCounter depth_counter(nested);
1103
1104        const float radius(
1105                // synfigapp::Main::get_bline_width().units(get_canvas()->rend_desc()) +
1106                get_bline_width() +
1107                (abs(get_work_area()->get_pw())+ abs(get_work_area()->get_ph()))*5);
1108
1109        // If we aren't using pressure width,
1110        // then set all the width to 1
1111        if(!get_pressure_width_flag())
1112        {
1113                std::list<synfig::Real>::iterator iter;
1114                for(iter=width_data->begin();iter!=width_data->end();++iter)
1115                {
1116                        *iter=1.0;
1117                }
1118        }
1119
1120        std::list<synfig::BLinePoint> bline;
1121        std::list<synfig::WidthPoint> wplist;
1122        bool loop_bline_flag(false);
1123
1124        //Changed by Adrian - use resident class :)
1125        //synfigapp::convert_stroke_to_bline(bline, *event.stroke_data,*event.width_data, synfigapp::Main::get_bline_width());
1126        // blineconv.width = synfigapp::Main::get_bline_width().units(get_canvas()->rend_desc());
1127        blineconv.width = get_bline_width();
1128
1129        if (get_local_threshold_flag())
1130        {
1131                float pw = get_work_area()->get_pw();
1132                float ph = get_work_area()->get_ph();
1133
1134                blineconv.pixelwidth = sqrt(pw*pw+ph*ph);
1135                blineconv.smoothness = get_lthres();
1136        }
1137
1138        if (get_global_threshold_flag())
1139        {
1140                blineconv.pixelwidth = 1;
1141                blineconv.smoothness = get_gthres();
1142        }
1143
1144        blineconv(bline,*stroke_data,*width_data);
1145
1146        if(get_layer_advanced_outline_flag())
1147        {
1148                wplistconv.err2max=get_width_max_error()/100;
1149                wplistconv(wplist, *stroke_data,*width_data);
1150                // returned widths are homogeneous position
1151                // let's convert it to standard position
1152                // as it is the default for new adv. outlines layers
1153                std::list<synfig::WidthPoint>::iterator iter;
1154                for(iter=wplist.begin(); iter!=wplist.end(); iter++)
1155                        iter->set_position(hom_to_std(ValueBase::List(bline.begin(), bline.end()), iter->get_position(), false, false));
1156        }
1157        // print out resutls
1158        //synfig::info("-----------widths");
1159        //std::list<synfig::WidthPoint>::iterator iter;
1160        //for(iter=wplist.begin();iter!=wplist.end();iter++)
1161        //{
1162                //if(!iter->get_dash())
1163                        //synfig::info("Widthpoint W=%f, P=%f", iter->get_width(), iter->get_position());
1164        //}
1165        // results end
1166
1167        //Postprocess to require minimum pressure
1168        if(get_min_pressure_flag())
1169        {
1170                synfigapp::BLineConverter::EnforceMinWidth(bline,get_min_pressure());
1171                if(get_layer_advanced_outline_flag())
1172                        synfigapp::WPListConverter::EnforceMinWidth(wplist,get_min_pressure());
1173        }
1174
1175        // If the start and end points are similar, then make them the same point
1176        if (get_auto_loop_flag() &&
1177                bline.size() > 2 &&
1178                (bline.front().get_vertex() - bline.back().get_vertex()).mag() <= radius)
1179        {
1180                loop_bline_flag=true;
1181                Vector tangent;
1182                Real width(0);
1183
1184                while (bline.size() > 2 &&
1185                           (bline.front().get_vertex() - bline.back().get_vertex()).mag() <= radius)
1186                {
1187                        Real size(Real(bline.size()));
1188                        tangent=bline.back().get_tangent1();
1189                        width=bline.back().get_width();
1190                        bline.pop_back();
1191                        std::list<synfig::WidthPoint>::iterator iter;
1192                        if(get_layer_advanced_outline_flag())
1193                                for(iter=wplist.begin(); iter!=wplist.end(); iter++)
1194                                        iter->set_position(iter->get_position()+1/(size-1));
1195                }
1196
1197                if(abs(bline.front().get_tangent1().norm()*tangent.norm().perp())>SIMILAR_TANGENT_THRESHOLD)
1198                {
1199                        // If the tangents are not similar, then
1200                        // split the tangents
1201                        bline.front().set_split_tangent_both(true);
1202                        bline.front().set_tangent1(tangent);
1203                }
1204                else
1205                {
1206                        // If the tangents are similar, then set the tangent
1207                        // to the average of the two
1208                        bline.front().set_tangent((tangent+bline.front().get_tangent1())*0.5f);
1209                }
1210
1211                // Add the widths of the two points
1212                {
1213                        Real tmp_width(bline.front().get_width()+width);
1214                        tmp_width=tmp_width<=1?tmp_width:1;
1215                        bline.front().set_width(tmp_width);
1216                        if(get_layer_advanced_outline_flag())
1217                        {
1218                                Real width_front=wplist.front().get_width();
1219                                Real width_back=wplist.back().get_width();
1220                                wplist.front().set_width((width_front+width_back)/2.0);
1221                                wplist.pop_back();
1222                        }
1223                }
1224        }
1225
1226        // If the bline only has one blinepoint, then there is nothing to do.
1227        if(bline.size() < 2)
1228        {
1229                // hide the 'stroke' line we were drawing, unless the user
1230                // explicitly requests that they are kept
1231                if (!getenv("SYNFIG_KEEP_ABORTED_DRAW_LINES"))
1232                        refresh_ducks();
1233
1234                return Smach::RESULT_OK;
1235        }
1236
1237        if(region_flag)
1238                return new_region(bline,radius);
1239
1240        return new_bline(bline,wplist,loop_bline_flag,radius);
1241}
1242
1243Smach::event_result
1244StateDraw_Context::new_bline(std::list<synfig::BLinePoint> bline,std::list<synfig::WidthPoint> wplist,bool loop_bline_flag,float radius)
1245{
1246        synfigapp::SelectionManager::LayerList layer_list = get_canvas_view()->get_selection_manager()->get_selected_layers();
1247
1248        // Create the action group
1249        synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Sketch Spline"));
1250
1251        bool shift_origin = false;
1252        Vector shift_origin_vector;
1253        bool join_start_no_extend=false,join_finish_no_extend=false;
1254        synfigapp::ValueDesc start_duck_value_desc,finish_duck_value_desc;
1255        bool extend_start=false,extend_finish=false,complete_loop=false;
1256        bool extend_start_join_same=false,extend_start_join_different=false;
1257        bool extend_finish_join_same=false,extend_finish_join_different=false;
1258        int start_duck_index = 0,finish_duck_index = 0; // initialized to keep the compiler happy; shouldn't be needed though
1259        ValueNode_BLine::Handle start_duck_value_node_bline=NULL,finish_duck_value_node_bline=NULL;
1260
1261        // Find any ducks at the start or end that we might attach to
1262        // (this used to only run if we didn't just draw a loop - ie. !loop_bline_flag
1263        // but having loops auto-connect can be useful as well)
1264        if(get_auto_extend_flag() || get_auto_link_flag())
1265        {
1266                etl::handle<Duck> start_duck(get_work_area()->find_duck(bline.front().get_vertex(),radius,Duck::TYPE_VERTEX));
1267                etl::handle<Duck> finish_duck(get_work_area()->find_duck(bline.back().get_vertex(),radius,Duck::TYPE_VERTEX));
1268
1269                // check whether the start of the new line extends an
1270                // existing line.  this is only the case if the new
1271                // line isn't a self-contained loop, and if the new
1272                // line starts at one of the ends of an existing line
1273                if(start_duck)do
1274                {
1275                        if(!(start_duck_value_desc=start_duck->get_value_desc()))break;
1276                        if(loop_bline_flag)break; // loops don't extend anything
1277                        if(!start_duck_value_desc.parent_is_value_node())break;
1278                        start_duck_index=start_duck_value_desc.get_index(); // which point on the line did we start drawing at
1279                        start_duck_value_node_bline=ValueNode_BLine::Handle::cast_dynamic(start_duck_value_desc.get_parent_value_node());
1280                        if(!get_auto_extend_flag())break;
1281
1282                        // don't extend looped blines
1283                        if(start_duck_value_node_bline&&!start_duck_value_node_bline->get_loop()&&
1284                           // did we start drawing at either end of the line?
1285                           (start_duck_index==0||start_duck_index==start_duck_value_node_bline->link_count()-1))
1286                        {
1287                                extend_start=true;
1288                                shift_origin=true;
1289                                shift_origin_vector=start_duck->get_origin();
1290                        }
1291                }while(0);
1292
1293                // check whether the end of the new line extends an
1294                // existing line.  this is only the case if the new
1295                // line isn't a self-contained loop, and if the new
1296                // line ends at one of the ends of an existing line
1297                if(finish_duck)do
1298                {
1299                        if(!(finish_duck_value_desc=finish_duck->get_value_desc()))break;
1300                        if(loop_bline_flag)break;
1301                        if(!finish_duck_value_desc.parent_is_value_node())break;
1302                        finish_duck_index=finish_duck_value_desc.get_index();
1303                        finish_duck_value_node_bline=ValueNode_BLine::Handle::cast_dynamic(finish_duck_value_desc.get_parent_value_node());
1304                        if(!get_auto_extend_flag())break;
1305
1306                        // don't extend looped blines
1307                        if(finish_duck_value_node_bline&&!finish_duck_value_node_bline->get_loop()&&
1308                           (finish_duck_index==0||finish_duck_index==finish_duck_value_node_bline->link_count()-1))
1309                        {
1310                                if(extend_start)
1311                                {
1312                                        // we've started and finished drawing at the end of a bline.  we can't
1313                                        // extend both blines, so unless we started and finished at the 2 ends
1314                                        // of the same bline, only extend the one we started on
1315                                        if(start_duck_value_node_bline==finish_duck_value_node_bline)
1316                                                complete_loop=extend_finish=true;
1317                                }else{
1318                                        extend_finish=true;
1319                                        shift_origin=true;
1320                                        shift_origin_vector=finish_duck->get_origin();
1321                                }
1322                        }
1323                }while(0);
1324
1325                // if the new line's start didn't extend an existing line,
1326                // check whether it needs to be linked to an existing duck
1327                if(!extend_start&&get_auto_link_flag()&&start_duck&&start_duck_value_desc)
1328                {
1329                        synfig::Type &type(start_duck_value_desc.get_value_type());
1330                        if (type == synfig::type_bline_point)
1331                                start_duck_value_desc=synfigapp::ValueDesc(LinkableValueNode::Handle::cast_dynamic(start_duck_value_desc.get_value_node()),0);
1332                        if (type == synfig::type_bline_point || type == synfig::type_vector)
1333                        {
1334                                if (!shift_origin || shift_origin_vector == start_duck->get_origin())
1335                                {
1336                                        shift_origin = true;
1337                                        shift_origin_vector = start_duck->get_origin();
1338                                        get_canvas_interface()->auto_export(start_duck_value_desc);
1339                                        if (extend_finish)
1340                                                if(start_duck_value_node_bline&&start_duck_value_node_bline==finish_duck_value_node_bline)
1341                                                        extend_finish_join_same=true;
1342                                                else
1343                                                        extend_finish_join_different=true;
1344                                        else
1345                                                join_start_no_extend=true;
1346                                }
1347                        }
1348                }
1349                // if the new line's end didn't extend an existing line,
1350                // check whether it needs to be linked to an existing duck
1351                if(!extend_finish&&get_auto_link_flag()&&finish_duck&&finish_duck_value_desc)
1352                {
1353                        synfig::Type &type(finish_duck_value_desc.get_value_type());
1354                        if (type == synfig::type_bline_point)
1355                                finish_duck_value_desc=synfigapp::ValueDesc(LinkableValueNode::Handle::cast_dynamic(finish_duck_value_desc.get_value_node()),0);
1356                        if (type == synfig::type_bline_point || type == synfig::type_vector)
1357                        {
1358                                if (!shift_origin || shift_origin_vector == finish_duck->get_origin())
1359                                {
1360                                        shift_origin = true;
1361                                        shift_origin_vector = finish_duck->get_origin();
1362                                        get_canvas_interface()->auto_export(finish_duck_value_desc);
1363                                        if(extend_start)
1364                                                if(finish_duck_value_node_bline&&start_duck_value_node_bline==finish_duck_value_node_bline)
1365                                                        extend_start_join_same=true;
1366                                                else
1367                                                        extend_start_join_different=true;
1368                                        else
1369                                                join_finish_no_extend=true;
1370                                }
1371                        }
1372                }
1373        }
1374
1375        ValueNode_BLine::Handle value_node;
1376        std::list<synfig::BLinePoint> trans_bline;
1377
1378        {
1379                std::list<synfig::BLinePoint>::iterator iter;
1380                const synfig::TransformStack& transform(get_work_area()->get_curr_transform_stack());
1381
1382                for(iter=bline.begin();iter!=bline.end();++iter)
1383                {
1384                        BLinePoint bline_point(*iter);
1385                        Point new_vertex(transform.unperform(bline_point.get_vertex()));
1386
1387                        bline_point.set_tangent1(
1388                                transform.unperform(
1389                                        bline_point.get_tangent1()+bline_point.get_vertex()
1390                                ) -new_vertex
1391                        );
1392
1393                        bline_point.set_tangent2(
1394                                transform.unperform(
1395                                        bline_point.get_tangent2()+bline_point.get_vertex()
1396                                ) -new_vertex
1397                        );
1398
1399                        if (shift_origin)
1400                                new_vertex=new_vertex-shift_origin_vector;
1401
1402                        bline_point.set_vertex(new_vertex);
1403
1404                        trans_bline.push_back(bline_point);
1405                }
1406                value_node=ValueNode_BLine::create(synfig::ValueBase(synfig::ValueBase::List(trans_bline.begin(), trans_bline.end()),loop_bline_flag));
1407
1408                Canvas::Handle canvas(get_canvas_view()->get_canvas());
1409                Layer::Handle layer(get_canvas_view()->get_selection_manager()->get_selected_layer());
1410                if (layer) canvas=layer->get_canvas();
1411                value_node->set_member_canvas(canvas);
1412        }
1413
1414        Smach::event_result result;
1415        synfig::ValueNode_DynamicList::ListEntry source;
1416
1417        // the new line's start extends an existing line
1418        if(extend_start)
1419        {
1420                int target_offset = 0;
1421                if(complete_loop)trans_bline.pop_back();
1422                trans_bline.pop_front();
1423                if(start_duck_index==0)
1424                {       // We need to reverse the BLine first.
1425                        reverse_bline(trans_bline);
1426                        reverse_wplist(wplist);
1427                        result=extend_bline_from_begin(start_duck_value_node_bline,trans_bline,wplist,complete_loop);
1428                        source=start_duck_value_node_bline->list.front();
1429                        target_offset=trans_bline.size();
1430                }
1431                else
1432                {
1433                        result=extend_bline_from_end(start_duck_value_node_bline,trans_bline,wplist,complete_loop);
1434                        source=start_duck_value_node_bline->list.back();
1435                }
1436
1437                if(extend_start_join_different)
1438                        LinkableValueNode::Handle::cast_dynamic(source.value_node)->
1439                                set_link("point",finish_duck_value_desc.get_value_node());
1440                else if(extend_start_join_same)
1441                        LinkableValueNode::Handle::cast_dynamic(source.value_node)->
1442                                set_link("point",synfigapp::ValueDesc(LinkableValueNode::Handle::cast_dynamic(start_duck_value_node_bline->
1443                                                                                                        list[target_offset+finish_duck_index].value_node),0).get_value_node());
1444                return result;
1445        }
1446
1447        // the new line's end extends an existing line
1448        if(extend_finish)
1449        {
1450                int target_offset = 0;
1451                trans_bline.pop_back();
1452                if(finish_duck_index==0)
1453                {
1454                        result=extend_bline_from_begin(finish_duck_value_node_bline,trans_bline, wplist,false);
1455                        source=finish_duck_value_node_bline->list.front();
1456                        target_offset=trans_bline.size();
1457                }
1458                else
1459                {       // We need to reverse the BLine first.
1460                        reverse_bline(trans_bline);
1461                        reverse_wplist(wplist);
1462                        result=extend_bline_from_end(finish_duck_value_node_bline,trans_bline, wplist,false);
1463                        source=finish_duck_value_node_bline->list.back();
1464                }
1465
1466                if(extend_finish_join_different)
1467                        LinkableValueNode::Handle::cast_dynamic(source.value_node)->
1468                                set_link("point",start_duck_value_desc.get_value_node());
1469                else if(extend_finish_join_same)
1470                        LinkableValueNode::Handle::cast_dynamic(source.value_node)->
1471                                set_link("point",synfigapp::ValueDesc(LinkableValueNode::Handle::cast_dynamic(finish_duck_value_node_bline->
1472                                                                                                        list[target_offset+start_duck_index].value_node),0).get_value_node());
1473                return result;
1474        }
1475
1476        if (join_start_no_extend)
1477                LinkableValueNode::Handle::cast_dynamic(value_node->list.front().value_node)->
1478                  set_link("point",start_duck_value_desc.get_value_node());
1479
1480        if (join_finish_no_extend)
1481                LinkableValueNode::Handle::cast_dynamic(value_node->list.back().value_node)->
1482                  set_link("point",finish_duck_value_desc.get_value_node());
1483
1484        if(get_auto_export_flag())
1485                if (!get_canvas_interface()->add_value_node(value_node,get_id()))
1486                {
1487                        /* it's no big deal, is it?  let's keep the shape anyway */
1488                        // get_canvas_view()->get_ui_interface()->error(_("Unable to add value node"));
1489                        // group.cancel();
1490                        // increment_id();
1491                        // return Smach::RESULT_ERROR;
1492                }
1493
1494        last_stroke=value_node;
1495        last_stroke_id=get_id();
1496
1497        {
1498                // Create the layer(s)
1499                Layer::Handle layer, layer2, somelayer;
1500                Canvas::Handle canvas(get_canvas_view()->get_canvas());
1501                int depth(0);
1502
1503                // we are temporarily using the layer to hold something
1504                somelayer=get_canvas_view()->get_selection_manager()->get_selected_layer();
1505                if(somelayer)
1506                {
1507                        depth=somelayer->get_depth();
1508                        canvas=somelayer->get_canvas();
1509                }
1510
1511                // fill_last_stroke() will take care of clearing the selection if we're calling it
1512                if((get_layer_outline_flag() || get_layer_advanced_outline_flag()) && get_layer_region_flag())
1513                {
1514                        if (fill_last_stroke_and_unselect_other_layers() == Smach::RESULT_ERROR)
1515                        {
1516                                get_canvas_view()->get_selection_manager()->set_selected_layers(layer_list);
1517                                get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
1518                                group.cancel();
1519                                return Smach::RESULT_ERROR;
1520                        }
1521                }
1522                else
1523                        get_canvas_interface()->get_selection_manager()->clear_selected_layers();
1524
1525                //int number(synfig::UniqueID().get_uid());
1526
1527                synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);
1528
1529                // if they're both defined, we'll add the region later
1530                if(get_layer_outline_flag() || get_layer_advanced_outline_flag())
1531                {
1532                        if(get_layer_outline_flag())
1533                        {
1534                                layer=get_canvas_interface()->add_layer_to("outline",canvas,depth);
1535                                if (!layer)
1536                                {
1537                                        get_canvas_view()->get_selection_manager()->set_selected_layers(layer_list);
1538                                        get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
1539                                        group.cancel();
1540                                        return Smach::RESULT_ERROR;
1541                                }
1542                                layer->set_description(get_id()+_(" Outline"));
1543
1544                                layer->set_param("blend_method",get_blend());
1545                                get_canvas_interface()->signal_layer_param_changed()(layer,"blend_method");
1546
1547                                layer->set_param("amount",get_opacity());
1548                                get_canvas_interface()->signal_layer_param_changed()(layer,"amount");
1549
1550                                layer->set_param("width",get_bline_width());
1551                                get_canvas_interface()->signal_layer_param_changed()(layer,"width");
1552
1553                                layer->set_param("round_tip[0]", get_round_ends_flag());
1554                                get_canvas_interface()->signal_layer_param_changed()(layer, "round_tip[0]");
1555
1556                                layer->set_param("round_tip[1]", get_round_ends_flag());
1557                                get_canvas_interface()->signal_layer_param_changed()(layer, "round_tip[1]");
1558                        }
1559                        if(get_layer_advanced_outline_flag())
1560                        {
1561                                layer2=get_canvas_interface()->add_layer_to("advanced_outline",canvas,depth);
1562                                if (!layer2)
1563                                {
1564                                        get_canvas_view()->get_selection_manager()->set_selected_layers(layer_list);
1565                                        get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
1566                                        group.cancel();
1567                                        return Smach::RESULT_ERROR;
1568                                }
1569                                layer2->set_description(get_id()+_(" Advanced Outline"));
1570
1571                                layer2->set_param("blend_method",get_blend());
1572                                get_canvas_interface()->signal_layer_param_changed()(layer2,"blend_method");
1573
1574                                layer2->set_param("amount",get_opacity());
1575                                get_canvas_interface()->signal_layer_param_changed()(layer2,"amount");
1576
1577                                layer2->set_param("width",get_bline_width());
1578                                get_canvas_interface()->signal_layer_param_changed()(layer2,"width");
1579
1580                                // advanced outline tip types: 1, rounded 2, squared 3, peak 4, flat
1581                                if(get_round_ends_flag())
1582                                {
1583                                        layer2->set_param((ValueBase(),"start_tip"), 1);
1584                                        get_canvas_interface()->signal_layer_param_changed()(layer2, (ValueBase(),"start_tip"));
1585
1586                                        layer2->set_param((ValueBase(),"end_tip"), 1);
1587                                        get_canvas_interface()->signal_layer_param_changed()(layer2, (ValueBase(), "end_tip"));
1588                                }
1589                                else
1590                                {
1591                                        layer2->set_param((ValueBase(),"start_tip"), 4);
1592                                        get_canvas_interface()->signal_layer_param_changed()(layer2, (ValueBase(), "start_tip"));
1593
1594                                        layer2->set_param((ValueBase(),"end_tip"), 4);
1595                                        get_canvas_interface()->signal_layer_param_changed()(layer2, (ValueBase(), "end_tip"));
1596                                }
1597                        }
1598                }
1599                else if(get_layer_region_flag())
1600                {
1601                        layer=get_canvas_interface()->add_layer_to("region",canvas,depth);
1602                        if (!layer)
1603                        {
1604                                get_canvas_view()->get_selection_manager()->set_selected_layers(layer_list);
1605                                get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
1606                                group.cancel();
1607                                return Smach::RESULT_ERROR;
1608                        }
1609                        layer->set_description(get_id()+_(" Region"));
1610
1611                        layer->set_param("blend_method",get_blend());
1612                        get_canvas_interface()->signal_layer_param_changed()(layer,"blend_method");
1613
1614                        layer->set_param("amount",get_opacity());
1615                        get_canvas_interface()->signal_layer_param_changed()(layer,"amount");
1616                }
1617
1618                if(get_feather_size())
1619                {
1620                        if(layer)
1621                        {
1622                                layer->set_param("feather",get_feather_size());
1623                                get_canvas_interface()->signal_layer_param_changed()(layer,"feather");
1624                        }
1625                        if(get_layer_advanced_outline_flag())
1626                        {
1627                                layer2->set_param("feather",get_feather_size());
1628                                get_canvas_interface()->signal_layer_param_changed()(layer2,"feather");
1629                        }
1630
1631                }
1632                if(get_layer_outline_flag()) assert(layer);
1633                if(get_layer_advanced_outline_flag()) assert(layer2);
1634                //layer->set_description(strprintf("Stroke %d",number));
1635                //get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());
1636
1637                if (shift_origin)
1638                {
1639                        if(layer)
1640                                get_canvas_interface()->change_value(synfigapp::ValueDesc(layer,"origin"),shift_origin_vector);
1641                        if(layer2)
1642                                get_canvas_interface()->change_value(synfigapp::ValueDesc(layer2,"origin"),shift_origin_vector);
1643                }
1644                        // Regular Outline or Region
1645                if(layer)
1646                {
1647                        synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
1648                        assert(action);
1649                        action->set_param("canvas",get_canvas());
1650                        action->set_param("canvas_interface",get_canvas_interface());
1651                        action->set_param("layer",layer);
1652                        if(!action->set_param("param",String("bline")))
1653                                synfig::error("LayerParamConnect didn't like \"param\"");
1654                        if(!action->set_param("value_node",ValueNode::Handle(value_node)))
1655                                synfig::error("LayerParamConnect didn't like \"value_node\"");
1656
1657                        if(!get_canvas_interface()->get_instance()->perform_action(action))
1658                        {
1659                                get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
1660                                group.cancel();
1661                                increment_id();
1662                                //refresh_ducks();
1663                                return Smach::RESULT_ERROR;
1664                        }
1665                        layer_list.push_back(layer);
1666                }
1667                // Advanced Outline
1668                if(layer2)
1669                {
1670                        synfigapp::Action::Handle action2(synfigapp::Action::create("LayerParamConnect"));
1671                        assert(action2);
1672                        ValueNode_WPList::Handle value_node_wplist;
1673                        value_node_wplist=ValueNode_WPList::create(synfig::ValueBase(synfig::ValueBase::List(wplist.begin(), wplist.end())));
1674                        if(value_node_wplist) value_node_wplist->set_member_canvas(get_canvas());
1675                        action2->set_param("canvas",get_canvas());
1676                        action2->set_param("canvas_interface",get_canvas_interface());
1677                        action2->set_param("layer", layer2);
1678                        action2->set_param("param", String("wplist"));
1679                        action2->set_param("value_node", ValueNode::Handle(value_node_wplist));
1680                        if(!get_canvas_interface()->get_instance()->perform_action(action2))
1681                        {
1682                                get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
1683                                group.cancel();
1684                                increment_id();
1685                                //refresh_ducks();
1686                                return Smach::RESULT_ERROR;
1687                        }
1688                        synfigapp::Action::Handle action3(synfigapp::Action::create("LayerParamConnect"));
1689                        assert(action3);
1690                        action3->set_param("canvas",get_canvas());
1691                        action3->set_param("canvas_interface",get_canvas_interface());
1692                        action3->set_param("layer", layer2);
1693                        if(!action3->set_param("param",String("bline")))
1694                                synfig::error("LayerParamConnect didn't like \"param\"");
1695                        if(!action3->set_param("value_node",ValueNode::Handle(value_node)))
1696                                synfig::error("LayerParamConnect didn't like \"value_node\"");
1697                        if(!get_canvas_interface()->get_instance()->perform_action(action3))
1698                        {
1699                                get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
1700                                group.cancel();
1701                                increment_id();
1702                                //refresh_ducks();
1703                                return Smach::RESULT_ERROR;
1704                        }
1705                        layer_list.push_back(layer2);
1706                }
1707                get_canvas_view()->get_selection_manager()->set_selected_layers(layer_list);
1708        }
1709        increment_id();
1710        return Smach::RESULT_ACCEPT;
1711}
1712
1713#ifdef _DEBUG
1714static void
1715debug_show_vertex_list(int iteration, std::list<synfigapp::ValueDesc>& vertex_list,
1716                                           std::string title, int current)
1717{
1718        std::list<synfigapp::ValueDesc>::iterator i = vertex_list.begin();
1719        printf("\n%s\n  ----- iter %d : ", title.c_str(), iteration);
1720        int c = 0;
1721        synfig::LinkableValueNode::Handle last = 0;
1722        int start = -1;
1723        int index;
1724        int prev;
1725        int dir = 0;
1726        bool started = false;
1727        for(;i!=vertex_list.end();i++,c++)
1728        {
1729                synfigapp::ValueDesc value_desc(*i);
1730
1731                if (value_desc.parent_is_value_node()) {
1732                        if(value_desc.parent_is_linkable_value_node())
1733                        {
1734                                index = value_desc.get_index();
1735                                // printf("<%d>", index);
1736                                if (last == synfig::LinkableValueNode::Handle::cast_reinterpret(value_desc.get_parent_value_node()))
1737                                {
1738                                        // printf("\n%s:%d\n", __FILE__, __LINE__);
1739                                        if (start != -1)
1740                                        {
1741                                                // printf("\n%s:%d\n", __FILE__, __LINE__);
1742                                                if (c == current)
1743                                                {
1744                                                        // printf("\n%s:%d\n", __FILE__, __LINE__);
1745                                                        if (dir)
1746                                                        {
1747                                                                if (started) printf(", "); else started = true;
1748                                                                printf("%d--%d", start, prev);
1749                                                        }
1750                                                        else
1751                                                        {
1752                                                                if (started) printf(", "); else started = true;
1753                                                                printf("%d", start);
1754                                                        }
1755                                                        printf(", *%d*", index);
1756                                                        start = -1;
1757                                                }
1758                                                else if (dir == 0)
1759                                                {
1760                                                        // printf("\n%s:%d\n", __FILE__, __LINE__);
1761                                                        if (index == start + 1)
1762                                                        {
1763                                                                // printf("\n%s:%d\n", __FILE__, __LINE__);
1764                                                                dir = 1;
1765                                                                prev = index;
1766                                                        }
1767                                                        else if (index == start - 1)
1768                                                        {
1769                                                                // printf("\n%s:%d\n", __FILE__, __LINE__);
1770                                                                dir = -1;
1771                                                                prev = index;
1772                                                        }
1773                                                        else
1774                                                        {
1775                                                                if (started) printf(", "); else started = true;
1776                                                                printf("%d", start);
1777                                                                start = index;
1778                                                        }
1779                                                }
1780                                                else if (index == prev + dir)
1781                                                {
1782                                                        // printf("\n%s:%d\n", __FILE__, __LINE__);
1783                                                        prev = index;
1784                                                }
1785                                                else
1786                                                {
1787                                                        // printf("\n%s:%d\n", __FILE__, __LINE__);
1788                                                        if (started) printf(", "); else started = true;
1789                                                        if (prev != start)
1790                                                                printf("%d--%d", start, prev);
1791                                                        else
1792                                                                printf("%d", start);
1793                                                        // printf("\n%s:%d\n", __FILE__, __LINE__);
1794                                                        start = index;
1795                                                        dir = 0;
1796                                                }
1797                                        }
1798                                        else
1799                                        {
1800                                                // printf("\n%s:%d\n", __FILE__, __LINE__);
1801                                                if (c == current)
1802                                                {
1803                                                        if (started) printf(", "); else started = true;
1804                                                        printf("*%d*", index);
1805                                                }
1806                                                else
1807                                                {
1808                                                        // printf("\n%s:%d\n", __FILE__, __LINE__);
1809                                                        start = index;
1810                                                        dir = 0;
1811                                                }
1812                                        }
1813                                }
1814                                else
1815                                {
1816                                        // printf("\n%s:%d\n", __FILE__, __LINE__);
1817                                        if (last)
1818                                        {
1819                                                // printf("\n%s:%d\n", __FILE__, __LINE__);
1820                                                if (start != -1)
1821                                                {
1822                                                        if (started) printf(", "); else started = true;
1823                                                        if (dir != 0)
1824                                                                printf("%d--%d", start, prev);
1825                                                        else
1826                                                                printf("%d", start);
1827                                                }
1828                                                // printf("\n%s:%d\n", __FILE__, __LINE__);
1829                                                printf(") ");
1830                                        }
1831                                        // printf("\n%s:%d\n", __FILE__, __LINE__);
1832                                        last = synfig::LinkableValueNode::Handle::cast_reinterpret(value_desc.get_parent_value_node());
1833                                        printf("%d:(", synfig::LinkableValueNode::Handle::cast_reinterpret(value_desc.get_parent_value_node())->link_count());
1834                                        started = false;
1835                                        // printf("\n%s:%d\n", __FILE__, __LINE__);
1836                                        if (c == current)
1837                                        {
1838                                                start = -1;
1839                                                printf("*%d*", index);
1840                                        }
1841                                        else
1842                                        {
1843                                                // printf("\n%s:%d\n", __FILE__, __LINE__);
1844                                                start = index;
1845                                                dir = 0;
1846                                        }
1847                                        // printf("\n%s:%d\n", __FILE__, __LINE__);
1848                                }
1849                                // printf("\n%s:%d\n", __FILE__, __LINE__);
1850                        }
1851                        else if (last)
1852                                if (last) printf("?!) ");
1853                }
1854                else
1855                {
1856                        last = 0;
1857                        printf("? ");
1858                }
1859        }
1860        if (last)
1861        {
1862                if (started) printf(", "); else started = true;
1863                if (start != -1)
1864                {
1865                        if (dir != 0)
1866                                printf("%d--%d", start, prev);
1867                        else
1868                                printf("%d", start);
1869                }
1870                printf(")");
1871        }
1872        printf("\n");
1873}
1874#else  // _DEBUG
1875#define debug_show_vertex_list(a,b,c,d)
1876#endif  // _DEBUG
1877
1878Smach::event_result
1879StateDraw_Context::new_region(std::list<synfig::BLinePoint> bline, synfig::Real radius)
1880{
1881        // Create the action group
1882        synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Define Region"));
1883
1884        std::list<synfigapp::ValueDesc> vertex_list;
1885
1886        printf("new_region with %zd bline points\n", bline.size());
1887
1888        // First we need to come up with a rough list of
1889        // BLinePoints that we are going to be using to
1890        // define our region.
1891        {
1892                std::list<synfig::BLinePoint>::iterator iter;
1893                for(iter=bline.begin();iter!=bline.end();++iter)
1894                {
1895                        etl::handle<Duck> duck(get_work_area()->find_duck(iter->get_vertex(),0,Duck::TYPE_VERTEX));
1896
1897                        if(!duck)
1898                        {
1899                                synfig::info(__FILE__":%d: Nothing to enclose!",__LINE__);
1900                                return Smach::RESULT_OK;
1901                        }
1902
1903                        assert(duck->get_type()==Duck::TYPE_VERTEX);
1904
1905                        synfigapp::ValueDesc value_desc(duck->get_value_desc());
1906
1907                        if(!value_desc)
1908                        {
1909                                synfig::info(__FILE__":%d: Got a hit, but no ValueDesc on this duck",__LINE__);
1910                                continue;
1911                        }
1912
1913                        if (value_desc.get_value_type() == synfig::type_bline_point)
1914                        {
1915                                //if(vertex_list.empty() || value_desc!=vertex_list.back())
1916                                vertex_list.push_back(value_desc);
1917                                assert(vertex_list.back().is_valid());
1918                        }
1919                }
1920        }
1921
1922        assert(vertex_list.back().is_valid());
1923
1924        printf("vertex list with %zd bline points\n", vertex_list.size());
1925
1926        // Remove any duplicates
1927        {
1928        }
1929
1930        ValueNode_BLine::Handle value_node_bline;
1931
1932        // Now we need to test for the trivial case,
1933        // which is where all of the vertices
1934        // come from one BLine.
1935        if(vertex_list.front().parent_is_linkable_value_node())
1936        {
1937                bool trivial_case(true);
1938                ValueNode::Handle trivial_case_value_node;
1939
1940                trivial_case_value_node=vertex_list.front().get_parent_value_node();
1941
1942                std::list<synfigapp::ValueDesc>::iterator iter;
1943                for(iter=vertex_list.begin();iter!=vertex_list.end();++iter)
1944                {
1945                        if(trivial_case_value_node!=iter->get_parent_value_node())
1946                        {
1947                                trivial_case=false;
1948                                break;
1949                        }
1950                }
1951
1952                // \todo - re-enable this code
1953                if(trivial_case && false)
1954                {
1955                        synfig::info("all points are on the same bline, so just fill that line");
1956                        value_node_bline=ValueNode_BLine::Handle::cast_dynamic(trivial_case_value_node);
1957
1958                        synfig::info("the line has %d vertices", value_node_bline->link_count());
1959
1960                        if(value_node_bline->link_count() <= 2)
1961                        {
1962                                synfig::info(__FILE__":%d: Vertex list too small to make region.",__LINE__);
1963                                return Smach::RESULT_OK;
1964                        }
1965                }
1966        }
1967
1968        if(!value_node_bline)
1969                if(vertex_list.size()<=2)
1970                {
1971                        synfig::info(__FILE__":%d: Vertex list too small to make region.",__LINE__);
1972                        return Smach::RESULT_OK;
1973                }
1974
1975        // Now we need to clean the list of vertices up
1976        // a bit. This includes inserting missing vertices
1977        // and removing extraneous ones.
1978        // We can do this in multiple passes.
1979        if(!value_node_bline)
1980        {
1981                debug_show_vertex_list(0, vertex_list, "before shifting stuff", -1);
1982                // rearrange the list so that the first and last node are on different blines
1983                std::list<synfigapp::ValueDesc>::iterator iter, start;
1984                ValueNode::Handle last_value_node = vertex_list.back().get_parent_value_node();
1985                for(iter = vertex_list.begin(); iter!=vertex_list.end(); iter++)
1986                        if (iter->get_parent_value_node() != last_value_node)
1987                        {
1988                                vertex_list.insert(vertex_list.end(), vertex_list.begin(), iter);
1989                                vertex_list.erase(vertex_list.begin(), iter);
1990                                break;
1991                        }
1992
1993                debug_show_vertex_list(0, vertex_list, "before detecting direction and limits", -1);
1994                // rearrange the list so that the first and last node are on different blines
1995                iter = vertex_list.begin();
1996                while (iter!=vertex_list.end())
1997                {
1998                        // make a note of which bline we're looking at
1999                        ValueNode::Handle parent_value_node = iter->get_parent_value_node();
2000                        start = iter;
2001                        int points_in_line = synfig::LinkableValueNode::Handle::cast_reinterpret(parent_value_node)->link_count();
2002                        bool looped = (*parent_value_node)(get_time()).get_loop();
2003                        int this_index, last_index = iter->get_index();
2004                        int min_index = last_index, max_index = last_index;
2005                        bool whole;
2006                        int direction = 0;
2007
2008                        // printf("there are %d points in this line - first is index %d\n", points_in_line, last_index);
2009
2010                        // while we're looking at the same bline, keep going
2011                        iter++;
2012                        while (iter != vertex_list.end() && iter->get_parent_value_node() == parent_value_node)
2013                        {
2014                                this_index = iter->get_index();
2015                                // printf("index went from %d to %d\n", last_index, this_index);
2016                                if (looped)
2017                                {
2018                                        if (this_index - last_index > points_in_line/2)
2019                                                while (this_index - last_index > points_in_line/2)
2020                                                        this_index -= points_in_line;
2021                                        else if (last_index - this_index > points_in_line/2)
2022                                                while (last_index - this_index > points_in_line/2)
2023                                                        this_index += points_in_line;
2024                                }
2025
2026                                if (this_index < min_index) min_index = this_index;
2027                                if (this_index > max_index) max_index = this_index;
2028
2029                                // printf("so let's imagine index went from %d to %d\n", last_index, this_index);
2030                                if (this_index > last_index)
2031                                        direction++;
2032                                else if (this_index < last_index)
2033                                        direction--;
2034
2035                                last_index = this_index;
2036                                iter++;
2037                        }
2038
2039                        // printf("min %d and max %d\n", min_index, max_index);
2040                        whole = max_index - min_index >= points_in_line;
2041                        min_index = (min_index % points_in_line + points_in_line) % points_in_line;
2042                        max_index = (max_index % points_in_line + points_in_line) % points_in_line;
2043                        // they drew around a shape more than once - what's the start/end point?  does it matter?
2044                        if (whole) min_index = max_index = (min_index + max_index) / 2;
2045                        // printf("processed min %d max %d whole %d\n", min_index, max_index, whole);
2046
2047                        if (direction < 0)
2048                        {
2049                                if (whole)
2050                                {
2051                                        // printf("whole (down) (%d) ", min_index);
2052                                        for (int i = min_index; i >= 0; i--)
2053                                        {
2054                                                // printf("%d ", i);
2055                                                vertex_list.insert(start, synfigapp::ValueDesc(parent_value_node, i));
2056                                        }
2057                                        for (int i = points_in_line - 1; i >= min_index; i--)
2058                                        {
2059                                                // printf("%d ", i);
2060                                                vertex_list.insert(start, synfigapp::ValueDesc(parent_value_node, i));
2061                                        }
2062                                }
2063                                else
2064                                {
2065                                        // printf("part (down) (%d -> %d) ", max_index, min_index);
2066                                        for (int i = max_index; i != min_index; i--)
2067                                        {
2068                                                if (i == -1) i = points_in_line - 1;
2069                                                // printf("%d ", i);
2070                                                vertex_list.insert(start, synfigapp::ValueDesc(parent_value_node, i));
2071                                        }
2072                                        vertex_list.insert(start, synfigapp::ValueDesc(parent_value_node, min_index));
2073                                }
2074                        }
2075                        else
2076                        {
2077                                if (whole)
2078                                {
2079                                        // printf("whole (%d) ", min_index);
2080                                        for (int i = min_index; i < points_in_line; i++)
2081                                        {
2082                                                // printf("%d ", i);
2083                                                vertex_list.insert(start, synfigapp::ValueDesc(parent_value_node, i));
2084                                        }
2085                                        for (int i = 0; i <= min_index; i++)
2086                                        {
2087                                                // printf("%d ", i);
2088                                                vertex_list.insert(start, synfigapp::ValueDesc(parent_value_node, i));
2089                                        }
2090                                }
2091                                else
2092                                {
2093                                        // printf("part (%d -> %d) ", min_index, max_index);
2094                                        for (int i = min_index; i != max_index; i++)
2095                                        {
2096                                                if (i == points_in_line) i = 0;
2097                                                // printf("%d ", i);
2098                                                vertex_list.insert(start, synfigapp::ValueDesc(parent_value_node, i));
2099                                        }
2100                                        vertex_list.insert(start, synfigapp::ValueDesc(parent_value_node, max_index));
2101                                }
2102                        }
2103                        // printf("\n");
2104                        // debug_show_vertex_list(0, vertex_list, "after insert", -1);
2105                        vertex_list.erase(start, iter);
2106                        // debug_show_vertex_list(0, vertex_list, "after delete", -1);
2107                }
2108
2109                debug_show_vertex_list(0, vertex_list, "continuous vertices", -1);
2110
2111                // \todo reenable or delete this section
2112                int i=100;
2113                for(bool done=false;!done && i<30;i++)
2114                {
2115                        debug_show_vertex_list(i, vertex_list, "in big loop", -1);
2116
2117                        // Set done to "true" for now. If
2118                        // any updates are performed, we will
2119                        // change it back to false.
2120                        done=true;
2121
2122                        std::list<synfigapp::ValueDesc>::iterator prev,next;
2123                        prev=vertex_list.end();prev--;  // Set prev to the last ValueDesc
2124                        next=vertex_list.begin();
2125                        iter=next++; // Set iter to the first value desc, and next to the second
2126
2127                        int current = 0;
2128                        for(;iter!=vertex_list.end();prev=iter,iter++,next++,current++)
2129                        {
2130                                // we need to be able to erase(next) and can't do that if next is end()
2131                                if (next == vertex_list.end()) next = vertex_list.begin();
2132                                debug_show_vertex_list(i, vertex_list, "in loop around vertices", current);
2133                                synfigapp::ValueDesc value_prev(*prev);
2134                                synfigapp::ValueDesc value_desc(*iter);
2135                                synfigapp::ValueDesc value_next(*next);
2136
2137                                assert(value_desc.is_valid());
2138                                assert(value_next.is_valid());
2139                                assert(value_prev.is_valid());
2140
2141                                // synfig::info("-------");
2142                                // synfig::info(__FILE__":%d: value_prev 0x%08X:%d",__LINE__,value_prev.get_parent_value_node().get(),value_prev.get_index());
2143                                // synfig::info(__FILE__":%d: value_desc 0x%08X:%d",__LINE__,value_desc.get_parent_value_node().get(),value_desc.get_index());
2144                                // synfig::info(__FILE__":%d: value_next 0x%08X:%d",__LINE__,value_next.get_parent_value_node().get(),value_next.get_index());
2145
2146                                /*
2147                                  if(value_prev.parent_is_value_node() && value_desc.parent_is_value_node() && value_next.parent_is_value_node())
2148                                  {
2149                                  // Remove random extraneous vertices
2150                                  if(value_prev.get_parent_value_node()==value_next.get_parent_value_node() &&
2151                                  value_prev.get_parent_value_node()!=value_desc.get_parent_value_node())
2152                                  {
2153                                  vertex_list.erase(iter);
2154                                  done=false;
2155                                  break;
2156                                  }
2157                                  }
2158                                */
2159
2160                                // // Remove duplicate vertices
2161
2162                                // // if previous is the same as current or
2163                                // //    current is the same as next, remove current
2164                                // if(value_prev.get_value_node()==value_desc.get_value_node() ||
2165                                //    value_desc.get_value_node()==value_next.get_value_node())
2166                                // {
2167                                //      vertex_list.erase(iter);
2168                                //      done=false;
2169                                //      printf("erased node - i = %d\n", i);
2170                                //      break;
2171                                // }
2172
2173                                // // if previous is the same as next, remove previous?  or next?
2174                                // if(value_prev.get_value_node()==value_next.get_value_node())
2175                                // {
2176                                //      vertex_list.erase(next);
2177                                //      // vertex_list.erase(prev);
2178                                //      done=false;
2179                                //      printf("erased node - i = %d\n", i);
2180                                //      break;
2181                                // }
2182
2183                                // if 'this' and 'next' both have parents
2184                                if (value_desc.parent_is_value_node() && value_next.parent_is_value_node())
2185                                {
2186                                        // if they are both on the same bline - this has been handled by new code above
2187                                        if (value_desc.get_parent_value_node() == value_next.get_parent_value_node())
2188                                        {
2189                                                // // if (next != vertex_list.end())
2190                                                // {
2191                                                //      printf("parent loop is %d and node loop is ??\n",
2192                                                //                 (*(value_desc.get_parent_value_node()))(get_time()).get_loop()
2193                                                //                 // value_desc.get_value_node().get_loop(),
2194                                                //              );
2195                                                //
2196                                                //      // Fill in missing vertices
2197                                                //      // \todo take loops into account: seeing (15, 2, 3, 4) probably means that (0, 1) is missing, not 14 through 3
2198                                                //      if(value_desc.get_index()<value_next.get_index()-1)
2199                                                //      {
2200                                                //              debug_show_vertex_list(i, vertex_list,
2201                                                //                                                         strprintf("same parent, different points this %d < next-1 %d",
2202                                                //                                                                               value_desc.get_index(), ((value_next.get_index()-1))),
2203                                                //                                                         current);
2204                                                //              for (int index = value_desc.get_index()+1; index < value_next.get_index(); index++)
2205                                                //              {
2206                                                //                      printf("inserting up %d\n", index);
2207                                                //                      vertex_list.insert(next, synfigapp::ValueDesc(value_desc.get_parent_value_node(), index));
2208                                                //              }
2209                                                //              debug_show_vertex_list(i, vertex_list, "new list", current);
2210                                                //              done=false;
2211                                                //              break;
2212                                                //      }
2213                                                //      if(value_next.get_index()<value_desc.get_index()-1)
2214                                                //      {
2215                                                //              debug_show_vertex_list(i, vertex_list,
2216                                                //                                                         strprintf("same parent, different points next %d < this-1 %d",
2217                                                //                                                                               value_next.get_index(), ((value_desc.get_index()-1))),
2218                                                //                                                         current);
2219                                                //              for (int index = value_desc.get_index()-1; index > value_next.get_index(); index--)
2220                                                //              {
2221                                                //                      printf("inserting down %d\n", index);
2222                                                //                      vertex_list.insert(next, synfigapp::ValueDesc(value_desc.get_parent_value_node(), index));
2223                                                //              }
2224                                                //              debug_show_vertex_list(i, vertex_list, "new list", current);
2225                                                //              done=false;
2226                                                //              break;
2227                                                //      }
2228                                                // }
2229                                        }
2230                                        // 'this' and 'next' have different parents
2231                                        else
2232                                        {
2233                                                ValueNode::Handle v1 = value_desc.get_value_node();
2234                                                ValueNode::Handle v2 = value_desc.get_parent_value_node();
2235                                                if (v1 == v2)
2236                                                        printf("same\n");
2237                                                else
2238                                                        printf("different\n");
2239
2240                                                if (value_desc.get_value_node() != value_next.get_value_node())
2241                                                {
2242                                                        // Ensure that connections between blines are properly connected
2243                                                        BLinePoint vertex(value_desc.get_value(get_time()).get(BLinePoint()));
2244                                                        BLinePoint vertex_next(value_next.get_value(get_time()).get(BLinePoint()));
2245
2246                                                        //synfig::info("--------");
2247                                                        //synfig::info(__FILE__":%d: vertex: [%f, %f]",__LINE__,vertex.get_vertex()[0],vertex.get_vertex()[1]);
2248                                                        //synfig::info(__FILE__":%d: vertex_next: [%f, %f]",__LINE__,vertex_next.get_vertex()[0],vertex_next.get_vertex()[1]);
2249
2250                                                        // if this vertex is close to the next one, replace this vertex with a new one
2251                                                        // and erase the next one
2252                                                        printf("this point is %5.2f from the next point - compare with %5.2f\n",
2253                                                                   (vertex.get_vertex()-vertex_next.get_vertex()).mag_squared(),
2254                                                                   radius*radius);
2255                                                        if((vertex.get_vertex()-vertex_next.get_vertex()).mag_squared()<radius*radius)
2256                                                        {
2257                                                                printf("in one - it's close\n");
2258                                                                ValueNode_Composite::Handle value_node;
2259                                                                ValueNode_Composite::Handle value_node_next;
2260                                                                value_node=ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()->
2261                                                                                                                                                                         clone(value_desc.get_value_node()->get_parent_canvas()));
2262                                                                value_node_next=ValueNode_Composite::Handle::cast_dynamic(value_next.get_value_node()->
2263                                                                                                                                                                                  clone(value_next.get_value_node()->get_parent_canvas()));
2264                                                                if(!value_node || !value_node_next)
2265                                                                {
2266                                                                        synfig::info(__FILE__":%d: Unable to properly connect blines.",__LINE__);
2267                                                                        continue;
2268                                                                }
2269                                                                // \todo if next isn't split, don't we want to copy its 'Tangent 1' instead?
2270                                                                value_node->set_link("t2",value_node_next->get_link("t2"));
2271                                                                value_node->set_link("split",ValueNode_Const::create(true));
2272
2273                                                                // get_canvas_interface()->auto_export(value_node);
2274                                                                printf("exporting\n");
2275                                                                get_canvas_interface()->add_value_node(value_node,value_node->get_id() + strprintf("foo %d", rand()));
2276
2277                                                                assert(value_node->is_exported());
2278                                                                // replace 'this' with the new valuenode
2279                                                                *iter=synfigapp::ValueDesc(get_canvas(),value_node->get_id());
2280                                                                printf("erasing next\n");
2281                                                                printf("erasing next point\n");
2282                                                                vertex_list.erase(next);
2283                                                                done=false;
2284                                                                break;
2285                                                        } // this vertex isn't close to the next one
2286                                                        else if (value_prev.parent_is_value_node())
2287                                                        {
2288                                                                printf("in two - it's far\n");
2289                                                                // \todo this only makes sense if prev is on the same bline
2290                                                                printf("this is index %d\n", value_desc.get_index());
2291                                                                printf("prev is index %d\n", value_prev.get_index());
2292                                                                bool positive_trend(value_desc.get_index()>value_prev.get_index());
2293
2294                                                                if(positive_trend)
2295                                                                {
2296                                                                        printf("positive trend\n");
2297                                                                        printf("comparing index %d < link_count()-1 = %d-1 = %d\n",
2298                                                                                   value_desc.get_index(),
2299                                                                                   LinkableValueNode::Handle::cast_static(value_desc.get_parent_value_node())->link_count(),
2300                                                                                   LinkableValueNode::Handle::cast_static(value_desc.get_parent_value_node())->link_count()-1);
2301                                                                        if (value_desc.get_index()<LinkableValueNode::Handle::cast_static(value_desc.get_parent_value_node())->link_count()-1)
2302                                                                        {
2303                                                                                printf("in two - b\n");
2304                                                                                printf("inserting node with index %d\n", value_desc.get_index()+1);
2305                                                                                vertex_list.insert(next,
2306                                                                                                                   synfigapp::ValueDesc(value_desc.get_parent_value_node(),
2307                                                                                                                                                                value_desc.get_index()+1));
2308                                                                                done=false;
2309                                                                                break;
2310                                                                        }
2311                                                                }
2312                                                                else // !positive_trend
2313                                                                {
2314                                                                        printf("negative trend\n");
2315                                                                        if(value_desc.get_index()>0)
2316                                                                        {
2317                                                                                printf("in two - a\n");
2318                                                                                printf("inserting node on this line with index %d\n",
2319                                                                                           value_desc.get_index()-1);
2320                                                                                vertex_list.insert(next,
2321                                                                                                                   synfigapp::ValueDesc(value_desc.get_parent_value_node(),
2322                                                                                                                                                                value_desc.get_index()-1));
2323                                                                                done=false;
2324                                                                                break;
2325                                                                        }
2326                                                                }
2327                                                        }
2328                                                }
2329                                        }
2330                                }
2331                        }
2332                }
2333
2334                if(vertex_list.size()<=2)
2335                {
2336                        synfig::info(__FILE__":%d: Vertex list too small to make region.",__LINE__);
2337                        return Smach::RESULT_OK;
2338                }
2339
2340                debug_show_vertex_list(i, vertex_list, "finished tidying list", -1);
2341        }
2342
2343        // If we aren't the trivial case,
2344        // then go ahead and create the new
2345        // BLine value node
2346        if(!value_node_bline)
2347        {
2348                synfig::info("not all points are on the same bline");
2349                value_node_bline=ValueNode_BLine::create();
2350
2351                std::list<synfigapp::ValueDesc>::iterator iter;
2352                for(iter=vertex_list.begin();iter!=vertex_list.end();++iter)
2353                {
2354                        // Ensure that the vertex is exported.
2355                        get_canvas_interface()->auto_export(*iter);
2356
2357                        value_node_bline->add(iter->get_value_node());
2358                        //value_node_bline->add(ValueNode_BLine::ListEntry(iter->get_value_node()));
2359                }
2360
2361                value_node_bline->set_loop(true);
2362        }
2363
2364        get_canvas_interface()->auto_export(value_node_bline);
2365
2366        // Now we create the region layer
2367        // Create the layer
2368        {
2369                Layer::Handle layer;
2370                Canvas::Handle canvas(get_canvas_view()->get_canvas());
2371                int depth(0);
2372
2373                // we are temporarily using the layer to hold something
2374                layer=get_canvas_view()->get_selection_manager()->get_selected_layer();
2375                if(layer)
2376                {
2377                        depth=layer->get_depth();
2378                        canvas=layer->get_canvas();
2379                }
2380
2381                synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);
2382
2383                layer=get_canvas_interface()->add_layer_to("region",canvas,depth);
2384                if (!layer)
2385                {
2386                        get_canvas_view()->get_ui_interface()->error(_("Unable to create layer"));
2387                        group.cancel();
2388                        return Smach::RESULT_ERROR;
2389                }
2390
2391                if(get_feather_size())
2392                {
2393                        layer->set_param("feather",get_feather_size());
2394                        get_canvas_interface()->signal_layer_param_changed()(layer,"feather");
2395                }
2396                get_canvas_interface()->signal_layer_param_changed()(layer,"color");
2397
2398                synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
2399
2400                assert(action);
2401
2402                action->set_param("canvas",get_canvas());
2403                action->set_param("canvas_interface",get_canvas_interface());
2404                action->set_param("layer",layer);
2405                if(!action->set_param("param",String("bline")))
2406                        synfig::error("LayerParamConnect didn't like \"param\"");
2407                if(!action->set_param("value_node",ValueNode::Handle(value_node_bline)))
2408                        synfig::error("LayerParamConnect didn't like \"value_node\"");
2409
2410                if(!get_canvas_interface()->get_instance()->perform_action(action))
2411                {
2412                        get_canvas_view()->get_ui_interface()->error(_("Unable to create Region layer"));
2413                        group.cancel();
2414                        return Smach::RESULT_ERROR;
2415                }
2416                get_canvas_view()->get_selection_manager()->set_selected_layer(layer);
2417        }
2418
2419        return Smach::RESULT_ACCEPT;
2420}
2421
2422void
2423StateDraw_Context::refresh_ducks()
2424{
2425        get_canvas_view()->queue_rebuild_ducks();
2426/*
2427        get_work_area()->clear_ducks();
2428
2429
2430        std::list< etl::smart_ptr<std::list<synfig::Point> > >::iterator iter;
2431
2432        for(iter=stroke_list.begin();iter!=stroke_list.end();++iter)
2433        {
2434                get_work_area()->add_stroke(*iter);
2435        }
2436
2437        get_work_area()->queue_draw();
2438*/
2439}
2440
2441
2442Smach::event_result
2443StateDraw_Context::extend_bline_from_begin(ValueNode_BLine::Handle value_node,std::list<synfig::BLinePoint> bline,std::list<synfig::WidthPoint> wplist,bool complete_loop)
2444{
2445
2446        // Recreate the bline that is going to be inserted
2447        // First copy the list of BlinePoints
2448        std::list<synfig::BLinePoint> inserted_bline(bline.begin(), bline.end());
2449        // Add at the end the first BLinePoint of the bline to extend (it is the place where it connects)
2450        inserted_bline.push_back((*value_node)(get_canvas()->get_time()).get_list().front().get(BLinePoint()));
2451        // if doing complete loop then add at the start the last BLinePoint of the bline to extend
2452        // (it is where the loop closes)
2453        if(complete_loop)
2454                inserted_bline.push_front((*value_node)(get_canvas()->get_time()).get_list().back().get(BLinePoint()));
2455        // store the length of the inserted bline and the number of segments
2456        Real inserted_length(bline_length(ValueBase::List(inserted_bline.begin(), inserted_bline.end()), false, NULL));
2457        int inserted_size(inserted_bline.size());
2458        // Determine if the bline that the layer belongs to is a Advanced Outline
2459        bool is_advanced_outline(false);
2460        Layer::Handle layer_parent;
2461        std::set<Node*>::iterator niter;
2462        for(niter=value_node->parent_set.begin();niter!=value_node->parent_set.end();++niter)
2463        {
2464                layer_parent=Layer::Handle::cast_dynamic(*niter);
2465                if(layer_parent && layer_parent->get_name() == "advanced_outline")
2466                {
2467                        is_advanced_outline=true;
2468                        break;
2469                }
2470        }
2471
2472        // Create the action group
2473        synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Extend Spline"));
2474
2475        if(is_advanced_outline)
2476        {
2477                ValueNode_WPList::Handle wplist_value_node(ValueNode_WPList::Handle::cast_dynamic(layer_parent->dynamic_param_list().find("wplist")->second));
2478                if(wplist_value_node)
2479                {
2480                        // Calculate the number of blinepoints of the original bline
2481                        int value_node_size((*value_node)(get_canvas()->get_time()).get_list().size());
2482                        // Calculate the length of the original bline
2483                        Real value_node_length(bline_length(ValueBase((*value_node)(get_canvas()->get_time()).get_list()), false, NULL));
2484                        // Retrieve the homogeneous parameter value form the layer
2485                        bool homogeneous(layer_parent->get_param("homogeneous").get(bool()));
2486                        //
2487                        // Calculate the new boundaries for each width point on the old wplist
2488                        // and modify the boundaries on the old wplist
2489                        //
2490                        std::list<synfig::WidthPoint> old_wplist;
2491                        ValueBase wplist_value_base((*wplist_value_node)(get_canvas()->get_time()));
2492                        const ValueBase::List &wplist_value_base_list = wplist_value_base.get_list();
2493                        for(ValueBase::List::const_iterator i = wplist_value_base_list.begin(); i != wplist_value_base_list.end(); ++i)
2494                                old_wplist.push_back(i->get(synfig::WidthPoint()));
2495                        std::list<synfig::WidthPoint>::iterator witer;
2496                        int i;
2497                        for(i=0, witer=old_wplist.begin(); witer!=old_wplist.end(); witer++, i++)
2498                        {
2499                                synfigapp::Action::Handle action(synfigapp::Action::create("ValueDescSet"));
2500                                assert(action);
2501                                action->set_param("canvas", get_canvas());
2502                                action->set_param("canvas_interface",get_canvas_interface());
2503                                synfigapp::ValueDesc value_desc;
2504                                Real lb_new;
2505                                ValueNode_Composite::Handle composite(ValueNode_Composite::Handle::cast_dynamic(wplist_value_node->get_link(i)));
2506                                if(composite)
2507                                {
2508                                        value_desc=synfigapp::ValueDesc(composite,4);
2509                                        assert(value_desc.is_valid());
2510                                        WidthPoint wpi(*witer);
2511                                        Real lb(wpi.get_lower_bound());
2512                                        Real ub(wpi.get_upper_bound());
2513                                        Real range(ub-lb);
2514                                        Real l1(inserted_length);
2515                                        Real l2(value_node_length);
2516                                        int s1(complete_loop?inserted_size-2:inserted_size-1);
2517                                        int s2(value_node_size-1);
2518                                        if(homogeneous)
2519                                        {
2520                                                lb_new=ub-(l1+l2)*range/l2;
2521                                        }
2522                                        else
2523                                        {
2524                                                lb_new=ub-(s1+s2)*range/s2;
2525                                        }
2526                                }
2527                                else
2528                                {
2529                                        group.cancel();
2530                                        return Smach::RESULT_ERROR;
2531                                }
2532                                action->set_param("value_desc",value_desc);
2533                                action->set_param("new_value", ValueBase(lb_new));
2534                                if(!get_canvas_interface()->get_instance()->perform_action(action))
2535                                {
2536                                        get_canvas_view()->get_ui_interface()->error(_("Unable to set lower boundary for wplist"));
2537                                        group.cancel();
2538                                        return Smach::RESULT_ERROR;
2539                                }
2540                        }
2541                        //
2542                        // Calculate the new boundaries for each widthpoint of the inserted wplist
2543                        // and insert each one in the wplist form the layer.
2544                        // Don't add the widthpoint with position equal to 1.0
2545                        // to avoid conflicts with the first of the existing wplist.
2546                        // Don't add the widthpoint with position equal to 0.0 if doing
2547                        // complete loops.
2548                        //
2549                        for(witer=wplist.begin(); witer!=wplist.end();witer++)
2550                        {
2551                                if(witer->get_position() == 1.0)
2552                                        continue;
2553                                if(complete_loop && witer->get_position() == 0.0)
2554                                        continue;
2555                                synfigapp::Action::Handle action(synfigapp::Action::create("ValueNodeDynamicListInsert"));
2556                                assert(action);
2557                                synfigapp::ValueDesc value_desc(wplist_value_node,0);
2558                                action->set_param("canvas", get_canvas());
2559                                action->set_param("canvas_interface",get_canvas_interface());
2560                                action->set_param("value_desc", value_desc);
2561                                // Prepare the time to insert
2562                                Real lb(witer->get_lower_bound());
2563                                Real ub(witer->get_upper_bound());
2564                                Real range(ub-lb);
2565                                Real l1(inserted_length);
2566                                Real l2(value_node_length);
2567                                int s1(complete_loop?inserted_size-2:inserted_size-1);
2568                                int s2(value_node_size-1);
2569                                if(homogeneous)
2570                                {
2571                                        witer->set_upper_bound(lb+(l1+l2)*range/l1);
2572                                }
2573                                else
2574                                {
2575                                        witer->set_upper_bound(lb+(s1+s2)*range/s1);
2576                                }
2577                                if(!action->set_param("item",ValueNode::Handle(ValueNode_Composite::create(*witer))))
2578                                        synfig::error("ACTION didn't like \"item\"");
2579                                if(!get_canvas_interface()->get_instance()->perform_action(action))
2580                                {
2581                                        get_canvas_view()->get_ui_interface()->error(_("Unable to insert item"));
2582                                        group.cancel();
2583                                        return Smach::RESULT_ERROR;
2584                                }
2585                        }
2586                } // endif wplist_value_node exists
2587        } // endif is avanced outline
2588
2589        if (complete_loop)
2590        {
2591                synfigapp::Action::Handle action(synfigapp::Action::create("ValueNodeDynamicListLoop"));
2592                assert(action);
2593
2594                action->set_param("canvas",get_canvas());
2595                action->set_param("canvas_interface",get_canvas_interface());
2596                action->set_param("value_node",ValueNode::Handle(value_node));
2597
2598                if(!get_canvas_interface()->get_instance()->perform_action(action))
2599                {
2600                        get_canvas_view()->get_ui_interface()->error(_("Unable to set loop for spline"));
2601                        group.cancel();
2602                        return Smach::RESULT_ERROR;
2603                }
2604        }
2605
2606        std::list<synfig::BLinePoint>::reverse_iterator iter;
2607        for(iter=bline.rbegin();!(iter==bline.rend());++iter)
2608        {
2609                ValueNode_Composite::Handle composite(ValueNode_Composite::create(*iter));
2610
2611                synfigapp::Action::Handle action(synfigapp::Action::create("ValueNodeDynamicListInsert"));
2612
2613                assert(action);
2614                synfigapp::ValueDesc value_desc(value_node,0);
2615
2616                action->set_param("canvas",get_canvas());
2617                action->set_param("canvas_interface",get_canvas_interface());
2618                action->set_param("value_desc",value_desc);
2619                if(!action->set_param("item",ValueNode::Handle(composite)))
2620                        synfig::error("ACTION didn't like \"item\"");
2621
2622                if(!get_canvas_interface()->get_instance()->perform_action(action))
2623                {
2624                        get_canvas_view()->get_ui_interface()->error(_("Unable to insert item"));
2625                        group.cancel();
2626                        return Smach::RESULT_ERROR;
2627                }
2628        }
2629
2630        last_stroke=value_node;
2631        return Smach::RESULT_ACCEPT;
2632}
2633
2634Smach::event_result
2635StateDraw_Context::extend_bline_from_end(ValueNode_BLine::Handle value_node,std::list<synfig::BLinePoint> bline,std::list<synfig::WidthPoint> wplist,bool complete_loop)
2636{
2637        // Recreate the bline that is going to be inserted
2638        // First copy the list of BlinePoints
2639        std::list<synfig::BLinePoint> inserted_bline(bline.begin(), bline.end());
2640        // Add at the start, the last BLinePoint of the bline to extend (it is the place where it connects)
2641        inserted_bline.push_front((*value_node)(get_canvas()->get_time()).get_list().back().get(BLinePoint()));
2642        // if doing complete loop then add at the end the last BLinePoint of the bline to extend
2643        // (it is where the loop closes)
2644        if(complete_loop)
2645                inserted_bline.push_back((*value_node)(get_canvas()->get_time()).get_list().front().get(BLinePoint()));
2646        // store the length of the inserted bline and the number of segments
2647        Real inserted_length(bline_length(ValueBase::List(inserted_bline.begin(), inserted_bline.end()), false, NULL));
2648        int inserted_size(inserted_bline.size());
2649        // Determine if the bline that the layer belongs to is a Advanced Outline
2650        bool is_advanced_outline(false);
2651        Layer::Handle layer_parent;
2652        std::set<Node*>::iterator niter;
2653        for(niter=value_node->parent_set.begin();niter!=value_node->parent_set.end();++niter)
2654        {
2655                layer_parent=Layer::Handle::cast_dynamic(*niter);
2656                if(layer_parent && layer_parent->get_name() == "advanced_outline")
2657                {
2658                        is_advanced_outline=true;
2659                        break;
2660                }
2661        }
2662
2663        // Create the action group
2664        synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Extend Spline"));
2665
2666        if(is_advanced_outline)
2667        {
2668                ValueNode_WPList::Handle wplist_value_node(ValueNode_WPList::Handle::cast_dynamic(layer_parent->dynamic_param_list().find("wplist")->second));
2669                if(wplist_value_node)
2670                {
2671                        // Calculate the number of blinepoints of the original bline
2672                        int value_node_size((*value_node)(get_canvas()->get_time()).get_list().size());
2673                        // Calculate the length of the original bline
2674                        Real value_node_length(bline_length(ValueBase((*value_node)(get_canvas()->get_time()).get_list()), false, NULL));
2675                        // Retrieve the homogeneous parameter value form the layer
2676                        bool homogeneous(layer_parent->get_param("homogeneous").get(bool()));
2677                        //
2678                        // Calculate the new boundaries for each width point on the old wplist
2679                        // and modify the boundaries on the old wplist
2680                        //
2681                        std::list<synfig::WidthPoint> old_wplist;
2682                        ValueBase wplist_value_base((*wplist_value_node)(get_canvas()->get_time()));
2683                        const ValueBase::List &wplist_value_base_list = wplist_value_base.get_list();
2684                        for(ValueBase::List::const_iterator i = wplist_value_base_list.begin(); i != wplist_value_base_list.end(); ++i)
2685                                old_wplist.push_back(i->get(synfig::WidthPoint()));
2686                        std::list<synfig::WidthPoint>::iterator witer;
2687                        int i;
2688                        for(i=0, witer=old_wplist.begin(); witer!=old_wplist.end(); witer++, i++)
2689                        {
2690                                synfigapp::Action::Handle action(synfigapp::Action::create("ValueDescSet"));
2691                                assert(action);
2692                                action->set_param("canvas", get_canvas());
2693                                action->set_param("canvas_interface",get_canvas_interface());
2694                                synfigapp::ValueDesc value_desc;
2695                                Real ub_new;
2696                                ValueNode_Composite::Handle composite(ValueNode_Composite::Handle::cast_dynamic(wplist_value_node->get_link(i)));
2697                                if(composite)
2698                                {
2699                                        value_desc=synfigapp::ValueDesc(composite,5);
2700                                        assert(value_desc.is_valid());
2701                                        WidthPoint wpi(*witer);
2702                                        Real lb(wpi.get_lower_bound());
2703                                        Real ub(wpi.get_upper_bound());
2704                                        Real range(ub-lb);
2705                                        Real l1(inserted_length);
2706                                        Real l2(value_node_length);
2707                                        int s1(complete_loop?inserted_size-2:inserted_size-1);
2708                                        int s2(value_node_size-1);
2709                                        if(homogeneous)
2710                                        {
2711                                                ub_new=lb+(l1+l2)*range/l2;
2712                                        }
2713                                        else
2714                                        {
2715                                                ub_new=lb+(s1+s2)*range/s2;
2716                                        }
2717                                }
2718                                else
2719                                {
2720                                        group.cancel();
2721                                        return Smach::RESULT_ERROR;
2722                                }
2723                                action->set_param("value_desc",value_desc);
2724                                action->set_param("new_value", ValueBase(ub_new));
2725                                if(!get_canvas_interface()->get_instance()->perform_action(action))
2726                                {
2727                                        get_canvas_view()->get_ui_interface()->error(_("Unable to set upper boundary for wplist"));
2728                                        group.cancel();
2729                                        return Smach::RESULT_ERROR;
2730                                }
2731                        }
2732                        //
2733                        // Calculate the new boundaries for each widthpoint of the inserted wplist
2734                        // and insert each one in the wplist form the layer.
2735                        // Don't add the widthpoint with position equal to 1.0
2736                        // to avoid conflicts with the first of the existing wplist.
2737                        // Don't add the widthpoint with position equal to 0.0 if doing
2738                        // complete loops.
2739                        //
2740                        for(witer=wplist.begin(); witer!=wplist.end();witer++)
2741                        {
2742                                if(witer->get_position() == 0.0)
2743                                        continue;
2744                                if(complete_loop && witer->get_position() == 1.0)
2745                                        continue;
2746                                synfigapp::Action::Handle action(synfigapp::Action::create("ValueNodeDynamicListInsert"));
2747                                assert(action);
2748                                synfigapp::ValueDesc value_desc(wplist_value_node,0);
2749                                action->set_param("canvas", get_canvas());
2750                                action->set_param("canvas_interface",get_canvas_interface());
2751                                action->set_param("value_desc", value_desc);
2752                                // Prepare the time to insert
2753                                Real lb(witer->get_lower_bound());
2754                                Real ub(witer->get_upper_bound());
2755                                Real range(ub-lb);
2756                                Real l1(inserted_length);
2757                                Real l2(value_node_length);
2758                                int s1(complete_loop?inserted_size-2:inserted_size-1);
2759                                int s2(value_node_size-1);
2760                                if(homogeneous)
2761                                {
2762                                        witer->set_lower_bound(ub-(l1+l2)*range/l1);
2763                                }
2764                                else
2765                                {
2766                                        witer->set_lower_bound(ub-(s1+s2)*range/s1);
2767                                }
2768                                if(!action->set_param("item",ValueNode::Handle(ValueNode_Composite::create(*witer))))
2769                                        synfig::error("ACTION didn't like \"item\"");
2770                                if(!get_canvas_interface()->get_instance()->perform_action(action))
2771                                {
2772                                        get_canvas_view()->get_ui_interface()->error(_("Unable to insert item"));
2773                                        group.cancel();
2774                                        return Smach::RESULT_ERROR;
2775                                }
2776                        }
2777                } // endif wplist_value_node exists
2778        } // endif is avanced outline
2779
2780        if (complete_loop)
2781        {
2782                synfigapp::Action::Handle action(synfigapp::Action::create("ValueNodeDynamicListLoop"));
2783                assert(action);
2784
2785                action->set_param("canvas",get_canvas());
2786                action->set_param("canvas_interface",get_canvas_interface());
2787                action->set_param("value_node",ValueNode::Handle(value_node));
2788
2789                if(!get_canvas_interface()->get_instance()->perform_action(action))
2790                {
2791                        get_canvas_view()->get_ui_interface()->error(_("Unable to set loop for spline"));
2792                        group.cancel();
2793                        return Smach::RESULT_ERROR;
2794                }
2795        }
2796
2797        std::list<synfig::BLinePoint>::iterator iter;
2798        for(iter=bline.begin();iter!=bline.end();++iter)
2799        {
2800                ValueNode_Composite::Handle composite(ValueNode_Composite::create(*iter));
2801
2802                synfigapp::Action::Handle action(synfigapp::Action::create("ValueNodeDynamicListInsert"));
2803
2804                assert(action);
2805                synfigapp::ValueDesc value_desc(value_node,value_node->link_count());
2806
2807                action->set_param("canvas",get_canvas());
2808                action->set_param("canvas_interface",get_canvas_interface());
2809                action->set_param("value_desc",value_desc);
2810                if(!action->set_param("item",ValueNode::Handle(composite)))
2811                        synfig::error("ACTION didn't like \"item\"");
2812
2813                if(!get_canvas_interface()->get_instance()->perform_action(action))
2814                {
2815                        get_canvas_view()->get_ui_interface()->error(_("Unable to insert item"));
2816                        group.cancel();
2817                        //refresh_ducks();
2818                        return Smach::RESULT_ERROR;
2819                }
2820        }
2821        last_stroke=value_node;
2822        return Smach::RESULT_ACCEPT;
2823}
2824
2825void
2826StateDraw_Context::reverse_bline(std::list<synfig::BLinePoint> &bline)
2827{
2828        int i;
2829
2830        std::list<synfig::BLinePoint>::iterator iter,eiter;
2831        iter=bline.begin();
2832        eiter=bline.end();
2833        eiter--;
2834        for(i=0;i<(int)bline.size()/2;++iter,--eiter,i++)
2835        {
2836                iter_swap(iter,eiter);
2837                iter->reverse();
2838                eiter->reverse();
2839        }
2840}
2841
2842void
2843StateDraw_Context::reverse_wplist(std::list<synfig::WidthPoint> &wplist)
2844{
2845        std::list<synfig::WidthPoint>::iterator iter;
2846        for(iter=wplist.begin();iter!=wplist.end();iter++)
2847                iter->reverse();
2848}
2849
2850
2851Smach::event_result
2852StateDraw_Context::fill_last_stroke_and_unselect_other_layers()
2853{
2854        if(!last_stroke)
2855                return Smach::RESULT_OK;
2856
2857        synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("Fill Stroke"));
2858
2859        Layer::Handle layer;
2860
2861        get_canvas_interface()->auto_export(last_stroke);
2862
2863        synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);
2864
2865        Canvas::Handle canvas(get_canvas_view()->get_canvas());
2866        int depth(0);
2867
2868        layer=get_canvas_view()->get_selection_manager()->get_selected_layer();
2869        if(layer)
2870        {
2871                depth=layer->get_depth();
2872                canvas=layer->get_canvas();
2873        }
2874
2875        get_canvas_interface()->get_selection_manager()->clear_selected_layers();
2876        layer=get_canvas_interface()->add_layer_to("region", canvas, depth);
2877        if (!layer) return Smach::RESULT_ERROR;
2878        layer->set_description(last_stroke_id + _(" Region"));
2879
2880        layer->set_param("blend_method",get_blend());
2881        get_canvas_interface()->signal_layer_param_changed()(layer,"blend_method");
2882
2883        layer->set_param("amount",get_opacity());
2884        get_canvas_interface()->signal_layer_param_changed()(layer,"amount");
2885
2886        synfigapp::Action::Handle action(synfigapp::Action::create("LayerParamConnect"));
2887
2888        assert(action);
2889
2890        action->set_param("canvas",get_canvas());
2891        action->set_param("canvas_interface",get_canvas_interface());
2892        action->set_param("layer",layer);
2893        if(!action->set_param("param",String("bline")))
2894                synfig::error("LayerParamConnect didn't like \"param\"");
2895        if(!action->set_param("value_node",ValueNode::Handle(last_stroke)))
2896                synfig::error("LayerParamConnect didn't like \"value_node\"");
2897
2898        if(!get_canvas_interface()->get_instance()->perform_action(action))
2899        {
2900                get_canvas_view()->get_ui_interface()->error(_("Unable to create Region layer"));
2901                group.cancel();
2902                return Smach::RESULT_OK;
2903        }
2904        get_canvas_view()->get_selection_manager()->set_selected_layer(layer);
2905        return Smach::RESULT_OK;
2906}
2907
2908void
2909StateDraw_Context::fill_last_stroke()
2910{
2911        if(!last_stroke)
2912                return;
2913
2914        synfigapp::SelectionManager::LayerList layer_list = get_canvas_view()->get_selection_manager()->get_selected_layers();
2915        fill_last_stroke_and_unselect_other_layers();
2916        get_canvas_view()->get_selection_manager()->set_selected_layers(layer_list);
2917}
2918
2919void
2920StateDraw_Context::toggle_layer_creation()
2921{
2922  // don't allow none layer creation
2923  if (get_layer_region_flag() +
2924     get_layer_outline_flag() +
2925     get_layer_advanced_outline_flag() == 0)
2926  {
2927    if(layer_region_flag) set_layer_region_flag(true);
2928    else if(layer_outline_flag) set_layer_outline_flag(true);
2929    else if(layer_advanced_outline_flag) set_layer_advanced_outline_flag(true);
2930  }
2931
2932        // update layer flags
2933        layer_region_flag = get_layer_region_flag();
2934        layer_outline_flag = get_layer_outline_flag();
2935        layer_advanced_outline_flag = get_layer_advanced_outline_flag();
2936}
Note: See TracBrowser for help on using the repository browser.