コード例 #1
0
void
Action::ValueDescCreateChildBone::prepare()
{
	clear();

	if (!value_desc.parent_is_value_node()
	 || !value_desc.is_parent_desc_declared()
	 || !value_desc.get_parent_desc().is_value_node() )
			throw Error(Error::TYPE_NOTREADY);

	Action::Handle action = ValueNodeStaticListInsertSmart::create();
	action->set_param("canvas", get_canvas());
	action->set_param("canvas_interface", get_canvas_interface());
	action->set_param("time", time);
	
	const ValueDesc &parent_desc = value_desc.get_parent_desc();
	if (parent_desc.get_parent_desc().get_value_type() == type_list)
	{
		// Adding bone to Skeleton layer
		action->set_param("value_desc", parent_desc);
	} else {
		// Adding bone to Skeleton Deform layer
		action->set_param("value_desc", parent_desc.get_parent_desc());
	}
		

	if (!action->is_ready())
		throw Error(Error::TYPE_NOTREADY);
	add_action_front(action);
}
コード例 #2
0
void
Action::BLinePointTangentSplitAngle::prepare()
{
    clear();
    {
        Action::Handle action;
        action=Action::create("ValueDescSet");
        if(!action)
            throw Error(_("Couldn't find action \"ValueDescSet\""));
        action->set_param("canvas",get_canvas());
        action->set_param("canvas_interface",get_canvas_interface());
        action->set_param("value_desc",ValueDesc(value_node,value_node->get_link_index_from_name("split_angle")));
        action->set_param("time",time);
        action->set_param("new_value",synfig::ValueBase(true));
        assert(action->is_ready());
        if(!action->is_ready())
            throw Error(Error::TYPE_NOTREADY);
        add_action(action);
    }
}
コード例 #3
0
void
Action::ValueDescRemoveSmart::prepare()
{
	ValueNodes::iterator it;
	clear();
	for(it=value_nodes.begin();it!=value_nodes.end();++it)
	{
		synfig::ValueNode_DynamicList::Handle value_node(it->first);
		std::list<int> l(it->second.begin(), it->second.end());
		std::list<int>::iterator i;
		// sor the indexes to perform the actions from higher to lower index
		l.sort();
		int prev_index=-1;
		for(i=l.begin();i!=l.end();++i)
		{
			int index(*i);
			// This prevents duplicated index
			if(index==prev_index)
				continue;
			prev_index=index;
			Action::Handle action;
			// If we are in animate editing mode
			if(get_edit_mode()&MODE_ANIMATE)
				action=Action::create("ActivepointSetOff");
			else
				action=Action::create("ValueNodeDynamicListRemove");
			if(!action)
				throw Error(_("Unable to find action (bug)"));
			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("time",time);
			action->set_param("origin",origin);
			action->set_param("value_desc",ValueDesc(value_node,index));
			if(!action->is_ready())
				throw Error(Error::TYPE_NOTREADY);
			add_action_front(action);
		}
	}
}
コード例 #4
0
void
Action::ColorSet::prepare()
{
	clear();

	std::list<ValueDesc>::iterator iter;
	for (iter = value_desc_list.begin(); iter != value_desc_list.end(); ++iter)
	{
		ValueDesc& value_desc(*iter);

		Action::Handle action = Action::create("ValueDescSet");
		action->set_param("canvas", get_canvas());
		action->set_param("canvas_interface", get_canvas_interface());
		action->set_param("value_desc", value_desc);
		action->set_param("new_value", ValueBase(color));
		action->set_param("time", time);

		if (!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);

		add_action_front(action);
	}
}
コード例 #5
0
void
Action::ValueDescCreateChildBone::prepare()
{
	clear();

	if (!value_desc.parent_is_value_node()
	 || !value_desc.is_parent_desc_declared()
	 || !value_desc.get_parent_desc().is_value_node() )
			throw Error(Error::TYPE_NOTREADY);

	Action::Handle action = ValueNodeStaticListInsertSmart::create();
	action->set_param("canvas", get_canvas());
	action->set_param("canvas_interface", get_canvas_interface());
	action->set_param("value_desc", value_desc.get_parent_desc());
	action->set_param("time", time);

	assert(action->is_ready());
	if (!action->is_ready())
		throw Error(Error::TYPE_NOTREADY);
	add_action_front(action);
}
コード例 #6
0
void
Action::ValueDescBLineLink::prepare()
{
    if (value_desc_list.empty())
        throw Error(Error::TYPE_NOTREADY);

    clear();

    ValueNode_DynamicList::Handle bline_value_node(ValueNode_DynamicList::Handle::cast_dynamic(value_desc.get_parent_value_node()));
    bool loop(bline_value_node->get_loop());
    int loop_adjust(loop ? 0 : -1);
    const std::vector<ValueBase> bline((*bline_value_node)(time).get_list());
    int size = bline.size();
    Real amount = (index + origin + loop_adjust) / (size + loop_adjust);
    // This is the standard amount, let's calculate the homogeneous amount
    // since by default, homogeneous is 'on' for new BLineLink
    // Note: if bline is looped, then consider the loop option of
    // BLineLink looped too.
    amount=std_to_hom(ValueBase(bline), amount, loop, loop);
    LinkableValueNode::Handle calculated_value_node;
    Action::Handle action;

    ValueNode::Handle loop_value_node(ValueNode_Const::create(loop));
    ValueNode::Handle amount_value_node(ValueNode_Const::create(amount));
    ValueNode::Handle homogeneous_value_node(ValueNode_Const::create(true));

    for (std::list<ValueDesc>::iterator iter = value_desc_list.begin(); iter != value_desc_list.end(); ++iter)
    {
        ValueDesc& value_desc(*iter);

        // parent is BLINEPOINT ValueNode
        if (value_desc.parent_is_linkable_value_node() &&
                value_desc.get_parent_value_node()->get_type() == ValueBase::TYPE_BLINEPOINT &&
                ValueNode_Composite::Handle::cast_dynamic(value_desc.get_parent_value_node()))
        {
            String link_name(synfig::LinkableValueNode::Handle::cast_reinterpret(value_desc.get_parent_value_node())->
                             link_name(value_desc.get_index()));
            if (link_name == "t1" || link_name == "t2")
                calculated_value_node = ValueNode_BLineCalcTangent::create(ValueBase::TYPE_VECTOR);
            else if (link_name == "width")
                calculated_value_node = ValueNode_BLineCalcWidth::create(ValueBase::TYPE_REAL);
            else if (link_name == "point")
                calculated_value_node = ValueNode_BLineCalcVertex::create(ValueBase::TYPE_VECTOR);
            else
            {
                synfig::warning("can't link '%s'", link_name.c_str());
                continue;
            }

            action = ValueNodeLinkConnect::create();
            action->set_param("parent_value_node", value_desc.get_parent_value_node());
            action->set_param("index", value_desc.get_index());
        }
        // BLINEPOINT ValueNode - link its vertex
        else if (value_desc.is_value_node() &&
                 value_desc.get_value_type() == ValueBase::TYPE_BLINEPOINT &&
                 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
        {
            calculated_value_node = ValueNode_BLineCalcVertex::create(ValueBase::TYPE_VECTOR);
            action = ValueNodeLinkConnect::create();
            action->set_param("parent_value_node", value_desc.get_value_node());
            action->set_param("index", 0); // index for 'vertex' in 'composite'
        }
        // exported ValueNode
        else if (value_desc.parent_is_canvas())
        {
            if (value_desc.get_value_type() == ValueBase::TYPE_VECTOR)
                calculated_value_node = ValueNode_BLineCalcVertex::create(ValueBase::TYPE_VECTOR);
            else if (value_desc.get_value_type() == ValueBase::TYPE_REAL)
                calculated_value_node = ValueNode_BLineCalcWidth::create(ValueBase::TYPE_REAL);
            else
                continue;

            calculated_value_node->set_link("bline",  bline_value_node);
            calculated_value_node->set_link("loop",   ValueNode_Const::create(loop));
            calculated_value_node->set_link("amount", ValueNode_Const::create(amount));
            calculated_value_node->set_link("homogeneous", ValueNode_Const::create(true));

            action = ValueNodeReplace::create();
            action->set_param("canvas", get_canvas());
            action->set_param("canvas_interface", get_canvas_interface());
            action->set_param("src", ValueNode::Handle(calculated_value_node));
            action->set_param("dest", value_desc.get_value_node());

            assert(action->is_ready());
            if (!action->is_ready()) throw Error(Error::TYPE_NOTREADY);
            add_action_front(action);

            continue;
        }
        else if (value_desc.parent_is_layer_param())
        {
            // VECTOR layer parameter
            if (value_desc.get_value_type() == ValueBase::TYPE_VECTOR)
                calculated_value_node = ValueNode_BLineCalcVertex::create(ValueBase::TYPE_VECTOR);
            // REAL layer parameter
            else if (value_desc.get_value_type() == ValueBase::TYPE_REAL)
                calculated_value_node = ValueNode_BLineCalcWidth::create(ValueBase::TYPE_REAL);
            // ANGLE layer parameter
            else if (value_desc.get_value_type() == ValueBase::TYPE_ANGLE)
                calculated_value_node = ValueNode_BLineCalcTangent::create(ValueBase::TYPE_ANGLE);
            else
                continue;

            action = LayerParamConnect::create();
            action->set_param("layer", value_desc.get_layer());
            action->set_param("param", value_desc.get_param_name());
        }
        else
            continue;

        calculated_value_node->set_link("bline",  bline_value_node );
        calculated_value_node->set_link("loop",   loop_value_node  );
        calculated_value_node->set_link("amount", amount_value_node);
        calculated_value_node->set_link("homogeneous", homogeneous_value_node);

        action->set_param("canvas", get_canvas());
        action->set_param("canvas_interface", get_canvas_interface());
        action->set_param("value_node", ValueNode::Handle(calculated_value_node));

        assert(action->is_ready());
        if (!action->is_ready()) throw Error(Error::TYPE_NOTREADY);
        add_action_front(action);
    }
}
コード例 #7
0
ファイル: valuedescset.cpp プロジェクト: ZurbaXI/synfig
void
Action::ValueDescSet::prepare()
{
	clear();

	// If we are a reference value node, then
	// we need to distribute the changes to the
	// referenced value node
	if(value_desc.is_value_node() && ValueNode_Reference::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueDesc reference_value_desc(ValueNode_Reference::Handle::cast_dynamic(value_desc.get_value_node()),0);
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",value);
		action->set_param("value_desc",reference_value_desc);
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}

	// if we are a boneinfluence value node, then we need to distribute the changes to the linked value node
	// This is only valid for vector type converted to bone influence
	// Not valid for a whole blinepoint converted to bone influence
	if(value_desc.is_value_node() && value.get_type() == type_vector)
	{
		if (ValueNode_BoneInfluence::Handle bone_influence_value_node =
			ValueNode_BoneInfluence::Handle::cast_dynamic(value_desc.get_value_node()))
		{
			ValueDesc bone_influence_value_desc(bone_influence_value_node,
												bone_influence_value_node->get_link_index_from_name("link"));

			if (bone_influence_value_node->has_inverse_transform())
				value = bone_influence_value_node->get_inverse_transform().get_transformed(value.get(Vector()));
			else
				throw Error(_("this node isn't editable - in the future it will be greyed to prevent editing"));

			Action::Handle action(Action::create("ValueDescSet"));

			if(!action)
				throw Error(_("Unable to find action ValueDescSet (bug)"));

			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("time",time);
			action->set_param("new_value",value);
			action->set_param("value_desc",bone_influence_value_desc);

			if(!action->is_ready())
				throw Error(Error::TYPE_NOTREADY);

			add_action(action);

			return;
		}
	}

    // Set ValueNode_Average
	if(value_desc.is_value_node() && ValueNode_Average::check_type(value.get_type()))
	{
		if (ValueNode_Average::Handle bone_average_value_node =
			ValueNode_Average::Handle::cast_dynamic(value_desc.get_value_node()))
		{
			ValueBase::List values_list;
			values_list.reserve(bone_average_value_node->link_count());
			for(int i = 0; i < bone_average_value_node->link_count(); ++i)
				values_list.push_back((*bone_average_value_node->get_link(i))(time));

			ValueAverage::set_average_value_generic(values_list.begin(), values_list.end(), value);

			for(int i = 0; i < bone_average_value_node->link_count(); ++i)
			{
				Action::Handle action(Action::create("ValueDescSet"));

				if(!action)
					throw Error(_("Unable to find action ValueDescSet (bug)"));

				action->set_param("canvas",get_canvas());
				action->set_param("canvas_interface",get_canvas_interface());
				action->set_param("time",time);
				action->set_param("new_value",values_list[i]);
				action->set_param("value_desc",ValueDesc(value_desc.get_value_node(), i));

				if(!action->is_ready())
					throw Error(Error::TYPE_NOTREADY);

				add_action(action);
			}

			return;
		}
	}

    // Set ValueNode_WeightedAverage
	if(value_desc.is_value_node() && ValueNode_WeightedAverage::check_type(value.get_type()))
	{
		if (ValueNode_WeightedAverage::Handle bone_weighted_average_value_node =
			ValueNode_WeightedAverage::Handle::cast_dynamic(value_desc.get_value_node()))
		{
			ValueBase::List values_list;
			values_list.reserve(bone_weighted_average_value_node->link_count());
			for(int i = 0; i < bone_weighted_average_value_node->link_count(); ++i)
				values_list.push_back((*bone_weighted_average_value_node->get_link(i))(time));

			ValueBase values_list_value(values_list);
			ValueAverage::set_average_value_weighted(values_list_value, value);
			const ValueBase::List &new_values_list = values_list_value.get_list();

			for(int i = 0; i < bone_weighted_average_value_node->link_count(); ++i)
			{
				Action::Handle action(Action::create("ValueDescSet"));

				if(!action)
					throw Error(_("Unable to find action ValueDescSet (bug)"));

				action->set_param("canvas",get_canvas());
				action->set_param("canvas_interface",get_canvas_interface());
				action->set_param("time",time);
				action->set_param("new_value",new_values_list[i]);
				action->set_param("value_desc",ValueDesc(value_desc.get_value_node(), i));

				if(!action->is_ready())
					throw Error(Error::TYPE_NOTREADY);

				add_action(action);
			}

			return;
		}
	}

	// If we are a bone link value node, then
	// we need to change the transformation part
	if(value_desc.is_value_node() && ValueNode_BoneLink::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueNode_BoneLink::Handle value_node = ValueNode_BoneLink::Handle::cast_dynamic(value_desc.get_value_node());
		ValueDesc base_value_desc(value_node, value_node->get_link_index_from_name("base_value"));

		ValueBase new_base_value =
			ValueTransformation::back_transform(
				value_node->get_bone_transformation(time), value );

		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_base_value);
		action->set_param("value_desc",base_value_desc);
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}

	// If we are a composite value node, then
	// we need to distribute the changes to the
	// individual parts
	// except if we are TYPE WIDTHPOINT which is handled individually
	if(value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
	 && value_desc.get_value_node()->get_type()!=type_width_point)
	{
		ValueBase components[8];
		int n_components(0);
		Type &type(value.get_type());
		if (type == type_vector)
		{
			components[0]=value.get(Vector())[0];
			components[1]=value.get(Vector())[1];
			n_components=2;
		}
		else
		if (type == type_color)
		{
			components[0]=value.get(Color()).get_r();
			components[1]=value.get(Color()).get_g();
			components[2]=value.get(Color()).get_b();
			components[3]=value.get(Color()).get_a();
			n_components=4;
		}
		else
		if (type == type_segment)
		{
			components[0]=value.get(Segment()).p1;
			components[1]=value.get(Segment()).t1;
			components[2]=value.get(Segment()).p2;
			components[3]=value.get(Segment()).t2;
			n_components=4;
		}
		else
		if (type == type_transformation)
		{
			components[0]=value.get(Transformation()).offset;
			components[1]=value.get(Transformation()).angle;
			components[2]=value.get(Transformation()).skew_angle;
			components[3]=value.get(Transformation()).scale;
			n_components=4;
		}
		else
		if (type == type_bline_point)
		{
			components[0]=value.get(BLinePoint()).get_vertex();
			components[1]=value.get(BLinePoint()).get_width();
			components[2]=value.get(BLinePoint()).get_origin();
			components[3]=value.get(BLinePoint()).get_split_tangent_both();
			components[4]=value.get(BLinePoint()).get_tangent1();
			components[5]=value.get(BLinePoint()).get_tangent2();
			components[6]=value.get(BLinePoint()).get_split_tangent_radius();
			components[7]=value.get(BLinePoint()).get_split_tangent_angle();
			n_components=8;
		}
		else
		if (dynamic_cast<synfig::types_namespace::TypeWeightedValueBase*>(&type) != NULL)
		{
			types_namespace::TypeWeightedValueBase *tp =
				dynamic_cast<synfig::types_namespace::TypeWeightedValueBase*>(&type);
			components[0]=tp->extract_weight(value);
			components[1]=tp->extract_value(value);
			n_components=2;
		}
		else
			throw Error(_("Bad type for composite (%s)"), type.description.local_name.c_str());

		for(int i=0;i<n_components;i++)
		{
			ValueDesc component_value_desc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),i);
			Action::Handle action(Action::create("ValueDescSet"));
			if(!action)
				throw Error(_("Unable to find action ValueDescSet (bug)"));
			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("time",time);
			action->set_param("new_value",components[i]);
			action->set_param("value_desc",component_value_desc);
			if(!action->is_ready())
				throw Error(Error::TYPE_NOTREADY);
			add_action(action);
		}
		return;
	}

	// If we are a RADIAL composite value node, then
	// we need to distribute the changes to the
	// individual parts
	if(value_desc.is_value_node() && ValueNode_RadialComposite::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueBase components[6];
		int n_components(0);
		Type &type(value.get_type());
		if (type == type_vector)
		{
			Angle old_angle = (*(ValueNode_RadialComposite::Handle::cast_dynamic(
									 value_desc.get_value_node())->get_link("theta")))(time).get(Angle());
			Vector vect(value.get(Vector()));
			components[0]=vect.mag();
			Angle change = Angle(Angle::tan(vect[1],vect[0])) - old_angle;
			while (change < Angle::deg(-180)) change += Angle::deg(360);
			while (change > Angle::deg(180)) change -= Angle::deg(360);
			components[1]=old_angle + change;
			n_components=2;
		}
		else
		if (type == type_color)
		{
			components[0]=value.get(Color()).get_y();
			components[1]=value.get(Color()).get_s();
			components[2]=value.get(Color()).get_hue();
			components[3]=value.get(Color()).get_a();
			n_components=4;
		}
		else
			throw Error(_("Bad type for radial composite (%s)"), type.description.local_name.c_str());

		for(int i=0;i<n_components;i++)
		{
			ValueDesc component_value_desc(ValueNode_RadialComposite::Handle::cast_dynamic(value_desc.get_value_node()),i);
			Action::Handle action(Action::create("ValueDescSet"));
			if(!action)
				throw Error(_("Unable to find action ValueDescSet (bug)"));
			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("time",time);
			action->set_param("new_value",components[i]);
			action->set_param("value_desc",component_value_desc);
			if(!action->is_ready())
				throw Error(Error::TYPE_NOTREADY);
			add_action(action);
		}
		return;
	}

	// Perform reverse manipulations

	// If we are a scale value node, then edit the link
	// such that it will scale to our target value
	if (ValueNode_Scale::Handle scale_value_node = ValueNode_Scale::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		if(! scale_value_node->is_invertible(time))
		{
			synfig::warning(_("Attempt to edit scale ValueNode with a scale factor of zero."));
			return;
		}
		ValueBase new_value;
		if (value.get_type() == type_angle)
			new_value = scale_value_node->get_inverse(time, value.get(Angle()));
		else if(value.get_type() == type_vector)
			new_value = scale_value_node->get_inverse(time, value.get(Vector()));
		else if(value.get_type() == type_real)
			new_value = scale_value_node->get_inverse(time, value.get(Real()));
		else
			throw Error(_("Inverse manipulation of %s scale values not implemented in core."), value.type_name().c_str());
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_value);
		action->set_param("value_desc",ValueDesc(scale_value_node, scale_value_node->get_link_index_from_name("link")));
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
    // Range: disallow values outside the range
	if (ValueNode_Range::Handle range_value_node = ValueNode_Range::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueBase new_value;
		if (value.get_type() == type_angle)
			new_value = range_value_node->get_inverse(time, value.get(Angle()));
		else
			throw Error(_("Inverse manipulation of %s range values not implemented in core."), value.type_name().c_str());
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_value);
		action->set_param("value_desc",ValueDesc(range_value_node,range_value_node->get_link_index_from_name("link")));
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
	// Integer: integer values only
	if (ValueNode_Integer::Handle integer_value_node = ValueNode_Integer::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueBase new_value;
		if (value.get_type() == type_angle)
			new_value = integer_value_node->get_inverse(time, value.get(Angle()));
		else if(value.get_type() == type_real)
			new_value = integer_value_node->get_inverse(time, value.get(Real()));
		else
			throw Error(_("Inverse manipulation of %s scale values not implemented in core."), value.type_name().c_str());
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_value);
		action->set_param("value_desc",ValueDesc(integer_value_node,integer_value_node->get_link_index_from_name("link")));
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
	// Real: Reverse manipulations for Real->Angle convert
	if (ValueNode_Real::Handle real_value_node = ValueNode_Real::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueBase new_value;
		if (value.get_type() == type_angle)
			new_value = real_value_node->get_inverse(time, value.get(Angle()));
		else
			throw Error(_("Inverse manipulation of %s scale values not implemented in core."), value.type_name().c_str());
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_value);
		action->set_param("value_desc",ValueDesc(real_value_node,real_value_node->get_link_index_from_name("link")));
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
	// BlineCalcWidth: modify the scale value node
	// so that the target width is achieved
	if (ValueNode_BLineCalcWidth::Handle bline_width = ValueNode_BLineCalcWidth::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		Real old_width((*bline_width)(time).get(Real()));
		Real scale((*(bline_width->get_link("scale")))(time).get(Real()));
		ValueBase new_width(value.get(Real()) * scale / old_width);
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_width);
		action->set_param("value_desc",ValueDesc(bline_width, bline_width->get_link_index_from_name("scale")));
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
	// BLineCalcVertex: snap the point to the nearest
	// allowed position.
	if (ValueNode_BLineCalcVertex::Handle bline_vertex = ValueNode_BLineCalcVertex::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueNode_BLine::Handle bline = ValueNode_BLine::Handle::cast_dynamic(bline_vertex->get_link("bline"));
		Real radius = 0.0;
		Real new_amount;
		if (((*(bline_vertex->get_link("loop")))(time).get(bool())))
		{
			// The bline is looped. Animation may require an amount parameter
			// outside the range of 0-1, so make sure that the amount does
			// not change drastically.
			Real amount_old((*(bline_vertex->get_link("amount")))(time).get(Real()));

			Real amount_new = synfig::find_closest_point((*bline)(time), value.get(Vector()), radius, bline->get_loop());
			Real difference = fmod( fmod(amount_new - amount_old, 1.0) + 1.0 , 1.0);
			//fmod is called twice to avoid negative values
			if (difference > 0.5)
				difference=difference-1.0;
			new_amount = amount_old+difference;
		}
		else
			new_amount = synfig::find_closest_point((*bline)(time), value.get(Vector()), radius, bline->get_loop());
		bool homogeneous((*(bline_vertex->get_link("homogeneous")))(time).get(bool()));
		if(homogeneous)
			new_amount=std_to_hom((*bline)(time), new_amount, (*(bline_vertex->get_link("loop")))(time).get(bool()), bline->get_loop() );
		Action::Handle action(Action::create("ValueDescSet"));
		if(!action)
			throw Error(_("Unable to find action ValueDescSet (bug)"));
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("time",time);
		action->set_param("new_value",new_amount);
		action->set_param("value_desc",ValueDesc(bline_vertex, bline_vertex->get_link_index_from_name("amount")));
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
	// BLineCalcTangent: adjust scale and offset
	// to achieve the desired tangent
	if (ValueNode_BLineCalcTangent::Handle bline_tangent = ValueNode_BLineCalcTangent::Handle::cast_dynamic(value_desc.get_value_node()))
	{
		ValueBase new_scale;
		ValueDesc scale_value_desc(bline_tangent,bline_tangent->get_link_index_from_name("scale"));
		ValueDesc offset_value_desc(bline_tangent,bline_tangent->get_link_index_from_name("offset"));
		Type &type(value_desc.get_value_type());
		if (type == type_real)
		{
			Real old_length = (*bline_tangent)(time).get(Real());
			Real new_length = value.get(Vector()).mag();
			Real scale((*(bline_tangent->get_link("scale")))(time).get(Real()));
			bool fixed_length((*(bline_tangent->get_link("fixed_length")))(time).get(bool()));
			if (fixed_length)
			{
				new_scale = new_length;
			}
			else
			{
				if (old_length == 0) return;
				new_scale = new_length * scale / old_length;
			}
		}
		else
		if (type == type_vector)
		{
			Vector old_tangent = (*bline_tangent)(time).get(Vector());
			Angle old_angle = old_tangent.angle();
			Real old_length = old_tangent.mag();
			Angle new_angle = value.get(Vector()).angle();
			Real new_length = value.get(Vector()).mag();
			Angle old_offset((*(bline_tangent->get_link("offset")))(time).get(Angle()));
			Real scale((*(bline_tangent->get_link("scale")))(time).get(Real()));
			bool fixed_length((*(bline_tangent->get_link("fixed_length")))(time).get(bool()));
			if (fixed_length)
			{
				new_scale = new_length;
			}
			else
			if (old_length != 0)
			{
				new_scale = new_length * scale / old_length;
				Action::Handle action(Action::create("ValueDescSet"));
				if(!action)
					throw Error(_("Unable to find action ValueDescSet (bug)"));
				action->set_param("canvas",get_canvas());
				action->set_param("canvas_interface",get_canvas_interface());
				action->set_param("time",time);
				action->set_param("new_value", ValueBase(old_offset + new_angle - old_angle));
				action->set_param("value_desc",offset_value_desc);
				if(!action->is_ready())
					throw Error(Error::TYPE_NOTREADY);
				add_action(action);
			}
		}
		else
		if (type == type_angle)
		{
			Angle old_angle = (*bline_tangent)(time).get(Angle());
			Angle new_angle = value.get(Angle());
			Angle old_offset((*(bline_tangent->get_link("offset")))(time).get(Angle()));
			Action::Handle action(Action::create("ValueDescSet"));
			if(!action)
				throw Error(_("Unable to find action ValueDescSet (bug)"));
			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("time",time);
			action->set_param("new_value", ValueBase(old_offset + new_angle - old_angle));
			action->set_param("value_desc",offset_value_desc);
			if(!action->is_ready())
				throw Error(Error::TYPE_NOTREADY);
			add_action(action);
			return;
		}

		if (new_scale.get(bool()))
		{
			Action::Handle action(Action::create("ValueDescSet"));
			if(!action)
				throw Error(_("Unable to find action ValueDescSet (bug)"));
			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			action->set_param("time",time);
			action->set_param("new_value",new_scale);
			action->set_param("value_desc",scale_value_desc);
			if(!action->is_ready())
				throw Error(Error::TYPE_NOTREADY);
			add_action(action);
		}
		return;
	}

	// end reverse manipulations

	// WidthPoint Composite: adjust the width point position
	// to achieve the desired point on bline
	// (Code copied from BLineCalcVertex above)
	if (value_desc.parent_is_linkable_value_node() && value_desc.get_parent_value_node()->get_type() == type_list)
	{
		if(ValueNode_DynamicList::Handle::cast_dynamic(value_desc.get_parent_value_node())->get_contained_type() == type_width_point)
		{
			ValueNode_WPList::Handle wplist=ValueNode_WPList::Handle::cast_dynamic(value_desc.get_parent_value_node());
			if(wplist)
			{
				bool wplistloop(wplist->get_loop());
				ValueNode_BLine::Handle bline(ValueNode_BLine::Handle::cast_dynamic(wplist->get_bline()));
				ValueNode_Composite::Handle wpoint_composite(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()));
				if(bline && wpoint_composite)
				{
					bool blineloop(bline->get_loop());
					// Retrieve the homogeneous layer parameter
					bool homogeneous=false;
					Layer::Handle layer_parent;
					std::set<Node*>::iterator iter;
					for(iter=wplist->parent_set.begin();iter!=wplist->parent_set.end();++iter)
						{
							Layer::Handle layer;
							layer=Layer::Handle::cast_dynamic(*iter);
							if(layer && layer->get_name() == "advanced_outline")
							{
								homogeneous=layer->get_param("homogeneous").get(bool());
								break;
							}
						}
					Real radius = 0.0;
					Real new_amount;
					WidthPoint wp((*wpoint_composite)(time).get(WidthPoint()));
					if (wplistloop)
					{
						// The wplist is looped. Animation may require a position parameter
						// outside the range of 0-1, so make sure that the position doesn't
						// change drastically.
						Real amount_old(wp.get_norm_position(wplistloop));
						Real amount_old_b(wp.get_bound_position(wplistloop));
						// If it is homogeneous then convert it to standard
						amount_old=homogeneous?hom_to_std((*bline)(time), amount_old, wplistloop, blineloop):amount_old;
						// grab a new position given by duck's position on the bline
						Real amount_new = synfig::find_closest_point((*bline)(time), value.get(Vector()), radius, blineloop);
						// calculate the difference between old and new amounts
						Real difference = fmod( fmod(amount_new - amount_old, 1.0) + 1.0 , 1.0);
						//fmod is called twice to avoid negative values
						if (difference > 0.5)
							difference=difference-1.0;
						// calculate a new value for the position
						new_amount=amount_old+difference;
						// restore the homogeneous value if needed
						new_amount = homogeneous ? std_to_hom((*bline)(time), new_amount, wplistloop, blineloop) : new_amount;
						// this is the difference between the new amount and the old amount inside the boundaries
						Real bound_diff((wp.get_lower_bound() + new_amount*(wp.get_upper_bound()-wp.get_lower_bound()))-amount_old_b);
						// add the new diff to the current amount
						new_amount = wp.get_position() + bound_diff;
					}
					else
					{
						// grab a new amount given by duck's position on the bline
						new_amount = synfig::find_closest_point((*bline)(time), value.get(Vector()), radius, blineloop);
						// if it is homogeneous then convert to it
						new_amount = homogeneous ? std_to_hom((*bline)(time), new_amount, wplistloop, blineloop) : new_amount;
						// convert the value inside the boundaries
						new_amount = wp.get_lower_bound()+new_amount*(wp.get_upper_bound()-wp.get_lower_bound());
					}
					Action::Handle action(Action::create("ValueDescSet"));
					if(!action)
						throw Error(_("Unable to find action ValueDescSet (bug)"));
					action->set_param("canvas",get_canvas());
					action->set_param("canvas_interface",get_canvas_interface());
					action->set_param("time",time);
					action->set_param("new_value",new_amount);
					action->set_param("value_desc",ValueDesc(wpoint_composite, wpoint_composite->get_link_index_from_name("position")));
					if(!action->is_ready())
						throw Error(Error::TYPE_NOTREADY);
					add_action(action);
					return;
				}
			}
		}
	}

	// end reverse manipulations

	// if value desc has parent value node and parent is composite widthpoint type and index is 4 or 5
	// then we are changing the value of a widthpoint boundary.
	// It is needed to check that we aren't doing the boundary range zero

	if(value_desc.parent_is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_parent_value_node()))
	{
		ValueNode_Composite::Handle parent_value_node;
		parent_value_node=parent_value_node.cast_dynamic(value_desc.get_parent_value_node());
		assert(parent_value_node);
		int i=value_desc.get_index();
		if(parent_value_node->get_type() == type_width_point && (i==4 || i==5))
		{
			ValueNode::Handle low(parent_value_node->get_link("lower_bound"));
			ValueNode::Handle upp(parent_value_node->get_link("upper_bound"));
			Real new_value(value.get(Real()));
			Real lower = (*low)(Time(0.0)).get(Real());
			Real upper = (*upp)(Time(0.0)).get(Real());
			if( (i==4 && new_value > (upper- 0.00000001))
			||  (i==5 && new_value < (lower+ 0.00000001)) )
			{
				throw Error(_("It is forbidden to set lower boundary equal or bigger than upper boundary"));
				return;
			}
		}
	}

	// If we are changing the z_depth range parameters
	// send a signal to the canvas interface to say that the layer has changed
	if(value_desc.parent_is_layer_param()
	   &&
	   (value_desc.get_param_name() =="z_range"
		||
		value_desc.get_param_name() =="z_range_position"
		||
		value_desc.get_param_name() =="z_range_depth")
	   )
	{
		if (get_canvas_interface() && recursive)
		{
			get_canvas_interface()->signal_layer_z_range_changed()(value_desc.get_layer(),true);
		}
	}

	// If we are in animate editing mode
	// TODO: Can we replace local_value to value after all parameters will be converted into ValueBase type?
	if((animate || get_edit_mode()&MODE_ANIMATE) && !value_desc.get_static())
	{
		ValueNode_Animated::Handle& value_node(value_node_animated);
		// If this value isn't a ValueNode_Animated, but
		// it is somewhat constant, then go ahead and convert
		// it to a ValueNode_Animated.
		if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
		{
			ValueBase value;
			if(value_desc.is_value_node())
				value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
			else
				value=value_desc.get_value();
			Interpolation interp=value.get_interpolation();
			if(!value_node)value_node=ValueNode_Animated::create(value,time);
			// Be sure that the newly created waypoint is set with the default
			// interpolations.
			synfig::ValueNode_Animated::WaypointList::iterator iter(value_node->find(time));
			iter->set_before(interp==INTERPOLATION_UNDEFINED?synfigapp::Main::get_interpolation():interp);
			iter->set_after(interp==INTERPOLATION_UNDEFINED?synfigapp::Main::get_interpolation():interp);
			value_node->set_interpolation(interp);
			Action::Handle action;
			if(!value_desc.is_value_node())
			{
				action=(ValueDescConnect::create());
				action->set_param("dest",value_desc);
				action->set_param("src",ValueNode::Handle(value_node));
			}
			else
			{
				action=Action::create("ValueNodeReplace");
				action->set_param("dest",value_desc.get_value_node());
				action->set_param("src",ValueNode::Handle(value_node));
			}
			action->set_param("canvas",get_canvas());
			action->set_param("canvas_interface",get_canvas_interface());
			if(!action->is_ready())
				throw Error(Error::TYPE_NOTREADY);
			add_action_front(action);
		}
		else
		{
			value_node=value_node.cast_dynamic(value_desc.get_value_node());
		}
		if(!value_node)
			throw Error(_("Direct manipulation of this ValueNode type is not yet supported"));
		synfig::ValueNode_Animated::WaypointList::iterator iter;
		Waypoint waypoint;
		Action::Handle action(WaypointSetSmart::create());
		try
		{
			iter=value_node->find(time);
			// value_node->find throws an exception
			// when no waypoint is found at given time
			waypoint=*iter;
		}catch(Exception::NotFound)
		{
			waypoint=value_node->new_waypoint_at_time(time);
			Interpolation inter=value_node->get_interpolation();
			waypoint.set_before(inter==INTERPOLATION_UNDEFINED?synfigapp::Main::get_interpolation():inter);
			waypoint.set_after(inter==INTERPOLATION_UNDEFINED?synfigapp::Main::get_interpolation():inter);
		}
		waypoint.set_value(value);
		action->set_param("canvas",get_canvas());
		action->set_param("canvas_interface",get_canvas_interface());
		action->set_param("value_node",ValueNode::Handle(value_node));
		action->set_param("waypoint",waypoint);
		if(!action->is_ready())
			throw Error(Error::TYPE_NOTREADY);
		add_action(action);
		return;
	}
	else						// We are not in animate editing mode
	{
		if(value_desc.is_value_node())
		{
			if(ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
			{
				Action::Handle action(ValueNodeConstSet::create());
				action->set_param("canvas",get_canvas());
				action->set_param("canvas_interface",get_canvas_interface());
				action->set_param("value_node",value_desc.get_value_node());
				action->set_param("new_value",value);
				if(!action->is_ready())
					throw Error(Error::TYPE_NOTREADY);
				add_action_front(action);
				return;
			}
			else
			if(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
			{
				// If we are in not animate mode let's assume that the user wants to offset the
				// animated value node by the difference.
				// this is valid only for value types that allows it.
				ValueNode_Animated::Handle animated=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
				Waypoint waypoint;
				Type &type=animated->get_type();
				Type &value_type=value.get_type();
				if(value_type==type &&
					(  type == type_integer
					|| type == type_angle
					|| type == type_time
					|| type == type_real
					|| type == type_vector)
					)
				{
					synfig::ValueNode_Animated::WaypointList::const_iterator iter;
					for(iter=animated->waypoint_list().begin(); iter<animated->waypoint_list().end(); iter++)
					{
						waypoint=*iter;
						ValueBase waypoint_value(waypoint.get_value());
						if (type == type_integer)
							waypoint_value=ValueBase(waypoint_value.get(int())+value.get(int())-(*animated)(time).get(int()));
						else
						if (type == type_angle)
							waypoint_value=ValueBase(waypoint_value.get(Angle())+value.get(Angle())-(*animated)(time).get(Angle()));
						else
						if (type == type_time)
							waypoint_value=ValueBase(waypoint_value.get(Time())+value.get(Time())-(*animated)(time).get(Time()));
						else
						if (type == type_real)
							waypoint_value=ValueBase(waypoint_value.get(Real())+value.get(Real())-(*animated)(time).get(Real()));
						else
						if (type == type_vector)
							waypoint_value=ValueBase(waypoint_value.get(Vector())+value.get(Vector())-(*animated)(time).get(Vector()));

						waypoint.set_value(waypoint_value);
						Action::Handle action(WaypointSet::create());
						action->set_param("canvas",get_canvas());
						action->set_param("canvas_interface",get_canvas_interface());
						action->set_param("value_node",ValueNode::Handle(animated));
						action->set_param("waypoint",waypoint);
						if(!action->is_ready())
							throw Error(Error::TYPE_NOTREADY);
						add_action(action);
					}
					return;
				}
				else
					throw Error(_("You must be in Animate-Editing-Mode to directly manipulate this value"));
			}
			else
				throw Error(_("Direct manipulation of this ValueNode type is not yet supported"));
		}
		else
		if(value_desc.parent_is_layer_param() && !value_desc.is_value_node())
		{
			Action::Handle layer_param_set(LayerParamSet::create());
			layer_param_set->set_param("canvas",get_canvas());
			layer_param_set->set_param("canvas_interface",get_canvas_interface());
			layer_param_set->set_param("layer",value_desc.get_layer());
			layer_param_set->set_param("param",value_desc.get_param_name());
			layer_param_set->set_param("new_value",value);
			if(!layer_param_set->is_ready())
				throw Error(Error::TYPE_NOTREADY);
			add_action_front(layer_param_set);
			return;
		}
		throw Error(_("Unsupported ValueDesc type"));
	}

	
}
コード例 #8
0
void
Action::ValueDescSkeletonLink::prepare()
{
	if (value_desc_list.empty())
		throw Error(Error::TYPE_NOTREADY);

	clear();

	// get bone
	ValueNode_Bone::Handle bone_value_node;
	if (value_desc.parent_is_value_node())
		bone_value_node = ValueNode_Bone::Handle::cast_dynamic(value_desc.get_parent_value_node());

	if (!bone_value_node)
		throw Error(Error::TYPE_NOTREADY);

	// get static list of bones (skeleton layer)
	const ValueDesc &parent = value_desc.get_parent_desc();
	ValueNode_StaticList::Handle bone_list_value_node;
	if (parent.parent_is_value_node())
		bone_list_value_node = ValueNode_StaticList::Handle::cast_dynamic(parent.get_parent_value_node());

	if (!bone_list_value_node)
		throw Error(Error::TYPE_NOTREADY);

	// bones list
	typedef std::set<ValueNode_Bone::Handle> Set;
	ValueBase::List value_bone_list = (*bone_list_value_node)(time).get_list();
	Set list;
	for(int i = 0; i < bone_list_value_node->link_count(); ++i)
	{
		ValueNode_Bone::Handle bone_value_node =
			ValueNode_Bone::Handle::cast_dynamic(bone_list_value_node->get_link(i));
		if (bone_value_node)
			list.insert(bone_value_node);
	}
	
	if (list.empty())
		throw Error(Error::TYPE_NOTREADY);

	// process all selected ducks
	Set current_list;
	for(std::list<ValueDesc>::iterator iter = value_desc_list.begin(); iter != value_desc_list.end(); ++iter)
	{
		ValueDesc& value_desc(*iter);

		// skip region/outline origin
		if (value_desc.parent_is_layer()
		 && value_desc.get_param_name() == "origin"
		 && (value_desc.get_layer()->get_name() == "advanced_outline"
		  || value_desc.get_layer()->get_name() == "outline"
		  || value_desc.get_layer()->get_name() == "region"))
			continue;

		// check type
		Type &type(value_desc.get_value_type());
		if (!ValueNode_BoneLink::check_type(type)
		 || !ValueNode_WeightedAverage::check_type(type)
		 || !ValueVector::check_type(type) )
			continue;

		// don't link bones to bones
		if (value_desc.parent_is_value_node()
		 && ValueNode_Bone::Handle::cast_dynamic(value_desc.get_parent_value_node()) )
			continue;
		
		// List of bones influencing current item
		current_list.clear();
		for(Set::iterator i = list.begin(); i != list.end(); ++i)
			if ((*i)->have_influence_on(time, ValueVector::get_vector(value_desc.get_value(time))))
				current_list.insert(*i);

		if (current_list.empty()) continue;

		ValueNode::Handle node;

		if (current_list.size() > 1)
		{
			// make average node
			ValueNode_WeightedAverage::Handle average_node = new ValueNode_WeightedAverage(type, get_canvas());

			// get type of weighted value
			types_namespace::TypeWeightedValueBase *wt = ValueAverage::get_weighted_type_for(type);
			assert(wt != NULL);

			// add each bone from influence_list to Average convert
			for(Set::iterator i = current_list.begin(); i != current_list.end(); ++i)
			{
				// make bone link
				ValueNode_BoneLink::Handle bone_link_node =
					ValueNode_BoneLink::create(value_desc.get_value(time));

				bone_link_node->set_link("bone", ValueNode_Const::create(ValueBase(*i), get_canvas()));
				bone_link_node->set_link("base_value",
					ValueNode_Composite::create(
						ValueTransformation::back_transform(
							bone_link_node->get_bone_transformation(time),
							value_desc.get_value(time) )));

				// make weighted value
				ValueNode_Composite::Handle weighted_node =
					ValueNode_Composite::create(wt->create_weighted_value(1, value_desc.get_value(time)), get_canvas());

				weighted_node->set_link("value", bone_link_node);

				// add
				average_node->add(ValueNode::Handle(weighted_node));
			}

			node = average_node;
		}
		else
		{
			// make bone link
			ValueNode_BoneLink::Handle bone_link_node =
				ValueNode_BoneLink::create(value_desc.get_value(time));

			bone_link_node->set_link("bone", ValueNode_Const::create(ValueBase(*current_list.begin()), get_canvas()));
			bone_link_node->set_link("base_value",
				ValueNode_Composite::create(
					ValueTransformation::back_transform(
						bone_link_node->get_bone_transformation(time),
						value_desc.get_value(time) )));

			node = bone_link_node;
		}

		if (!node) continue;

		// enqueue suitable action to assign node
		if (value_desc.parent_is_canvas())
		{
			Action::Handle action = ValueNodeReplace::create();
			action->set_param("canvas", get_canvas());
			action->set_param("canvas_interface", get_canvas_interface());
			action->set_param("src", node);
			action->set_param("dest", value_desc.get_value_node());

			assert(action->is_ready());
			if (!action->is_ready()) throw Error(Error::TYPE_NOTREADY);
			add_action_front(action);
		}
		else
		if (value_desc.parent_is_layer())
		{
			Action::Handle action = LayerParamConnect::create();
			action->set_param("layer", value_desc.get_layer());
			action->set_param("param", value_desc.get_param_name());
			action->set_param("canvas", get_canvas());
			action->set_param("canvas_interface", get_canvas_interface());
			action->set_param("value_node", node);

			assert(action->is_ready());
			if (!action->is_ready()) throw Error(Error::TYPE_NOTREADY);
			add_action_front(action);
		}
		else
		if (value_desc.parent_is_value_node())
		{
			Action::Handle action = ValueNodeLinkConnect::create();
			action->set_param("canvas", get_canvas());
			action->set_param("canvas_interface", get_canvas_interface());
			action->set_param("parent_value_node", value_desc.get_parent_value_node());
			action->set_param("index", value_desc.get_index());
			action->set_param("value_node", node);

			assert(action->is_ready());
			if (!action->is_ready()) throw Error(Error::TYPE_NOTREADY);
			add_action_front(action);
		}
	}
}