1 /* === S Y N F I G ========================================================= */
2 /*! \file valuedesclink.cpp
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007, 2008 Chris Moore
10 ** Copyright (c) 2010 Carlos López
12 ** This package is free software; you can redistribute it and/or
13 ** modify it under the terms of the GNU General Public License as
14 ** published by the Free Software Foundation; either version 2 of
15 ** the License, or (at your option) any later version.
17 ** This package is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ** General Public License for more details.
23 /* ========================================================================= */
25 /* === H E A D E R S ======================================================= */
34 #include "valuedesclink.h"
36 #include <synfigapp/canvasinterface.h>
37 #include <synfig/valuenode_const.h>
38 #include <synfig/valuenode_scale.h>
40 #include <synfigapp/general.h>
46 using namespace synfig;
47 using namespace synfigapp;
48 using namespace Action;
50 /* === M A C R O S ========================================================= */
52 ACTION_INIT(Action::ValueDescLink);
53 ACTION_SET_NAME(Action::ValueDescLink,"ValueDescLink");
54 ACTION_SET_LOCAL_NAME(Action::ValueDescLink,N_("Link"));
55 ACTION_SET_TASK(Action::ValueDescLink,"connect");
56 ACTION_SET_CATEGORY(Action::ValueDescLink,Action::CATEGORY_VALUEDESC);
57 ACTION_SET_PRIORITY(Action::ValueDescLink,0);
58 ACTION_SET_VERSION(Action::ValueDescLink,"0.0");
59 ACTION_SET_CVS_ID(Action::ValueDescLink,"$Id$");
61 /* === G L O B A L S ======================================================= */
63 /* === P R O C E D U R E S ================================================= */
65 /* === M E T H O D S ======================================================= */
67 Action::ValueDescLink::ValueDescLink():
68 poison(false), status_level(0), link_scalar(0.0)
73 Action::ValueDescLink::get_param_vocab()
75 ParamVocab ret(Action::CanvasSpecific::get_param_vocab());
77 ret.push_back(ParamDesc("value_desc",Param::TYPE_VALUEDESC)
78 .set_local_name(_("ValueDesc to smart link"))
79 .set_requires_multiple()
86 Action::ValueDescLink::is_candidate(const ParamList &x)
88 return candidate_check(get_param_vocab(),x);
92 Action::ValueDescLink::set_param(const synfig::String& name, const Action::Param ¶m)
94 if(name=="time" && param.get_type()==Param::TYPE_TIME)
96 time=param.get_time();
100 // don't bother looking for the best value to use if there's already been an error
101 if (poison==true) return false;
103 if(name=="value_desc" && param.get_type()==Param::TYPE_VALUEDESC)
105 ValueDesc value_desc(param.get_value_desc());
107 if(value_desc.is_value_node() && value_desc.get_value_node()->is_exported())
109 if(link_value_node==value_desc.get_value_node())
112 if(link_value_node && link_value_node->is_exported())
115 status_message = (_("Cannot link two different exported values ('") +
116 value_desc.get_value_node()->get_id() + _("' and '") +
117 link_value_node->get_id()) + _("')");
121 link_value_node=value_desc.get_value_node();
122 link_scalar=value_desc.get_scalar();
123 status_message = _("Used exported ValueNode ('") + link_value_node->get_id() + _("').");
125 else if(value_desc.is_value_node())
130 status_message = _("Using the only available ValueNode.");
131 link_value_node=value_desc.get_value_node();
132 link_scalar=value_desc.get_scalar();
134 else if(link_value_node->is_exported())
136 // we've already seen an exported value, so use that rather than the current value
138 // Use the one that is referenced more
139 else if(link_value_node->rcount()!=value_desc.get_value_node()->rcount())
141 if(link_value_node->rcount()<value_desc.get_value_node()->rcount())
144 status_message = _("Using the most referenced ValueNode.");
145 link_value_node=value_desc.get_value_node();
146 link_scalar=value_desc.get_scalar();
148 else if (status_level <= 2)
151 status_message = _("Using the most referenced ValueNode.");
154 // If the current link value node is a constant and
155 // this one isn't, then give preference to the exotic
156 else if(ValueNode_Const::Handle::cast_dynamic(link_value_node) && !ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
159 status_message = _("There's a tie for most referenced; using the animated ValueNode.");
160 link_value_node=value_desc.get_value_node();
161 link_scalar=value_desc.get_scalar();
163 else if(ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()) && !ValueNode_Const::Handle::cast_dynamic(link_value_node))
165 if (status_level <= 3)
168 status_message = _("There's a tie for most referenced; using the animated ValueNode.");
171 // If both are animated, and this one has more waypoints, then use the one with more waypoints
172 else if(ValueNode_Animated::Handle::cast_dynamic(link_value_node) &&
173 ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()) &&
174 ValueNode_Animated::Handle::cast_dynamic(link_value_node)->waypoint_list().size() !=
175 ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node())->waypoint_list().size())
177 if (ValueNode_Animated::Handle::cast_dynamic(link_value_node)->waypoint_list().size() <
178 ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node())->waypoint_list().size())
181 status_message = _("There's a tie for most referenced, and both are animated; using the one with the most waypoints.");
182 link_value_node=value_desc.get_value_node();
183 link_scalar=value_desc.get_scalar();
185 else if (status_level <= 4)
188 status_message = _("There's a tie for most referenced, and both are animated; using the one with the most waypoints.");
191 // If both are Linkable Value Nodes and has waypoint in its children, use the one with more waypoints
192 else if(LinkableValueNode::Handle::cast_dynamic(link_value_node) &&
193 LinkableValueNode::Handle::cast_dynamic(value_desc.get_value_node()) &&
194 LinkableValueNode::Handle::cast_dynamic(link_value_node)->get_times().size() !=
195 LinkableValueNode::Handle::cast_dynamic(value_desc.get_value_node())->get_times().size())
197 if(LinkableValueNode::Handle::cast_dynamic(link_value_node)->get_times().size() <
198 LinkableValueNode::Handle::cast_dynamic(value_desc.get_value_node())->get_times().size())
201 status_message = _("There's a tie for most referenced, and both are linkable value node animated; using the one with the most waypoints.");
202 link_value_node=value_desc.get_value_node();
203 link_scalar=value_desc.get_scalar();
205 else if (status_level <= 4)
208 status_message = _("There's a tie for most referenced, and both are linkable value node animated; using the one with the most waypoints.");
211 // Use the one that was least recently changed
212 else if(link_value_node->get_time_last_changed()!=value_desc.get_value_node()->get_time_last_changed())
214 if(link_value_node->get_time_last_changed()>value_desc.get_value_node()->get_time_last_changed())
217 status_message = _("Everything is tied; using the least recently modified value.");
218 link_value_node=value_desc.get_value_node();
219 link_scalar=value_desc.get_scalar();
221 else if (status_level <= 5)
224 status_message = _("Everything is tied; using the least recently modified value.");
230 status_message = _("Absolutely everything is tied.");
234 if(value_desc_list.size() && value_desc.get_value_type()!=value_desc_list.front().get_value_type())
236 // Everything must be of the same type
238 status_message = (strprintf(_("Cannot link two values of different types ('%s' and '%s')"),
239 ValueBase::type_local_name(value_desc.get_value_type()).c_str(),
240 ValueBase::type_local_name(value_desc_list.front().get_value_type()).c_str()));
244 value_desc_list.push_back(value_desc);
249 return Action::CanvasSpecific::set_param(name,param);
253 Action::ValueDescLink::is_ready()const
257 if(value_desc_list.size()<=1)
259 return Action::CanvasSpecific::is_ready();
263 Action::ValueDescLink::prepare()
266 throw Error(status_message.c_str());
268 if(value_desc_list.empty())
269 throw Error(Error::TYPE_NOTREADY);
275 status_message = _("No ValueNodes were available, so one was created.");
276 ValueDesc& value_desc(value_desc_list.back());
278 link_value_node=ValueNode_Const::create(value_desc.get_value(time));
280 Action::Handle action(Action::create("ValueDescConnect"));
282 action->set_param("canvas",get_canvas());
283 action->set_param("canvas_interface",get_canvas_interface());
284 action->set_param("src",link_value_node);
285 action->set_param("dest",value_desc);
287 assert(action->is_ready());
288 if(!action->is_ready())
289 throw Error(Error::TYPE_NOTREADY);
291 add_action_front(action);
294 // Check if the selected link value node is already a scale -1.0 Linkable Value Node
295 bool link_is_scaled(false);
296 if(synfig::ValueNode_Scale::Handle::cast_dynamic(link_value_node))
298 synfig::ValueNode_Const::Handle scale_vn(
299 synfig::ValueNode_Const::Handle::cast_dynamic(
300 synfig::ValueNode_Scale::Handle::cast_dynamic(link_value_node)->get_link(1)
304 if((*scale_vn)(synfig::Time(0))==synfig::ValueBase(Real(-1.0)))
308 std::list<ValueDesc>::iterator iter;
309 Real current_scalar(1.0);
310 bool found_inverse(false);
311 // Check if we are dealing the case of linking differnt types of tangents
312 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
314 ValueDesc& v_desc(*iter);
315 // If parent is linkable value node
316 if(v_desc.parent_is_linkable_value_node())
318 // if the link describe to any tangent (index 4 or 5), continue
319 if(v_desc.get_index() == 4 || v_desc.get_index() == 5)
321 synfig::Real iter_scalar=v_desc.get_scalar();
322 // Let's compare the sign of scalar of the value node witht the current one
323 // and remember if a change of sign is seen.
324 if(iter_scalar*current_scalar < 0) // if they have different signs
327 current_scalar=iter_scalar;
342 // found_inverse = true only if all they are tangents and some are inversed tangents
343 //Noe let's loop throug all the value desc
344 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
346 ValueDesc& value_desc(*iter);
348 // only one of the selected items can be exported - that's the one we're linking to
349 // don't link it to itself
350 if (value_desc.is_exported())
352 // Don't link the selected to itself (maybe it is redundant with the previous check)
353 if(value_desc.get_value_node() == link_value_node)
355 // If we found inverse means that all they are tangents and some are differnt scalar (different colors)
358 //Check if the current value node has opposite scalar than the link
359 // value node to convert to scale -1.0 before connect.
360 // Check also if the link value node is NOT also a scale -1
361 if( (value_desc.get_scalar()*link_scalar<0) && (link_is_scaled==false) )
363 //Let's create a Scale Value Node
364 synfig::ValueNode::Handle scale_value_node=synfig::LinkableValueNode::create("scale",iter->get_value(time));
365 if(!scale_value_node)
366 throw Error(Error::TYPE_BUG);
367 scale_value_node->set_parent_canvas(get_canvas());
368 //Let's connect the new Scale Value Node to the value node
369 Action::Handle action1(Action::create("ValueDescConnect"));
371 throw Error(Error::TYPE_CRITICAL);
372 action1->set_param("canvas",get_canvas());
373 action1->set_param("canvas_interface",get_canvas_interface());
374 action1->set_param("dest",value_desc);
375 action1->set_param("src",scale_value_node);
376 assert(action1->is_ready());
377 if(!action1->is_ready())
378 throw Error(Error::TYPE_NOTREADY);
379 add_action_front(action1);
381 //Let's Connect the link value node to the scale value node link subparam
382 Action::Handle action2(Action::create("ValueNodeLinkConnect"));
384 throw Error(Error::TYPE_CRITICAL);
386 action2->set_param("canvas",get_canvas());
387 action2->set_param("canvas_interface",get_canvas_interface());
388 action2->set_param("parent_value_node",scale_value_node);
389 action2->set_param("index",0);
390 action2->set_param("value_node",link_value_node);
391 assert(action2->is_ready());
392 if(!action2->is_ready())
393 throw Error(Error::TYPE_NOTREADY);
394 add_action_front(action2);
396 //Let's Set the scale to -1
397 Action::Handle action3(Action::create("ValueNodeConstSet"));
399 throw Error(Error::TYPE_CRITICAL);
401 action3->set_param("canvas",get_canvas());
402 action3->set_param("canvas_interface",get_canvas_interface());
403 action3->set_param("value_node",synfig::LinkableValueNode::Handle::cast_dynamic(scale_value_node)->get_link(1));
404 action3->set_param("new_value",synfig::ValueBase(Real(-1.0)));
405 assert(action3->is_ready());
406 if(!action3->is_ready())
407 throw Error(Error::TYPE_NOTREADY);
408 add_action_front(action3);
410 else if((iter->get_scalar()*link_scalar<0) && (link_is_scaled==true) )
412 //Let's connect the link value node -> link to the value node
413 // There is not needed conversion to scale of the value node
414 // because the link value node is already a scale -1
415 Action::Handle action4(Action::create("ValueDescConnect"));
417 throw Error(Error::TYPE_CRITICAL);
418 action4->set_param("canvas",get_canvas());
419 action4->set_param("canvas_interface",get_canvas_interface());
420 action4->set_param("dest",value_desc);
421 action4->set_param("src",synfig::ValueNode_Scale::Handle::cast_dynamic(link_value_node)->get_link(0));
422 assert(action4->is_ready());
423 if(!action4->is_ready())
424 throw Error(Error::TYPE_NOTREADY);
425 add_action_front(action4);
429 //Let's connect the link value node to the value node
430 Action::Handle action(Action::create("ValueDescConnect"));
432 action->set_param("canvas",get_canvas());
433 action->set_param("canvas_interface",get_canvas_interface());
434 action->set_param("src",link_value_node);
435 action->set_param("dest",value_desc);
437 assert(action->is_ready());
438 if(!action->is_ready())
439 throw Error(Error::TYPE_NOTREADY);
441 add_action_front(action);
444 else // Not found inverse so do a regualr link
446 //Let's connect the link value node to the value node
447 Action::Handle action(Action::create("ValueDescConnect"));
449 action->set_param("canvas",get_canvas());
450 action->set_param("canvas_interface",get_canvas_interface());
451 action->set_param("src",link_value_node);
452 action->set_param("dest",value_desc);
454 assert(action->is_ready());
455 if(!action->is_ready())
456 throw Error(Error::TYPE_NOTREADY);
458 add_action_front(action);
463 synfig::info("http://synfig.org/Linking#Tier_%d : %s", status_level, status_message.c_str());