/* === S Y N F I G ========================================================= */
/*!	\file duckmatic.cpp
**	\brief Template File
**
**	\legal
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
**	Copyright (c) 2007, 2008 Chris Moore
**	Copyright (c) 2009, 2011 Nikita Kitaev
**	Copyright (c) 2011 Carlos López
**	Copyright (c) 2015 Blanchi Jérôme
**
**	This file is part of Synfig.
**
**	Synfig is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 2 of the License, or
**	(at your option) any later version.
**
**	Synfig is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with Synfig.  If not, see <https://www.gnu.org/licenses/>.
**	\endlegal
*/
/* ========================================================================= */

/* === H E A D E R S ======================================================= */

#ifdef USING_PCH
#	include "pch.h"
#else
#ifdef HAVE_CONFIG_H
#	include <config.h>
#endif

#include <gui/duckmatic.h>

#include <algorithm>
#include <fstream>

#include <gui/app.h>
#include <gui/canvasview.h>
#include <gui/ducktransform_matrix.h>
#include <gui/ducktransform_origin.h>
#include <gui/ducktransform_rotate.h>
#include <gui/ducktransform_scale.h>
#include <gui/ducktransform_translate.h>
#include <gui/localization.h>
#include <gui/onemoment.h>

#include <synfig/context.h>
#include <synfig/curve_helper.h>
#include <synfig/layers/layer_filtergroup.h>
#include <synfig/layers/layer_pastecanvas.h>
#include <synfig/pair.h>
#include <synfig/paramdesc.h>
#include <synfig/segment.h>
#include <synfig/valuenodes/valuenode_animated.h>
#include <synfig/valuenodes/valuenode_bline.h>
#include <synfig/valuenodes/valuenode_blinecalctangent.h>
#include <synfig/valuenodes/valuenode_blinecalcvertex.h>
#include <synfig/valuenodes/valuenode_blinecalcwidth.h>
#include <synfig/valuenodes/valuenode_bone.h>
#include <synfig/valuenodes/valuenode_boneinfluence.h>
#include <synfig/valuenodes/valuenode_boneweightpair.h>
#include <synfig/valuenodes/valuenode_composite.h>
#include <synfig/valuenodes/valuenode_range.h>
#include <synfig/valuenodes/valuenode_scale.h>
#include <synfig/valuenodes/valuenode_staticlist.h>
#include <synfig/valuenodes/valuenode_timedswap.h>
#include <synfig/valuenodes/valuenode_wplist.h>

#include <synfigapp/canvasinterface.h>
#include <synfigapp/value_desc.h>

#endif

/* === U S I N G =========================================================== */

using namespace synfig;
using namespace studio;

/* === M A C R O S ========================================================= */

/* 0.33333333333333333 makes for nice short tangent handles,
   1.0 makes them draw as their real length */
#define TANGENT_HANDLE_SCALE 0.33333333333333333

/* leave this alone or the bezier won't lie on top of the bline */
#define TANGENT_BEZIER_SCALE 0.33333333333333333

/* === I N L I N E ======================================================= */
synfig::GUID calc_duck_guid(const synfigapp::ValueDesc& value_desc, const synfig::TransformStack& transform_stack);
void set_duck_value_desc(Duck& duck, const synfigapp::ValueDesc& value_desc, const synfig::TransformStack& transform_stack);
void set_duck_value_desc(Duck& duck, const synfigapp::ValueDesc& value_desc, const synfig::String& sub_name, const synfig::TransformStack& transform_stack);

/* === P R O C E D U R E S ================================================= */

/* === M E T H O D S ======================================================= */

/* === E N T R Y P O I N T ================================================= */

Duckmatic::Duckmatic(etl::loose_handle<synfigapp::CanvasInterface> canvas_interface):
	canvas_interface(canvas_interface),
	type_mask(Type(
		Duck::TYPE_ALL
	  & ~( Duck::TYPE_WIDTH
		 | Duck::TYPE_BONE_RECURSIVE
		 | Duck::TYPE_WIDTHPOINT_POSITION ))),
	type_mask_state(Duck::TYPE_NONE),
	alternative_mode_(false),
	lock_animation_mode_(false),
	grid_snap(false),
	guide_snap(false),
	grid_size(1.0/4.0,1.0/4.0),
	grid_color(synfig::Color(159.0/255.0,159.0/255.0,159.0/255.0)),
	guides_color(synfig::Color(111.0/255.0,111.0/255.0,1.0)),
	zoom(1.0),
	prev_zoom(1.0),
	show_persistent_strokes(true),
	axis_lock(false),
	drag_offset_(0, 0)
{
	clear_duck_dragger();
	clear_bezier_dragger();
}

Duckmatic::~Duckmatic()
{
	clear_ducks();

	DEBUG_LOG("SYNFIG_DEBUG_DESTRUCTORS",
		"Duckmatic::~Duckmatic(): Deleted");
}

void
Duckmatic::clear_ducks()
{
	for(;!duck_changed_connections.empty();duck_changed_connections.pop_back())duck_changed_connections.back().disconnect();

	duck_data_share_map.clear();
	duck_map.clear();

	//duck_list_.clear();
	bezier_list_.clear();
	stroke_list_.clear();

	if(show_persistent_strokes)
		stroke_list_=persistent_stroke_list_;
}


/*
-- ** -- D U C K  M A N I P U L A T I O N  M E T H O D S-----------------------
*/

bool
Duckmatic::duck_is_selected(const Duck::Handle& duck)const
{
	return duck && selected_ducks.count(duck->get_guid());
}

void
Duckmatic::clear_selected_ducks()
{
	selected_ducks.clear();
	signal_duck_selection_changed_();
}

Duck::Handle
Duckmatic::get_selected_duck()const
{
	if(selected_ducks.empty() || duck_map.empty())
		return 0;
	return duck_map.find(*selected_ducks.begin())->second;
}

Duckmatic::Bezier::Handle
Duckmatic::get_selected_bezier()const
{
	return selected_bezier;
}

void
Duckmatic::refresh_selected_ducks()
{
/*
	std::set<Duck::Handle>::iterator iter;
	std::set<Duck::Handle> new_set;
	if(duck_list().empty())
	{
		selected_duck_list.clear();
		signal_duck_selection_changed_();
		return;
	}

	for(iter=selected_duck_list.begin();iter!=selected_duck_list.end();++iter)
	{
		Duck::Handle similar(find_similar_duck(*iter));
		if(similar)
		{
			new_set.insert(similar);
		}
	}
	selected_duck_list=new_set;
*/
	GUIDSet old_set(selected_ducks);
	GUIDSet::const_iterator iter;

	for(iter=old_set.begin();iter!=old_set.end();++iter)
	{
		if(duck_map.count(*iter)==0)
			selected_ducks.erase(*iter);
	}

	signal_duck_selection_changed_();
}

bool
Duckmatic::is_duck_group_selectable(const Duck::Handle& x)const
{
	const Type type(get_type_mask());

	if (((x->get_type() && (!(type & x->get_type()))) ||
		 !x->get_editable()))
		return false;

	synfigapp::ValueDesc value_desc(x->get_value_desc());
	if(value_desc.parent_is_layer() && (type & Duck::TYPE_POSITION))
	{
		Layer::Handle layer(value_desc.get_layer());
		String layer_name(layer->get_name());

		if (layer_name == "outline" || layer_name == "region" || layer_name == "plant" ||
			layer_name == "polygon" || layer_name == "curve_gradient" || layer_name == "advanced_outline")
			return false;

		if(Layer_PasteCanvas::Handle::cast_dynamic(layer) &&
			!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())
		{
			ValueNode::Handle parent_value_node(value_desc.get_parent_value_node());
			if (ValueNode_Composite::Handle composite = ValueNode_Composite::Handle::cast_dynamic(parent_value_node))
			{
				if (parent_value_node->get_type() == type_bline_point &&
					ValueNode_BLineCalcVertex::Handle::cast_dynamic(
							composite->get_link("point")))
					return false;
				// widths ducks of the widthpoints
				// Do not avoid selection of the width ducks from widthpoints
				//if (parent_value_node->get_type() == type_width_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;
			}
			// position ducks of the widthpoints
			else if (ValueNode_WPList::Handle::cast_dynamic(parent_value_node))
				return false;

		}
	}
	return true;
}

void
Duckmatic::select_all_ducks()
{
	DuckMap::const_iterator iter;
	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
Duckmatic::toggle_select_ducks_in_box(const synfig::Vector& tl,const synfig::Vector& br)
{
	Vector vmin, vmax;
	vmin[0]=std::min(tl[0],br[0]);
	vmin[1]=std::min(tl[1],br[1]);
	vmax[0]=std::max(tl[0],br[0]);
	vmax[1]=std::max(tl[1],br[1]);

	{
		DuckMap::const_iterator iter;
		for(iter=duck_map.begin();iter!=duck_map.end();++iter)
		{
			Point p(iter->second->get_trans_point());
			if(p[0]<=vmax[0] && p[0]>=vmin[0] && p[1]<=vmax[1] && p[1]>=vmin[1] &&
				is_duck_group_selectable(iter->second))
				toggle_select_duck(iter->second);
		}
	}
}

void
Duckmatic::select_ducks_in_box(const synfig::Vector& tl,const synfig::Vector& br)
{
	Vector vmin, vmax;
	vmin[0]=std::min(tl[0],br[0]);
	vmin[1]=std::min(tl[1],br[1]);
	vmax[0]=std::max(tl[0],br[0]);
	vmax[1]=std::max(tl[1],br[1]);

//	Type type(get_type_mask());

	DuckMap::const_iterator iter;
	for(iter=duck_map.begin();iter!=duck_map.end();++iter)
	{
		Point p(iter->second->get_trans_point());
		if(p[0]<=vmax[0] && p[0]>=vmin[0] && p[1]<=vmax[1] && p[1]>=vmin[1])
		{
			if(is_duck_group_selectable(iter->second))
				select_duck(iter->second);
		}
	}
}

int
Duckmatic::count_selected_ducks()const
{
	return selected_ducks.size();
}

void
Duckmatic::select_duck(const Duck::Handle& duck)
{
	if(duck)
	{
		selected_ducks.insert(duck->get_guid());
		signal_duck_selection_changed_();

		if(selected_ducks.size() == 1)
		{
			signal_duck_selection_single_(duck);
		}
	}
}

DuckList
Duckmatic::get_selected_ducks()const
{
	DuckList ret;
	GUIDSet::const_iterator iter;
	const Type type(get_type_mask());

	for(iter=selected_ducks.begin();iter!=selected_ducks.end();++iter)
	{
		const DuckMap::const_iterator d_iter(duck_map.find(*iter));

		if(d_iter==duck_map.end())
			continue;

		if(( d_iter->second->get_type() && (!(type & d_iter->second->get_type())) ) )
			continue;

		ret.push_back(d_iter->second);
	}
	return ret;
}


DuckList
Duckmatic::get_ducks_in_box(const synfig::Vector& tl,const synfig::Vector& br)const
{
	Vector vmin, vmax;
	vmin[0]=std::min(tl[0],br[0]);
	vmin[1]=std::min(tl[1],br[1]);
	vmax[0]=std::max(tl[0],br[0]);
	vmax[1]=std::max(tl[1],br[1]);

	DuckList ret;

//  Type type(get_type_mask());

	DuckMap::const_iterator iter;
	for(iter=duck_map.begin();iter!=duck_map.end();++iter)
	{
		Point p(iter->second->get_trans_point());
		if(p[0]<=vmax[0] && p[0]>=vmin[0] && p[1]<=vmax[1] && p[1]>=vmin[1])
		{
		  //  if(is_duck_group_selectable(iter->second))
			ret.push_back(iter->second);
		}
	}
	return ret;
}

DuckList
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_FIRST_VERTEX) ret.push_back(iter->second);
	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)
		if (!(iter->second->get_type()&Duck::TYPE_POSITION) &&
			!(iter->second->get_type()&Duck::TYPE_FIRST_VERTEX) &&
			!(iter->second->get_type()&Duck::TYPE_VERTEX) &&
			!(iter->second->get_type()&Duck::TYPE_TANGENT))
			ret.push_back(iter->second);
	return ret;
}

void
Duckmatic::unselect_duck(const Duck::Handle& duck)
{
	if(duck && selected_ducks.count(duck->get_guid()))
	{
		selected_ducks.erase(duck->get_guid());
		signal_duck_selection_changed_();
	}
}

void
Duckmatic::toggle_select_duck(const Duck::Handle& duck)
{
	if(duck_is_selected(duck))
		unselect_duck(duck);
	else
		select_duck(duck);
}

void
Duckmatic::translate_selected_ducks(const synfig::Vector& vector)
{
	if(duck_dragger_)
		duck_dragger_->duck_drag(this,vector);
}

void
Duckmatic::start_duck_drag(const synfig::Vector& offset)
{
	if(duck_dragger_)
		duck_dragger_->begin_duck_drag(this,offset);

	//drag_offset_=offset;
	drag_offset_=find_duck(offset)->get_trans_point();
}

bool
Duckmatic::end_duck_drag()
{
	if(duck_dragger_)
		return duck_dragger_->end_duck_drag(this);
	return false;
}

void
Duckmatic::update_ducks()
{
	Time time(get_time());
	DuckList duck_list(get_duck_list());
	const DuckList selected_ducks(get_selected_ducks());
	DuckList::const_iterator selected_iter;
	if(get_selected_bezier())
	{
		Duck::Handle c1(get_selected_bezier()->c1);
		Duck::Handle c2(get_selected_bezier()->c2);
		if(c1->get_value_desc().parent_is_linkable_value_node())
		{
			ValueNode_Composite::Handle composite(ValueNode_Composite::Handle::cast_dynamic(c1->get_value_desc().get_parent_value_node()));
			LinkableValueNode::Handle duck_value_node(LinkableValueNode::Handle::cast_dynamic(c1->get_value_desc().get_value_node()));
			// it belongs to a composite and it is a BLinePoint
			if(composite && composite->get_type() == type_bline_point && duck_value_node)
			{
				int index(c1->get_value_desc().get_index());
				Duck::Handle origin_duck = c1->get_origin_duck();
				// Search all the rest of ducks
				for (DuckList::iterator iter = duck_list.begin(); iter != duck_list.end(); ++iter)
					// if the other duck has the same origin and it is tangent type
					if ( (*iter)->get_origin_duck()==origin_duck && (*iter)->get_type() == Duck::TYPE_TANGENT)
					{
						ValueNode_Composite::Handle iter_composite;
						iter_composite=ValueNode_Composite::Handle::cast_dynamic((*iter)->get_value_desc().get_parent_value_node());
						// and their parent valuenode are the same
						if(iter_composite.get() == composite.get())
						{
							BLinePoint bp=(*composite)(time).get(BLinePoint());
							int t1_index=composite->get_link_index_from_name("t1");
							int t2_index=composite->get_link_index_from_name("t2");
							if(index==t1_index && (*iter)->get_value_desc().get_index()!=t1_index)
							{
								bp.set_tangent1(c1->get_point());
								Vector t2(bp.get_tangent2());
								(*iter)->set_point(Point(t2));
							}
							else if(index==t2_index && (*iter)->get_value_desc().get_index()!=t2_index)
							{
								// Create a new BLinePoint
								BLinePoint nbp;
								// Terporary set the flags for the new BLinePoint to all split
								nbp.set_split_tangent_both(true);
								// Now we can set the tangents. Tangent2 won't be modified by tangent1
								nbp.set_tangent1(c1->get_point());
								nbp.set_tangent2(bp.get_tangent1());
								// Now update the flags
								nbp.set_split_tangent_radius(bp.get_split_tangent_radius());
								nbp.set_split_tangent_angle(bp.get_split_tangent_angle());
								// Now retrieve the updated tangent2 (which will be stored as t1, see below)
								Vector t1(nbp.get_tangent2());
								(*iter)->set_point(Point(t1));
							}
						}
					}
			}
		}
		if(c2->get_value_desc().parent_is_linkable_value_node())
		{
			ValueNode_Composite::Handle composite(ValueNode_Composite::Handle::cast_dynamic(c2->get_value_desc().get_parent_value_node()));
			LinkableValueNode::Handle duck_value_node(LinkableValueNode::Handle::cast_dynamic(c2->get_value_desc().get_value_node()));
			// it belongs to a composite and it is a BLinePoint
			if(composite && composite->get_type() == type_bline_point && duck_value_node)
			{
				int index(c2->get_value_desc().get_index());
				Duck::Handle origin_duck = c2->get_origin_duck();
				// Search all the rest of ducks
				for (DuckList::iterator iter = duck_list.begin(); iter != duck_list.end(); ++iter) {
					// if the other duck has the same origin and it is tangent type
					if ( (*iter)->get_origin_duck()==origin_duck && (*iter)->get_type() == Duck::TYPE_TANGENT)
					{
						ValueNode_Composite::Handle iter_composite;
						iter_composite=ValueNode_Composite::Handle::cast_dynamic((*iter)->get_value_desc().get_parent_value_node());
						// and their parent valuenode are the same
						if(iter_composite.get() == composite.get())
						{
							BLinePoint bp=(*composite)(time).get(BLinePoint());
							int t1_index=composite->get_link_index_from_name("t1");
							int t2_index=composite->get_link_index_from_name("t2");
							if(index==t1_index && (*iter)->get_value_desc().get_index()!=t1_index)
							{
								bp.set_tangent1(c2->get_point());
								Vector t2(bp.get_tangent2());
								(*iter)->set_point(Point(t2));
							}
							else if(index==t2_index && (*iter)->get_value_desc().get_index()!=t2_index)
							{
								// Create a new BLinePoint
								BLinePoint nbp;
								// Terporary set the flags for the new BLinePoint to all split
								nbp.set_split_tangent_both(true);
								// Now we can set the tangents. Tangent2 won't be modified by tangent1
								nbp.set_tangent1(c2->get_point());
								nbp.set_tangent2(bp.get_tangent1());
								// Now update the flags
								nbp.set_split_tangent_radius(bp.get_split_tangent_radius());
								nbp.set_split_tangent_angle(bp.get_split_tangent_angle());
								// Now retrieve the updated tangent2 (which will be stored as t1, see below)
								Vector t1(nbp.get_tangent2());
								(*iter)->set_point(Point(t1));
							}
						}
					}
				}
			}
		}
	}
	for (selected_iter=selected_ducks.begin(); selected_iter!=selected_ducks.end(); ++selected_iter)
	{
		Duck::Handle duck(*selected_iter);
		if(!duck)
			return;
		if (duck->get_type() == Duck::TYPE_VERTEX || duck->get_type() == Duck::TYPE_POSITION)
		{
			ValueNode_BLineCalcVertex::Handle bline_vertex =
				ValueNode_BLineCalcVertex::Handle::cast_dynamic(duck->get_value_desc().get_value_node());
			if (!bline_vertex && duck->get_value_desc().parent_is_value_desc()) {
				ValueNode_Composite::Handle composite =
					ValueNode_Composite::Handle::cast_dynamic(duck->get_value_desc().get_value_node());
				if (composite)
					bline_vertex =
						ValueNode_BLineCalcVertex::Handle::cast_dynamic(
							composite->get_link(
								duck->get_value_desc().get_sub_name() ));
			}

			if (bline_vertex)
			{
				synfig::Real radius = 0.0;
				synfig::Point point(0.0, 0.0);
				bool bline_loop = false;
				ValueNode::LooseHandle bline = bline_vertex->get_bline_handle(bline_loop);
				if (!bline) {
					warning(_("Internal error: duckmatic: It is a BLine Vertex, but it has not a BLine link"));
					return;
				}
				Real amount = synfig::find_closest_point((*bline)(time), duck->get_point(), radius, bline_loop, &point);
				bool homogeneous((*(bline_vertex->get_link("homogeneous")))(time).get(bool()));
				if(homogeneous)
					amount=std_to_hom((*bline)(time), amount, ((*(bline_vertex->get_link("loop")))(time).get(bool())), bline_loop );
				ValueNode::Handle vertex_amount_value_node(bline_vertex->get_link("amount"));
				duck->set_point(point);

				for (DuckList::iterator iter = duck_list.begin(); iter != duck_list.end(); ++iter) {
					if ( (*iter)->get_origin_duck()==duck /*&& !duck_is_selected(*iter)*/ )
					{
						ValueNode::Handle duck_value_node = (*iter)->get_value_desc().get_value_node();
						if (duck_value_node)
						{
							ValueNode_Composite::Handle duck_value_node_composite = ValueNode_Composite::Handle::cast_dynamic(duck_value_node);
							ValueNode::Handle sub_duck_value_node =
									duck_value_node_composite && (*iter)->get_value_desc().parent_is_value_desc()
								  ? ValueNode::Handle(duck_value_node_composite->get_link( (*iter)->get_value_desc().get_sub_name() ))
								  : duck_value_node;
							if (sub_duck_value_node)
							{
								if ( ValueNode_BLineCalcTangent::Handle bline_tangent =
										ValueNode_BLineCalcTangent::Handle::cast_dynamic(sub_duck_value_node) )
								{
									if (bline_tangent->get_link("amount") == vertex_amount_value_node)
									{
										synfig::Type &type(bline_tangent->get_type());
										if (type == type_angle)
										{
											Angle angle((*bline_tangent)(time, amount).get(Angle()));
											(*iter)->set_point(Point(Angle::cos(angle).get(), Angle::sin(angle).get()));
											(*iter)->set_rotations(Angle::deg(0)); //hack: rotations are a relative value
										}
										else
										if (type == type_real)
											(*iter)->set_point(Point((*bline_tangent)(time, amount).get(Real()), 0));
										else
										if (type == type_vector)
											(*iter)->set_point((*bline_tangent)(time, amount).get(Vector()));
									}
								} else
								if ( ValueNode_BLineCalcWidth::Handle bline_width =
										ValueNode_BLineCalcWidth::Handle::cast_dynamic(sub_duck_value_node) )
								{
									if (bline_width->get_link("amount") == vertex_amount_value_node)
										(*iter)->set_point(Point((*bline_width)(time, amount).get(Real()), 0));
								}
							}
						}
					}
				}
			}
		}
		// We are moving a tangent handle
		else
		if(duck->get_type() == Duck::TYPE_TANGENT)
		{
			if (duck->get_value_desc().parent_is_value_desc()
			 && duck->get_value_desc().is_value_node() )
			{
				ValueNode_Composite::Handle composite(ValueNode_Composite::Handle::cast_dynamic(duck->get_value_desc().get_value_node()));
				if (composite && composite->get_type() == type_bline_point)
				{
					ValueNode::Handle duck_value_node(composite->get_link(duck->get_value_desc().get_sub_name()));
					// it belongs to a composite and it is a BLinePoint
					if (duck_value_node)
					{
						int index(duck->get_value_desc().get_index());
						Duck::Handle origin_duck = duck->get_origin_duck();
						// Search all the rest of ducks
						for (DuckList::iterator iter = duck_list.begin(); iter != duck_list.end(); ++iter) {
							// if the other duck has the same origin and it is tangent type
							if ( (*iter)->get_origin_duck()==origin_duck && (*iter)->get_type() == Duck::TYPE_TANGENT)
							{
								ValueNode_Composite::Handle iter_composite;
								iter_composite=ValueNode_Composite::Handle::cast_dynamic((*iter)->get_value_desc().get_parent_value_node());
								// and their parent valuenode are the same
								if(iter_composite.get() == composite.get())
								{
									// Check if the other tangent is also selected, in that case
									// it is going to be moved itself so don't update it.
									bool selected=false;
									DuckList::const_iterator iter2;
									for(iter2=selected_ducks.begin(); iter2!=selected_ducks.end(); ++iter2)
										if(*iter == *iter2)
											selected=true;
									if(!selected)
									{
										BLinePoint bp=(*composite)(time).get(BLinePoint());
										int t1_index=composite->get_link_index_from_name("t1");
										int t2_index=composite->get_link_index_from_name("t2");
										if(index==t1_index && (*iter)->get_value_desc().get_index()!=t1_index)
										{
											bp.set_tangent1(duck->get_point());
											Vector t2(bp.get_tangent2());
											(*iter)->set_point(Point(t2));
										}
										else if(index==t2_index && (*iter)->get_value_desc().get_index()!=t2_index)
										{
											// Create a new BLinePoint
											BLinePoint nbp;
											// Terporary set the flags for the new BLinePoint to all split
											nbp.set_split_tangent_both(true);
											// Now we can set the tangents. Tangent2 won't be modified by tangent1
											nbp.set_tangent1(duck->get_point());
											nbp.set_tangent2(bp.get_tangent1());
											// Now update the flags
											nbp.set_split_tangent_radius(bp.get_split_tangent_radius());
											nbp.set_split_tangent_angle(bp.get_split_tangent_angle());
											// Now retrieve the updated tangent2 (which will be stored as t1, see below)
											Vector t1(nbp.get_tangent2());
											(*iter)->set_point(Point(t1));
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
}


void
Duckmatic::start_bezier_drag(const synfig::Vector& offset, float bezier_click_pos)
{
	if(bezier_dragger_)
		bezier_dragger_->begin_bezier_drag(this,offset,bezier_click_pos);
}

void
Duckmatic::translate_selected_bezier(const synfig::Vector& vector)
{
	if(bezier_dragger_)
		bezier_dragger_->bezier_drag(this,vector);
}

bool
Duckmatic::end_bezier_drag()
{
	if(bezier_dragger_)
		return bezier_dragger_->end_bezier_drag(this);
	return false;
}

/*
-- ** -- grid and guide M E T H O D S----------------------------
*/

void
Duckmatic::set_grid_size(const synfig::Vector &s)
{
	if(grid_size!=s)
	{
		grid_size=s;
		signal_grid_changed().emit();
	}
}

void
Duckmatic::set_grid_color(const synfig::Color &c)
{
	if(grid_color!=c)
	{
		grid_color=c;
		signal_grid_changed().emit();
	}
}

void
Duckmatic::set_grid_snap(bool x)
{
	if(grid_snap!=x)
	{
		grid_snap=x;
		signal_grid_changed().emit();
	}
}

void
Duckmatic::set_guide_snap(bool x)
{
	if(guide_snap!=x)
	{
		guide_snap=x;
		signal_grid_changed().emit();
	}
}

void
Duckmatic::set_guides_color(const synfig::Color &c)
{
	if(guides_color!=c)
	{
		guides_color=c;
		signal_grid_changed().emit();
	}
}
double
Duckmatic::calculate_distance_from_guide(const Guide& guide, const Point& point)const
{
	return std::fabs((cos(guide.angle.get())*(guide.point[1]-point[1])) - (sin(guide.angle.get())*(guide.point[0] - point[0])));
}


Duckmatic::GuideList::iterator
Duckmatic::find_guide(synfig::Point pos, float radius, Guide** second_best_guide_match)
{
	GuideList::iterator iter,best(guide_list_.end());
	if (second_best_guide_match != nullptr)
		*second_best_guide_match = nullptr;

	float dist(radius);
	float second_dist(radius);

	for (iter=guide_list_.begin();iter!=guide_list_.end();++iter) {
		float amount = calculate_distance_from_guide(*iter,pos);
		if (amount < dist) {
			if (second_best_guide_match != nullptr && best != guide_list_.end()) {
				*second_best_guide_match = &(*best);
				second_dist = dist;
			}
			dist = amount;
			best = iter;
		} else if (second_best_guide_match != nullptr && amount < second_dist) {

			// Is distance equal best match? It could be the current best match guide or another guide with same distance.
			// If the former, skip it.
			if (approximate_equal(amount, dist)) {
				// If it is a equivalent linear equation of the current best match, ignore it
				// equivalent linear equation : same slope/angle, and the pivot point matches the other equation

				// same slope?
				if (approximate_zero(fmod(Angle::rad(best->angle - iter->angle).get(), Angle::rad(Angle::one()).get()))) {
					// y - y0 == slope * (x - x0)
					if (approximate_equal(best->point[1] - iter->point[1], tan(iter->angle.get()) * (best->point[0] - iter->point[0])))
						continue;
				}
			}
			*second_best_guide_match = &(*iter);
			second_dist = amount;
		}
	}
	return best;
}

Point
Duckmatic::snap_point_to_grid(const synfig::Point& x)const
{
	Point ret(x);
	float radius(0.1/zoom);

	GuideList::const_iterator guide;
	Guide* second_best_guide_match = nullptr;
	guide = find_guide(ret,radius, &second_best_guide_match);
	bool has_guide = guide != guide_list_.end();

	if(get_grid_snap())
	{
		Point snap(
			floor(ret[0]/get_grid_size()[0]+0.5)*get_grid_size()[0],
			floor(ret[1]/get_grid_size()[1]+0.5)*get_grid_size()[1]);
		float distance_from_guide = calculate_distance_from_guide(*guide, ret);
		if(std::fabs(snap[0]-ret[0])<=radius && (!has_guide || std::fabs(snap[0]-ret[0])<=distance_from_guide))
			ret[0]=snap[0],has_guide=false;
		if(std::fabs(snap[1]-ret[1])<=radius && (!has_guide || std::fabs(snap[1]-ret[1])<=distance_from_guide))
			ret[1]=snap[1],has_guide=false;
	}

	if(guide_snap && has_guide)
	{
		bool possible_intersection_close = second_best_guide_match != nullptr && (second_best_guide_match->angle != guide->angle);
		if (possible_intersection_close){
			float guides_intersection_x = 0, guides_intersection_y = 0;
			if (guide->angle != synfig::Angle::deg(90) && second_best_guide_match->angle != synfig::Angle::deg(90)){
				float slope_best = tan(guide->angle.get()), slope_second_best_guide_match = tan(second_best_guide_match->angle.get());
				float bestX = guide->point[0], bestY = guide->point[1], lastBestX = second_best_guide_match->point[0], lastBestY = second_best_guide_match->point[1];
				guides_intersection_x = ( bestY - lastBestY + slope_second_best_guide_match*lastBestX - slope_best*bestX )/(slope_second_best_guide_match - slope_best);
				guides_intersection_y = slope_best*(guides_intersection_x - bestX) + bestY;
				possible_intersection_close = (pow(pow(ret[1] - guides_intersection_y, 2.0) + pow(ret[0] - guides_intersection_x, 2.0), 0.5)) <= radius*3;
			} else if (guide->angle != second_best_guide_match->angle){
				if (synfig::Angle::deg(guide->angle).get() == 90){
					guides_intersection_x = guide->point[0];
					guides_intersection_y = tan(second_best_guide_match->angle.get())*(second_best_guide_match->point[0]) + second_best_guide_match->point[1];
				} else if (synfig::Angle::deg(second_best_guide_match->angle).get() == 90){
					guides_intersection_x = second_best_guide_match->point[0];
					guides_intersection_y = tan(guide->angle.get())*(guide->point[0]) + guide->point[1];
				}
				possible_intersection_close = (pow(pow(ret[1] - guides_intersection_y, 2.0) + pow(ret[0] - guides_intersection_x, 2.0), 0.5)) <= radius*3;
			}
			if (possible_intersection_close) {
				ret[0] = guides_intersection_x;
				ret[1] = guides_intersection_y;
			}
		}
		if (!possible_intersection_close && guide->angle == synfig::Angle::deg(90))
			ret[0] = guide->point[0];
		else if (!possible_intersection_close && guide->angle == synfig::Angle::deg(0))
			ret[1] = guide->point[1];
		else if (!possible_intersection_close){
			float slope1 = tan(guide->angle.get());
			float slope2 = -1.0/slope1;
			float x1 = guide->point[0], y1 = guide->point[1];
			ret[0] = (x[1] - y1 + slope1*x1 - slope2*x[0])/(slope1 - slope2);
			ret[1] = slope1*(ret[0] - x1) + y1;
		}
	}

	if(axis_lock)
	{
		ret-=drag_offset_;
		if(std::fabs(ret[0])<std::fabs(ret[1]))
			ret[0]=0;
		else
			ret[1]=0;
		ret+=drag_offset_;
	}

	return ret;
}

/*
-- ** -- S I G N A L S  M E T H O D S----------------------------
*/
void
Duckmatic::signal_user_click_selected_ducks(int button)
{
	const DuckList ducks(get_selected_ducks());
	DuckList::const_iterator iter;

	for(iter=ducks.begin();iter!=ducks.end();++iter)
	{
		(*iter)->signal_user_click(button)();
	}
}

void
Duckmatic::signal_edited_duck(const Duck::Handle& duck, bool moving)
{
	if (moving && !duck->get_edit_immediatelly()) return;

	if (duck->get_type() == Duck::TYPE_ANGLE)
	{
		if(!duck->signal_edited()(*duck))
		{
			throw String("Bad edit");
		}
	}
	else if (App::restrict_radius_ducks &&
			 duck->is_radius())
	{
		Point point(duck->get_point());
		bool changed = false;

		if (point[0] < 0)
		{
			point[0] = 0;
			changed = true;
		}
		if (point[1] < 0)
		{
			point[1] = 0;
			changed = true;
		}

		if (changed) duck->set_point(point);

		if(!duck->signal_edited()(*duck))
		{
			throw String("Bad edit");
		}
	}
	else
	{
		if(!duck->signal_edited()(*duck))
		{
			throw String("Bad edit");
		}
	}
}


void
Duckmatic::signal_edited_selected_ducks(bool moving)
{
	const DuckList ducks(get_selected_ducks());
	DuckList::const_iterator iter;

	synfig::GUIDSet old_set(selected_ducks);

	// If we have more than 20 things to move, then display
	// something to explain that it may take a moment
	//std::shared_ptr<OneMoment> wait; if(ducks.size()>20)wait = std::make_shared<OneMoment>();
	for(iter=ducks.begin();iter!=ducks.end();++iter)
	{
		try
		{
			if (!moving || (*iter)->get_edit_immediatelly())
				signal_edited_duck(*iter);
		}
		catch (const String&)
		{
			selected_ducks=old_set;
			synfig::warning("signals must not throw exceptions");
			// signals must not throw exceptions!!!
			//throw;
		}
	}
	selected_ducks=old_set;
}

bool
Duckmatic::on_duck_changed(const studio::Duck &duck,const synfigapp::ValueDesc& value_desc)
{
	bool lock_animation = get_lock_animation_mode();
	synfig::Point value=duck.get_point();
	synfig::Type &type(value_desc.get_value_type());
	if (type == type_real)
	{
		if (value_desc.parent_is_value_node())
		{
			etl::handle<ValueNode_Bone> bone_node =
				etl::handle<ValueNode_Bone>::cast_dynamic(
					value_desc.get_parent_value_node());
			if (bone_node)
			{
				int index1 = bone_node->get_link_index_from_name("scalex");
				int index2 = bone_node->get_link_index_from_name("scalelx");
				int angleIndex = bone_node->get_link_index_from_name("angle");
				if (value_desc.get_index() == index1
				 || value_desc.get_index() == index2)
				{
					//Bone bone((*bone_node)(get_time()).get(Bone()));
					//Real prev_duck_length = bone.get_length() * bone.get_scalex() * bone.get_scalex();
					//Real duck_length = duck.get_point().mag();
					//Real prev_length = value_desc.get_value(get_time()).get(Real());
					//Real new_length = prev_length == 0.f || prev_duck_length == 0.f
					//                ? duck_length
					//                : prev_length * duck_length / prev_duck_length;
					Real new_length = duck.get_point().mag();
					Angle angle = (*bone_node->get_link(angleIndex))(get_time()).get(Angle());
					angle += duck.get_rotations();
					return canvas_interface->change_value(synfigapp::ValueDesc(bone_node, angleIndex, value_desc.get_parent_desc()), angle, lock_animation)
						&& canvas_interface->change_value(value_desc, new_length, lock_animation);
				}
			}
		}

		// Zoom duck value (PasteCanvas and Zoom layers) should be
		// converted back from exponent to normal
		if( duck.get_exponential() ) {
			return canvas_interface->change_value(value_desc,log(value.mag()),lock_animation);
		} else {
			return canvas_interface->change_value(value_desc,value.mag(),lock_animation);
		}
	}
	else
	if (type == type_angle)
		//return canvas_interface->change_value(value_desc,Angle::tan(value[1],value[0]),lock_animation);
		return canvas_interface->change_value(value_desc, value_desc.get_value(get_time()).get(Angle()) + duck.get_rotations(),lock_animation);
	else
	if (type == type_transformation)
	{
		if ( duck.get_move_origin()
		  && duck.get_origin_duck()
		  && duck.get_value_desc().is_valid()
		  && duck.get_value_desc().parent_is_layer()
		  && Layer_PasteCanvas::Handle::cast_dynamic(duck.get_value_desc().get_layer())
		  && duck.get_value_desc().get_param_name() == "origin" )
		{
			Point origin = duck.get_value_desc().get_value(get_time()).get(Point());
			Transformation transformation = duck.get_origin_duck()->get_value_desc().get_value(get_time()).get(Transformation());
			Point delta_offset = duck.get_origin_duck()->get_point() - transformation.offset;
			Point delta_origin = transformation.back_transform(delta_offset, false);
			transformation.offset += delta_offset;
			origin += delta_origin;
			return canvas_interface->change_value(duck.get_value_desc(), origin, lock_animation)
				&& canvas_interface->change_value(duck.get_origin_duck()->get_value_desc(), transformation, lock_animation);
		}
		else
		{
			Transformation transformation = value_desc.get_value(get_time()).get(Transformation());
			switch(duck.get_type()) {
			case Duck::TYPE_POSITION:
				transformation.offset = value;
				break;
			case Duck::TYPE_ANGLE:
				transformation.angle += duck.get_rotations();
				break;
			case Duck::TYPE_SKEW:
				transformation.skew_angle += duck.get_rotations();
				break;
			case Duck::TYPE_SCALE:
				transformation.scale = transformation.scale.multiply_coords(duck.get_point());
				break;
			case Duck::TYPE_SCALE_X:
				transformation.scale[0] *= duck.get_point()[0];
				break;
			case Duck::TYPE_SCALE_Y:
				transformation.scale[1] *= duck.get_point()[0];
				break;
			default:
				break;
			}

			return canvas_interface->change_value(value_desc, transformation, lock_animation);
		}
		return false;
	}
	else
	if (type == type_bline_point)
	{
		BLinePoint point = value_desc.get_value(get_time()).get(BLinePoint());
		switch(duck.get_type()) {
		case Duck::TYPE_VERTEX:
			point.set_vertex(duck.get_point());
			break;
		case Duck::TYPE_WIDTH:
			point.set_width(duck.get_point().mag());
			break;
		case Duck::TYPE_TANGENT:
			if (duck.get_scalar() < 0.f)
				point.set_tangent1(duck.get_point());
			else
			if (point.get_merge_tangent_both())
				point.set_tangent1(duck.get_point());
			else
			if (point.get_split_tangent_both())
				point.set_tangent2(duck.get_point());
			else
			if (point.get_split_tangent_angle())
			{
				point.set_tangent1( Point(duck.get_point().mag(), point.get_tangent1().angle()) );
				point.set_tangent2(duck.get_point());
			}
			else
			{
				point.set_tangent1( Point(point.get_tangent1().mag(), duck.get_point().angle()) );
				point.set_tangent2(duck.get_point());
			}
			break;
		default:
			break;
		}

		return canvas_interface->change_value(value_desc, point, lock_animation);
	}

	return canvas_interface->change_value(value_desc,value,lock_animation);
}

void
Duckmatic::connect_signals(const Duck::Handle& duck, const synfigapp::ValueDesc& value_desc, CanvasView& canvas_view)
{
	duck->signal_edited().connect(
		sigc::bind(
			sigc::mem_fun(
				*this,
				&studio::Duckmatic::on_duck_changed),
			value_desc));
	duck->signal_user_click(2).connect(
		sigc::bind(
			sigc::bind(
				sigc::bind(
					sigc::mem_fun(
						canvas_view,
						&studio::CanvasView::popup_param_menu),
					false),
				1.0f),
			value_desc));
}

/*
-- ** -- DUCK BEZIER STOKE ADD/ERASE/FIND...  M E T H O D S----------------------------
*/
void
Duckmatic::add_duck(const Duck::Handle& duck)
{
	//if(!duck_map.count(duck->get_guid()))
	{
		if(duck_data_share_map.count(duck->get_data_guid()))
		{
			duck->set_shared_point(duck_data_share_map[duck->get_data_guid()]);
		}
		else
		{
			std::shared_ptr<synfig::Point> point = std::make_shared<Point>(duck->get_point());
			duck->set_shared_point(point);
			duck_data_share_map[duck->get_data_guid()]=point;
		}

		duck_map.insert(duck);
	}

	last_duck_guid=duck->get_guid();
}

void
Duckmatic::add_bezier(const Bezier::Handle& bezier)
{
	bezier_list_.push_back(bezier);
}

void
Duckmatic::add_stroke(std::shared_ptr<std::list<synfig::Point>> stroke_point_list, const synfig::Color& color)
{
	assert(stroke_point_list);

	for (const auto& stroke : stroke_list_)	{
		if (stroke->stroke_data == stroke_point_list)
			return;
	}

	etl::handle<Stroke> stroke(new Stroke());

	stroke->stroke_data=stroke_point_list;
	stroke->color=color;

	stroke_list_.push_back(stroke);
}

void
Duckmatic::add_persistent_stroke(std::shared_ptr<std::list<synfig::Point>> stroke_point_list, const synfig::Color& color)
{
	add_stroke(stroke_point_list,color);
	persistent_stroke_list_.push_back(stroke_list_.back());
}

void
Duckmatic::clear_persistent_strokes()
{
	persistent_stroke_list_.clear();
	redo_stroke_list_.clear();
}

void
Duckmatic::set_show_persistent_strokes(bool x)
{
	if(x!=show_persistent_strokes)
	{
		show_persistent_strokes=x;
		if(x)
			stroke_list_=persistent_stroke_list_;
		else
			stroke_list_.clear();
	}
}

void
Duckmatic::erase_duck(const Duck::Handle& duck)
{
	duck_map.erase(duck->get_guid());
}

Duck::Handle
Duckmatic::find_similar_duck(Duck::Handle duck)
{
	DuckMap::const_iterator iter(duck_map.find(duck->get_guid()));
	if(iter!=duck_map.end())
		return iter->second;
	return 0;

/*  std::list<Duck::Handle>::reverse_iterator iter;

	for(iter=duck_list_.rbegin();iter!=duck_list_.rend();++iter)
	{
		if(*iter!=duck && **iter==*duck)
		{
			//synfig::info("Found similar duck! (iter:%08x vs. duck:%08x)",iter->get(), duck.get());
			return *iter;
		}
	}
	return 0;
*/
}

Duck::Handle
Duckmatic::add_similar_duck(Duck::Handle duck)
{
	Duck::Handle similar(find_similar_duck(duck));
	if(!similar)
	{
		add_duck(duck);
		return duck;
	}
	return similar;
}

void
Duckmatic::erase_bezier(const Bezier::Handle& bezier)
{
	for(auto iter = bezier_list_.begin(); iter != bezier_list_.end(); ++iter)
	{
		if(*iter==bezier)
		{
			bezier_list_.erase(iter);
			return;
		}
	}
	synfig::warning("Unable to find bezier to erase!");
}

Duck::Handle
Duckmatic::last_duck()const
{
	DuckMap::const_iterator iter(duck_map.find(last_duck_guid));
	if(iter!=duck_map.end())
		return iter->second;
	return 0;
}

Duckmatic::Bezier::Handle
Duckmatic::last_bezier()const
{
	return bezier_list_.back();
}

Duck::Handle
Duckmatic::find_duck(synfig::Point point, synfig::Real radius, Duck::Type type)
{
	if(radius==0)radius=10000000;

	if(type==Duck::TYPE_DEFAULT)
		type=get_type_mask();

	Real closest(10000000);
	Duck::Handle ret;
	std::vector<Duck::Handle> ret_vector;

	DuckMap::const_iterator iter;

	for(iter=duck_map.begin();iter!=duck_map.end();++iter)
	{
		const Duck::Handle& duck(iter->second);

		if(duck->get_ignore() ||
			(duck->get_type() && !(type & duck->get_type())))
			continue;

		Real dist((duck->get_trans_point()-point).mag_squared());

		bool equal;
		equal=fabs(dist-closest)<0.0000001?true:false;
		if(dist<closest || equal)
		{
			// if there are two ducks at the "same" position, keep track of them
			if(equal)
			{
				// if we haven't any duck stored keep track of last found
				if(!ret_vector.size())
					ret_vector.push_back(ret);
				// and also keep track of the one on the same place
				ret_vector.push_back(duck);
			}
			// we have another closer duck then discard the stored
			else if (ret_vector.size())
				ret_vector.clear();
			closest=dist;
			ret=duck;
		}
	}

	// Prioritization of duck selection when are in the same place.
	bool found(false);
	if(ret_vector.size())
	{
		unsigned int i;
		for(i=0; i<ret_vector.size();i++)
			if(ret_vector[i]->get_type() & Duck::TYPE_WIDTHPOINT_POSITION)
			{
				ret=ret_vector[i];
				found=true;
				break;
			}
		if(!found)
			for(i=0; i<ret_vector.size();i++)
				if(ret_vector[i]->get_type() & Duck::TYPE_WIDTH)
				{
					ret=ret_vector[i];
					found=true;
					break;
				}
		if(!found)
			for(i=0; i<ret_vector.size();i++)
				if(ret_vector[i]->get_type() & Duck::TYPE_RADIUS)
				{
					ret=ret_vector[i];
					found=true;
					break;
				}
		if(!found)
			for(i=0; i<ret_vector.size();i++)
				if(ret_vector[i]->get_type() & Duck::TYPE_FIRST_VERTEX)
				{
					ret=ret_vector[i];
					found=true;
					break;
				}
		if(!found)
			for(i=0; i<ret_vector.size();i++)
				if(ret_vector[i]->get_type() & Duck::TYPE_VERTEX)
				{
					ret=ret_vector[i];
					found=true;
					break;
				}
		if(!found)
			for(i=0; i<ret_vector.size();i++)
				if(ret_vector[i]->get_type() & Duck::TYPE_TANGENT)
				{
					ret=ret_vector[i];
					found=true;
					break;
				}
		if(!found)
			for(i=0; i<ret_vector.size();i++)
				if(ret_vector[i]->get_type() & Duck::TYPE_POSITION)
				{
					ret=ret_vector[i];
					found=true;
					break;
				}
	}
	if(radius==0 || closest<radius*radius)
		return ret;

	return 0;
}

Duckmatic::Bezier::Handle
Duckmatic::find_bezier(synfig::Point point, synfig::Real radius,float* location)
{
	return find_bezier(point,radius,radius,location);
}

Duckmatic::Bezier::Handle
Duckmatic::find_bezier(synfig::Point pos, synfig::Real scale, synfig::Real radius, float* location)
{
	if(radius==0)radius=10000000;
	Real closest(10000000);
	Bezier::Handle ret;

	bezier<Point>	curve;

	Real	d,step;
	float	time = 0;
	float	best_time = 0;

	for (const auto& item : bezier_list()) {
		curve[0] = item->p1->get_trans_point();
		curve[1] = item->c1->get_trans_point();
		curve[2] = item->c2->get_trans_point();
		curve[3] = item->p2->get_trans_point();
		curve.sync();

#if 0
		// I don't know why this doesn't work
		time=curve.find_closest(pos,6);
		d=((curve(time)-pos).mag_squared());

#else
		//set the step size based on the size of the picture
		d = (curve[1] - curve[0]).mag() + (curve[2]-curve[1]).mag() + (curve[3]-curve[2]).mag();

		step = d/(2*scale); //want to make the distance between lines happy

		step = std::max(step,0.01); //100 samples should be plenty
		step = std::min(step,0.1); //10 is minimum

		d = find_closest(curve,pos,step,&closest,&time);
#endif

		if(d < closest)
		{
			closest = d;
			ret = item;
			best_time=time;
		}
	}

	if(closest < radius*radius)
	{
		if(location)
			*location = best_time;  // We need to square-root this because we were dealing with squared distances

		return ret;
	}

	return 0;
}


/*
-- ** -- Duckmatic sketch M E T H O D S----------------------------
*/
bool
Duckmatic::save_sketch(const synfig::filesystem::Path& filename) const
{
	ChangeLocale change_locale(LC_NUMERIC, "C");
	std::ofstream file(filename.c_str());

	if(!file)return false;

	file<<"SKETCH"<<std::endl;

	for (const auto& persistent_stroke : persistent_stroke_list_) {
		file<<"C "
			<< persistent_stroke->color.get_r() << ' '
			<< persistent_stroke->color.get_g() << ' '
			<< persistent_stroke->color.get_b()
		<< std::endl;
		for (const auto& point : *persistent_stroke->stroke_data) {
			file<<"V "
				<< point[0] << ' '
				<< point[1]
			<< std::endl;
		}
	}
	if(!file)return false;
	sketch_filename_=filename;
	signal_sketch_saved_();
	return true;
}

bool
Duckmatic::load_sketch(const synfig::filesystem::Path& filename)
{
	ChangeLocale change_locale(LC_NUMERIC, "C");
	std::ifstream file(filename.c_str());

	if(!file)
		return false;

	std::string line;
	getline(file,line);

	if(line!="SKETCH")
	{
		synfig::error("Not a sketch");
		return false;
	}

	std::shared_ptr<std::list<synfig::Point>> stroke_data;

	while(file)
	{
		getline(file,line);

		if(line.empty())
			continue;

		switch(line[0])
		{
		case 'C':
		case 'c':
			{
				stroke_data = std::make_shared<std::list<synfig::Point>>();
				float r,g,b;
				if(!strscanf(line,"C %f %f %f",&r, &g, &b))
				{
					synfig::warning("Bad color line \"%s\"",line.c_str());
					r=0;g=0;b=0;
				}
				add_persistent_stroke(stroke_data, synfig::Color(r,g,b));
			}
			break;
		case 'V':
		case 'v':
			if(!stroke_data)
			{
				stroke_data = std::make_shared<std::list<synfig::Point>>();
				add_persistent_stroke(stroke_data, synfig::Color(0,0,0));
			}
			float x,y;
			if(!strscanf(line,"V %f %f",&x, &y))
				synfig::warning("Bad vertex \"%s\"",line.c_str());
			else
				stroke_data->push_back(synfig::Vector(x,y));
			break;
		default:
			synfig::warning("Unexpected sketch token '%c'",line[0]);
			break;
		}
	}

	sketch_filename_=filename;
	return true;
}


void
Duckmatic::add_ducks_layers(synfig::Canvas::Handle canvas, std::set<synfig::Layer::Handle>& selected_layer_set, CanvasView::Handle canvas_view, synfig::TransformStack& transform_stack, int *out_transform_count)
{
	int transforms(0);

#define QUEUE_REBUILD_DUCKS     sigc::mem_fun(*canvas_view,&CanvasView::queue_rebuild_ducks)

	if(!canvas)
	{
		synfig::warning("Duckmatic::add_ducks_layers(): Layer doesn't have canvas set");
		return;
	}
	for(Canvas::iterator iter(canvas->begin());iter!=canvas->end();++iter)
	{
		Layer::Handle layer(*iter);

		if(selected_layer_set.count(layer))
		{
			if(!curr_transform_stack_set)
			{
				curr_transform_stack_set=true;
				curr_transform_stack=transform_stack;
			}

			// This layer is currently selected.
			duck_changed_connections.push_back(layer->signal_changed().connect(QUEUE_REBUILD_DUCKS));

			// do the bounding box thing
			synfig::Rect& bbox = canvas_view->get_bbox();

			// special calculations for Layer_PasteCanvas
			Layer_PasteCanvas::Handle layer_pastecanvas( Layer_PasteCanvas::Handle::cast_dynamic(layer) );
			synfig::Rect layer_bounds = layer_pastecanvas
									  ? layer_pastecanvas->get_bounding_rect_context_dependent(canvas_view->get_context_params())
									  : layer->get_bounding_rect();

			bbox|=transform_stack.perform(layer_bounds);

			// Grab the layer vocabulary
			Layer::Vocab vocab=layer->get_param_vocab();
			Layer::Vocab::iterator iter;

			for (iter = vocab.begin(); iter != vocab.end(); ++iter) {
				if(!iter->get_hidden() && !iter->get_invisible_duck())
				{
					synfigapp::ValueDesc value_desc(layer,iter->get_name());
					add_to_ducks(value_desc,canvas_view,transform_stack,&*iter);
					if(value_desc.is_value_node())
						duck_changed_connections.push_back(value_desc.get_value_node()->signal_changed().connect(QUEUE_REBUILD_DUCKS));
				}
			}
		}

		if(layer->active())
		{
			Transform::Handle trans(layer->get_transform());
			if(trans)
			{
				transform_stack.push(trans);
				transforms++;
			}
		}

		// If this is a paste canvas layer, then we need to
		// descend into it
		if(Layer_PasteCanvas::Handle layer_pastecanvas = Layer_PasteCanvas::Handle::cast_dynamic(layer))
		{
			transform_stack.push_back(
				new Transform_Matrix(
					layer->get_guid(),
					layer_pastecanvas->get_summary_transformation().get_matrix()
				)
			);

			Canvas::Handle child_canvas(layer->get_param("canvas").get(Canvas::Handle()));

			// keep stack
			if ( etl::handle<Layer_FilterGroup>::cast_dynamic(layer_pastecanvas)
			  && layer_pastecanvas->get_amount() > 0.5 )
			{
				transforms++;
				add_ducks_layers(child_canvas,selected_layer_set,canvas_view,transform_stack, &transforms);
			}
			else
			{
				add_ducks_layers(child_canvas,selected_layer_set,canvas_view,transform_stack);
				transform_stack.pop();
			}
		}
	}

	if (out_transform_count)
	{
		// keep stack and return count transforms ...
		*out_transform_count += transforms;
	}
	else
	{
		// ... or remove all of the transforms we have added
		while(transforms--) { transform_stack.pop(); }
	}

#undef QUEUE_REBUILD_DUCKS
}

/*
-- ** -- add_to_ducks GIANT  M E T H O D S-------------------------------------
-- ** -- -----------------------------------------------------------------------
-- ** -- S H O U L D  B E  S I M P L I F  I E D---------------------------------
-- ** -- -----------------------------------------------------------------------
---**-----------------------TODO-Must be simplified!(1500 lines length)-------
-- ** -- -----------------------------------------------------------------------
*/
bool
Duckmatic::add_to_ducks(const synfigapp::ValueDesc& value_desc, CanvasView::Handle canvas_view, const synfig::TransformStack& transform_stack, const synfig::ParamDesc* param_desc)
{
	synfig::Type &type=value_desc.get_value_type();
#define REAL_COOKIE		reinterpret_cast<synfig::ParamDesc*>(28)

	if (type == type_real)
	{
		if(!param_desc || param_desc==REAL_COOKIE || !param_desc->get_origin().empty())
		{
			Duck::Handle duck = new Duck();
			set_duck_value_desc(*duck, value_desc, transform_stack);
			duck->set_radius(true);
			duck->set_type(Duck::TYPE_RADIUS);

			// put the duck on the right hand side of the center
			// Zoom parameter value (PasteCanvas and Zoom layers)
			// should be represented as exponent
			if ( param_desc && param_desc!=REAL_COOKIE && param_desc->get_exponential() )
			{
				duck->set_point(Point(exp(value_desc.get_value(get_time()).get(Real())), 0));
				duck->set_exponential(param_desc->get_exponential());
			} else {
				duck->set_point(Point(value_desc.get_value(get_time()).get(Real()), 0));
				duck->set_exponential(false);
			}

			if(value_desc.is_value_node())
			{
				// If the ValueNode can be directly manipulated,
				// then set it as so.
				duck->set_editable(synfigapp::is_editable(value_desc.get_value_node()));
			}
			else
			{
				duck->set_editable(true);
			}

			if(param_desc && param_desc!=REAL_COOKIE)
			{
				if(!param_desc->get_origin().empty())
				{
					synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin());
					/*
					duck->set_origin(value_desc_origin.get_value(get_time()).get(synfig::Point()));
					*/
					add_to_ducks(value_desc_origin,canvas_view, transform_stack);

					Layer::Handle layer=value_desc.get_layer();
					if(Layer_PasteCanvas::Handle::cast_dynamic(layer))
					{
						Vector focus(layer->get_param("focus").get(Vector()));
						duck->set_origin(last_duck()->get_point() + focus);
					}
					else
						duck->set_origin(last_duck());
				}
				duck->set_scalar(param_desc->get_scalar());
			}

			duck->signal_edited().clear(); // value_desc.get_value_type() == type_real:
			duck->signal_edited().connect(
				sigc::bind(
					sigc::mem_fun(
						*this,
						&studio::Duckmatic::on_duck_changed),
					value_desc));

			duck->signal_user_click(2).connect(
				sigc::bind(
					sigc::bind(
						sigc::bind(
							sigc::mem_fun(
								*canvas_view,
								&studio::CanvasView::popup_param_menu),
							false),
						0.0f),
					value_desc));

			add_duck(duck);

			return true;
		}
	}
	else
	if (type == type_angle)
	{
		if(!param_desc || param_desc==REAL_COOKIE || !param_desc->get_origin().empty())
		{
			Duck::Handle duck = new Duck();
			duck->set_type(Duck::TYPE_ANGLE);
			set_duck_value_desc(*duck, value_desc, transform_stack);
			synfig::Angle angle;

			angle=value_desc.get_value(get_time()).get(Angle());
			duck->set_point(Point(Angle::cos(angle).get(),Angle::sin(angle).get()));
			if(value_desc.is_value_node())
			{
				ValueNode::Handle value_node=value_desc.get_value_node();
				//duck->set_name(strprintf("%x",value_node.get()));

				// If the ValueNode can be directly manipulated,
				// then set it as so.
				duck->set_editable(synfigapp::is_editable(value_desc.get_value_node()));
			}
			else
			{
				//angle=(value_desc.get_value().get(Angle()));
				//duck->set_point(Point(Angle::cos(angle).get(),Angle::sin(angle).get()));
				//duck->set_name(strprintf("%x",value_desc.get_layer().get())+value_desc.get_param_name());
				duck->set_editable(true);
			}

			if(param_desc && param_desc!=REAL_COOKIE)
			{
				if(!param_desc->get_origin().empty())
				{
					synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin());
					/*
					duck->set_origin(value_desc_origin.get_value(get_time()).get(synfig::Point()));
					*/
					add_to_ducks(value_desc_origin,canvas_view, transform_stack);
					duck->set_origin(last_duck());
				}
				duck->set_scalar(param_desc->get_scalar());
			}

			duck->signal_edited().clear(); // value_desc.get_value_type() == type_angle:
			duck->signal_edited().connect(
				sigc::bind(
					sigc::mem_fun(
						*this,
						&studio::Duckmatic::on_duck_changed),
					value_desc));

			duck->signal_user_click(2).connect(
				sigc::bind(
					sigc::bind(
						sigc::bind(
							sigc::mem_fun(
								*canvas_view,
								&studio::CanvasView::popup_param_menu),
							false),
						0.0f),
					value_desc));

			add_duck(duck);

			return true;
		}
	}
	else
	if (type == type_vector)
	{
		Layer_PasteCanvas::Handle layer;
		if (value_desc.parent_is_layer())
			layer = Layer_PasteCanvas::Handle::cast_dynamic(value_desc.get_layer());
		if (!layer) {
			Duck::Handle duck = new Duck();
			set_duck_value_desc(*duck, value_desc, transform_stack);
			ValueNode_Composite::Handle blinepoint_value_node;
			int index;
			bool done(false);
			if(value_desc.parent_is_linkable_value_node()
				&&
				value_desc.get_parent_value_node()->get_type() == type_bline_point)
			{
				blinepoint_value_node=ValueNode_Composite::Handle::cast_dynamic(value_desc.get_parent_value_node());
				if(blinepoint_value_node)
				{
					index=blinepoint_value_node->get_link_index_from_name("t2");
					if(index==value_desc.get_index())
					{
						BLinePoint bp=(*blinepoint_value_node)(get_time()).get(BLinePoint());
						Vector t2=bp.get_tangent2();
						duck->set_point(t2);
						done=true;
					}
				}
			}
			if(!done)
				duck->set_point(value_desc.get_value(get_time()).get(Point()));

			if(value_desc.is_value_node())
			{
				// if the vertex is converted to 'bone influence', add the bones' ducks
				if (ValueNode_BoneInfluence::Handle bone_influence_vertex_value_node =
					ValueNode_BoneInfluence::Handle::cast_dynamic(value_desc.get_value_node()))
					add_to_ducks(synfigapp::ValueDesc(bone_influence_vertex_value_node,
													  bone_influence_vertex_value_node->get_link_index_from_name("bone_weight_list")),
								 canvas_view, transform_stack);

				// If the ValueNode can be directly manipulated,
				// then set it as so.
				duck->set_editable(synfigapp::is_editable(value_desc.get_value_node()));
			}
			else
			{
				//duck->set_point(value_desc.get_value().get(Point()));
				//duck->set_name(strprintf("%x",value_desc.get_layer().get())+value_desc.get_param_name());
				duck->set_editable(true);
			}

			// If we were passed a parameter description
			if(param_desc)
			{
				if(!param_desc->get_connect().empty())
				{
					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))!=duck_map.end())
					{
						connect_duck=duck_map[calc_duck_guid(value_desc_origin, transform_stack)];
					}
					else
					{
						add_to_ducks(value_desc_origin,canvas_view, transform_stack);
						connect_duck=last_duck();
					}
					duck->set_connect_duck(connect_duck);
				}
				if(!param_desc->get_box().empty())
				{
					synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_box());
					add_to_ducks(value_desc_origin,canvas_view, transform_stack);
					duck->set_box_duck(last_duck());
				}

				// If we have an origin
				if(!param_desc->get_origin().empty())
				{
					synfigapp::ValueDesc value_desc_origin(value_desc.get_layer(),param_desc->get_origin());
					/*
					duck->set_origin(value_desc_origin.get_value(get_time()).get(synfig::Point()));
					*/
					add_to_ducks(value_desc_origin,canvas_view, transform_stack);
					duck->set_origin(last_duck());
					duck->set_type(Duck::TYPE_VERTEX);
				}
				else
					duck->set_type(Duck::TYPE_POSITION);

				duck->set_scalar(param_desc->get_scalar());
			}
			else
				duck->set_type(Duck::TYPE_POSITION);

			duck->signal_edited().clear(); // value_desc.get_value_type() == type_vector:
			duck->signal_edited().connect(
				sigc::bind(
					sigc::mem_fun(
						*this,
						&studio::Duckmatic::on_duck_changed),
					value_desc));

			duck->signal_user_click(2).connect(
				sigc::bind(
					sigc::bind(
						sigc::bind(
							sigc::mem_fun(
								*canvas_view,
								&studio::CanvasView::popup_param_menu),
							false),
						1.0f),
					value_desc));

			add_duck(duck);

			return true;
		}
	}
	else
	if (type == type_transformation)
	{
		if (value_desc.parent_is_layer() && param_desc)
		{
			Layer_PasteCanvas::Handle layer = Layer_PasteCanvas::Handle::cast_dynamic(value_desc.get_layer());
			if (layer)
			{
				synfigapp::ValueDesc origin_value_desc(value_desc.get_layer(), "origin");
				Transformation transformation = value_desc.get_value(get_time()).get(Transformation());

				bool editable = !value_desc.is_value_node()
					|| synfigapp::is_editable(value_desc.get_value_node());
				bool origin_editable = !origin_value_desc.is_value_node()
					|| synfigapp::is_editable(origin_value_desc.get_value_node());
				origin_editable = origin_editable && editable;
				Point axis_x(1, transformation.angle);
				Point axis_y(1, transformation.angle + Angle::deg(90.f) + transformation.skew_angle);

				Point screen_offset = transform_stack.perform(transformation.offset);
				Point screen_axis_x = transform_stack.perform(transformation.offset + axis_x) - screen_offset;
				Point screen_axis_y = transform_stack.perform(transformation.offset + axis_y) - screen_offset;
				Real scalar_x = screen_axis_x.mag();
				if (scalar_x > 0.0) scalar_x = 1.0/scalar_x;
				Real scalar_y = screen_axis_y.mag();
				if (scalar_y > 0.0) scalar_y = 1.0/scalar_y;
				scalar_x /= zoom;
				scalar_y /= zoom;
				Real pw = canvas_interface->get_canvas()->rend_desc().get_pw();
				Real ph = canvas_interface->get_canvas()->rend_desc().get_ph();
				scalar_x *= 75.0 * fabs(pw);
				scalar_y *= 75.0 * fabs(ph);

				Duck::Handle duck;

				// add offset duck
				duck = new Duck();
				set_duck_value_desc(*duck, value_desc, "offset", transform_stack);
				duck->set_point(transformation.offset);
				duck->set_editable(editable);
				duck->set_type(Duck::TYPE_POSITION);
				connect_signals(duck, duck->get_value_desc(), *canvas_view);
				add_duck(duck);

				Duck::Handle origin_duck = duck;

				// add angle duck
				duck = new Duck();
				duck->set_type(Duck::TYPE_ANGLE);
				set_duck_value_desc(*duck, value_desc, "angle", transform_stack);
				duck->set_point(Point(0.8,transformation.angle));
				duck->set_scalar(scalar_x);
				duck->set_editable(editable);
				duck->set_origin(origin_duck);
				connect_signals(duck, duck->get_value_desc(), *canvas_view);
				add_duck(duck);

				Duck::Handle angle_duck = duck;

				// add skew duck
				duck = new Duck();
				duck->set_type(Duck::TYPE_SKEW);
				set_duck_value_desc(*duck, value_desc, "skew_angle", transform_stack);
				duck->set_point(Point(0.8,transformation.skew_angle));
				duck->set_scalar(scalar_y);
				duck->set_editable(editable);
				duck->set_origin(origin_duck);
				duck->set_axis_x_angle(angle_duck, Angle::deg(90));
				duck->set_axis_y_angle(angle_duck, Angle::deg(180));
				connect_signals(duck, duck->get_value_desc(), *canvas_view);
				add_duck(duck);

				Duck::Handle skew_duck = duck;

				// add scale-x duck
				duck = new Duck();
				duck->set_type(Duck::TYPE_SCALE_X);
				set_duck_value_desc(*duck, value_desc.get_sub_value("scale").get_sub_value("x"), transform_stack);
				duck->set_point(Point(1,0));
				duck->set_scalar(scalar_x);
				duck->set_editable(editable);
				duck->set_origin(origin_duck);
				duck->set_linear(true, angle_duck);
				connect_signals(duck, duck->get_value_desc(), *canvas_view);
				add_duck(duck);

				Duck::Handle scale_x_duck = duck;

				// add scale-y duck
				duck = new Duck();
				duck->set_type(Duck::TYPE_SCALE_Y);
				set_duck_value_desc(*duck, value_desc.get_sub_value("scale").get_sub_value("y"), transform_stack);
				duck->set_point(Point(1,0));
				duck->set_scalar(scalar_y);
				duck->set_editable(editable);
				duck->set_origin(origin_duck);
				duck->set_linear(true, skew_duck);
				connect_signals(duck, duck->get_value_desc(), *canvas_view);
				add_duck(duck);

				Duck::Handle scale_y_duck = duck;

				// add scale duck
				duck = new Duck();
				duck->set_type(Duck::TYPE_SCALE);
				set_duck_value_desc(*duck, value_desc, "scale", transform_stack);
				duck->set_point(Point(1,1));
				duck->set_lock_aspect(true);
				duck->set_editable(editable);
				duck->set_origin(origin_duck);
				duck->set_axis_x_angle(scale_x_duck);
				duck->set_axis_x_mag(scale_x_duck);
				duck->set_axis_y_angle(scale_y_duck);
				duck->set_axis_y_mag(scale_y_duck);
				duck->set_track_axes(true);
				connect_signals(duck, duck->get_value_desc(), *canvas_view);
				add_duck(duck);

				// add move-origin duck
				if (origin_editable) {
					duck = new Duck();
					set_duck_value_desc(*duck, origin_value_desc, transform_stack);
					duck->set_point(Point(0, -0.2));
					duck->set_editable(origin_editable);
					duck->set_type(Duck::TYPE_POSITION);
					duck->set_origin(origin_duck);
					duck->set_move_origin(true);
					duck->set_scalar(scalar_y);
					duck->set_axis_y_angle(scale_y_duck);
					duck->set_track_axes(true);
					connect_signals(duck, duck->get_origin_duck()->get_value_desc(), *canvas_view);
					add_duck(duck);
				}

				return true;
			}
		}
	}
	else
	if (type == type_segment)
	{
		int index;
		Bezier::Handle bezier(new Bezier());
		ValueNode_Composite::Handle value_node;

		if(value_desc.is_value_node() &&
			(value_node=ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())))
		{
			index=value_node->get_link_index_from_name("p1");
			if(!add_to_ducks(synfigapp::ValueDesc(value_node,index),canvas_view,transform_stack))
				return false;
			bezier->p1=last_duck();
			bezier->p1->set_type(Duck::TYPE_VERTEX);

			index=value_node->get_link_index_from_name("t1");
			if(!add_to_ducks(synfigapp::ValueDesc(value_node,index),canvas_view,transform_stack))
				return false;
			bezier->c1=last_duck();
			bezier->c1->set_type(Duck::TYPE_TANGENT);
			bezier->c1->set_origin(bezier->p1);
			bezier->c1->set_scalar(TANGENT_BEZIER_SCALE);
			bezier->c1->set_tangent(true);

			index=value_node->get_link_index_from_name("p2");
			if(!add_to_ducks(synfigapp::ValueDesc(value_node,index),canvas_view,transform_stack))
				return false;
			bezier->p2=last_duck();
			bezier->p2->set_type(Duck::TYPE_VERTEX);

			index=value_node->get_link_index_from_name("t2");
			if(!add_to_ducks(synfigapp::ValueDesc(value_node,index),canvas_view,transform_stack))
				return false;
			bezier->c2=last_duck();
			bezier->c2->set_type(Duck::TYPE_TANGENT);
			bezier->c2->set_origin(bezier->p2);
			bezier->c2->set_scalar(-TANGENT_BEZIER_SCALE);
			bezier->c2->set_tangent(true);

			bezier->signal_user_click(2).connect(
				sigc::bind(
					sigc::mem_fun(
						*canvas_view,
						&studio::CanvasView::popup_param_menu_bezier),
					value_desc));

			add_bezier(bezier);
		}
		else if(value_desc.get_value().is_valid())
		{
			Segment segment=value_desc.get_value().get(Segment());
			Duck::Handle duck_p, duck_c;
			synfig::String name;
			if(param_desc)
				name=param_desc->get_local_name();
			else
				name=value_desc.get_guid_string();

			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 Duck(segment.t1);
			duck_c->set_name(name+".T1");
			duck_c->set_type(Duck::TYPE_TANGENT);
			add_duck(duck_c);
			duck_c->set_origin(duck_p);
			duck_c->set_scalar(TANGENT_HANDLE_SCALE);
			duck_c->set_tangent(true);

			bezier->p1=duck_p;
			bezier->c1=duck_c;

			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 Duck(segment.t2);
			duck_c->set_type(Duck::TYPE_TANGENT);
			duck_c->set_name(name+".T2");
			add_duck(duck_c);
			duck_c->set_origin(duck_p);
			duck_c->set_scalar(-TANGENT_HANDLE_SCALE);
			duck_c->set_tangent(true);

			bezier->p2=duck_p;
			bezier->c2=duck_c;
			add_bezier(bezier);
		}

		return true;
	}
	else
	if (type == type_bline_point)
	{
		bool editable = !value_desc.is_value_node() || synfigapp::is_editable(value_desc.get_value_node());
		BLinePoint point = value_desc.get_value(get_time()).get(BLinePoint());

		Duck::Handle duck;

		// add vertex duck
		duck = new Duck();
		set_duck_value_desc(*duck, value_desc, "point", transform_stack);
		duck->set_point(point.get_vertex());
		duck->set_editable(editable);
		duck->set_type(Duck::TYPE_VERTEX);
		connect_signals(duck, duck->get_value_desc(), *canvas_view);
		add_duck(duck);

		Duck::Handle vertex_duck = duck;

		// add tangent1 duck
		duck = new Duck();
		duck->set_type(Duck::TYPE_TANGENT);
		set_duck_value_desc(*duck, value_desc, "t1", transform_stack);
		duck->set_point(point.get_tangent1());
		duck->set_editable(editable);
		duck->set_origin(vertex_duck);
		connect_signals(duck, duck->get_value_desc(), *canvas_view);
		add_duck(duck);

		// add tangent2 duck
		duck = new Duck();
		duck->set_type(Duck::TYPE_TANGENT);
		set_duck_value_desc(*duck, value_desc, "t2", transform_stack);
		duck->set_point(point.get_tangent2());
		duck->set_editable(editable);
		duck->set_origin(vertex_duck);
		duck->set_scalar(-1);
		connect_signals(duck, duck->get_value_desc(), *canvas_view);
		add_duck(duck);

		return true;
	}
	else
	if (type == type_list)
	{
		// Check for BLine
		if (value_desc.is_value_node() &&
			ValueNode_BLine::Handle::cast_dynamic(value_desc.get_value_node()))
		{
			ValueNode_BLine::Handle value_node;
			value_node=ValueNode_BLine::Handle::cast_dynamic(value_desc.get_value_node());

			int i,first=-1;

			Bezier::Handle bezier;
			Duck::Handle first_duck, first_tangent2_duck;

			for (i = 0; i < value_node->link_count(); i++)
			{
				float amount(value_node->list[i].amount_at_time(get_time()));

				// skip vertices that aren't fully on
				if (amount < 0.9999f)
					continue;

				// remember the index of the first vertex we didn't skip
				if (first == -1)
					first = i;

				ValueNode::Handle sub_node = value_node->get_link(i);
				bool editable = synfigapp::is_editable(sub_node);
				BLinePoint bline_point((*value_node->get_link(i))(get_time()).get(BLinePoint()));
				synfigapp::ValueDesc sub_value_desc(value_node, i, value_desc);

				// Now add the ducks:

				Duck::Handle duck;

				// ----Vertex Duck

				duck = new Duck(bline_point.get_vertex());
				set_duck_value_desc(*duck, sub_value_desc, "point", transform_stack);
				duck->set_editable(editable);
				duck->set_type(Duck::TYPE_VERTEX);
				if(param_desc)
				{
					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());
					}
				}
				duck=add_similar_duck(duck);
				if(i==first) first_duck=duck;
				connect_signals(duck, duck->get_value_desc(), *canvas_view);

				Duck::Handle vertex_duck = duck;

				// ----Width duck

				Duck::Handle width;

				// Add the width duck if it is a parameter with a hint (ie. "width") or if it isn't a parameter
				//if (!   ((param_desc && !param_desc->get_hint().empty()) || !param_desc)   )
				if (param_desc && param_desc->get_hint().empty())
				{
					// if it's a parameter without a hint, then don't add the width duck
					// (This prevents width ducks from being added to region layers, and possibly other cases)
				}
				else
				{
					// add width duck

					duck = new Duck();
					set_duck_value_desc(*duck, sub_value_desc, "width", transform_stack);
					duck->set_radius(true);
					duck->set_point(Point(bline_point.get_width(), 0));
					duck->set_editable(editable);
					duck->set_type(Duck::TYPE_WIDTH);
					duck->set_origin(vertex_duck);
					connect_signals(duck, duck->get_value_desc(), *canvas_view);

					// if the bline is a layer's parameter, scale the width duck by the layer's "width" parameter
					if (param_desc)
					{
						ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),param_desc->get_hint()).get_value(get_time()));
						Real gv(value_desc.get_layer()->get_outline_grow_mark());
						if(value.same_type_as(synfig::Real()))
							duck->set_scalar(exp(gv)*value.get(synfig::Real())*0.5f);
						// if it doesn't have a "width" parameter, scale by 0.5f instead
						else
							duck->set_scalar(0.5f);
					}
					// otherwise just present the raw unscaled width
					else
						duck->set_scalar(0.5f);

					add_duck(duck);
					width = duck;
				}

				// each bezier uses t2 of one point and t1 of the next
				// the first time through this loop we won't have the t2 duck from the previous vertex
				// and so we don't make a bezier.  instead we skip on to t2 for this point
				Duck::Handle tangent1_duck;
				if(bezier)
				{
					// Add the tangent1 duck
					duck = new Duck(bline_point.get_tangent1());
					set_duck_value_desc(*duck, sub_value_desc, "t1", transform_stack);
					duck->set_editable(editable);
					duck=add_similar_duck(duck);

					duck->set_origin(vertex_duck);
					duck->set_scalar(-TANGENT_BEZIER_SCALE);
					duck->set_tangent(true);
					duck->set_shared_point(std::shared_ptr<Point>());
					duck->set_shared_angle(std::shared_ptr<Angle>());
					duck->set_shared_mag(std::shared_ptr<Real>());
					connect_signals(duck, duck->get_value_desc(), *canvas_view);

					// each bezier uses t2 of one point and t1 of the next
					// we should already have a bezier, so add the t1 of this point to it

					bezier->p2=vertex_duck;
					bezier->c2=duck;

					bezier->signal_user_click(2).connect(
						sigc::bind(
							sigc::mem_fun(
								*canvas_view,
								&studio::CanvasView::popup_param_menu_bezier),
							synfigapp::ValueDesc(value_node,i)));

					bezier->signal_user_doubleclick(1).connect(
						sigc::bind(
							sigc::mem_fun(
								*canvas_view,
								&studio::CanvasView::create_new_vertex_on_bline),
							synfigapp::ValueDesc(value_node,i)));

					add_bezier(bezier);
					bezier=0;
					tangent1_duck = duck;
				}

				// don't start a new bezier for the last point in the line if we're not looped
				if ((i+1>=value_node->link_count() && !value_node->get_loop()))
					continue;

				bezier=new Bezier();

				// Add the tangent2 duck
				Duck::Handle tangent2_duck;
				duck = new Duck(bline_point.get_tangent2());
				set_duck_value_desc(*duck, sub_value_desc, "t2", transform_stack);
				duck->set_editable(editable);

				duck=add_similar_duck(duck);
				duck->set_origin(vertex_duck);
				duck->set_scalar(TANGENT_BEZIER_SCALE);
				duck->set_tangent(true);
				duck->set_shared_point(std::shared_ptr<Point>());
				duck->set_shared_angle(std::shared_ptr<Angle>());
				duck->set_shared_mag(std::shared_ptr<Real>());
				connect_signals(duck, duck->get_value_desc(), *canvas_view);

				bezier->p1=vertex_duck;
				bezier->c1=duck;
				tangent2_duck = duck;
				if (i == first) first_tangent2_duck = tangent2_duck;

				// link tangents
				if (tangent1_duck && tangent2_duck && !bline_point.get_split_tangent_both()) {
					if (bline_point.get_merge_tangent_both())
					{
						std::shared_ptr<synfig::Point> point = std::make_shared<Point>(tangent1_duck->get_point());
						tangent1_duck->set_shared_point(point);
						tangent2_duck->set_shared_point(point);
					}
					else
					if (!bline_point.get_split_tangent_angle())
					{
						std::shared_ptr<synfig::Angle> angle = std::make_shared<Angle>(
							approximate_zero( tangent1_duck->get_point().mag() )
						  ? tangent2_duck->get_point().angle()
						  : tangent1_duck->get_point().angle() );
						tangent1_duck->set_shared_angle(angle);
						tangent2_duck->set_shared_angle(angle);
					}
					else
					if (!bline_point.get_split_tangent_radius())
					{
						std::shared_ptr<synfig::Real> mag = std::make_shared<Real>(tangent1_duck->get_point().mag());
						tangent1_duck->set_shared_mag(mag);
						tangent2_duck->set_shared_mag(mag);
					}
				}
			}

	// Loop if necessary
	if(bezier && value_node->get_loop())
	{
		ValueNode::Handle sub_node = value_node->get_link(first);
		bool editable = synfigapp::is_editable(sub_node);
		bool is_bline_point = sub_node->get_type() == type_bline_point;
		BLinePoint bline_point;
		if (is_bline_point) bline_point = (*sub_node)(get_time()).get(BLinePoint());

				ValueNode_BoneInfluence::Handle bone_influence_vertex_value_node(
					ValueNode_BoneInfluence::Handle::cast_dynamic(value_node->get_link(first)));
				ValueNode_Composite::Handle composite_bone_link_value_node;
				synfig::TransformStack bone_transform_stack(transform_stack);
				if (bone_influence_vertex_value_node)
				{
					// apply bones transformation to the ducks
					composite_bone_link_value_node = ValueNode_Composite::Handle::cast_dynamic(
						bone_influence_vertex_value_node->get_link("link") );

					if(param_desc)
					{
						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);
							synfig::GUID guid(calc_duck_guid(value_desc_origin, transform_stack));
							bone_transform_stack.push(new Transform_Origin(guid^synfig::GUID::hasher("origin"), last_duck()));
						}
					}

					Matrix transform(bone_influence_vertex_value_node->calculate_transform(get_time()));
					synfig::GUID guid(bone_influence_vertex_value_node->get_link("bone_weight_list")->get_guid());

					bone_transform_stack.push(new Transform_Matrix(guid, transform));
				}

				// Add the vertex duck
				Duck::Handle duck;
				Duck::Handle vertex_duck(first_duck);
				Duck::Handle tangent2_duck(first_tangent2_duck);
				synfigapp::ValueDesc sub_value_desc(value_node,first,value_desc);

				// Add the tangent1 duck
				duck = new Duck(bline_point.get_tangent1());
				set_duck_value_desc(*duck, sub_value_desc, "t1", transform_stack);
				duck->set_editable(editable);

				duck=add_similar_duck(duck);
				duck->set_origin(vertex_duck);
				duck->set_scalar(-TANGENT_BEZIER_SCALE);
				duck->set_tangent(true);
				duck->set_shared_point(std::shared_ptr<Point>());
				duck->set_shared_angle(std::shared_ptr<Angle>());
				duck->set_shared_mag(std::shared_ptr<Real>());
				connect_signals(duck, duck->get_value_desc(), *canvas_view);

				bezier->p2=vertex_duck;
				bezier->c2=duck;

				bezier->signal_user_click(2).connect(
					sigc::bind(
						sigc::mem_fun(
							*canvas_view,
							&studio::CanvasView::popup_param_menu_bezier),
						synfigapp::ValueDesc(value_node,first)));

				bezier->signal_user_doubleclick(1).connect(
					sigc::bind(
						sigc::mem_fun(
							*canvas_view,
							&studio::CanvasView::create_new_vertex_on_bline),
						synfigapp::ValueDesc(value_node,first)));

				add_bezier(bezier);
				bezier=0;
				Duck::Handle tangent1_duck = duck;

				// link tangents
				if (tangent1_duck && tangent2_duck && !bline_point.get_split_tangent_both()) {
					if (bline_point.get_merge_tangent_both())
					{
						std::shared_ptr<synfig::Point> point = std::make_shared<Point>(tangent1_duck->get_point());
						tangent1_duck->set_shared_point(point);
						tangent2_duck->set_shared_point(point);
					}
					else
					if (!bline_point.get_split_tangent_angle())
					{
						std::shared_ptr<synfig::Angle> angle = std::make_shared<Angle>(
							approximate_zero( tangent1_duck->get_point().mag() )
						  ? tangent2_duck->get_point().angle()
						  : tangent1_duck->get_point().angle() );
						tangent1_duck->set_shared_angle(angle);
						tangent2_duck->set_shared_angle(angle);
					}
					else
					if (!bline_point.get_split_tangent_radius())
					{
						std::shared_ptr<synfig::Real> mag = std::make_shared<Real>(tangent1_duck->get_point().mag());
						tangent1_duck->set_shared_mag(mag);
						tangent2_duck->set_shared_mag(mag);
					}
				}
			}
			return true;
		}

		else // Check for StaticList
		if(value_desc.is_value_node() &&
			ValueNode_StaticList::Handle::cast_dynamic(value_desc.get_value_node()))
		{
			ValueNode_StaticList::Handle value_node;
			value_node=ValueNode_StaticList::Handle::cast_dynamic(value_desc.get_value_node());
			int i;

			synfig::Type &contained_type(value_node->get_contained_type());
			if (contained_type == type_vector)
			{
				Bezier bezier;
				Duck::Handle first_duck, duck;
				int first = -1;
				for(i=0;i<value_node->link_count();i++)
				{
					if(!add_to_ducks(synfigapp::ValueDesc(value_node,i),canvas_view,transform_stack))
						return false;
					duck = last_duck();

					// remember the index of the first vertex we didn't skip
					if (first == -1)
					{
						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()));
*/
//						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()));
					}
					duck->set_type(Duck::TYPE_VERTEX);
					bezier.p1=bezier.p2;bezier.c1=bezier.c2;
					bezier.p2=bezier.c2=duck;

					if (first != i)
					{
						Bezier::Handle 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,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;

					Bezier::Handle 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 (contained_type == type_segment)
			{
				for(i=0;i<value_node->link_count();i++)
				{
					if(!add_to_ducks(synfigapp::ValueDesc(value_node,i),canvas_view,transform_stack))
						return false;
				}
			}
			else
			if (contained_type == type_bone_object)
			{
				for(i=0;i<value_node->link_count();i++)
					if(!add_to_ducks(synfigapp::ValueDesc(value_node,i,value_desc),canvas_view,transform_stack))
						return false;
			}
			else
			if (contained_type == type_bone_weight_pair)
			{
				for(i=0;i<value_node->link_count();i++)
					if(!add_to_ducks(synfigapp::ValueDesc(value_node,i),canvas_view,transform_stack))
						return false;
			}
			else
			if (value_node->get_contained_type() == types_namespace::TypePair<Bone, Bone>::instance)
			{
				bool edit_second = value_desc.parent_is_layer() && value_desc.get_layer()->active();
				for(i=0;i<value_node->link_count();i++)
				{
					ValueNode_Composite::Handle value_node_composite =
						ValueNode_Composite::Handle::cast_dynamic(
							value_node->get_link(i) );
					if (value_node_composite)
					{
						if (!add_to_ducks(
							synfigapp::ValueDesc(
								value_node_composite,
								value_node_composite->get_link_index_from_name(edit_second ? "second" : "first"),
								synfigapp::ValueDesc(value_node,i,value_desc) ),
							canvas_view,
							transform_stack ))
									return false;
					}
				}
			}
			else
				return false;
		}

		else // Check for WPList
		if(value_desc.is_value_node() &&
			ValueNode_WPList::Handle::cast_dynamic(value_desc.get_value_node()))
		{
			ValueNode_WPList::Handle value_node;
			bool homogeneous=true; // if we have an exported WPList without a layer consider it homogeneous
			value_node=ValueNode_WPList::Handle::cast_dynamic(value_desc.get_value_node());
			if(!value_node)
			{
				error("expected a ValueNode_WPList");
				assert(0);
			}
			ValueNode::Handle bline(value_node->get_bline());
			// it is not possible to place any widthpoint's duck if there is
			// not associated bline.
			if(!bline)
				return false;
			// Retrieve the homogeneous layer parameter
			Layer::Handle layer_parent;
			if(value_desc.parent_is_layer())
				layer_parent=value_desc.get_layer();
			if(layer_parent)
				{
					String layer_name(layer_parent->get_name());
					if(layer_name=="advanced_outline")
						homogeneous=layer_parent->get_param("homogeneous").get(bool());
				}
			int i;
			for (i = 0; i < value_node->link_count(); i++)
			{
				float amount(value_node->list[i].amount_at_time(get_time()));
				// skip width points that aren't fully on
				if (amount < 0.9999f)
					continue;
				WidthPoint width_point((*value_node->get_link(i))(get_time()).get(WidthPoint()));
				// try casting the width point to Composite - this tells us whether it is composite or not
				ValueNode_Composite::Handle composite_width_point_value_node(
					ValueNode_Composite::Handle::cast_dynamic(value_node->get_link(i)));
				if(composite_width_point_value_node) // Add the position
				{
					Duck::Handle pduck = new Duck();
					synfigapp::ValueDesc wpoint_value_desc(value_node, i); // The i-widthpoint on WPList
					pduck->set_type(Duck::TYPE_WIDTHPOINT_POSITION);
					set_duck_value_desc(*pduck, wpoint_value_desc, transform_stack);
					// This is a quick hack to obtain the ducks position.
					// The position by amount and the amount by position
					// has to be written considering the bline length too
					// optionally
					ValueNode_BLineCalcVertex::Handle bline_calc_vertex(ValueNode_BLineCalcVertex::create(Vector(0,0)));
					bline_calc_vertex->set_link("bline", bline);
					bline_calc_vertex->set_link("loop", ValueNode_Const::create(false));
					bline_calc_vertex->set_link("amount", ValueNode_Const::create(width_point.get_norm_position(value_node->get_loop())));
					bline_calc_vertex->set_link("homogeneous", ValueNode_Const::create(homogeneous));
					pduck->set_point((*bline_calc_vertex)(get_time()).get(Vector()));
					// hack end
					pduck->set_editable(synfigapp::is_editable(wpoint_value_desc.get_value_node()));
					pduck->signal_edited().clear();
					pduck->signal_edited().connect(sigc::bind(sigc::mem_fun(*this, &studio::Duckmatic::on_duck_changed), wpoint_value_desc));
					pduck->signal_user_click(2).clear();
					pduck->signal_user_click(2).connect(
						sigc::bind(
							sigc::bind(
								sigc::bind(
									sigc::mem_fun(
										*canvas_view,
										&studio::CanvasView::popup_param_menu),
									false),
								1.0f),
							wpoint_value_desc));
					add_duck(pduck);
					if(param_desc)
					{
						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);
							pduck->set_origin(last_duck());
						}
					}
					// add the width duck
					int index=composite_width_point_value_node->get_link_index_from_name("width");
					if (add_to_ducks(synfigapp::ValueDesc(composite_width_point_value_node,index),canvas_view,transform_stack))
					{
						Duck::Handle wduck;
						wduck=last_duck();
						wduck->set_origin(pduck);
						wduck->set_type(Duck::TYPE_WIDTH);
						// if the composite comes from a layer get the layer's "width" parameter and scale the
						// duck by that value.
						if (param_desc)
						{
							ValueBase value(synfigapp::ValueDesc(value_desc.get_layer(),"width").get_value(get_time()));
							Real gv(value_desc.get_layer()->get_outline_grow_mark());
							if(value.same_type_as(synfig::Real()))
								wduck->set_scalar(exp(gv)*(value.get(synfig::Real())*0.5f));
							// if it doesn't have a "width" parameter, scale by 0.5f instead
							else
								wduck->set_scalar(0.5f);
						}
						// otherwise just present the raw unscaled width
						else
							wduck->set_scalar(0.5f);
					}
					else
						return false;
				}
			}
			return true;
		}
		else // Check for DynamicList
		if(value_desc.is_value_node() &&
			ValueNode_DynamicList::Handle::cast_dynamic(value_desc.get_value_node()))
		{
			ValueNode_DynamicList::Handle value_node;
			value_node=ValueNode_DynamicList::Handle::cast_dynamic(value_desc.get_value_node());
			int i;

			if(value_node->get_contained_type()==type_vector)
			{
				Bezier bezier;
				Duck::Handle 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;
					duck = last_duck();

					// remember the index of the first vertex we didn't skip
					if (first == -1)
					{
						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()));
*/
//						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()));
					}
					duck->set_type(Duck::TYPE_VERTEX);
					bezier.p1 = bezier.p2;
					bezier.c1 = bezier.c2;
					bezier.p2 = duck;
					bezier.c2 = duck;

					if (first != i)
					{
						Bezier::Handle 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,i)));
					}
				}

				if (value_node->get_loop() && first != -1 && first_duck != duck)
				{
					duck = first_duck;

					bezier.p1 = bezier.p2;
					bezier.c1 = bezier.c2;
					bezier.p2 = duck;
					bezier.c2 = duck;

					Bezier::Handle 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()==type_segment)
			{
				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;
				}
			}
			else
				return false;
		}
		else
		{
			// WRITEME
		}

		return true;
	}
	else
	if (type == type_bone_object
	 || type == type_bone_valuenode)
	{
		const synfigapp::ValueDesc &orig_value_desc = value_desc;
		ValueNode::Handle value_node(value_desc.get_value_node());

		if (type == type_bone_valuenode)
		{
			assert(value_desc.parent_is_value_node());
			value_node = (*value_node)(get_time()).get(ValueNode_Bone::Handle());
		}
		else
			assert(value_desc.parent_is_linkable_value_node() || value_desc.parent_is_canvas());

		Duck::Handle fake_duck;
		Duck::Handle tip_duck;
		synfig::TransformStack origin_transform_stack(transform_stack), bone_transform_stack;
		bool recursive(get_type_mask() & Duck::TYPE_BONE_RECURSIVE);

		ValueNode_Bone::Handle bone_value_node;
		if (!(bone_value_node = ValueNode_Bone::Handle::cast_dynamic(value_node)))
		{
			error("expected a ValueNode_Bone");
			assert(0);
			return false;
		}

		bool do_not_show_bone_width = false;
		{
			bool is_skeleton_deformation_layer_in_pose_mode = false;

			const synfig::Node* node = bone_value_node.get();
			Layer::ConstHandle parent_layer;
			while (node->parent_count() && !(parent_layer = dynamic_cast<const Layer*>(node)))
			{
				node = node->get_first_parent();
			}
			if (parent_layer) {
				if (parent_layer->get_name() == "skeleton_deformation") {
					if (parent_layer->active())
						is_skeleton_deformation_layer_in_pose_mode = true;
				}
			}
			do_not_show_bone_width = is_skeleton_deformation_layer_in_pose_mode;
		}

		synfig::GUID guid(bone_value_node->get_guid());
		Time time(get_time());
		Bone bone((*bone_value_node)(time).get(Bone()));
		bool invertible(true);
		Angle angle;
		Angle::deg parent_angle(0);

		{
			Matrix transform;
			bool has_parent(!bone.is_root());
			if (has_parent)
			{
				Bone parent_bone((*bone.get_parent())(time).get(Bone()));

				// add the parent's ducks too
				add_to_ducks(synfigapp::ValueDesc(bone_value_node, bone_value_node->get_link_index_from_name("parent"), value_desc),canvas_view,transform_stack);

				transform = parent_bone.get_animated_matrix();
				origin_transform_stack.push(new Transform_Matrix(guid, transform));
				bone_transform_stack = origin_transform_stack;
				invertible = transform.is_invertible();

				Vector scale(parent_bone.get_local_scale());
				bone_transform_stack.push(new Transform_Translate(guid, Point((scale[0])*bone.get_origin()[0],
																			  (scale[1])*bone.get_origin()[1])));
				origin_transform_stack.push(new Transform_Scale(guid, scale));

#ifdef TRY_TO_ALIGN_WIDTH_DUCKS
				// this stuff doesn't work very well - we can find out
				// the cumulative angle and so place the duck on the
				// right of the circle, but recursive scales in the
				// parent can cause the radius to look wrong, and the
				// duck to appear off-center
				printf("%s:%d bone %s:\n", __FILE__, __LINE__, bone.get_name().c_str());
				while (true) {
					printf("%s:%d parent_angle = %5.2f + %5.2f = %5.2f\n", __FILE__, __LINE__,
						   Angle::deg(parent_angle).get(), Angle::deg(parent_bone.get_angle()).get(),
						   Angle::deg(parent_angle + (parent_bone.get_angle())).get());
					parent_angle += parent_bone.get_angle();
					if (parent_bone.is_root()) break;
					parent_bone = (*parent_bone.get_parent())(time).get(Bone());
				}
				printf("%s:%d finally %5.2f\n\n", __FILE__, __LINE__, Angle::deg(parent_angle).get());
#endif
			}
			else
			{
				bone_transform_stack = origin_transform_stack;
				bone_transform_stack.push(new Transform_Translate(guid, bone.get_origin()));
			}
		}

		Bezier::Handle bezier = new Bezier();

		bone_transform_stack.push(new Transform_Rotate(guid, bone.get_angle()));

		// origin
		{
			synfigapp::ValueDesc value_desc(bone_value_node, bone_value_node->get_link_index_from_name("origin"), orig_value_desc);

			Duck::Handle duck = new Duck();
			duck->set_type(Duck::TYPE_POSITION);
			set_duck_value_desc(*duck, value_desc, origin_transform_stack);
			duck->set_point(value_desc.get_value(time).get(Point()));

			// if the ValueNode can be directly manipulated, then set it as so
			duck->set_editable(!invertible ? false :
							   !value_desc.is_value_node() ? true :
							   synfigapp::is_editable(value_desc.get_value_node()));

			duck->signal_edited().clear();
			duck->signal_edited().connect(sigc::bind(sigc::mem_fun(*this, &studio::Duckmatic::on_duck_changed), value_desc));
			duck->signal_user_click(2).connect(sigc::bind(sigc::bind(sigc::bind(sigc::mem_fun(*canvas_view,
																							  &studio::CanvasView::popup_param_menu),
																				false), // bezier
																	 0.0f),				// location
														  value_desc));					// value_desc
			add_duck(duck);
			bezier->p1 = bezier->c1 = duck;
		}

		//parent tip fake
		{
			if(!bone.is_root()){
				synfigapp::ValueDesc parent_value_desc(bone_value_node, bone_value_node->get_link_index_from_name("parent"), orig_value_desc);;
				Bone parent_bone = (*(bone.get_parent()))(time).get(Bone());

				if(parent_bone.get_parent()){
					Point origin = parent_bone.get_origin();
					Matrix bm = parent_bone.get_animated_matrix();
					Real bscale = parent_bone.get_scalelx();

					parent_bone = (*parent_bone.get_parent())(time).get(Bone());
					Matrix m = parent_bone.get_animated_matrix();
					Real scale = parent_bone.get_scalelx();
					origin[0]*=scale;

					//Changing parent's origin to global coordinates
					origin = m.get_transformed(origin);

					//Obtaining Tip's location in global coordinates
					origin += Point(bscale*bm.axis(0)[0],bscale*bm.axis(0)[1]);

					//Converting tip's coordinates into local bone coordinates
					m = bone.get_animated_matrix().get_inverted();
					origin = m.get_transformed(origin);

					synfigapp::ValueDesc scale_value_desc(bone_value_node, bone_value_node->get_link_index_from_name(recursive ? "scalex" : "scalelx"), orig_value_desc);

					Duck::Handle duck = new Duck();
					duck->set_type(Duck::TYPE_VERTEX);
					set_duck_value_desc(*duck, scale_value_desc, bone_transform_stack);
					duck->set_point(origin);
					bezier->p2 = bezier->c2 = duck;

					add_bezier(bezier);
				}
			}
		}

		// fake
		{
			synfigapp::ValueDesc value_desc(bone_value_node, bone_value_node->get_link_index_from_name("name"), orig_value_desc);

			Duck::Handle duck = new Duck();
			duck->set_type(Duck::TYPE_NONE);
			set_duck_value_desc(*duck, value_desc, bone_transform_stack);
			duck->set_point(Point(0, 0));

			duck->set_ignore(true);
			add_duck(duck);
			fake_duck = last_duck();
		}

		// angle
		{
			synfigapp::ValueDesc value_desc(bone_value_node, bone_value_node->get_link_index_from_name("angle"), orig_value_desc);

			Duck::Handle duck = new Duck();
			duck->set_type(Duck::TYPE_ANGLE);
			set_duck_value_desc(*duck, value_desc, bone_transform_stack);

			angle = value_desc.get_value(time).get(Angle());
			Real length(bone.get_length() * (bone.get_scalex() * bone.get_scalelx()));
			duck->set_point(Point(length*0.9, 0));

			// if the ValueNode can be directly manipulated, then set it as so
			duck->set_editable(!value_desc.is_value_node() ? true :
							   synfigapp::is_editable(value_desc.get_value_node()));

			duck->signal_edited().clear();
			duck->signal_edited().connect(sigc::bind(sigc::mem_fun(*this, &studio::Duckmatic::on_duck_changed), value_desc));
			duck->signal_user_click(2).connect(sigc::bind(sigc::bind(sigc::bind(sigc::mem_fun(*canvas_view,
																							  &studio::CanvasView::popup_param_menu),
																				false), // bezier
																	 0.0f),				// location
														  value_desc)); 				// value_desc
			duck->set_origin(fake_duck);
			add_duck(duck);
		}

		// tip
		{
			synfigapp::ValueDesc value_desc(bone_value_node, bone_value_node->get_link_index_from_name(recursive ? "scalex" : "scalelx"), orig_value_desc);

			Duck::Handle duck = new Duck();
			duck->set_type(Duck::TYPE_VERTEX);
			set_duck_value_desc(*duck, value_desc, bone_transform_stack);
			//Real length = bone.get_length()*bone.get_scalex()*bone.get_scalelx();
			Real length = value_desc.get_value(time).get(Real());
			duck->set_point(Vector(length, 0.0));

			// if the ValueNode can be directly manipulated, then set it as so
			duck->set_editable(!invertible ? false :
							   !value_desc.is_value_node() ? true :
							   synfigapp::is_editable(value_desc.get_value_node()));

			duck->signal_edited().clear();
			duck->signal_edited().connect(sigc::bind(sigc::mem_fun(*this, &studio::Duckmatic::on_duck_changed), value_desc));
			duck->signal_user_click(2).connect(
				sigc::bind(
					sigc::bind(
						sigc::bind(
							sigc::mem_fun(
								*canvas_view,
								&studio::CanvasView::popup_param_menu
							),
							false // bezier
						),
						0.0f // location
					),
					value_desc
				)
			);
			duck->set_origin(fake_duck);
			add_duck(duck);
			tip_duck = last_duck();
		}

		// origin width
		if (!do_not_show_bone_width)
		{

			synfigapp::ValueDesc value_desc(bone_value_node, bone_value_node->get_link_index_from_name("width"), orig_value_desc);

			Duck::Handle duck = new Duck();
			duck->set_type(Duck::TYPE_WIDTH);
			set_duck_value_desc(*duck, value_desc, bone_transform_stack);
			duck->set_radius(true);
			duck->set_scalar(1);
			duck->set_point(Point(0, value_desc.get_value(time).get(Real())));

			// if the ValueNode can be directly manipulated, then set it as so
			duck->set_editable(!invertible ? false :
							   !value_desc.is_value_node() ? true :
							   synfigapp::is_editable(value_desc.get_value_node()));

			duck->signal_edited().clear();
			duck->signal_edited().connect(sigc::bind(sigc::mem_fun(*this, &studio::Duckmatic::on_duck_changed), value_desc));
			duck->signal_user_click(2).connect(sigc::bind(sigc::bind(sigc::bind(sigc::mem_fun(*canvas_view,
							&studio::CanvasView::popup_param_menu),
						false), // bezier
					0.0f),				// location
				value_desc));					// value_desc
			duck->set_origin(fake_duck);
			add_duck(duck);
		}

		// tip width
		if (!do_not_show_bone_width)
		{

			synfigapp::ValueDesc value_desc(bone_value_node, bone_value_node->get_link_index_from_name("tipwidth"), orig_value_desc);

			Duck::Handle duck = new Duck();
			duck->set_type(Duck::TYPE_WIDTH);
			set_duck_value_desc(*duck, value_desc, bone_transform_stack);
			duck->set_radius(true);
			duck->set_scalar(1);
			duck->set_point(Point(0, value_desc.get_value(time).get(Real())));

			// if the ValueNode can be directly manipulated, then set it as so
			duck->set_editable(!invertible ? false :
							   !value_desc.is_value_node() ? true :
							   synfigapp::is_editable(value_desc.get_value_node()));

			duck->signal_edited().clear();
			duck->signal_edited().connect(sigc::bind(sigc::mem_fun(*this, &studio::Duckmatic::on_duck_changed), value_desc));
			duck->signal_user_click(2).connect(sigc::bind(sigc::bind(sigc::bind(sigc::mem_fun(*canvas_view,
							&studio::CanvasView::popup_param_menu),
						false), // bezier
					0.0f),				// location
				value_desc));					// value_desc
			duck->set_origin(tip_duck);
			add_duck(duck);
		}

		return true;
	}
	else
	if (type == type_bone_weight_pair)
	{
		ValueNode_BoneWeightPair::Handle value_node;
		if(value_desc.is_value_node() &&
			(value_node=ValueNode_BoneWeightPair::Handle::cast_dynamic(value_desc.get_value_node())))
			add_to_ducks(synfigapp::ValueDesc(value_node, value_node->get_link_index_from_name("bone"), value_desc), canvas_view, transform_stack);
	}

	return false;
}


/*
-- ** -- DuckDrag_Translate M E T H O D S----------------------------
*/
void
DuckDrag_Translate::begin_duck_drag(Duckmatic* duckmatic, const synfig::Vector& offset)
{
	is_moving = false;

	Duck::Handle duck = duckmatic->find_duck(offset);
	assert(duck);
	Duck::Handle origin_duck = duck;
	while(origin_duck->get_move_origin() && origin_duck->get_origin_duck())
		origin_duck = origin_duck->get_origin_duck();
	
	last_translate_ = Vector(0, 0);
	drag_offset_ = duck->get_trans_point();
	snap_offset_ = origin_duck->get_trans_point() - drag_offset_;

	const DuckList selected_ducks(duckmatic->get_selected_ducks());
	DuckList::const_iterator iter;

	positions.clear();
	for(iter=selected_ducks.begin();iter!=selected_ducks.end();++iter)
	{
		Point p((*iter)->get_trans_point());
		positions.push_back(p);
	}
}

bool
DuckDrag_Translate::end_duck_drag(Duckmatic* duckmatic)
{
	if(is_moving)
	{
		duckmatic->signal_edited_selected_ducks();
		return true;
	}
	else
	{
		duckmatic->signal_user_click_selected_ducks(0);
		return false;
	}
}

void
DuckDrag_Translate::duck_drag(Duckmatic* duckmatic, const synfig::Vector& vector)
{
	const DuckList selected_ducks(duckmatic->get_selected_ducks());
	DuckList::const_iterator iter;

	synfig::Vector offset =
		  duckmatic->snap_point_to_grid(vector + snap_offset_)
		- snap_offset_
		- drag_offset_;
	int i;
	Time time(duckmatic->get_time());

	// 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)
			(*iter)->set_trans_point(positions[i] + offset, time);

	// 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] + offset, time);

	last_translate_ = offset;

	if(last_translate_.mag()>0.0001)
		is_moving = true;

	if (is_moving)
		duckmatic->signal_edited_selected_ducks(true);

	// then patch up the tangents for the vertices we've moved
	duckmatic->update_ducks();
}

/*
-- ** -- BezierDrag_Default M E T H O D S----------------------------
*/
void
BezierDrag_Default::begin_bezier_drag(Duckmatic* duckmatic, const synfig::Vector& offset, float bezier_click_pos)
{
	is_moving = false;
	drag_offset_=offset;
	click_pos_=bezier_click_pos;

	Duck::Handle c1(duckmatic->get_selected_bezier()->c1);
	Duck::Handle c2(duckmatic->get_selected_bezier()->c2);

	c1_initial = c1->get_trans_point();
	c2_initial = c2->get_trans_point();
	last_translate_ = synfig::Vector(0,0);

	if (c1 == duckmatic->get_selected_bezier()->p1
		&& c2 == duckmatic->get_selected_bezier()->p2)
	{
		// This is a polygon segment
		// We can't bend the curve, so drag it instead
		c1_ratio = 1.0;
		c2_ratio = 1.0;

	}
	else
	{
		// This is a bline segment, so we can bend the curve

		// Magic Bezier Drag Equations follow! (stolen from Inkscape)
		// "weight" describes how the influence of the drag should be
		// distributed among the handles;
		// 0 = front handle only, 1 = back handle only.

		float t = bezier_click_pos;
		float weight;
		if (t <= 1.0/6.0 ) weight=0;
		else if (t <= 0.5 ) weight = (pow((6 * t - 1) / 2.0, 3)) / 2;
		else if (t <= 5.0 / 6.0) weight = (1 - pow((6 * (1-t) - 1) / 2.0, 3)) / 2 + 0.5;
		else weight = 1;

		c1_ratio = (1-weight)/(3*t*(1-t)*(1-t));
		c2_ratio = weight/(3*t*t*(1-t));
	}
}

void
BezierDrag_Default::bezier_drag(Duckmatic* duckmatic, const synfig::Vector& vector)
{
	synfig::Vector vect(duckmatic->snap_point_to_grid(vector)-drag_offset_);
	Time time(duckmatic->get_time());

	synfig::Vector c1_offset(vect[0]*c1_ratio, vect[1]*c1_ratio);
	synfig::Vector c2_offset(vect[0]*c2_ratio, vect[1]*c2_ratio);

	Duck::Handle c1(duckmatic->get_selected_bezier()->c1);
	Duck::Handle c2(duckmatic->get_selected_bezier()->c2);

	c1->set_trans_point(c1_initial+c1_offset, time);
	c2->set_trans_point(c2_initial+c2_offset, time);

	last_translate_=vect;
	if(last_translate_.mag()>0.0001)
		is_moving = true;

	if (is_moving) {
		duckmatic->signal_edited_duck(c1, true);
		duckmatic->signal_edited_duck(c2, true);
	}

	duckmatic->update_ducks();
}

bool
BezierDrag_Default::end_bezier_drag(Duckmatic* duckmatic)
{
	if(is_moving)
	{
		Duck::Handle c1(duckmatic->get_selected_bezier()->c1);
		Duck::Handle c2(duckmatic->get_selected_bezier()->c2);

		duckmatic->signal_edited_duck(c1);
		duckmatic->signal_edited_duck(c2);

		return true;
	}
	else
	{
		return false;
	}
}

/*
-- ** -- Duckmatic::Push M E T H O D S----------------------------
*/
Duckmatic::Push::Push(Duckmatic *duckmatic_):
	duckmatic_(duckmatic_)
{
	duck_map=duckmatic_->duck_map;
	bezier_list_=duckmatic_->bezier_list_;
	duck_data_share_map=duckmatic_->duck_data_share_map;
	stroke_list_=duckmatic_->stroke_list_;
	duck_dragger_=duckmatic_->duck_dragger_;
	needs_restore=true;
}

Duckmatic::Push::~Push()
{
	if(needs_restore)
		restore();
}

void
Duckmatic::Push::restore()
{
	duckmatic_->duck_map=duck_map;
	duckmatic_->bezier_list_=bezier_list_;
	duckmatic_->duck_data_share_map=duck_data_share_map;
	duckmatic_->stroke_list_=stroke_list_;
	duckmatic_->duck_dragger_=duck_dragger_;
	needs_restore=false;
}

/*
-- ** -- inline M E T H O D S----------------------------
*/
inline synfig::GUID calc_duck_guid(const synfigapp::ValueDesc& value_desc, const synfig::TransformStack& transform_stack)
{
	return value_desc.get_guid() % transform_stack.get_guid();
}

//! sets duck name, value_desc, transform_stack and GUID
inline void set_duck_value_desc(Duck& duck, const synfigapp::ValueDesc& value_desc, const synfig::TransformStack& transform_stack)
{
	duck.set_name(value_desc.get_guid_string());
	duck.set_value_desc(value_desc);
	duck.set_transform_stack(transform_stack);
	duck.set_guid(calc_duck_guid(value_desc, transform_stack));
}

//! sets duck name, value_desc and GUID
inline void set_duck_value_desc(Duck& duck, const synfigapp::ValueDesc& value_desc, const synfig::String& sub_name, const synfig::TransformStack& transform_stack)
{
	set_duck_value_desc(duck, value_desc.get_sub_value(sub_name), transform_stack);
}
