1 /* === S Y N F I G ========================================================= */
2 /*! \file valuedescset.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 "layerparamset.h"
34 #include "valuenodeconstset.h"
35 #include "valuedescconnect.h"
36 #include "waypointsetsmart.h"
38 #include "valuedescset.h"
39 #include <synfigapp/canvasinterface.h>
40 #include <synfig/valuenode_bline.h>
41 #include <synfig/valuenode_blinecalctangent.h>
42 #include <synfig/valuenode_blinecalcvertex.h>
43 #include <synfig/valuenode_blinecalcwidth.h>
44 #include <synfig/valuenode_composite.h>
45 #include <synfig/valuenode_radialcomposite.h>
46 #include <synfig/valuenode_range.h>
47 #include <synfig/valuenode_reference.h>
48 #include <synfig/valuenode_scale.h>
49 #include <synfigapp/main.h>
51 #include <synfigapp/general.h>
57 using namespace synfig;
58 using namespace synfigapp;
59 using namespace Action;
61 /* === M A C R O S ========================================================= */
63 ACTION_INIT_NO_GET_LOCAL_NAME(Action::ValueDescSet);
64 ACTION_SET_NAME(Action::ValueDescSet,"ValueDescSet");
65 ACTION_SET_LOCAL_NAME(Action::ValueDescSet,N_("Set ValueDesc"));
66 ACTION_SET_TASK(Action::ValueDescSet,"set");
67 ACTION_SET_CATEGORY(Action::ValueDescSet,Action::CATEGORY_VALUEDESC);
68 ACTION_SET_PRIORITY(Action::ValueDescSet,0);
69 ACTION_SET_VERSION(Action::ValueDescSet,"0.0");
70 ACTION_SET_CVS_ID(Action::ValueDescSet,"$Id$");
72 /* === G L O B A L S ======================================================= */
74 /* === P R O C E D U R E S ================================================= */
76 /* === M E T H O D S ======================================================= */
78 Action::ValueDescSet::ValueDescSet():
84 Action::ValueDescSet::get_local_name()const
86 return strprintf(_("Set %s"),
88 ? value_desc.get_description().c_str()
93 Action::ValueDescSet::get_param_vocab()
95 ParamVocab ret(Action::CanvasSpecific::get_param_vocab());
97 ret.push_back(ParamDesc("value_desc",Param::TYPE_VALUEDESC)
98 .set_local_name(_("ValueDesc"))
101 ret.push_back(ParamDesc("new_value",Param::TYPE_VALUE)
102 .set_local_name(_("ValueBase"))
105 ret.push_back(ParamDesc("time",Param::TYPE_TIME)
106 .set_local_name(_("Time"))
114 Action::ValueDescSet::is_candidate(const ParamList &x)
116 return candidate_check(get_param_vocab(),x);
120 Action::ValueDescSet::set_param(const synfig::String& name, const Action::Param ¶m)
122 if(name=="value_desc" && param.get_type()==Param::TYPE_VALUEDESC)
124 value_desc=param.get_value_desc();
129 if(name=="new_value" && param.get_type()==Param::TYPE_VALUE)
131 value=param.get_value();
136 if(name=="time" && param.get_type()==Param::TYPE_TIME)
138 time=param.get_time();
143 return Action::CanvasSpecific::set_param(name,param);
147 Action::ValueDescSet::is_ready()const
149 if(!value_desc || !value.is_valid())
151 return Action::CanvasSpecific::is_ready();
155 Action::ValueDescSet::prepare()
159 // If our tangents are merged, and
160 // our first tangent is being manipulated,
161 // then we also need to adjust the other
163 if( value_desc.parent_is_value_node() &&
164 value_desc.get_parent_value_node()->get_type()==ValueBase::TYPE_BLINEPOINT &&
165 (value_desc.get_name()=="t1" || value_desc.get_name()=="t2") &&
166 //(value_desc.get_index()==4 || value_desc.get_index()==5) &&
167 (*value_desc.get_parent_value_node())(time).get(BLinePoint()).get_split_tangent_flag()==false)
170 ValueNode_Composite::Handle parent_value_node;
171 parent_value_node=parent_value_node.cast_dynamic(value_desc.get_parent_value_node());
172 assert(parent_value_node);
174 Vector t1((*parent_value_node->get_link("t1"))(time));
175 Vector t2((*parent_value_node->get_link("t2"))(time));
178 //if (value_desc.get_index()==4) {
179 if (value_desc.get_name()=="t1") {
180 ValueNode_Composite::Handle parent_value_node;
181 parent_value_node=parent_value_node.cast_dynamic(value_desc.get_parent_value_node());
183 assert(parent_value_node);
185 Action::Handle action(Action::create("ValueDescSet"));
188 throw Error(_("Unable to find action ValueDescSet (bug)"));
190 action->set_param("canvas",get_canvas());
191 action->set_param("canvas_interface",get_canvas_interface());
192 action->set_param("time",time);
193 action->set_param("new_value",value);
194 action->set_param("value_desc",ValueDesc(parent_value_node, parent_value_node->get_link_index_from_name("t2")));
196 if(!action->is_ready())
197 throw Error(Error::TYPE_NOTREADY);
203 // If we are a reference value node, then
204 // we need to distribute the changes to the
205 // referenced value node
206 if(value_desc.is_value_node() && ValueNode_Reference::Handle::cast_dynamic(value_desc.get_value_node()))
208 ValueDesc reference_value_desc(ValueNode_Reference::Handle::cast_dynamic(value_desc.get_value_node()),0);
210 Action::Handle action(Action::create("ValueDescSet"));
213 throw Error(_("Unable to find action ValueDescSet (bug)"));
215 action->set_param("canvas",get_canvas());
216 action->set_param("canvas_interface",get_canvas_interface());
217 action->set_param("time",time);
218 action->set_param("new_value",value);
219 action->set_param("value_desc",reference_value_desc);
221 if(!action->is_ready())
222 throw Error(Error::TYPE_NOTREADY);
229 // If we are a composite value node, then
230 // we need to distribute the changes to the
232 if(value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
234 ValueBase components[6];
236 switch(value.get_type())
238 case ValueBase::TYPE_VECTOR:
239 components[0]=value.get(Vector())[0];
240 components[1]=value.get(Vector())[1];
243 case ValueBase::TYPE_COLOR:
244 components[0]=value.get(Color()).get_r();
245 components[1]=value.get(Color()).get_g();
246 components[2]=value.get(Color()).get_b();
247 components[3]=value.get(Color()).get_a();
250 case ValueBase::TYPE_SEGMENT:
251 components[0]=value.get(Segment()).p1;
252 components[1]=value.get(Segment()).t1;
253 components[2]=value.get(Segment()).p2;
254 components[3]=value.get(Segment()).t2;
257 case ValueBase::TYPE_BLINEPOINT:
259 BLinePoint bline_point(value);
260 components[0]=bline_point.get_vertex();
261 components[1]=bline_point.get_width();
262 components[2]=bline_point.get_origin();
263 components[3]=bline_point.get_split_tangent_flag();
264 components[4]=bline_point.get_tangent1();
265 components[5]=bline_point.get_tangent2();
270 throw Error(_("Bad type for composite (%s)"),ValueBase::type_local_name(value.get_type()).c_str());
274 for(int i=0;i<n_components;i++)
276 ValueDesc component_value_desc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),i);
278 Action::Handle action(Action::create("ValueDescSet"));
281 throw Error(_("Unable to find action ValueDescSet (bug)"));
283 action->set_param("canvas",get_canvas());
284 action->set_param("canvas_interface",get_canvas_interface());
285 action->set_param("time",time);
286 action->set_param("new_value",components[i]);
287 action->set_param("value_desc",component_value_desc);
289 if(!action->is_ready())
290 throw Error(Error::TYPE_NOTREADY);
299 // If we are a RADIAL composite value node, then
300 // we need to distribute the changes to the
302 if(value_desc.is_value_node() && ValueNode_RadialComposite::Handle::cast_dynamic(value_desc.get_value_node()))
304 ValueBase components[6];
306 switch(value.get_type())
308 case ValueBase::TYPE_VECTOR:
310 Angle old_angle = (*(ValueNode_RadialComposite::Handle::cast_dynamic(
311 value_desc.get_value_node())->get_link("theta")))(time).get(Angle());
312 Vector vect(value.get(Vector()));
313 components[0]=vect.mag();
314 Angle change = Angle(Angle::tan(vect[1],vect[0])) - old_angle;
315 while (change < Angle::deg(-180)) change += Angle::deg(360);
316 while (change > Angle::deg(180)) change -= Angle::deg(360);
317 components[1]=old_angle + change;
321 case ValueBase::TYPE_COLOR:
322 components[0]=value.get(Color()).get_y();
323 components[1]=value.get(Color()).get_s();
324 components[2]=value.get(Color()).get_hue();
325 components[3]=value.get(Color()).get_a();
329 throw Error(_("Bad type for radial composite (%s)"),ValueBase::type_local_name(value.get_type()).c_str());
332 for(int i=0;i<n_components;i++)
334 ValueDesc component_value_desc(ValueNode_RadialComposite::Handle::cast_dynamic(value_desc.get_value_node()),i);
336 Action::Handle action(Action::create("ValueDescSet"));
339 throw Error(_("Unable to find action ValueDescSet (bug)"));
341 action->set_param("canvas",get_canvas());
342 action->set_param("canvas_interface",get_canvas_interface());
343 action->set_param("time",time);
344 action->set_param("new_value",components[i]);
345 action->set_param("value_desc",component_value_desc);
347 if(!action->is_ready())
348 throw Error(Error::TYPE_NOTREADY);
356 // Perform reverse manipulations
358 // If we are a scale value node, then edit the link
359 // such that it will scale to our target value
360 if (ValueNode_Scale::Handle scale_value_node = ValueNode_Scale::Handle::cast_dynamic(value_desc.get_value_node()))
362 if(! scale_value_node->is_invertible(time))
364 synfig::warning(_("Attempt to edit scale ValueNode with a scale factor of zero."));
370 if (value.get_type() == ValueBase::TYPE_ANGLE)
371 new_value = scale_value_node->get_inverse(time, value.get(Angle()));
372 else if (value.get_type() == ValueBase::TYPE_REAL)
373 throw Error(_("Inverse manipulation of real scale values not implemented in core."));
375 new_value = scale_value_node->get_inverse(time, value.get(Vector()));
377 Action::Handle action(Action::create("ValueDescSet"));
380 throw Error(_("Unable to find action ValueDescSet (bug)"));
382 action->set_param("canvas",get_canvas());
383 action->set_param("canvas_interface",get_canvas_interface());
384 action->set_param("time",time);
385 action->set_param("new_value",new_value);
386 action->set_param("value_desc",ValueDesc(scale_value_node, scale_value_node->get_link_index_from_name("link")));
388 if(!action->is_ready())
389 throw Error(Error::TYPE_NOTREADY);
395 // Range: disallow values outside the range
396 if (ValueNode_Range::Handle range_value_node = ValueNode_Range::Handle::cast_dynamic(value_desc.get_value_node()))
400 if (value.get_type() == ValueBase::TYPE_ANGLE)
401 new_value = range_value_node->get_inverse(time, value.get(Angle()));
402 else if (value.get_type() == ValueBase::TYPE_REAL)
403 throw Error(_("Inverse manipulation of real range values not implemented in core."));
405 new_value = range_value_node->get_inverse(time, value.get(Vector()));
407 Action::Handle action(Action::create("ValueDescSet"));
410 throw Error(_("Unable to find action ValueDescSet (bug)"));
412 action->set_param("canvas",get_canvas());
413 action->set_param("canvas_interface",get_canvas_interface());
414 action->set_param("time",time);
415 action->set_param("new_value",new_value);
416 action->set_param("value_desc",ValueDesc(range_value_node,range_value_node->get_link_index_from_name("link")));
418 if(!action->is_ready())
419 throw Error(Error::TYPE_NOTREADY);
425 // BlineCalcWidth: modify the scale value node
426 // so that the target width is achieved
427 if (ValueNode_BLineCalcWidth::Handle bline_width = ValueNode_BLineCalcWidth::Handle::cast_dynamic(value_desc.get_value_node()))
429 Real old_width((*bline_width)(time).get(Real()));
430 Real scale((*(bline_width->get_link("scale")))(time).get(Real()));
432 ValueBase new_width(value.get(Real()) * scale / old_width);
434 Action::Handle action(Action::create("ValueDescSet"));
437 throw Error(_("Unable to find action ValueDescSet (bug)"));
439 action->set_param("canvas",get_canvas());
440 action->set_param("canvas_interface",get_canvas_interface());
441 action->set_param("time",time);
442 action->set_param("new_value",new_width);
443 action->set_param("value_desc",ValueDesc(bline_width, bline_width->get_link_index_from_name("scale")));
445 if(!action->is_ready())
446 throw Error(Error::TYPE_NOTREADY);
452 // BLineCalcVertex: snap the point to the nearest
454 if (ValueNode_BLineCalcVertex::Handle bline_vertex = ValueNode_BLineCalcVertex::Handle::cast_dynamic(value_desc.get_value_node()))
456 ValueNode_BLine::Handle bline = ValueNode_BLine::Handle::cast_dynamic(bline_vertex->get_link("bline"));
458 ValueBase new_amount;
459 if (((*(bline_vertex->get_link("loop")))(time).get(bool()))){
460 // The bline is looped. Animation may require an amount parameter
461 // outside the range of 0-1, so make sure that the amount does
462 // not change drastically.
463 Real amount_old((*(bline_vertex->get_link("amount")))(time).get(Real()));
464 Real amount_new = synfig::find_closest_point((*bline)(time), value, radius, bline->get_loop());
465 Real difference = fmod( fmod(amount_new - amount_old, 1.0) + 1.0 , 1.0);
466 //fmod is called twice to avoid negative values
467 if (difference > 0.5) difference=difference-1.0;
469 new_amount = amount_old+difference;
471 new_amount = synfig::find_closest_point((*bline)(time), value, radius, bline->get_loop());
474 Action::Handle action(Action::create("ValueDescSet"));
477 throw Error(_("Unable to find action ValueDescSet (bug)"));
479 action->set_param("canvas",get_canvas());
480 action->set_param("canvas_interface",get_canvas_interface());
481 action->set_param("time",time);
482 action->set_param("new_value",new_amount);
483 action->set_param("value_desc",ValueDesc(bline_vertex, bline_vertex->get_link_index_from_name("amount")));
485 if(!action->is_ready())
486 throw Error(Error::TYPE_NOTREADY);
493 // BLineCalcTangent: adjust scale and offset
494 // to achieve the desired tangent
495 if (ValueNode_BLineCalcTangent::Handle bline_tangent = ValueNode_BLineCalcTangent::Handle::cast_dynamic(value_desc.get_value_node()))
498 ValueDesc scale_value_desc(bline_tangent,bline_tangent->get_link_index_from_name("scale"));
499 ValueDesc offset_value_desc(bline_tangent,bline_tangent->get_link_index_from_name("offset"));
501 switch(value_desc.get_value_type())
503 case ValueBase::TYPE_REAL:
505 Real old_length = (*bline_tangent)(time).get(Real());
506 Real new_length = value.get(Vector()).mag();
507 Real scale((*(bline_tangent->get_link("scale")))(time).get(Real()));
508 bool fixed_length((*(bline_tangent->get_link("fixed_length")))(time).get(bool()));
512 new_scale = new_length;
517 new_scale = new_length * scale / old_length;
520 case ValueBase::TYPE_VECTOR:
522 Vector old_tangent = (*bline_tangent)(time).get(Vector());
523 Angle old_angle = old_tangent.angle();
524 Real old_length = old_tangent.mag();
525 Angle new_angle = value.get(Vector()).angle();
526 Real new_length = value.get(Vector()).mag();
527 Angle old_offset((*(bline_tangent->get_link("offset")))(time).get(Angle()));
528 Real scale((*(bline_tangent->get_link("scale")))(time).get(Real()));
529 bool fixed_length((*(bline_tangent->get_link("fixed_length")))(time).get(bool()));
532 new_scale = new_length;
537 new_scale = new_length * scale / old_length;
540 Action::Handle action(Action::create("ValueDescSet"));
543 throw Error(_("Unable to find action ValueDescSet (bug)"));
545 action->set_param("canvas",get_canvas());
546 action->set_param("canvas_interface",get_canvas_interface());
547 action->set_param("time",time);
548 action->set_param("new_value", ValueBase(old_offset + new_angle - old_angle));
549 action->set_param("value_desc",offset_value_desc);
551 if(!action->is_ready())
552 throw Error(Error::TYPE_NOTREADY);
559 case ValueBase::TYPE_ANGLE:
561 Angle old_angle = (*bline_tangent)(time).get(Angle());
562 Angle new_angle = value.get(Vector()).angle();
563 Angle old_offset((*(bline_tangent->get_link("offset")))(time).get(Angle()));
566 Action::Handle action(Action::create("ValueDescSet"));
569 throw Error(_("Unable to find action ValueDescSet (bug)"));
571 action->set_param("canvas",get_canvas());
572 action->set_param("canvas_interface",get_canvas_interface());
573 action->set_param("time",time);
574 action->set_param("new_value", ValueBase(old_offset + new_angle - old_angle));
575 action->set_param("value_desc",offset_value_desc);
577 if(!action->is_ready())
578 throw Error(Error::TYPE_NOTREADY);
590 Action::Handle action(Action::create("ValueDescSet"));
593 throw Error(_("Unable to find action ValueDescSet (bug)"));
595 action->set_param("canvas",get_canvas());
596 action->set_param("canvas_interface",get_canvas_interface());
597 action->set_param("time",time);
598 action->set_param("new_value",new_scale);
599 action->set_param("value_desc",scale_value_desc);
601 if(!action->is_ready())
602 throw Error(Error::TYPE_NOTREADY);
609 // end reverse manipulations
613 // If we are merging the tangents of a BLinePoint,
614 // we must also set the second tangent for things
615 // to interpolate properly
616 if (value_desc.parent_is_value_node() &&
617 value_desc.get_parent_value_node()->get_type()==ValueBase::TYPE_BLINEPOINT &&
618 value_desc.get_index()==3)
620 ValueNode_Composite::Handle parent_value_node;
621 parent_value_node=parent_value_node.cast_dynamic(value_desc.get_parent_value_node());
623 assert(parent_value_node);
625 // are we splitting or merging the tangents?
626 if (value.get(bool()))
628 // we are splitting tangents
630 Action::Handle action(Action::create("ValueDescSet"));
633 throw Error(_("Unable to find action ValueDescSet (bug)"));
635 action->set_param("canvas",get_canvas());
636 action->set_param("canvas_interface",get_canvas_interface());
637 action->set_param("time",time);
638 action->set_param("new_value",(*parent_value_node->get_link("t1"))(time));
639 action->set_param("value_desc",ValueDesc(parent_value_node,parent_value_node->get_link_index_from_name("t2")));
641 if(!action->is_ready())
642 throw Error(Error::TYPE_NOTREADY);
648 // we are merging tangents
650 // the merged tangent should be the average of the 2 tangents we're merging
651 ValueBase average(((Vector)((*parent_value_node->get_link("t1"))(time)) +
652 (Vector)((*parent_value_node->get_link("t2"))(time))) / 2);
655 Action::Handle action(Action::create("ValueDescSet"));
658 throw Error(_("Unable to find action ValueDescSet (bug)"));
660 action->set_param("canvas",get_canvas());
661 action->set_param("canvas_interface",get_canvas_interface());
662 action->set_param("time",time);
663 action->set_param("new_value",average);
664 action->set_param("value_desc",ValueDesc(parent_value_node,parent_value_node->get_link_index_from_name("t1")));
666 if(!action->is_ready())
667 throw Error(Error::TYPE_NOTREADY);
673 Action::Handle action(Action::create("ValueDescSet"));
676 throw Error(_("Unable to find action ValueDescSet (bug)"));
678 action->set_param("canvas",get_canvas());
679 action->set_param("canvas_interface",get_canvas_interface());
680 action->set_param("time",time);
681 action->set_param("new_value",average);
682 action->set_param("value_desc",ValueDesc(parent_value_node,parent_value_node->get_link_index_from_name("t2")));
684 if(!action->is_ready())
685 throw Error(Error::TYPE_NOTREADY);
694 if( value_desc.parent_is_value_node())
697 if(value_desc.get_parent_value_node()->get_type()==ValueBase::TYPE_BLINEPOINT)
700 if(value_desc.get_index()==4)
703 if((*value_desc.get_parent_value_node())(time).get(BLinePoint()).get_split_tangent_flag()==false)
712 ValueBase local_value;
713 local_value.set_static(false);
714 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
716 if(value_desc.is_value_node())
717 local_value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
719 local_value=value_desc.get_value();
721 // If we are in animate editing mode
722 if(get_edit_mode()&MODE_ANIMATE && !local_value.get_static())
725 ValueNode_Animated::Handle& value_node(value_node_animated);
727 // If this value isn't a ValueNode_Animated, but
728 // it is somewhat constant, then go ahead and convert
729 // it to a ValueNode_Animated.
730 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
733 if(value_desc.is_value_node())
734 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
736 value=value_desc.get_value();
738 if(!value_node)value_node=ValueNode_Animated::create(value,time);
739 //if(!value_node)value_node=ValueNode_Animated::create(value.get_type());
741 Action::Handle action;
743 if(!value_desc.is_value_node())
745 action=(ValueDescConnect::create());
746 action->set_param("dest",value_desc);
747 action->set_param("src",ValueNode::Handle(value_node));
751 action=Action::create("ValueNodeReplace");
752 action->set_param("dest",value_desc.get_value_node());
753 action->set_param("src",ValueNode::Handle(value_node));
756 action->set_param("canvas",get_canvas());
757 action->set_param("canvas_interface",get_canvas_interface());
759 if(!action->is_ready())
760 throw Error(Error::TYPE_NOTREADY);
762 add_action_front(action);
766 value_node=value_node.cast_dynamic(value_desc.get_value_node());
770 throw Error(_("Direct manipulation of this ValueNode type is not yet supported"));
772 Action::Handle action(WaypointSetSmart::create());
774 //Waypoint waypoint(value,time);
776 Waypoint waypoint(value_node->new_waypoint_at_time(time));
777 waypoint.set_value(value);
779 waypoint.set_before(synfigapp::Main::get_interpolation());
780 waypoint.set_after(synfigapp::Main::get_interpolation());
782 action->set_param("canvas",get_canvas());
783 action->set_param("canvas_interface",get_canvas_interface());
784 action->set_param("value_node",ValueNode::Handle(value_node));
785 action->set_param("waypoint",waypoint);
787 if(!action->is_ready())
788 throw Error(Error::TYPE_NOTREADY);
796 if(value_desc.is_value_node())
798 if(ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
800 Action::Handle action(ValueNodeConstSet::create());
801 synfig::ValueNode_Const::Handle localvaluenode(ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()));
802 value.set_static(localvaluenode->get_static());
803 action->set_param("canvas",get_canvas());
804 action->set_param("canvas_interface",get_canvas_interface());
805 action->set_param("value_node",value_desc.get_value_node());
806 action->set_param("new_value",value);
808 if(!action->is_ready())
809 throw Error(Error::TYPE_NOTREADY);
811 add_action_front(action);
815 if(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
816 throw Error(_("You must be in Animate-Editing-Mode to directly manipulate this value"));
818 throw Error(_("Direct manipulation of this ValueNode type is not yet supported"));
821 if(value_desc.parent_is_layer_param() && !value_desc.is_value_node())
823 Action::Handle layer_param_set(LayerParamSet::create());
824 synfig::ValueBase localvalue(value_desc.get_value());
825 value.set_static(local_value.get_static());
826 layer_param_set->set_param("canvas",get_canvas());
827 layer_param_set->set_param("canvas_interface",get_canvas_interface());
828 layer_param_set->set_param("layer",value_desc.get_layer());
829 layer_param_set->set_param("param",value_desc.get_param_name());
830 layer_param_set->set_param("new_value",value);
832 if(!layer_param_set->is_ready())
833 throw Error(Error::TYPE_NOTREADY);
835 add_action_front(layer_param_set);
839 throw Error(_("Unsupported ValueDesc type"));