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 else if(LinkableValueNode::Handle::cast_dynamic(link_value_node) &&
217 LinkableValueNode::Handle::cast_dynamic(value_desc.get_value_node()) &&
218 LinkableValueNode::Handle::cast_dynamic(link_value_node)->get_times().size() !=
219 LinkableValueNode::Handle::cast_dynamic(value_desc.get_value_node())->get_times().size())
221 if(LinkableValueNode::Handle::cast_dynamic(link_value_node)->get_times().size() <
222 LinkableValueNode::Handle::cast_dynamic(value_desc.get_value_node())->get_times().size())
225 status_message = _("There's a tie for most referenced, and both are linkable value node animated; using the one with the most waypoints.");
226 link_value_node=value_desc.get_value_node();
228 else if (status_level <= 4)
231 status_message = _("There's a tie for most referenced, and both are linkable value node animated; using the one with the most waypoints.");
234 // Use the one that was least recently changed
235 else if(link_value_node->get_time_last_changed()!=value_desc.get_value_node()->get_time_last_changed())
237 if(link_value_node->get_time_last_changed()>value_desc.get_value_node()->get_time_last_changed())
240 status_message = _("Everything is tied; using the least recently modified value.");
241 link_value_node=value_desc.get_value_node();
243 else if (status_level <= 5)
246 status_message = _("Everything is tied; using the least recently modified value.");
252 status_message = _("Absolutely everything is tied.");
256 if(value_desc_list.size() && value_desc.get_value_type()!=value_desc_list.front().get_value_type())
258 // Everything must be of the same type
260 status_message = (strprintf(_("Cannot link two values of different types ('%s' and '%s')"),
261 ValueBase::type_local_name(value_desc.get_value_type()).c_str(),
262 ValueBase::type_local_name(value_desc_list.front().get_value_type()).c_str()));
266 value_desc_list.push_back(value_desc);
271 return Action::CanvasSpecific::set_param(name,param);
275 Action::ValueDescSmartLink::is_ready()const
279 if(value_desc_list.size()!=2)
281 return Action::CanvasSpecific::is_ready();
285 Action::ValueDescSmartLink::prepare()
288 throw Error(status_message.c_str());
290 if(value_desc_list.empty())
291 throw Error(Error::TYPE_NOTREADY);
295 if(value_desc_list.size()!=2)
296 throw Error(Error::TYPE_BUG);
298 ValueDesc& value_desc_t1(value_desc_list.front());
299 ValueDesc& value_desc_t2(value_desc_list.back());
300 t1 = value_desc_t1.get_value_node();
301 t2 = value_desc_t2.get_value_node();
305 // we should have a value node selected because is candidate
306 // should have checked it before
307 throw Error(Error::TYPE_BUG);
310 //See what is the tangent selected to convert.
311 ValueDesc& toconvert(value_desc_t2);
312 if(t1==link_value_node)
313 toconvert=value_desc_t2; // Convert t2
314 else if(t2==link_value_node)
315 toconvert=value_desc_t1; //Convert t1
316 else throw Error(Error::TYPE_BUG);
318 //Let's create a Scale Value Node
319 synfig::ValueNode::Handle scale_value_node=synfig::LinkableValueNode::create("scale",toconvert.get_value(time));
320 scale_value_node->set_parent_canvas(get_canvas());
321 //Let's connect the new Scale Value Node
322 Action::Handle action1(Action::create("ValueDescConnect"));
324 throw Error(Error::TYPE_CRITICAL);
325 action1->set_param("canvas",get_canvas());
326 action1->set_param("canvas_interface",get_canvas_interface());
327 action1->set_param("dest",toconvert);
328 action1->set_param("src",scale_value_node);
329 assert(action1->is_ready());
330 if(!action1->is_ready())
331 throw Error(Error::TYPE_NOTREADY);
332 add_action_front(action1);
335 //Let's Connect the link value node to the scale value node link subparam
336 Action::Handle action2(Action::create("ValueNodeLinkConnect"));
338 throw Error(Error::TYPE_CRITICAL);
340 action2->set_param("canvas",get_canvas());
341 action2->set_param("canvas_interface",get_canvas_interface());
342 action2->set_param("parent_value_node",scale_value_node);
343 action2->set_param("index",0);
344 action2->set_param("value_node",link_value_node);
345 assert(action2->is_ready());
346 if(!action2->is_ready())
347 throw Error(Error::TYPE_NOTREADY);
348 add_action_front(action2);
350 //Let's Set the scale to -1
351 Action::Handle action3(Action::create("ValueNodeConstSet"));
353 throw Error(Error::TYPE_CRITICAL);
355 action3->set_param("canvas",get_canvas());
356 action3->set_param("canvas_interface",get_canvas_interface());
357 action3->set_param("value_node",synfig::LinkableValueNode::Handle::cast_dynamic(scale_value_node)->get_link(1));
358 action3->set_param("new_value",synfig::ValueBase(Real(-1.0)));
359 assert(action3->is_ready());
360 if(!action3->is_ready())
361 throw Error(Error::TYPE_NOTREADY);
362 add_action_front(action3);
364 synfig::info("http://synfig.org/Linking#Tier_%d : %s", status_level, status_message.c_str());