1 /* === S Y N F I G ========================================================= */
2 /*! \file valuedescsmartlink.cpp
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
33 #include "valuedescsmartlink.h"
35 #include <synfigapp/canvasinterface.h>
36 #include <synfig/valuenode_const.h>
37 #include <synfig/valuenode_scale.h>
39 #include <synfigapp/general.h>
45 using namespace synfig;
46 using namespace synfigapp;
47 using namespace Action;
49 /* === M A C R O S ========================================================= */
51 ACTION_INIT(Action::ValueDescSmartLink);
52 ACTION_SET_NAME(Action::ValueDescSmartLink,"ValueDescSmartLink");
53 ACTION_SET_LOCAL_NAME(Action::ValueDescSmartLink,N_("Smart Link"));
54 ACTION_SET_TASK(Action::ValueDescSmartLink,"connect");
55 ACTION_SET_CATEGORY(Action::ValueDescSmartLink,Action::CATEGORY_VALUEDESC);
56 ACTION_SET_PRIORITY(Action::ValueDescSmartLink,0);
57 ACTION_SET_VERSION(Action::ValueDescSmartLink,"0.0");
58 ACTION_SET_CVS_ID(Action::ValueDescSmartLink,"$Id$");
60 /* === G L O B A L S ======================================================= */
62 /* === P R O C E D U R E S ================================================= */
64 /* === M E T H O D S ======================================================= */
66 Action::ValueDescSmartLink::ValueDescSmartLink(): poison(false), status_level(0)
71 Action::ValueDescSmartLink::get_param_vocab()
73 ParamVocab ret(Action::CanvasSpecific::get_param_vocab());
75 ret.push_back(ParamDesc("value_desc",Param::TYPE_VALUEDESC)
76 .set_local_name(_("ValueDesc to smart link"))
77 .set_requires_multiple()
84 Action::ValueDescSmartLink::is_candidate(const ParamList &x)
86 // If action parameters are not Value Desc
87 if(!candidate_check(get_param_vocab(),x))
89 // If the size of the List of Param is not two
91 // If both value desc aren't Linkable Value Nodes children
92 ParamList::const_iterator iter;
95 for(iter=x.begin(); iter!=x.end(); iter++)
97 if(iter->first == "value_desc")
99 params[counter]=iter->second;
105 Param pfront(params[0]);
106 Param pback(params[1]);
107 if(!pfront.get_value_desc().parent_is_linkable_value_node() ||
108 !pback.get_value_desc().parent_is_linkable_value_node())
110 // If both don't have opposite scalars.
111 if(!((pback.get_value_desc().get_scalar()< 0 && pfront.get_value_desc().get_scalar()> 0)
113 (pback.get_value_desc().get_scalar()> 0 && pfront.get_value_desc().get_scalar()< 0))
117 //We have reached two opposite tangents
122 Action::ValueDescSmartLink::set_param(const synfig::String& name, const Action::Param ¶m)
124 if(name=="time" && param.get_type()==Param::TYPE_TIME)
126 time=param.get_time();
130 // don't bother looking for the best value to use if there's already been an error
131 if (poison==true) return false;
133 if(name=="value_desc" && param.get_type()==Param::TYPE_VALUEDESC)
135 ValueDesc value_desc(param.get_value_desc());
137 if(value_desc.is_value_node() && value_desc.get_value_node()->is_exported())
139 if(link_value_node==value_desc.get_value_node())
142 if(link_value_node && link_value_node->is_exported())
145 status_message = (_("Cannot link two different exported values ('") +
146 value_desc.get_value_node()->get_id() + _("' and '") +
147 link_value_node->get_id()) + _("')");
151 link_value_node=value_desc.get_value_node();
152 status_message = _("Used exported ValueNode ('") + link_value_node->get_id() + _("').");
154 else if(value_desc.is_value_node())
159 status_message = _("Using the only available ValueNode.");
160 link_value_node=value_desc.get_value_node();
162 else if(link_value_node->is_exported())
164 // we've already seen an exported value, so use that rather than the current value
166 // Use the one that is referenced more
167 else if(link_value_node->rcount()!=value_desc.get_value_node()->rcount())
169 if(link_value_node->rcount()<value_desc.get_value_node()->rcount())
172 status_message = _("Using the most referenced ValueNode.");
173 link_value_node=value_desc.get_value_node();
175 else if (status_level <= 2)
178 status_message = _("Using the most referenced ValueNode.");
181 // If the current link value node is a constant and
182 // this one isn't, then give preference to the exotic
183 else if(ValueNode_Const::Handle::cast_dynamic(link_value_node) && !ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
186 status_message = _("There's a tie for most referenced; using the animated ValueNode.");
187 link_value_node=value_desc.get_value_node();
189 else if(ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()) && !ValueNode_Const::Handle::cast_dynamic(link_value_node))
191 if (status_level <= 3)
194 status_message = _("There's a tie for most referenced; using the animated ValueNode.");
197 // If both are animated, and this one has more waypoints, then use the one with more waypoints
198 else if(ValueNode_Animated::Handle::cast_dynamic(link_value_node) &&
199 ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()) &&
200 ValueNode_Animated::Handle::cast_dynamic(link_value_node)->waypoint_list().size() !=
201 ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node())->waypoint_list().size())
203 if (ValueNode_Animated::Handle::cast_dynamic(link_value_node)->waypoint_list().size() <
204 ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node())->waypoint_list().size())
207 status_message = _("There's a tie for most referenced, and both are animated; using the one with the most waypoints.");
208 link_value_node=value_desc.get_value_node();
210 else if (status_level <= 4)
213 status_message = _("There's a tie for most referenced, and both are animated; using the one with the most waypoints.");
216 // Use the one that was least recently changed
217 else if(link_value_node->get_time_last_changed()!=value_desc.get_value_node()->get_time_last_changed())
219 if(link_value_node->get_time_last_changed()>value_desc.get_value_node()->get_time_last_changed())
222 status_message = _("Everything is tied; using the least recently modified value.");
223 link_value_node=value_desc.get_value_node();
225 else if (status_level <= 5)
228 status_message = _("Everything is tied; using the least recently modified value.");
234 status_message = _("Absolutely everything is tied.");
238 if(value_desc_list.size() && value_desc.get_value_type()!=value_desc_list.front().get_value_type())
240 // Everything must be of the same type
242 status_message = (strprintf(_("Cannot link two values of different types ('%s' and '%s')"),
243 ValueBase::type_local_name(value_desc.get_value_type()).c_str(),
244 ValueBase::type_local_name(value_desc_list.front().get_value_type()).c_str()));
248 value_desc_list.push_back(value_desc);
253 return Action::CanvasSpecific::set_param(name,param);
257 Action::ValueDescSmartLink::is_ready()const
261 if(value_desc_list.size()!=2)
263 return Action::CanvasSpecific::is_ready();
267 Action::ValueDescSmartLink::prepare()
270 throw Error(status_message.c_str());
272 if(value_desc_list.empty())
273 throw Error(Error::TYPE_NOTREADY);
277 if(value_desc_list.size()!=2)
278 throw Error(Error::TYPE_BUG);
280 ValueDesc& value_desc_t1(value_desc_list.front());
281 ValueDesc& value_desc_t2(value_desc_list.back());
282 t1 = value_desc_t1.get_value_node();
283 t2 = value_desc_t2.get_value_node();
287 // we should have a value node selected because is candidate
288 // should have checked it before
289 throw Error(Error::TYPE_BUG);
292 //See what is the tangent selected to convert.
293 ValueDesc& toconvert(value_desc_t2);
294 if(t1==link_value_node)
295 toconvert=value_desc_t2; // Convert t2
296 else if(t2==link_value_node)
297 toconvert=value_desc_t1; //Convert t1
298 else throw Error(Error::TYPE_BUG);
300 //Let's create a Scale Value Node
301 synfig::ValueNode::Handle scale_value_node=synfig::LinkableValueNode::create("scale",toconvert.get_value(time));
302 scale_value_node->set_parent_canvas(get_canvas());
303 //Let's connect the new Scale Value Node
304 Action::Handle action1(Action::create("ValueDescConnect"));
306 throw Error(Error::TYPE_CRITICAL);
307 action1->set_param("canvas",get_canvas());
308 action1->set_param("canvas_interface",get_canvas_interface());
309 action1->set_param("dest",toconvert);
310 action1->set_param("src",scale_value_node);
311 assert(action1->is_ready());
312 if(!action1->is_ready())
313 throw Error(Error::TYPE_NOTREADY);
314 add_action_front(action1);
317 //Let's Connect the link value node to the scale value node link subparam
318 Action::Handle action2(Action::create("ValueNodeLinkConnect"));
320 throw Error(Error::TYPE_CRITICAL);
322 action2->set_param("canvas",get_canvas());
323 action2->set_param("canvas_interface",get_canvas_interface());
324 action2->set_param("parent_value_node",scale_value_node);
325 action2->set_param("index",0);
326 action2->set_param("value_node",link_value_node);
327 assert(action2->is_ready());
328 if(!action2->is_ready())
329 throw Error(Error::TYPE_NOTREADY);
330 add_action_front(action2);
332 //Let's Set the scale to -1
333 Action::Handle action3(Action::create("ValueNodeConstSet"));
335 throw Error(Error::TYPE_CRITICAL);
337 action3->set_param("canvas",get_canvas());
338 action3->set_param("canvas_interface",get_canvas_interface());
339 action3->set_param("value_node",synfig::LinkableValueNode::Handle::cast_dynamic(scale_value_node)->get_link(1));
340 action3->set_param("new_value",synfig::ValueBase(Real(-1.0)));
341 assert(action3->is_ready());
342 if(!action3->is_ready())
343 throw Error(Error::TYPE_NOTREADY);
344 add_action_front(action3);
346 synfig::info("http://synfig.org/Linking#Tier_%d : %s", status_level, status_message.c_str());