1 /* === S Y N F I G ========================================================= */
2 /*! \file duckmatic.cpp
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
36 #include <ETL/hermite>
38 #include "duckmatic.h"
39 #include <synfigapp/value_desc.h>
40 #include <synfig/general.h>
41 #include <synfig/paramdesc.h>
42 #include <synfig/valuenode_timedswap.h>
43 #include <synfig/valuenode_animated.h>
44 #include <synfig/valuenode_composite.h>
45 #include <synfig/valuenode_scale.h>
46 #include <synfig/valuenode_bline.h>
47 #include <synfig/valuenode_blinecalctangent.h>
48 #include <synfig/valuenode_blinecalcvertex.h>
49 #include <synfig/valuenode_blinecalcwidth.h>
51 #include <synfig/curve_helper.h>
53 #include <sigc++/retype_return.h>
54 #include <sigc++/retype.h>
55 #include <sigc++/hide.h>
56 #include <sigc++/bind.h>
58 #include "canvasview.h"
60 #include "onemoment.h"
66 /* === U S I N G =========================================================== */
70 using namespace synfig
;
71 using namespace studio
;
73 /* === M A C R O S ========================================================= */
75 /* 0.33333333333333333 makes for nice short tangent handles,
76 1.0 makes them draw as their real length */
77 #define TANGENT_HANDLE_SCALE 0.33333333333333333
79 /* leave this alone or the bezier won't lie on top of the bline */
80 #define TANGENT_BEZIER_SCALE 0.33333333333333333
82 /* === G L O B A L S ======================================================= */
84 /* === P R O C E D U R E S ================================================= */
86 /* === M E T H O D S ======================================================= */
88 /* === E N T R Y P O I N T ================================================= */
90 Duckmatic::Duckmatic():
91 type_mask(Duck::TYPE_ALL
-Duck::TYPE_WIDTH
),
94 grid_size(1.0/4.0,1.0/4.0),
95 show_persistent_strokes(true)
98 drag_offset_
=Point(0,0);
102 Duckmatic::~Duckmatic()
106 if (Duck::duck_count
)
107 synfig::error("%d ducks not yet deleted!", Duck::duck_count
);
109 if (getenv("SYNFIG_DEBUG_DESTRUCTORS"))
110 synfig::info("Duckmatic::~Duckmatic(): Deleted");
114 Duckmatic::clear_ducks()
116 duck_data_share_map
.clear();
119 //duck_list_.clear();
120 bezier_list_
.clear();
121 stroke_list_
.clear();
123 if(show_persistent_strokes
)
124 stroke_list_
=persistent_stroke_list_
;
127 //! Returns \a true if the given duck is currently selected
129 Duckmatic::duck_is_selected(const etl::handle
<Duck
> &duck
)const
131 return duck
&& selected_ducks
.count(duck
->get_guid());
135 Duckmatic::set_grid_size(const synfig::Vector
&s
)
140 signal_grid_changed();
145 Duckmatic::set_grid_snap(bool x
)
150 signal_grid_changed();
155 Duckmatic::set_guide_snap(bool x
)
160 signal_grid_changed();
164 Duckmatic::GuideList::iterator
165 Duckmatic::find_guide_x(synfig::Point pos
, float radius
)
167 GuideList::iterator iter
,best(guide_list_x_
.end());
169 for(iter
=guide_list_x_
.begin();iter
!=guide_list_x_
.end();++iter
)
171 float amount(abs(*iter
-pos
[0]));
181 Duckmatic::GuideList::iterator
182 Duckmatic::find_guide_y(synfig::Point pos
, float radius
)
184 GuideList::iterator iter
,best(guide_list_y_
.end());
186 for(iter
=guide_list_y_
.begin();iter
!=guide_list_y_
.end();++iter
)
188 float amount(abs(*iter
-pos
[1]));
199 Duckmatic::clear_selected_ducks()
201 selected_ducks
.clear();
202 signal_duck_selection_changed_();
205 etl::handle
<Duckmatic::Duck
>
206 Duckmatic::get_selected_duck()const
208 if(selected_ducks
.empty() || duck_map
.empty())
210 return duck_map
.find(*selected_ducks
.begin())->second
;
214 Duckmatic::refresh_selected_ducks()
217 std::set<etl::handle<Duck> >::iterator iter;
218 std::set<etl::handle<Duck> > new_set;
219 if(duck_list().empty())
221 selected_duck_list.clear();
222 signal_duck_selection_changed_();
226 for(iter=selected_duck_list.begin();iter!=selected_duck_list.end();++iter)
228 etl::handle<Duck> similar(find_similar_duck(*iter));
231 new_set.insert(similar);
234 selected_duck_list=new_set;
236 GUIDSet
old_set(selected_ducks
);
237 GUIDSet::const_iterator iter
;
239 for(iter
=old_set
.begin();iter
!=old_set
.end();++iter
)
241 if(duck_map
.count(*iter
)==0)
242 selected_ducks
.erase(*iter
);
245 signal_duck_selection_changed_();
249 Duckmatic::is_duck_group_selectable(const etl::handle
<Duck
>& x
)const
251 const Type
type(get_type_mask());
253 if (((x
->get_type() && (!(type
& x
->get_type()))) ||
257 synfigapp::ValueDesc
value_desc(x
->get_value_desc());
258 if(value_desc
.parent_is_layer_param() && type
& Duck::TYPE_POSITION
)
260 Layer::Handle
layer(value_desc
.get_layer());
261 String
layer_name(layer
->get_name());
263 if (layer_name
== "outline" || layer_name
== "region" || layer_name
== "plant" ||
264 layer_name
== "polygon" || layer_name
== "curve_gradient")
267 if((layer_name
=="PasteCanvas"|| layer_name
=="paste_canvas") &&
268 !layer
->get_param("children_lock").get(bool()))
271 else if (value_desc
.parent_is_value_node())
273 if (ValueNode_BLineCalcVertex::Handle::cast_dynamic(value_desc
.get_value_node()))
275 if (value_desc
.parent_is_linkable_value_node())
277 LinkableValueNode::Handle
parent_value_node(value_desc
.get_parent_value_node());
278 if (ValueNode_Composite::Handle::cast_dynamic(parent_value_node
) &&
279 parent_value_node
->get_type() == ValueBase::TYPE_BLINEPOINT
&&
280 ValueNode_BLineCalcVertex::Handle::cast_dynamic(
281 synfigapp::ValueDesc(parent_value_node
,
282 parent_value_node
->get_link_index_from_name("point")).get_value_node()))
290 Duckmatic::select_all_ducks()
292 DuckMap::const_iterator iter
;
293 for(iter
=duck_map
.begin();iter
!=duck_map
.end();++iter
)
294 if(is_duck_group_selectable(iter
->second
))
295 select_duck(iter
->second
);
297 unselect_duck(iter
->second
);
301 Duckmatic::unselect_all_ducks()
303 DuckMap::const_iterator iter
;
304 for(iter
=duck_map
.begin();iter
!=duck_map
.end();++iter
)
305 unselect_duck(iter
->second
);
309 Duckmatic::toggle_select_ducks_in_box(const synfig::Vector
& tl
,const synfig::Vector
& br
)
312 vmin
[0]=std::min(tl
[0],br
[0]);
313 vmin
[1]=std::min(tl
[1],br
[1]);
314 vmax
[0]=std::max(tl
[0],br
[0]);
315 vmax
[1]=std::max(tl
[1],br
[1]);
317 DuckMap::const_iterator iter
;
318 for(iter
=duck_map
.begin();iter
!=duck_map
.end();++iter
)
320 Point
p(iter
->second
->get_trans_point());
321 if(p
[0]<=vmax
[0] && p
[0]>=vmin
[0] && p
[1]<=vmax
[1] && p
[1]>=vmin
[1] &&
322 is_duck_group_selectable(iter
->second
))
323 toggle_select_duck(iter
->second
);
328 Duckmatic::select_ducks_in_box(const synfig::Vector
& tl
,const synfig::Vector
& br
)
331 vmin
[0]=std::min(tl
[0],br
[0]);
332 vmin
[1]=std::min(tl
[1],br
[1]);
333 vmax
[0]=std::max(tl
[0],br
[0]);
334 vmax
[1]=std::max(tl
[1],br
[1]);
336 // Type type(get_type_mask());
338 DuckMap::const_iterator iter
;
339 for(iter
=duck_map
.begin();iter
!=duck_map
.end();++iter
)
341 Point
p(iter
->second
->get_trans_point());
342 if(p
[0]<=vmax
[0] && p
[0]>=vmin
[0] && p
[1]<=vmax
[1] && p
[1]>=vmin
[1])
344 if(is_duck_group_selectable(iter
->second
))
345 select_duck(iter
->second
);
351 Duckmatic::count_selected_ducks()const
353 return selected_ducks
.size();
357 Duckmatic::select_duck(const etl::handle
<Duck
> &duck
)
361 selected_ducks
.insert(duck
->get_guid());
362 signal_duck_selection_changed_();
367 Duckmatic::get_selected_ducks()const
370 GUIDSet::const_iterator iter
;
371 const Type
type(get_type_mask());
373 for(iter
=selected_ducks
.begin();iter
!=selected_ducks
.end();++iter
)
375 const DuckMap::const_iterator
d_iter(duck_map
.find(*iter
));
377 if(d_iter
==duck_map
.end())
380 if(( d_iter
->second
->get_type() && (!(type
& d_iter
->second
->get_type())) ) )
383 ret
.push_back(d_iter
->second
);
389 Duckmatic::get_duck_list()const
392 DuckMap::const_iterator iter
;
393 for(iter
=duck_map
.begin();iter
!=duck_map
.end();++iter
)
394 ret
.push_back(iter
->second
);
399 Duckmatic::unselect_duck(const etl::handle
<Duck
> &duck
)
401 if(duck
&& selected_ducks
.count(duck
->get_guid()))
403 selected_ducks
.erase(duck
->get_guid());
404 signal_duck_selection_changed_();
409 Duckmatic::toggle_select_duck(const etl::handle
<Duck
> &duck
)
411 if(duck_is_selected(duck
))
418 Duckmatic::translate_selected_ducks(const synfig::Vector
& vector
)
421 duck_dragger_
->duck_drag(this,vector
);
425 Duckmatic::start_duck_drag(const synfig::Vector
& offset
)
428 duck_dragger_
->begin_duck_drag(this,offset
);
430 //drag_offset_=offset;
431 drag_offset_
=find_duck(offset
)->get_trans_point();
435 Duckmatic::end_duck_drag()
438 return duck_dragger_
->end_duck_drag(this);
443 Duckmatic::snap_point_to_grid(const synfig::Point
& x
, float radius
)const
447 GuideList::const_iterator guide_x
,guide_y
;
448 bool has_guide_x(false), has_guide_y(false);
450 guide_x
=find_guide_x(ret
,radius
);
451 if(guide_x
!=guide_list_x_
.end())
454 guide_y
=find_guide_y(ret
,radius
);
455 if(guide_y
!=guide_list_y_
.end())
461 floor(ret
[0]/get_grid_size()[0]+0.5)*get_grid_size()[0],
462 floor(ret
[1]/get_grid_size()[1]+0.5)*get_grid_size()[1]);
464 if(abs(snap
[0]-ret
[0])<=radius
&& (!has_guide_x
|| abs(snap
[0]-ret
[0])<=abs(*guide_x
-ret
[0])))
465 ret
[0]=snap
[0],has_guide_x
=false;
466 if(abs(snap
[1]-ret
[1])<=radius
&& (!has_guide_y
|| abs(snap
[1]-ret
[1])<=abs(*guide_y
-ret
[1])))
467 ret
[1]=snap
[1],has_guide_y
=false;
481 if(abs(ret
[0])<abs(ret
[1]))
492 DuckDrag_Translate::begin_duck_drag(Duckmatic
* duckmatic
, const synfig::Vector
& offset
)
494 last_translate_
=Vector(0,0);
496 drag_offset_
=duckmatic
->find_duck(offset
)->get_trans_point();
501 const DuckList
selected_ducks(duckmatic
->get_selected_ducks());
502 DuckList::const_iterator iter
;
505 for(iter
=selected_ducks
.begin();iter
!=selected_ducks
.end();++iter
)
507 Point
p((*iter
)->get_trans_point());
508 positions
.push_back(p
);
513 DuckDrag_Translate::end_duck_drag(Duckmatic
* duckmatic
)
515 if(last_translate_
.mag()>0.0001)
517 duckmatic
->signal_edited_selected_ducks();
522 duckmatic
->signal_user_click_selected_ducks(0);
528 DuckDrag_Translate::duck_drag(Duckmatic
* duckmatic
, const synfig::Vector
& vector
)
530 const DuckList
selected_ducks(duckmatic
->get_selected_ducks());
531 DuckList::const_iterator iter
;
533 synfig::Vector
vect(duckmatic
->snap_point_to_grid(vector
)-drag_offset_
);
535 Time
time(duckmatic
->get_time());
537 // drag the vertex and position ducks first
538 for (i
=0,iter
=selected_ducks
.begin(); iter
!=selected_ducks
.end(); ++iter
,i
++)
540 etl::handle
<Duck
> duck(*iter
);
541 if(duck
->get_type() == Duck::TYPE_VERTEX
|| duck
->get_type() == Duck::TYPE_POSITION
)
543 duck
->set_trans_point(positions
[i
]+vect
);
545 if (ValueNode_BLineCalcVertex::Handle bline_vertex
= ValueNode_BLineCalcVertex::Handle::cast_dynamic(duck
->get_value_desc().get_value_node()))
547 synfig::Point closest_point
= duck
->get_point();
548 synfig::Real radius
= 0.0;
549 ValueNode_BLine::Handle bline
= ValueNode_BLine::Handle::cast_dynamic(bline_vertex
->get_link(bline_vertex
->get_link_index_from_name("bline")));
550 synfig::find_closest_point(
556 duck
->set_point(closest_point
);
561 // then drag the others
562 for (i
=0,iter
=selected_ducks
.begin(); iter
!=selected_ducks
.end(); ++iter
,i
++)
563 if ((*iter
)->get_type() != Duck::TYPE_VERTEX
&& (*iter
)->get_type() != Duck::TYPE_POSITION
)
564 (*iter
)->set_trans_point(positions
[i
]+vect
);
566 // then patch up the tangents for the vertices we've moved
567 DuckList
duck_list(duckmatic
->get_duck_list());
568 for (iter
=selected_ducks
.begin(); iter
!=selected_ducks
.end(); ++iter
)
570 etl::handle
<Duck
> duck(*iter
);
571 if (duck
->get_type() == Duck::TYPE_VERTEX
|| duck
->get_type() == Duck::TYPE_POSITION
)
573 ValueNode_BLineCalcVertex::Handle
bline_vertex(ValueNode_BLineCalcVertex::Handle::cast_dynamic(duck
->get_value_desc().get_value_node()));
576 synfig::Real radius
= 0.0;
577 ValueNode_BLine::Handle
bline(ValueNode_BLine::Handle::cast_dynamic(bline_vertex
->get_link(bline_vertex
->get_link_index_from_name("bline"))));
578 Real amount
= synfig::find_closest_point((*bline
)(time
), duck
->get_point(), radius
, bline
->get_loop());
580 int vertex_amount_index(bline_vertex
->get_link_index_from_name("amount"));
581 ValueNode::Handle
vertex_amount_value_node(bline_vertex
->get_link(vertex_amount_index
));
583 DuckList::iterator iter
;
584 for (iter
=duck_list
.begin(); iter
!=duck_list
.end(); iter
++)
586 ValueNode::Handle
duck_value_node((*iter
)->get_value_desc().get_value_node());
587 if (ValueNode_BLineCalcTangent::Handle bline_tangent
= ValueNode_BLineCalcTangent::Handle::cast_dynamic(duck_value_node
))
589 if (bline_tangent
->get_link(bline_tangent
->get_link_index_from_name("amount")) == vertex_amount_value_node
)
591 switch (bline_tangent
->get_type())
593 case ValueBase::TYPE_ANGLE
:
595 Angle
angle((*bline_tangent
)(time
, amount
).get(Angle()));
596 (*iter
)->set_point(Point(Angle::cos(angle
).get(), Angle::sin(angle
).get()));
599 case ValueBase::TYPE_REAL
:
600 (*iter
)->set_point(Point((*bline_tangent
)(time
, amount
).get(Real()), 0));
602 case ValueBase::TYPE_VECTOR
:
603 (*iter
)->set_point((*bline_tangent
)(time
, amount
).get(Vector()));
610 else if (ValueNode_BLineCalcWidth::Handle bline_width
= ValueNode_BLineCalcWidth::Handle::cast_dynamic(duck_value_node
))
612 if (bline_width
->get_link(bline_width
->get_link_index_from_name("amount")) == vertex_amount_value_node
)
613 (*iter
)->set_point(Point((*bline_width
)(time
, amount
).get(Real()), 0));
620 last_translate_
=vect
;
624 Duckmatic::signal_edited_selected_ducks()
626 const DuckList
ducks(get_selected_ducks());
627 DuckList::const_iterator iter
;
629 synfig::GUIDSet
old_set(selected_ducks
);
631 // If we have more than 20 things to move, then display
632 // something to explain that it may take a moment
633 smart_ptr
<OneMoment
> wait
; if(ducks
.size()>20)wait
.spawn();
635 // Go ahead and call everyone's signals
636 for(iter
=ducks
.begin();iter
!=ducks
.end();++iter
)
638 if ((*iter
)->get_type() == Duck::TYPE_ANGLE
)
640 if(!(*iter
)->signal_edited_angle()((*iter
)->get_rotations()))
642 selected_ducks
=old_set
;
643 throw String("Bad edit");
646 else if (App::restrict_radius_ducks
&&
647 (*iter
)->is_radius())
649 Point
point((*iter
)->get_point());
650 bool changed
= false;
663 if (changed
) (*iter
)->set_point(point
);
665 if(!(*iter
)->signal_edited()(point
))
667 selected_ducks
=old_set
;
668 throw String("Bad edit");
673 if(!(*iter
)->signal_edited()((*iter
)->get_point()))
675 selected_ducks
=old_set
;
676 throw String("Bad edit");
680 selected_ducks
=old_set
;
684 Duckmatic::signal_user_click_selected_ducks(int button
)
686 const DuckList
ducks(get_selected_ducks());
687 DuckList::const_iterator iter
;
689 for(iter
=ducks
.begin();iter
!=ducks
.end();++iter
)
691 (*iter
)->signal_user_click(button
)();
696 Duckmatic::add_duck(const etl::handle
<Duck
> &duck
)
698 //if(!duck_map.count(duck->get_guid()))
700 if(duck_data_share_map
.count(duck
->get_data_guid()))
702 duck
->set_shared_point(duck_data_share_map
[duck
->get_data_guid()]);
706 etl::smart_ptr
<synfig::Point
> point(new Point(duck
->get_point()));
707 duck
->set_shared_point(point
);
708 duck_data_share_map
[duck
->get_data_guid()]=point
;
711 duck_map
.insert(duck
);
714 last_duck_guid
=duck
->get_guid();
718 Duckmatic::add_bezier(const etl::handle
<Bezier
> &bezier
)
720 bezier_list_
.push_back(bezier
);
724 Duckmatic::add_stroke(etl::smart_ptr
<std::list
<synfig::Point
> > stroke_point_list
, const synfig::Color
& color
)
726 assert(stroke_point_list
);
728 std::list
<etl::handle
<Stroke
> >::iterator iter
;
730 for(iter
=stroke_list_
.begin();iter
!=stroke_list_
.end();++iter
)
732 if((*iter
)->stroke_data
==stroke_point_list
)
736 etl::handle
<Stroke
> stroke(new Stroke());
738 stroke
->stroke_data
=stroke_point_list
;
741 stroke_list_
.push_back(stroke
);
745 Duckmatic::add_persistent_stroke(etl::smart_ptr
<std::list
<synfig::Point
> > stroke_point_list
, const synfig::Color
& color
)
747 add_stroke(stroke_point_list
,color
);
748 persistent_stroke_list_
.push_back(stroke_list_
.back());
752 Duckmatic::clear_persistent_strokes()
754 persistent_stroke_list_
.clear();
758 Duckmatic::set_show_persistent_strokes(bool x
)
760 if(x
!=show_persistent_strokes
)
762 show_persistent_strokes
=x
;
764 stroke_list_
=persistent_stroke_list_
;
766 stroke_list_
.clear();
771 Duckmatic::erase_duck(const etl::handle
<Duck
> &duck
)
773 duck_map
.erase(duck
->get_guid());
776 etl::handle
<Duckmatic::Duck
>
777 Duckmatic::find_similar_duck(etl::handle
<Duck
> duck
)
779 DuckMap::const_iterator
iter(duck_map
.find(duck
->get_guid()));
780 if(iter
!=duck_map
.end())
784 /* std::list<handle<Duck> >::reverse_iterator iter;
786 for(iter=duck_list_.rbegin();iter!=duck_list_.rend();++iter)
788 if(*iter!=duck && **iter==*duck)
790 //synfig::info("Found similar duck! (iter:%08x vs. duck:%08x)",iter->get(), duck.get());
798 etl::handle
<Duckmatic::Duck
>
799 Duckmatic::add_similar_duck(etl::handle
<Duck
> duck
)
801 etl::handle
<Duck
> similar(find_similar_duck(duck
));
811 Duckmatic::erase_bezier(const etl::handle
<Bezier
> &bezier
)
813 std::list
<handle
<Bezier
> >::iterator iter
;
815 for(iter
=bezier_list_
.begin();iter
!=bezier_list_
.end();++iter
)
819 bezier_list_
.erase(iter
);
823 synfig::warning("Unable to find bezier to erase!");
826 etl::handle
<Duckmatic::Duck
>
827 Duckmatic::last_duck()const
829 DuckMap::const_iterator
iter(duck_map
.find(last_duck_guid
));
830 if(iter
!=duck_map
.end())
835 etl::handle
<Duckmatic::Bezier
>
836 Duckmatic::last_bezier()const
838 return bezier_list_
.back();
841 etl::handle
<Duckmatic::Duck
>
842 Duckmatic::find_duck(synfig::Point point
, synfig::Real radius
, Duck::Type type
)
844 if(radius
==0)radius
=10000000;
846 if(type
==Duck::TYPE_DEFAULT
)
847 type
=get_type_mask();
849 Real
closest(10000000);
850 etl::handle
<Duck
> ret
;
852 DuckMap::const_iterator iter
;
854 for(iter
=duck_map
.begin();iter
!=duck_map
.end();++iter
)
856 const Duck::Handle
& duck(iter
->second
);
858 if(duck
->get_ignore())
860 Real
dist((duck
->get_trans_point()-point
).mag_squared());
862 if(duck
->get_type()&Duck::TYPE_VERTEX
)
864 else if(duck
->get_type()&Duck::TYPE_RADIUS
)
867 if(dist
<=closest
&& !( duck
->get_type() && (!(type
& duck
->get_type())) ) )
876 if(radius
==0 || closest
<radius
*radius
)
882 etl::handle
<Duckmatic::Bezier
>
883 Duckmatic::find_bezier(synfig::Point point
, synfig::Real radius
,float* location
)
885 return find_bezier(point
,radius
,radius
,location
);
888 etl::handle
<Duckmatic::Bezier
>
889 Duckmatic::find_bezier(synfig::Point pos
, synfig::Real scale
, synfig::Real radius
, float* location
)
891 if(radius
==0)radius
=10000000;
892 Real
closest(10000000);
893 etl::handle
<Bezier
> ret
;
901 for(std::list
<handle
<Bezier
> >::const_iterator iter
=bezier_list().begin();iter
!=bezier_list().end();++iter
)
903 curve
[0] = (*iter
)->p1
->get_trans_point();
904 curve
[1] = (*iter
)->c1
->get_trans_point();
905 curve
[2] = (*iter
)->c2
->get_trans_point();
906 curve
[3] = (*iter
)->p2
->get_trans_point();
910 // I don't know why this doesn't work
911 time
=curve
.find_closest(pos
,6);
912 d
=((curve(time
)-pos
).mag_squared());
915 //set the step size based on the size of the picture
916 d
= (curve
[1] - curve
[0]).mag() + (curve
[2]-curve
[1]).mag() + (curve
[3]-curve
[2]).mag();
918 step
= d
/(2*scale
); //want to make the distance between lines happy
920 step
= max(step
,0.01); //100 samples should be plenty
921 step
= min(step
,0.1); //10 is minimum
923 d
= find_closest(curve
,pos
,step
,&closest
,&time
);
934 if(closest
< radius
*radius
)
937 *location
= best_time
; // We need to square-root this because we were dealing with squared distances
946 Duckmatic::save_sketch(const synfig::String
& filename
)const
948 ChangeLocale
change_locale(LC_NUMERIC
, "C");
949 std::ofstream
file(filename
.c_str());
951 if(!file
)return false;
953 file
<<"SKETCH"<<endl
;
955 std::list
<etl::handle
<Stroke
> >::const_iterator iter
;
957 for(iter
=persistent_stroke_list_
.begin();iter
!=persistent_stroke_list_
.end();++iter
)
960 <<(*iter
)->color
.get_r()<<' '
961 <<(*iter
)->color
.get_g()<<' '
962 <<(*iter
)->color
.get_b()
964 std::list
<synfig::Point
>::const_iterator viter
;
965 for(viter
=(*iter
)->stroke_data
->begin();viter
!=(*iter
)->stroke_data
->end();++viter
)
973 if(!file
)return false;
974 sketch_filename_
=filename
;
975 signal_sketch_saved_();
980 Duckmatic::load_sketch(const synfig::String
& filename
)
982 ChangeLocale
change_locale(LC_NUMERIC
, "C");
983 std::ifstream
file(filename
.c_str());
993 synfig::error("Not a sketch");
997 etl::smart_ptr
<std::list
<synfig::Point
> > stroke_data
;
1011 stroke_data
.spawn();
1013 if(!strscanf(line
,"C %f %f %f",&r
, &g
, &b
))
1015 synfig::warning("Bad color line \"%s\"",line
.c_str());
1018 add_persistent_stroke(stroke_data
, synfig::Color(r
,g
,b
));
1025 stroke_data
.spawn();
1026 add_persistent_stroke(stroke_data
, synfig::Color(0,0,0));
1029 if(!strscanf(line
,"V %f %f",&x
, &y
))
1030 synfig::warning("Bad vertex \"%s\"",line
.c_str());
1032 stroke_data
->push_back(synfig::Vector(x
,y
));
1035 synfig::warning("Unexpected sketch token '%c'",line
[0]);
1040 sketch_filename_
=filename
;
1044 Duckmatic::Push::Push(Duckmatic
*duckmatic_
):
1045 duckmatic_(duckmatic_
)
1047 duck_map
=duckmatic_
->duck_map
;
1048 bezier_list_
=duckmatic_
->bezier_list_
;
1049 duck_data_share_map
=duckmatic_
->duck_data_share_map
;
1050 stroke_list_
=duckmatic_
->stroke_list_
;
1051 duck_dragger_
=duckmatic_
->duck_dragger_
;
1055 Duckmatic::Push::~Push()
1062 Duckmatic::Push::restore()
1064 duckmatic_
->duck_map
=duck_map
;
1065 duckmatic_
->bezier_list_
=bezier_list_
;
1066 duckmatic_
->duck_data_share_map
=duck_data_share_map
;
1067 duckmatic_
->stroke_list_
=stroke_list_
;
1068 duckmatic_
->duck_dragger_
=duck_dragger_
;
1069 needs_restore
=false;
1072 inline String
guid_string(const synfigapp::ValueDesc
& x
)
1074 if(x
.parent_is_layer_param())
1075 return strprintf("%s",x
.get_layer()->get_guid().get_string().c_str())+x
.get_param_name();
1076 //if(x.is_value_node())
1077 return strprintf("%s",x
.get_value_node()->get_guid().get_string().c_str());
1080 inline synfig::GUID
calc_duck_guid(const synfigapp::ValueDesc
& x
,const synfig::TransformStack
& transform_stack
)
1082 synfig::GUID
ret(0);
1084 if(x
.parent_is_layer_param())
1086 ret
=x
.get_layer()->get_guid()^synfig::GUID::hasher(x
.get_param_name());
1090 ret
=x
.get_value_node()->get_guid();
1093 ret
^=transform_stack
.get_guid();
1099 Duckmatic::create_duck_from(const synfigapp::ValueDesc& value_desc,etl::handle<CanvasView> canvas_view, const synfig::TransformStack& transform_stack, int modifier, synfig::ParamDesc *param_desc)
1101 synfig::GUID duck_guid(calc_duck_guid(value_desc,transform_stack)^synfig::GUID::hasher(modifier));
1102 etl::handle<Duck> duck=new Duck();
1109 Duckmatic::add_to_ducks(const synfigapp::ValueDesc
& value_desc
,etl::handle
<CanvasView
> canvas_view
, const synfig::TransformStack
& transform_stack
, synfig::ParamDesc
*param_desc
, int multiple
)
1111 ValueBase::Type type
=value_desc
.get_value_type();
1112 #define REAL_COOKIE reinterpret_cast<synfig::ParamDesc*>(28)
1115 case ValueBase::TYPE_REAL
:
1117 if(!param_desc
|| param_desc
==REAL_COOKIE
|| !param_desc
->get_origin().empty())
1119 etl::handle
<Duck
> duck
=new Duck();
1120 duck
->set_transform_stack(transform_stack
);
1121 duck
->set_radius(true);
1122 duck
->set_type(Duck::TYPE_RADIUS
);
1124 // put the duck on the right hand side of the center
1125 duck
->set_point(Point(value_desc
.get_value(get_time()).get(Real()), 0));
1126 duck
->set_name(guid_string(value_desc
));
1127 if(value_desc
.is_value_node())
1129 // If the ValueNode can be directly manipulated,
1130 // then set it as so.
1131 duck
->set_editable(synfigapp::is_editable(value_desc
.get_value_node()));
1135 duck
->set_editable(true);
1138 if(param_desc
&& param_desc
!=REAL_COOKIE
)
1140 if(!param_desc
->get_origin().empty())
1142 synfigapp::ValueDesc
value_desc_origin(value_desc
.get_layer(),param_desc
->get_origin());
1144 duck->set_origin(value_desc_origin.get_value(get_time()).get(synfig::Point()));
1146 add_to_ducks(value_desc_origin
,canvas_view
, transform_stack
);
1147 duck
->set_origin(last_duck());
1149 duck
->set_scalar(param_desc
->get_scalar());
1152 duck
->signal_edited().clear(); // value_desc.get_value_type() == ValueBase::TYPE_REAL:
1153 duck
->signal_edited().connect(
1157 &studio::CanvasView::on_duck_changed
),
1159 duck
->set_value_desc(value_desc
);
1161 duck
->signal_user_click(2).connect(
1167 &studio::CanvasView::popup_param_menu
),
1172 duck
->set_guid(calc_duck_guid(value_desc
,transform_stack
)^synfig::GUID::hasher(multiple
));
1180 case ValueBase::TYPE_ANGLE
:
1182 if(!param_desc
|| param_desc
==REAL_COOKIE
|| !param_desc
->get_origin().empty())
1184 etl::handle
<Duck
> duck
=new Duck();
1185 duck
->set_type(Duck::TYPE_ANGLE
);
1186 duck
->set_transform_stack(transform_stack
);
1187 synfig::Angle angle
;
1189 angle
=value_desc
.get_value(get_time()).get(Angle());
1190 duck
->set_point(Point(Angle::cos(angle
).get(),Angle::sin(angle
).get()));
1191 duck
->set_name(guid_string(value_desc
));
1192 if(value_desc
.is_value_node())
1194 ValueNode::Handle value_node
=value_desc
.get_value_node();
1195 //duck->set_name(strprintf("%x",value_node.get()));
1197 // If the ValueNode can be directly manipulated,
1198 // then set it as so.
1199 duck
->set_editable(synfigapp::is_editable(value_desc
.get_value_node()));
1203 //angle=(value_desc.get_value().get(Angle()));
1204 //duck->set_point(Point(Angle::cos(angle).get(),Angle::sin(angle).get()));
1205 //duck->set_name(strprintf("%x",value_desc.get_layer().get())+value_desc.get_param_name());
1206 duck
->set_editable(true);
1209 if(param_desc
&& param_desc
!=REAL_COOKIE
)
1211 if(!param_desc
->get_origin().empty())
1213 synfigapp::ValueDesc
value_desc_origin(value_desc
.get_layer(),param_desc
->get_origin());
1215 duck->set_origin(value_desc_origin.get_value(get_time()).get(synfig::Point()));
1217 add_to_ducks(value_desc_origin
,canvas_view
, transform_stack
);
1218 duck
->set_origin(last_duck());
1220 duck
->set_scalar(param_desc
->get_scalar());
1223 duck
->signal_edited().clear(); // value_desc.get_value_type() == ValueBase::TYPE_ANGLE:
1224 duck
->signal_edited_angle().clear();
1225 duck
->signal_edited_angle().connect(
1229 &studio::CanvasView::on_duck_angle_changed
),
1231 duck
->set_value_desc(value_desc
);
1233 duck
->signal_user_click(2).connect(
1239 &studio::CanvasView::popup_param_menu
),
1243 duck
->set_guid(calc_duck_guid(value_desc
,transform_stack
)^synfig::GUID::hasher(multiple
));
1251 case ValueBase::TYPE_VECTOR
:
1253 etl::handle
<Duck
> duck
=new Duck();
1254 duck
->set_transform_stack(transform_stack
);
1256 duck
->set_point(value_desc
.get_value(get_time()).get(Point()));
1257 duck
->set_name(guid_string(value_desc
));
1258 if(value_desc
.is_value_node())
1260 //duck->set_name(strprintf("%x",value_desc.get_value_node().get()));
1262 // If the ValueNode can be directly manipulated,
1263 // then set it as so.
1264 duck
->set_editable(synfigapp::is_editable(value_desc
.get_value_node()));
1268 //duck->set_point(value_desc.get_value().get(Point()));
1269 //duck->set_name(strprintf("%x",value_desc.get_layer().get())+value_desc.get_param_name());
1270 duck
->set_editable(true);
1273 // If we were passed a parameter description
1276 if(!param_desc
->get_connect().empty())
1278 synfigapp::ValueDesc
value_desc_origin(value_desc
.get_layer(),param_desc
->get_connect());
1279 Duck::Handle connect_duck
;
1280 if(duck_map
.find(calc_duck_guid(value_desc_origin
,transform_stack
)^synfig::GUID::hasher(0))!=duck_map
.end())
1282 connect_duck
=duck_map
[calc_duck_guid(value_desc_origin
,transform_stack
)^synfig::GUID::hasher(0)];
1286 add_to_ducks(value_desc_origin
,canvas_view
, transform_stack
);
1287 connect_duck
=last_duck();
1289 duck
->set_connect_duck(connect_duck
);
1291 if(!param_desc
->get_box().empty())
1293 synfigapp::ValueDesc
value_desc_origin(value_desc
.get_layer(),param_desc
->get_box());
1294 add_to_ducks(value_desc_origin
,canvas_view
, transform_stack
);
1295 duck
->set_box_duck(last_duck());
1298 // If we have an origin
1299 if(!param_desc
->get_origin().empty())
1301 synfigapp::ValueDesc
value_desc_origin(value_desc
.get_layer(),param_desc
->get_origin());
1303 duck->set_origin(value_desc_origin.get_value(get_time()).get(synfig::Point()));
1305 add_to_ducks(value_desc_origin
,canvas_view
, transform_stack
);
1306 duck
->set_origin(last_duck());
1307 duck
->set_type(Duck::TYPE_VERTEX
);
1310 duck
->set_type(Duck::TYPE_POSITION
);
1312 duck
->set_scalar(param_desc
->get_scalar());
1315 duck
->set_type(Duck::TYPE_POSITION
);
1317 duck
->signal_edited().clear(); // value_desc.get_value_type() == ValueBase::TYPE_VECTOR:
1318 duck
->signal_edited().connect(
1322 &studio::CanvasView::on_duck_changed
),
1324 duck
->set_value_desc(value_desc
);
1326 duck
->signal_user_click(2).connect(
1332 &studio::CanvasView::popup_param_menu
),
1336 duck
->set_guid(calc_duck_guid(value_desc
,transform_stack
)^synfig::GUID::hasher(multiple
));
1342 case ValueBase::TYPE_SEGMENT
:
1344 etl::handle
<Bezier
> bezier(new Bezier());
1345 ValueNode_Composite::Handle value_node
;
1347 if(value_desc
.is_value_node() &&
1348 (value_node
=ValueNode_Composite::Handle::cast_dynamic(value_desc
.get_value_node())))
1350 if(!add_to_ducks(synfigapp::ValueDesc(value_node
,0),canvas_view
,transform_stack
))
1352 bezier
->p1
=last_duck();
1353 bezier
->p1
->set_type(Duck::TYPE_VERTEX
);
1354 if(!add_to_ducks(synfigapp::ValueDesc(value_node
,1),canvas_view
,transform_stack
))
1356 bezier
->c1
=last_duck();
1357 bezier
->c1
->set_type(Duck::TYPE_TANGENT
);
1358 bezier
->c1
->set_origin(bezier
->p1
);
1359 bezier
->c1
->set_scalar(TANGENT_BEZIER_SCALE
);
1360 bezier
->c1
->set_tangent(true);
1362 if(!add_to_ducks(synfigapp::ValueDesc(value_node
,2),canvas_view
,transform_stack
))
1364 bezier
->p2
=last_duck();
1365 bezier
->p2
->set_type(Duck::TYPE_VERTEX
);
1366 if(!add_to_ducks(synfigapp::ValueDesc(value_node
,3),canvas_view
,transform_stack
))
1368 bezier
->c2
=last_duck();
1369 bezier
->c2
->set_type(Duck::TYPE_TANGENT
);
1370 bezier
->c2
->set_origin(bezier
->p2
);
1371 bezier
->c2
->set_scalar(-TANGENT_BEZIER_SCALE
);
1372 bezier
->c2
->set_tangent(true);
1374 bezier
->signal_user_click(2).connect(
1378 &studio::CanvasView::popup_param_menu_bezier
),
1383 else if(value_desc
.get_value().is_valid())
1385 Segment segment
=value_desc
.get_value();
1386 etl::handle
<Duck
> duck_p
,duck_c
;
1387 synfig::String name
;
1390 name
=param_desc
->get_local_name();
1394 name
=guid_string(value_desc
);
1397 duck_p
=new Duck(segment
.p1
);
1398 duck_p
->set_name(name
+".P1");
1399 duck_p
->set_type(Duck::TYPE_VERTEX
);
1402 duck_c
=new Duck(segment
.t1
);
1403 duck_c
->set_name(name
+".T1");
1404 duck_c
->set_type(Duck::TYPE_TANGENT
);
1406 duck_c
->set_origin(duck_p
);
1407 duck_c
->set_scalar(TANGENT_HANDLE_SCALE
);
1408 duck_c
->set_tangent(true);
1413 duck_p
=new Duck(segment
.p2
);
1414 duck_p
->set_name(name
+".P2");
1415 duck_p
->set_type(Duck::TYPE_VERTEX
);
1418 duck_c
=new Duck(segment
.t2
);
1419 duck_c
->set_type(Duck::TYPE_TANGENT
);
1420 duck_c
->set_name(name
+".T2");
1422 duck_c
->set_origin(duck_p
);
1423 duck_c
->set_scalar(-TANGENT_HANDLE_SCALE
);
1424 duck_c
->set_tangent(true);
1434 case ValueBase::TYPE_BLINEPOINT
:
1437 if(value_desc
.is_value_node() &&
1438 ValueNode_Composite::Handle::cast_dynamic(value_desc
.get_value_node()))
1440 ValueNode_Composite::Handle value_node
;
1441 value_node
=ValueNode_Composite::Handle::cast_dynamic(value_desc
.get_value_node());
1443 if(!add_to_ducks(synfigapp::ValueDesc(value_node
,0),canvas_view
,transform_stack
))
1445 etl::handle
<Duck
> vertex_duck(last_duck());
1446 vertex_duck
->set_type(Duck::TYPE_VERTEX
);
1447 if(!add_to_ducks(synfigapp::ValueDesc(value_node
,4),canvas_view
,transform_stack
))
1449 etl::handle
<Duck
> t1_duck(last_duck());
1451 t1_duck
->set_origin(vertex_duck
);
1452 t1_duck
->set_scalar(-TANGENT_HANDLE_SCALE
);
1453 t1_duck
->set_tangent(true);
1455 etl::handle
<Duck
> t2_duck
;
1457 // If the tangents are split
1458 if((*value_node
->get_link("split"))(get_time()).get(bool()))
1460 if(!add_to_ducks(synfigapp::ValueDesc(value_node
,5),canvas_view
,transform_stack
))
1462 t2_duck
=last_duck();
1463 t2_duck
->set_origin(vertex_duck
);
1464 t2_duck
->set_scalar(TANGENT_HANDLE_SCALE
);
1465 t2_duck
->set_tangent(true);
1469 if(!add_to_ducks(synfigapp::ValueDesc(value_node
,4),canvas_view
,transform_stack
))
1471 t2_duck
=last_duck();
1472 t2_duck
->set_origin(vertex_duck
);
1473 t2_duck
->set_scalar(TANGENT_HANDLE_SCALE
);
1474 t2_duck
->set_tangent(true);
1481 case ValueBase::TYPE_LIST
:
1484 if (value_desc
.is_value_node() &&
1485 ValueNode_BLine::Handle::cast_dynamic(value_desc
.get_value_node()))
1487 ValueNode_BLine::Handle value_node
;
1488 value_node
=ValueNode_BLine::Handle::cast_dynamic(value_desc
.get_value_node());
1492 etl::handle
<Bezier
> bezier
;
1493 etl::handle
<Duck
> first_duck
;
1494 etl::handle
<Duck
> duck
, tduck
;
1496 for (i
= 0; i
< value_node
->link_count(); i
++)
1498 float amount(value_node
->list
[i
].amount_at_time(get_time()));
1500 // skip vertices that aren't fully on
1501 if (amount
< 0.9999f
)
1504 // remember the index of the first vertex we didn't skip
1508 BLinePoint
bline_point((*value_node
->get_link(i
))(get_time()));
1510 // try casting the vertex to Composite - this tells us whether it is composite or not
1511 ValueNode_Composite::Handle
composite_vertex_value_node(
1512 ValueNode_Composite::Handle::cast_dynamic(value_node
->get_link(i
)));
1514 // add the vertex duck - it's a composite
1515 if(composite_vertex_value_node
)
1517 if (add_to_ducks(synfigapp::ValueDesc(composite_vertex_value_node
,0),canvas_view
,transform_stack
))
1522 duck
->set_type(Duck::TYPE_VERTEX
);
1524 duck
->signal_user_click(2).clear();
1525 duck
->signal_user_click(2).connect(
1531 &studio::CanvasView::popup_param_menu
),
1534 synfigapp::ValueDesc(value_node
,i
)));
1538 if(!param_desc
->get_origin().empty())
1540 synfigapp::ValueDesc
value_desc_origin(value_desc
.get_layer(),param_desc
->get_origin());
1541 add_to_ducks(value_desc_origin
,canvas_view
, transform_stack
);
1542 duck
->set_origin(last_duck());
1544 ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()));
1545 if(value.same_type_as(synfig::Point()))
1546 duck->set_origin(value.get(synfig::Point()));
1554 // else it's not a composite
1557 duck
=new Duck(bline_point
.get_vertex());
1560 duck
->set_transform_stack(transform_stack
);
1561 duck
->set_editable(false);
1562 //duck->set_name(strprintf("%x-vertex",value_node->get_link(i).get()));
1563 duck
->set_name(guid_string(synfigapp::ValueDesc(value_node
,i
))+".v");
1565 duck
->set_type(Duck::TYPE_VERTEX
);
1568 if(!param_desc
->get_origin().empty())
1570 synfigapp::ValueDesc
value_desc_origin(value_desc
.get_layer(),param_desc
->get_origin());
1571 add_to_ducks(value_desc_origin
,canvas_view
, transform_stack
);
1572 duck
->set_origin(last_duck());
1574 ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()));
1575 if(value.same_type_as(synfig::Point()))
1576 duck->set_origin(value.get(synfig::Point()));
1580 duck
->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node
,i
),transform_stack
)^synfig::GUID::hasher(".v"));
1581 duck
=add_similar_duck(duck
);
1585 // Add the width duck if it is a parameter with a hint (ie. "width") or if it isn't a parameter
1586 if ((param_desc
&& !param_desc
->get_hint().empty()) ||
1589 etl::handle
<Duck
> width
;
1590 if (add_to_ducks(synfigapp::ValueDesc(composite_vertex_value_node
,1),canvas_view
,transform_stack
,REAL_COOKIE
))
1593 width
->set_origin(duck
);
1594 width
->set_type(Duck::TYPE_WIDTH
);
1595 width
->set_name(guid_string(synfigapp::ValueDesc(value_node
,i
))+".w");
1597 // if the bline is a layer's parameter, scale the width duck by the layer's "width" parameter
1600 ValueBase
value(synfigapp::ValueDesc(value_desc
.get_layer(),param_desc
->get_hint()).get_value(get_time()));
1601 if(value
.same_type_as(synfig::Real()))
1602 width
->set_scalar(value
.get(synfig::Real())*0.5f
);
1603 // if it doesn't have a "width" parameter, scale by 0.5f instead
1605 width
->set_scalar(0.5f
);
1607 // otherwise just present the raw unscaled width
1609 width
->set_scalar(0.5f
);
1612 synfig::error("Unable to add width duck!");
1615 // each bezier uses t2 of one point and t1 of the next
1616 // the first time through this loop we won't have the t2 duck from the previous vertex
1617 // and so we don't make a bezier. instead we skip on to t2 for this point
1620 // Add the tangent1 duck
1621 if(composite_vertex_value_node
)
1623 if(!add_to_ducks(synfigapp::ValueDesc(composite_vertex_value_node
,4),canvas_view
,transform_stack
))
1629 tduck
=new Duck(bline_point
.get_tangent1());
1630 tduck
->set_transform_stack(transform_stack
);
1631 tduck
->set_editable(false);
1632 tduck
->set_name(guid_string(synfigapp::ValueDesc(value_node
,i
))+".t1");
1633 // tduck->set_name(strprintf("%x-tangent1",value_node->get_link(i).get()));
1634 tduck
->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node
,i
),transform_stack
)^synfig::GUID::hasher(".t1"));
1635 tduck
=add_similar_duck(tduck
);
1639 tduck
->set_origin(duck
);
1640 tduck
->set_scalar(-TANGENT_BEZIER_SCALE
);
1641 tduck
->set_tangent(true);
1646 bezier
->signal_user_click(2).connect(
1650 &studio::CanvasView::popup_param_menu_bezier
),
1651 synfigapp::ValueDesc(value_node
,i
)));
1653 duck
->signal_user_click(2).clear();
1654 duck
->signal_user_click(2).connect(
1660 &studio::CanvasView::popup_param_menu
),
1663 synfigapp::ValueDesc(value_node
,i
)));
1669 // don't start a new bezier for the last point in the line if we're not looped
1670 if(i
+1>=value_node
->link_count() && !value_node
->get_loop())
1673 bezier
=new Bezier();
1675 // Add the tangent2 duck
1676 if(composite_vertex_value_node
)
1678 int i
=bline_point
.get_split_tangent_flag()?5:4;
1679 if(!add_to_ducks(synfigapp::ValueDesc(composite_vertex_value_node
,i
),canvas_view
,transform_stack
,0,2))
1685 if(bline_point
.get_split_tangent_flag())
1686 tduck
=new Duck(bline_point
.get_tangent2());
1688 tduck
=new Duck(bline_point
.get_tangent1());
1690 tduck
->set_transform_stack(transform_stack
);
1691 tduck
->set_name(guid_string(synfigapp::ValueDesc(value_node
,i
))+".t2");
1692 tduck
->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node
,i
),transform_stack
)^synfig::GUID::hasher(".t2"));
1693 tduck
->set_editable(false);
1694 tduck
=add_similar_duck(tduck
);
1698 synfigapp::ValueDesc
value_desc_origin(value_desc
.get_layer(),param_desc
->get_origin());
1699 add_to_ducks(value_desc_origin
,canvas_view
, transform_stack
);
1700 duck
->set_origin(last_duck());
1702 ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()));
1703 if(value.same_type_as(synfig::Point()))
1704 duck->set_origin(value.get(synfig::Point()));
1706 // if(!param_desc->get_origin().empty())
1707 // duck->set_origin(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()).get(synfig::Point()));
1709 duck
->signal_user_click(2).clear();
1710 duck
->signal_user_click(2).connect(
1716 &studio::CanvasView::popup_param_menu
),
1719 synfigapp::ValueDesc(value_node
,i
)));
1723 tduck
->set_origin(duck
);
1724 tduck
->set_scalar(TANGENT_BEZIER_SCALE
);
1725 tduck
->set_tangent(true);
1731 // Loop if necessary
1732 if(bezier
&& value_node
->get_loop())
1734 BLinePoint
bline_point((*value_node
->get_link(first
))(get_time()));
1736 ValueNode_Composite::Handle
composite_vertex_value_node(
1737 ValueNode_Composite::Handle::cast_dynamic(
1738 value_node
->get_link(first
)));
1740 // Add the vertex duck
1743 // Add the tangent1 duck
1744 if(composite_vertex_value_node
)
1746 if(!add_to_ducks(synfigapp::ValueDesc(composite_vertex_value_node
,4),canvas_view
,transform_stack
))
1752 tduck
=new Duck(bline_point
.get_tangent1());
1753 tduck
->set_transform_stack(transform_stack
);
1754 tduck
->set_editable(false);
1755 tduck
->set_name(guid_string(synfigapp::ValueDesc(value_node
,first
))+".t1");
1756 //tduck->set_name(strprintf("%x-tangent1",value_node->get_link(first).get()));
1757 tduck
=add_similar_duck(tduck
);
1758 tduck
->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node
,first
),transform_stack
)^synfig::GUID::hasher(".t1"));
1762 tduck
->set_origin(duck
);
1763 tduck
->set_scalar(-TANGENT_BEZIER_SCALE
);
1764 tduck
->set_tangent(true);
1769 bezier
->signal_user_click(2).connect(
1773 &studio::CanvasView::popup_param_menu_bezier
),
1774 synfigapp::ValueDesc(value_node
,first
)));
1776 duck
->signal_user_click(2).clear();
1777 duck
->signal_user_click(2).connect(
1783 &studio::CanvasView::popup_param_menu
),
1786 synfigapp::ValueDesc(value_node
,first
)));
1793 else // Check for DynamicList
1794 if(value_desc
.is_value_node() &&
1795 ValueNode_DynamicList::Handle::cast_dynamic(value_desc
.get_value_node()))
1797 ValueNode_DynamicList::Handle value_node
;
1798 value_node
=ValueNode_DynamicList::Handle::cast_dynamic(value_desc
.get_value_node());
1801 if(value_node
->get_contained_type()==ValueBase::TYPE_VECTOR
)
1804 etl::handle
<Duck
> first_duck
, duck
;
1806 for(i
=0;i
<value_node
->link_count();i
++)
1808 if(!value_node
->list
[i
].status_at_time(get_time()))
1810 if(!add_to_ducks(synfigapp::ValueDesc(value_node
,i
),canvas_view
,transform_stack
))
1814 // remember the index of the first vertex we didn't skip
1823 synfigapp::ValueDesc
value_desc_origin(value_desc
.get_layer(),param_desc
->get_origin());
1824 add_to_ducks(value_desc_origin
,canvas_view
, transform_stack
);
1825 duck
->set_origin(last_duck());
1827 ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()));
1828 if(value.same_type_as(synfig::Point()))
1829 duck->set_origin(value.get(synfig::Point()));
1831 // if(!param_desc->get_origin().empty())
1832 // last_duck()->set_origin(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()).get(synfig::Point()));
1834 duck
->set_type(Duck::TYPE_VERTEX
);
1835 bezier
.p1
=bezier
.p2
;bezier
.c1
=bezier
.c2
;
1836 bezier
.p2
=bezier
.c2
=duck
;
1840 handle
<Bezier
> bezier_(new Bezier());
1841 bezier_
->p1
=bezier
.p1
;
1842 bezier_
->c1
=bezier
.c1
;
1843 bezier_
->p2
=bezier
.p2
;
1844 bezier_
->c2
=bezier
.c2
;
1845 add_bezier(bezier_
);
1846 last_bezier()->signal_user_click(2).connect(
1850 &studio::CanvasView::popup_param_menu_bezier
),
1851 synfigapp::ValueDesc(value_node
,i
)));
1855 if (value_node
->get_loop() && first
!= -1 && first_duck
!= duck
)
1859 bezier
.p1
=bezier
.p2
;bezier
.c1
=bezier
.c2
;
1860 bezier
.p2
=bezier
.c2
=duck
;
1862 handle
<Bezier
> bezier_(new Bezier());
1863 bezier_
->p1
=bezier
.p1
;
1864 bezier_
->c1
=bezier
.c1
;
1865 bezier_
->p2
=bezier
.p2
;
1866 bezier_
->c2
=bezier
.c2
;
1867 add_bezier(bezier_
);
1868 last_bezier()->signal_user_click(2).connect(
1872 &studio::CanvasView::popup_param_menu_bezier
),
1873 synfigapp::ValueDesc(value_node
,first
)));
1876 else if(value_node
->get_contained_type()==ValueBase::TYPE_SEGMENT
)
1878 for(i
=0;i
<value_node
->link_count();i
++)
1880 if(!value_node
->list
[i
].status_at_time(get_time()))
1882 if(!add_to_ducks(synfigapp::ValueDesc(value_node
,i
),canvas_view
,transform_stack
))