Esempio n. 1
0
bool
Action::ValueDescLink::set_param(const synfig::String& name, const Action::Param &param)
{
	if(name=="time" && param.get_type()==Param::TYPE_TIME)
	{
		time=param.get_time();
		return true;
	}

	// don't bother looking for the best value to use if there's already been an error
	if (poison==true) return false;

	if(name=="value_desc" && param.get_type()==Param::TYPE_VALUEDESC)
	{
		ValueDesc value_desc(param.get_value_desc());
		// If we are handling a Composite WidthPoint then use its position as param
		if(value_desc.is_value_node() && value_desc.parent_is_linkable_value_node())
		{
			synfig::ValueNode_Composite::Handle compo(synfig::ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()));
			if(compo)
			{
				String param_name;
				if (value_desc.parent_is_value_desc() && !value_desc.get_sub_name().empty())
				{
					LinkableValueNode::Vocab vocab = compo->get_children_vocab();
					for(LinkableValueNode::Vocab::const_iterator i = vocab.begin(); i != vocab.end(); ++i)
						if (i->get_name() == value_desc.get_sub_name())
							param_name = value_desc.get_sub_name();
				}
				
				//! Test used for with point handle
				if (param_name.empty() && compo->get_type() == type_width_point)
					param_name = "position";

				if (param_name.empty() && compo->get_type() == type_bline_point)
					param_name = "point";
				
				if ( compo->get_type() == type_bline_point
				  && param_name == "t2"
				  && (*compo)(time).get(BLinePoint()).get_merge_tangent_both())
				{
					param_name = "t1";
				}
				
				if (!param_name.empty())
				{
					synfigapp::Action::Param param(synfigapp::ValueDesc(compo, compo->get_link_index_from_name(param_name)));
					return set_param("value_desc", param);
				}
			}
		}

		if(value_desc.is_value_node() && value_desc.get_value_node()->is_exported())
		{
			if(link_value_node==value_desc.get_value_node())
				return true;

			if(link_value_node && link_value_node->is_exported())
			{
				poison=true;
				status_message = (_("Cannot link two different exported values ('") +
								  value_desc.get_value_node()->get_id() + _("' and '") +
								  link_value_node->get_id()) + _("')");
				return false;
			}

			link_value_node=value_desc.get_value_node();
			link_scalar=value_desc.parent_is_linkable_value_node()?value_desc.get_scalar():1.0;
			status_message = _("Used exported ValueNode ('") + link_value_node->get_id() + _("').");
		}
		else if(value_desc.is_value_node())
		{
			if(!link_value_node)
			{
				status_level = 1;
				status_message = _("Using the only available ValueNode.");
				link_value_node=value_desc.get_value_node();
				link_scalar=value_desc.parent_is_linkable_value_node()?value_desc.get_scalar():1.0;
			}
			else if(link_value_node->is_exported())
			{
				// we've already seen an exported value, so use that rather than the current value
			}
			// Use the one that is referenced more
			else if(link_value_node->rcount()!=value_desc.get_value_node()->rcount())
			{
				if(link_value_node->rcount()<value_desc.get_value_node()->rcount())
				{
					status_level = 2;
					status_message = _("Using the most referenced ValueNode.");
					link_value_node=value_desc.get_value_node();
					link_scalar=value_desc.parent_is_linkable_value_node()?value_desc.get_scalar():1.0;
				}
				else if (status_level <= 2)
				{
					status_level = 2;
					status_message = _("Using the most referenced ValueNode.");
				}
			}
			// If the current link value node is a constant and
			// this one isn't, then give preference to the exotic
			else if(ValueNode_Const::Handle::cast_dynamic(link_value_node) && !ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
			{
				status_level = 3;
				status_message = _("There's a tie for most referenced; using the animated ValueNode.");
				link_value_node=value_desc.get_value_node();
				link_scalar=value_desc.parent_is_linkable_value_node()?value_desc.get_scalar():1.0;
			}
			else if(ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()) && !ValueNode_Const::Handle::cast_dynamic(link_value_node))
			{
				if (status_level <= 3)
				{
					status_level = 3;
					status_message = _("There's a tie for most referenced; using the animated ValueNode.");
				}
			}
			// If both are animated, and this one has more waypoints, then use the one with more waypoints
			else if(ValueNode_Animated::Handle::cast_dynamic(link_value_node) &&
					ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()) &&
					ValueNode_Animated::Handle::cast_dynamic(link_value_node)->waypoint_list().size() !=
					ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node())->waypoint_list().size())
			{
				if (ValueNode_Animated::Handle::cast_dynamic(link_value_node)->waypoint_list().size() <
					ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node())->waypoint_list().size())
				{
					status_level = 4;
					status_message = _("There's a tie for most referenced, and both are animated; using the one with the most waypoints.");
					link_value_node=value_desc.get_value_node();
					link_scalar=value_desc.parent_is_linkable_value_node()?value_desc.get_scalar():1.0;
				}
				else if (status_level <= 4)
				{
					status_level = 4;
					status_message = _("There's a tie for most referenced, and both are animated; using the one with the most waypoints.");
				}
			}
			// If both are Linkable Value Nodes and has waypoint in its children, use the one with more waypoints
			else if(LinkableValueNode::Handle::cast_dynamic(link_value_node) &&
					LinkableValueNode::Handle::cast_dynamic(value_desc.get_value_node()) &&
					LinkableValueNode::Handle::cast_dynamic(link_value_node)->get_times().size() !=
					LinkableValueNode::Handle::cast_dynamic(value_desc.get_value_node())->get_times().size())
			{
				if(LinkableValueNode::Handle::cast_dynamic(link_value_node)->get_times().size() <
				LinkableValueNode::Handle::cast_dynamic(value_desc.get_value_node())->get_times().size())
				{
					status_level = 4;
					status_message = _("There's a tie for most referenced, and both are linkable value node animated; using the one with the most waypoints.");
					link_value_node=value_desc.get_value_node();
					link_scalar=value_desc.parent_is_linkable_value_node()?value_desc.get_scalar():1.0;
				}
				else if (status_level <= 4)
				{
					status_level = 4;
					status_message = _("There's a tie for most referenced, and both are linkable value node animated; using the one with the most waypoints.");
				}
			}
			// Use the one that was least recently changed
			else if(link_value_node->get_time_last_changed()!=value_desc.get_value_node()->get_time_last_changed())
			{
				if(link_value_node->get_time_last_changed()>value_desc.get_value_node()->get_time_last_changed())
				{
					status_level = 5;
					status_message = _("Everything is tied; using the least recently modified value.");
					link_value_node=value_desc.get_value_node();
					link_scalar=value_desc.parent_is_linkable_value_node()?value_desc.get_scalar():1.0;
				}
				else if (status_level <= 5)
				{
					status_level = 5;
					status_message = _("Everything is tied; using the least recently modified value.");
				}
			}
			else
			{
				status_level = 6;
				status_message = _("Absolutely everything is tied.");
			}
		}

		if(value_desc_list.size() && value_desc.get_value_type()!=value_desc_list.front().get_value_type())
		{
			// Everything must be of the same type
			poison=true;
			status_message = (strprintf(_("Cannot link two values of different types ('%s' and '%s')"),
										value_desc.get_value_type().description.local_name.c_str(),
										value_desc_list.front().get_value_type().description.local_name.c_str()));
			return false;
		}

		value_desc_list.push_back(value_desc);

		return true;
	}

	return Action::CanvasSpecific::set_param(name,param);
}