Remove .gitignore do nothing is ignored.
[synfig.git] / synfig-studio / trunk / src / gtkmm / duckmatic.cpp
index 3325d0c..0d88982 100644 (file)
@@ -44,6 +44,9 @@
 #include <synfig/valuenode_composite.h>
 #include <synfig/valuenode_scale.h>
 #include <synfig/valuenode_bline.h>
+#include <synfig/valuenode_blinecalctangent.h>
+#include <synfig/valuenode_blinecalcvertex.h>
+#include <synfig/valuenode_blinecalcwidth.h>
 
 #include <synfig/curve_helper.h>
 
@@ -108,18 +111,6 @@ Duckmatic::~Duckmatic()
 }
 
 void
-Duckmatic::set_flip_x(bool flip_x)
-{
-       flip_x_ = flip_x;
-}
-
-void
-Duckmatic::set_flip_y(bool flip_y)
-{
-       flip_y_ = flip_y;
-}
-
-void
 Duckmatic::clear_ducks()
 {
        duck_data_share_map.clear();
@@ -263,9 +254,10 @@ Duckmatic::is_duck_group_selectable(const etl::handle<Duck>& x)const
                 !x->get_editable()))
                return false;
 
-       if(x->get_value_desc().parent_is_layer_param() && type & Duck::TYPE_POSITION)
+       synfigapp::ValueDesc value_desc(x->get_value_desc());
+       if(value_desc.parent_is_layer_param() && type & Duck::TYPE_POSITION)
        {
-               Layer::Handle layer(x->get_value_desc().get_layer());
+               Layer::Handle layer(value_desc.get_layer());
                String layer_name(layer->get_name());
 
                if (layer_name == "outline" || layer_name == "region" || layer_name == "plant" ||
@@ -276,6 +268,30 @@ Duckmatic::is_duck_group_selectable(const etl::handle<Duck>& x)const
                   !layer->get_param("children_lock").get(bool()))
                        return false;
        }
+       else if (value_desc.parent_is_value_node())
+       {
+               if (ValueNode_BLineCalcVertex::Handle::cast_dynamic(value_desc.get_value_node()))
+                       return false;
+               if (value_desc.parent_is_linkable_value_node())
+               {
+                       LinkableValueNode::Handle parent_value_node(value_desc.get_parent_value_node());
+                       if (ValueNode_Composite::Handle::cast_dynamic(parent_value_node))
+                       {
+                               if (parent_value_node->get_type() == ValueBase::TYPE_BLINEPOINT &&
+                                       ValueNode_BLineCalcVertex::Handle::cast_dynamic(
+                                               parent_value_node->get_link("point")))
+                                       return false;
+                       }
+                       else if (ValueNode_BLine::Handle::cast_dynamic(parent_value_node))
+                       {
+                               ValueNode_Composite::Handle composite(ValueNode_Composite::Handle::cast_dynamic(
+                                                                                                                 value_desc.get_value_node()));
+                               if (composite &&
+                                       ValueNode_BLineCalcVertex::Handle::cast_dynamic(composite->get_link("point")))
+                                       return false;
+                       }
+               }
+       }
        return true;
 }
 
@@ -286,6 +302,16 @@ Duckmatic::select_all_ducks()
        for(iter=duck_map.begin();iter!=duck_map.end();++iter)
                if(is_duck_group_selectable(iter->second))
                        select_duck(iter->second);
+               else
+                       unselect_duck(iter->second);
+}
+
+void
+Duckmatic::unselect_all_ducks()
+{
+       DuckMap::const_iterator iter;
+       for(iter=duck_map.begin();iter!=duck_map.end();++iter)
+               unselect_duck(iter->second);
 }
 
 void
@@ -373,8 +399,14 @@ Duckmatic::get_duck_list()const
 {
        DuckList ret;
        DuckMap::const_iterator iter;
+       for(iter=duck_map.begin();iter!=duck_map.end();++iter) if (iter->second->get_type()&Duck::TYPE_POSITION) ret.push_back(iter->second);
+       for(iter=duck_map.begin();iter!=duck_map.end();++iter) if (iter->second->get_type()&Duck::TYPE_VERTEX  ) ret.push_back(iter->second);
+       for(iter=duck_map.begin();iter!=duck_map.end();++iter) if (iter->second->get_type()&Duck::TYPE_TANGENT ) ret.push_back(iter->second);
        for(iter=duck_map.begin();iter!=duck_map.end();++iter)
-               ret.push_back(iter->second);
+               if (!(iter->second->get_type()&Duck::TYPE_POSITION) &&
+                       !(iter->second->get_type()&Duck::TYPE_VERTEX) &&
+                       !(iter->second->get_type()&Duck::TYPE_TANGENT))
+                       ret.push_back(iter->second);
        return ret;
 }
 
@@ -515,21 +547,102 @@ DuckDrag_Translate::duck_drag(Duckmatic* duckmatic, const synfig::Vector& vector
 
        synfig::Vector vect(duckmatic->snap_point_to_grid(vector)-drag_offset_);
        int i;
+       Time time(duckmatic->get_time());
 
-       for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
+       // drag the vertex and position ducks first
+       for (i=0,iter=selected_ducks.begin(); iter!=selected_ducks.end(); ++iter,i++)
        {
-               if((*iter)->get_type()!=Duck::TYPE_VERTEX &&
-                  (*iter)->get_type()!=Duck::TYPE_POSITION)
-                       continue;
-               (*iter)->set_trans_point(positions[i]+vect);
+               etl::handle<Duck> duck(*iter);
+               if(duck->get_type() == Duck::TYPE_VERTEX || duck->get_type() == Duck::TYPE_POSITION)
+               {
+                       duck->set_trans_point(positions[i]+vect);
+
+                       ValueNode_BLineCalcVertex::Handle bline_vertex;
+                       ValueNode_Composite::Handle composite;
+
+                       if ((bline_vertex = ValueNode_BLineCalcVertex::Handle::cast_dynamic(duck->get_value_desc().get_value_node())) ||
+                               ((composite = ValueNode_Composite::Handle::cast_dynamic(duck->get_value_desc().get_value_node())) &&
+                                composite->get_type() == ValueBase::TYPE_BLINEPOINT &&
+                                (bline_vertex = ValueNode_BLineCalcVertex::Handle::cast_dynamic(composite->get_link("point")))))
+                       {
+                               synfig::Point closest_point = duck->get_point();
+                               synfig::Real radius = 0.0;
+                               ValueNode_BLine::Handle bline = ValueNode_BLine::Handle::cast_dynamic(bline_vertex->get_link(bline_vertex->get_link_index_from_name("bline")));
+                               synfig::find_closest_point(
+                                       (*bline)(time),
+                                       duck->get_point(),
+                                       radius,
+                                       bline->get_loop(),
+                                       &closest_point);
+                               duck->set_point(closest_point);
+                       }
+               }
        }
-       for(i=0,iter=selected_ducks.begin();iter!=selected_ducks.end();++iter,i++)
+
+       // then drag the others
+       for (i=0,iter=selected_ducks.begin(); iter!=selected_ducks.end(); ++iter,i++)
+               if ((*iter)->get_type() != Duck::TYPE_VERTEX && (*iter)->get_type() != Duck::TYPE_POSITION)
+                       (*iter)->set_trans_point(positions[i]+vect);
+
+       // then patch up the tangents for the vertices we've moved
+       DuckList duck_list(duckmatic->get_duck_list());
+       for (iter=selected_ducks.begin(); iter!=selected_ducks.end(); ++iter)
        {
-               if((*iter)->get_type()==Duck::TYPE_VERTEX ||
-                  (*iter)->get_type()==Duck::TYPE_POSITION)
-                       continue;
-               (*iter)->set_trans_point(positions[i]+vect);
+               etl::handle<Duck> duck(*iter);
+               if (duck->get_type() == Duck::TYPE_VERTEX || duck->get_type() == Duck::TYPE_POSITION)
+               {
+                       ValueNode_BLineCalcVertex::Handle bline_vertex;
+                       ValueNode_Composite::Handle composite;
+
+                       if ((bline_vertex = ValueNode_BLineCalcVertex::Handle::cast_dynamic(duck->get_value_desc().get_value_node())) ||
+                               ((composite = ValueNode_Composite::Handle::cast_dynamic(duck->get_value_desc().get_value_node())) &&
+                                composite->get_type() == ValueBase::TYPE_BLINEPOINT &&
+                                (bline_vertex = ValueNode_BLineCalcVertex::Handle::cast_dynamic(composite->get_link("point")))))
+                       {
+                               synfig::Real radius = 0.0;
+                               ValueNode_BLine::Handle bline(ValueNode_BLine::Handle::cast_dynamic(bline_vertex->get_link(bline_vertex->get_link_index_from_name("bline"))));
+                               Real amount = synfig::find_closest_point((*bline)(time), duck->get_point(), radius, bline->get_loop());
+
+                               int vertex_amount_index(bline_vertex->get_link_index_from_name("amount"));
+                               ValueNode::Handle vertex_amount_value_node(bline_vertex->get_link(vertex_amount_index));
+
+                               DuckList::iterator iter;
+                               for (iter=duck_list.begin(); iter!=duck_list.end(); iter++)
+                               {
+                                       ValueNode::Handle duck_value_node((*iter)->get_value_desc().get_value_node());
+                                       if (ValueNode_BLineCalcTangent::Handle bline_tangent = ValueNode_BLineCalcTangent::Handle::cast_dynamic(duck_value_node))
+                                       {
+                                               if (bline_tangent->get_link(bline_tangent->get_link_index_from_name("amount")) == vertex_amount_value_node)
+                                               {
+                                                       switch (bline_tangent->get_type())
+                                                       {
+                                                       case ValueBase::TYPE_ANGLE:
+                                                       {
+                                                               Angle angle((*bline_tangent)(time, amount).get(Angle()));
+                                                               (*iter)->set_point(Point(Angle::cos(angle).get(), Angle::sin(angle).get()));
+                                                               break;
+                                                       }
+                                                       case ValueBase::TYPE_REAL:
+                                                               (*iter)->set_point(Point((*bline_tangent)(time, amount).get(Real()), 0));
+                                                               break;
+                                                       case ValueBase::TYPE_VECTOR:
+                                                               (*iter)->set_point((*bline_tangent)(time, amount).get(Vector()));
+                                                               break;
+                                                       default:
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                                       else if (ValueNode_BLineCalcWidth::Handle bline_width = ValueNode_BLineCalcWidth::Handle::cast_dynamic(duck_value_node))
+                                       {
+                                               if (bline_width->get_link(bline_width->get_link_index_from_name("amount")) == vertex_amount_value_node)
+                                                       (*iter)->set_point(Point((*bline_width)(time, amount).get(Real()), 0));
+                                       }
+                               }
+                       }
+               }
        }
+
        last_translate_=vect;
 }
 
@@ -562,12 +675,12 @@ Duckmatic::signal_edited_selected_ducks()
                        Point point((*iter)->get_point());
                        bool changed = false;
 
-                       if (point[0] * (flip_x_ ? -1 : 1) < 0)
+                       if (point[0] < 0)
                        {
                                point[0] = 0;
                                changed = true;
                        }
-                       if (point[1] * (flip_y_ ? -1 : 1) < 0)
+                       if (point[1] < 0)
                        {
                                point[1] = 0;
                                changed = true;
@@ -768,21 +881,23 @@ Duckmatic::find_duck(synfig::Point point, synfig::Real radius, Duck::Type type)
        {
                const Duck::Handle& duck(iter->second);
 
-               if(duck->get_ignore())
+               if(duck->get_ignore() ||
+                  (duck->get_type() && !(type & duck->get_type())))
                        continue;
+
                Real dist((duck->get_trans_point()-point).mag_squared());
 
                if(duck->get_type()&Duck::TYPE_VERTEX)
                        dist*=1.0001;
+               else if(duck->get_type()&Duck::TYPE_TANGENT && duck->get_scalar()>0)
+                       dist*=1.00005;
                else if(duck->get_type()&Duck::TYPE_RADIUS)
                        dist*=0.9999;
 
-               if(dist<=closest && !( duck->get_type() && (!(type & duck->get_type())) ) )
+               if(dist<=closest)
                {
-                       {
-                               closest=dist;
-                               ret=duck;
-                       }
+                       closest=dist;
+                       ret=duck;
                }
        }
 
@@ -990,13 +1105,13 @@ inline String guid_string(const synfigapp::ValueDesc& x)
                return strprintf("%s",x.get_value_node()->get_guid().get_string().c_str());
 }
 
-inline GUID calc_duck_guid(const synfigapp::ValueDesc& x,const synfig::TransformStack& transform_stack)
+inline synfig::GUID calc_duck_guid(const synfigapp::ValueDesc& x,const synfig::TransformStack& transform_stack)
 {
-       GUID ret(0);
+       synfig::GUID ret(0);
 
        if(x.parent_is_layer_param())
        {
-               ret=x.get_layer()->get_guid()^GUID::hasher(x.get_param_name());
+               ret=x.get_layer()->get_guid()^synfig::GUID::hasher(x.get_param_name());
        }
        else
        {
@@ -1011,7 +1126,7 @@ inline GUID calc_duck_guid(const synfigapp::ValueDesc& x,const synfig::Transform
 Duck::Handle
 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)
 {
-       GUID duck_guid(calc_duck_guid(value_desc,transform_stack)^GUID::hasher(modifier));
+       synfig::GUID duck_guid(calc_duck_guid(value_desc,transform_stack)^synfig::GUID::hasher(modifier));
        etl::handle<Duck> duck=new Duck();
 
        return duck;
@@ -1034,8 +1149,8 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                        duck->set_radius(true);
                        duck->set_type(Duck::TYPE_RADIUS);
 
-                       // put the duck on the right hand side of the center, whether the display is flipped or not
-                       duck->set_point(Point(value_desc.get_value(get_time()).get(Real()) * (flip_x_ ? -1 : 1), 0));
+                       // put the duck on the right hand side of the center
+                       duck->set_point(Point(value_desc.get_value(get_time()).get(Real()), 0));
                        duck->set_name(guid_string(value_desc));
                        if(value_desc.is_value_node())
                        {
@@ -1074,13 +1189,15 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                        duck->signal_user_click(2).connect(
                                sigc::bind(
                                        sigc::bind(
-                                               sigc::mem_fun(
-                                                       *canvas_view,
-                                                       &studio::CanvasView::popup_param_menu),
+                                               sigc::bind(
+                                                       sigc::mem_fun(
+                                                               *canvas_view,
+                                                               &studio::CanvasView::popup_param_menu),
+                                                       false),
                                                0.0f),
                                        value_desc));
 
-                       duck->set_guid(calc_duck_guid(value_desc,transform_stack)^GUID::hasher(multiple));
+                       duck->set_guid(calc_duck_guid(value_desc,transform_stack)^synfig::GUID::hasher(multiple));
 
                        add_duck(duck);
 
@@ -1144,12 +1261,14 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                        duck->signal_user_click(2).connect(
                                sigc::bind(
                                        sigc::bind(
-                                               sigc::mem_fun(
-                                                       *canvas_view,
-                                                       &studio::CanvasView::popup_param_menu),
+                                               sigc::bind(
+                                                       sigc::mem_fun(
+                                                               *canvas_view,
+                                                               &studio::CanvasView::popup_param_menu),
+                                                       false),
                                                0.0f),
                                        value_desc));
-                       duck->set_guid(calc_duck_guid(value_desc,transform_stack)^GUID::hasher(multiple));
+                       duck->set_guid(calc_duck_guid(value_desc,transform_stack)^synfig::GUID::hasher(multiple));
 
                        add_duck(duck);
 
@@ -1186,9 +1305,9 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                {
                                        synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_connect());
                                        Duck::Handle connect_duck;
-                                       if(duck_map.find(calc_duck_guid(value_desc_origin,transform_stack)^GUID::hasher(0))!=duck_map.end())
+                                       if(duck_map.find(calc_duck_guid(value_desc_origin,transform_stack)^synfig::GUID::hasher(0))!=duck_map.end())
                                        {
-                                               connect_duck=duck_map[calc_duck_guid(value_desc_origin,transform_stack)^GUID::hasher(0)];
+                                               connect_duck=duck_map[calc_duck_guid(value_desc_origin,transform_stack)^synfig::GUID::hasher(0)];
                                        }
                                        else
                                        {
@@ -1235,18 +1354,20 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                        duck->signal_user_click(2).connect(
                                sigc::bind(
                                        sigc::bind(
-                                               sigc::mem_fun(
-                                                       *canvas_view,
-                                                       &studio::CanvasView::popup_param_menu),
+                                               sigc::bind(
+                                                       sigc::mem_fun(
+                                                               *canvas_view,
+                                                               &studio::CanvasView::popup_param_menu),
+                                                       false),
                                                1.0f),
                                        value_desc));
-                       duck->set_guid(calc_duck_guid(value_desc,transform_stack)^GUID::hasher(multiple));
+                       duck->set_guid(calc_duck_guid(value_desc,transform_stack)^synfig::GUID::hasher(multiple));
                        add_duck(duck);
 
                        return true;
                }
                break;
-/*     case ValueBase::TYPE_SEGMENT:
+       case ValueBase::TYPE_SEGMENT:
                {
                        etl::handle<Bezier> bezier(new Bezier());
                        ValueNode_Composite::Handle value_node;
@@ -1301,12 +1422,12 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                        name=guid_string(value_desc);
                                }
 
-                               duck_p=new class Duck(segment.p1);
+                               duck_p=new Duck(segment.p1);
                                duck_p->set_name(name+".P1");
                                duck_p->set_type(Duck::TYPE_VERTEX);
                                add_duck(duck_p);
 
-                               duck_c=new class Duck(segment.t1);
+                               duck_c=new Duck(segment.t1);
                                duck_c->set_name(name+".T1");
                                duck_c->set_type(Duck::TYPE_TANGENT);
                                add_duck(duck_c);
@@ -1317,12 +1438,12 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                bezier->p1=duck_p;
                                bezier->c1=duck_c;
 
-                               duck_p=new class Duck(segment.p2);
+                               duck_p=new Duck(segment.p2);
                                duck_p->set_name(name+".P2");
                                duck_p->set_type(Duck::TYPE_VERTEX);
                                add_duck(duck_p);
 
-                               duck_c=new class Duck(segment.t2);
+                               duck_c=new Duck(segment.t2);
                                duck_c->set_type(Duck::TYPE_TANGENT);
                                duck_c->set_name(name+".T2");
                                add_duck(duck_c);
@@ -1338,7 +1459,6 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                        return true;
                }
                break;
-*/
        case ValueBase::TYPE_BLINEPOINT:
        {
 
@@ -1433,9 +1553,11 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                                duck->signal_user_click(2).connect(
                                                        sigc::bind(
                                                                sigc::bind(
-                                                                       sigc::mem_fun(
-                                                                               *canvas_view,
-                                                                               &studio::CanvasView::popup_param_menu),
+                                                                       sigc::bind(
+                                                                               sigc::mem_fun(
+                                                                                       *canvas_view,
+                                                                                       &studio::CanvasView::popup_param_menu),
+                                                                               false),
                                                                        1.0f),
                                                                synfigapp::ValueDesc(value_node,i)));
                                                duck->set_value_desc(synfigapp::ValueDesc(value_node,i));
@@ -1474,17 +1596,17 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                        {
                                                if(!param_desc->get_origin().empty())
                                                {
-                                                               synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin());
-                                                               add_to_ducks(value_desc_origin,canvas_view, transform_stack);
-                                                               duck->set_origin(last_duck());
+                                                       synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin());
+                                                       add_to_ducks(value_desc_origin,canvas_view, transform_stack);
+                                                       duck->set_origin(last_duck());
 /*
-                                                               ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()));
-                                                               if(value.same_type_as(synfig::Point()))
-                                                                       duck->set_origin(value.get(synfig::Point()));
+                                                       ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()));
+                                                       if(value.same_type_as(synfig::Point()))
+                                                               duck->set_origin(value.get(synfig::Point()));
 */
                                                }
                                        }
-                                       duck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,i),transform_stack)^GUID::hasher(".v"));
+                                       duck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,i),transform_stack)^synfig::GUID::hasher(".v"));
                                        duck=add_similar_duck(duck);
 //                                     add_duck(duck);
                                }
@@ -1538,7 +1660,7 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                                tduck->set_editable(false);
                                                tduck->set_name(guid_string(synfigapp::ValueDesc(value_node,i))+".t1");
 //                                             tduck->set_name(strprintf("%x-tangent1",value_node->get_link(i).get()));
-                                               tduck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,i),transform_stack)^GUID::hasher(".t1"));
+                                               tduck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,i),transform_stack)^synfig::GUID::hasher(".t1"));
                                                tduck=add_similar_duck(tduck);
 //                                             add_duck(duck);
                                        }
@@ -1561,9 +1683,11 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                        duck->signal_user_click(2).connect(
                                                sigc::bind(
                                                        sigc::bind(
-                                                               sigc::mem_fun(
-                                                                       *canvas_view,
-                                                                       &studio::CanvasView::popup_param_menu),
+                                                               sigc::bind(
+                                                                       sigc::mem_fun(
+                                                                               *canvas_view,
+                                                                               &studio::CanvasView::popup_param_menu),
+                                                                       false),
                                                                1.0f),
                                                        synfigapp::ValueDesc(value_node,i)));
                                        duck->set_value_desc(synfigapp::ValueDesc(value_node,i));
@@ -1589,33 +1713,25 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                else
                                {
                                        if(bline_point.get_split_tangent_flag())
-                                       {
                                                tduck=new Duck(bline_point.get_tangent2());
-                                               tduck->set_transform_stack(transform_stack);
-                                               //tduck->set_name(strprintf("%x-tangent2",value_node->get_link(i).get()));
-                                               tduck->set_name(guid_string(synfigapp::ValueDesc(value_node,i))+".t2");
-                                               tduck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,i),transform_stack)^GUID::hasher(".t2"));
-                                       }
                                        else
-                                       {
                                                tduck=new Duck(bline_point.get_tangent1());
-                                               tduck->set_transform_stack(transform_stack);
-                                               //tduck->set_name(strprintf("%x-tangent1",value_node->get_link(i).get()));
-                                               tduck->set_name(guid_string(synfigapp::ValueDesc(value_node,i))+".t1");
-                                               tduck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,i),transform_stack)^GUID::hasher(".t1"));
-                                       }
+
+                                       tduck->set_transform_stack(transform_stack);
+                                       tduck->set_name(guid_string(synfigapp::ValueDesc(value_node,i))+".t2");
+                                       tduck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,i),transform_stack)^synfig::GUID::hasher(".t2"));
                                        tduck->set_editable(false);
                                        tduck=add_similar_duck(tduck);
 //                                     add_duck(duck);
                                        if(param_desc)
                                        {
-                                                               synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin());
-                                                               add_to_ducks(value_desc_origin,canvas_view, transform_stack);
-                                                               duck->set_origin(last_duck());
+                                               synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin());
+                                               add_to_ducks(value_desc_origin,canvas_view, transform_stack);
+                                               duck->set_origin(last_duck());
 /*
-                                                               ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()));
-                                                               if(value.same_type_as(synfig::Point()))
-                                                                       duck->set_origin(value.get(synfig::Point()));
+                                               ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()));
+                                               if(value.same_type_as(synfig::Point()))
+                                                       duck->set_origin(value.get(synfig::Point()));
 */
 //                                             if(!param_desc->get_origin().empty())
 //                                                     duck->set_origin(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()).get(synfig::Point()));
@@ -1624,12 +1740,14 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                        duck->signal_user_click(2).connect(
                                                sigc::bind(
                                                        sigc::bind(
-                                                               sigc::mem_fun(
-                                                                       *canvas_view,
-                                                                       &studio::CanvasView::popup_param_menu),
+                                                               sigc::bind(
+                                                                       sigc::mem_fun(
+                                                                               *canvas_view,
+                                                                               &studio::CanvasView::popup_param_menu),
+                                                                       false),
                                                                1.0f),
-                                                       synfigapp::ValueDesc(value_node,0)));
-                                       duck->set_value_desc(synfigapp::ValueDesc(value_node,0));
+                                                       synfigapp::ValueDesc(value_node,i)));
+                                       duck->set_value_desc(synfigapp::ValueDesc(value_node,i));
 
                                }
 
@@ -1668,7 +1786,7 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                        tduck->set_name(guid_string(synfigapp::ValueDesc(value_node,first))+".t1");
                                        //tduck->set_name(strprintf("%x-tangent1",value_node->get_link(first).get()));
                                        tduck=add_similar_duck(tduck);
-                                       tduck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,first),transform_stack)^GUID::hasher(".t1"));
+                                       tduck->set_guid(calc_duck_guid(synfigapp::ValueDesc(value_node,first),transform_stack)^synfig::GUID::hasher(".t1"));
                                        //add_duck(duck);
                                }
 
@@ -1690,9 +1808,11 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                duck->signal_user_click(2).connect(
                                        sigc::bind(
                                                sigc::bind(
-                                                       sigc::mem_fun(
-                                                               *canvas_view,
-                                                               &studio::CanvasView::popup_param_menu),
+                                                       sigc::bind(
+                                                               sigc::mem_fun(
+                                                                       *canvas_view,
+                                                                       &studio::CanvasView::popup_param_menu),
+                                                               false),
                                                        1.0f),
                                                synfigapp::ValueDesc(value_node,first)));
                                duck->set_value_desc(synfigapp::ValueDesc(value_node,first));
@@ -1713,23 +1833,32 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                        if(value_node->get_contained_type()==ValueBase::TYPE_VECTOR)
                        {
                                Bezier bezier;
+                               etl::handle<Duck> first_duck, duck;
+                               int first = -1;
                                for(i=0;i<value_node->link_count();i++)
                                {
                                        if(!value_node->list[i].status_at_time(get_time()))
                                                continue;
                                        if(!add_to_ducks(synfigapp::ValueDesc(value_node,i),canvas_view,transform_stack))
                                                return false;
-                                       etl::handle<Duck> duck(last_duck());
+                                       duck = last_duck();
 
-                                       if(param_desc)
+                                       // remember the index of the first vertex we didn't skip
+                                       if (first == -1)
                                        {
-                                                               synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin());
-                                                               add_to_ducks(value_desc_origin,canvas_view, transform_stack);
-                                                               duck->set_origin(last_duck());
+                                               first = i;
+                                               first_duck = duck;
+                                       }
+
+                                       if(param_desc && !param_desc->get_origin().empty())
+                                       {
+                                               synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin());
+                                               add_to_ducks(value_desc_origin,canvas_view, transform_stack);
+                                               duck->set_origin(last_duck());
 /*
-                                                               ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()));
-                                                               if(value.same_type_as(synfig::Point()))
-                                                                       duck->set_origin(value.get(synfig::Point()));
+                                               ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()));
+                                               if(value.same_type_as(synfig::Point()))
+                                                       duck->set_origin(value.get(synfig::Point()));
 */
 //                                             if(!param_desc->get_origin().empty())
 //                                                     last_duck()->set_origin(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_origin()).get_value(get_time()).get(synfig::Point()));
@@ -1738,7 +1867,7 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                        bezier.p1=bezier.p2;bezier.c1=bezier.c2;
                                        bezier.p2=bezier.c2=duck;
 
-                                       if(i>0)
+                                       if (first != i)
                                        {
                                                handle<Bezier> bezier_(new Bezier());
                                                bezier_->p1=bezier.p1;
@@ -1754,8 +1883,29 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                                                synfigapp::ValueDesc(value_node,i)));
                                        }
                                }
+
+                               if (value_node->get_loop() && first != -1 && first_duck != duck)
+                               {
+                                       duck = first_duck;
+
+                                       bezier.p1=bezier.p2;bezier.c1=bezier.c2;
+                                       bezier.p2=bezier.c2=duck;
+
+                                       handle<Bezier> bezier_(new Bezier());
+                                       bezier_->p1=bezier.p1;
+                                       bezier_->c1=bezier.c1;
+                                       bezier_->p2=bezier.p2;
+                                       bezier_->c2=bezier.c2;
+                                       add_bezier(bezier_);
+                                       last_bezier()->signal_user_click(2).connect(
+                                               sigc::bind(
+                                                       sigc::mem_fun(
+                                                               *canvas_view,
+                                                               &studio::CanvasView::popup_param_menu_bezier),
+                                                       synfigapp::ValueDesc(value_node,first)));
+                               }
                        }
-                       /*else if(value_node->get_contained_type()==ValueBase::TYPE_SEGMENT)
+                       else if(value_node->get_contained_type()==ValueBase::TYPE_SEGMENT)
                        {
                                for(i=0;i<value_node->link_count();i++)
                                {
@@ -1765,7 +1915,6 @@ Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc,etl::handle<Canva
                                                return false;
                                }
                        }
-                       */
                        else
                                return false;
                }