Move reverse manipulation code into ValueDescSet action
[synfig.git] / synfig-studio / src / synfigapp / actions / valuedescset.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file valuedescset.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007, 2008 Chris Moore
10 **
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.
15 **
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.
20 **      \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #ifdef USING_PCH
27 #       include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 #       include <config.h>
31 #endif
32
33 #include "layerparamset.h"
34 #include "valuenodeconstset.h"
35 #include "valuedescconnect.h"
36 #include "waypointsetsmart.h"
37
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>
50
51 #include <synfigapp/general.h>
52
53 #endif
54
55 using namespace std;
56 using namespace etl;
57 using namespace synfig;
58 using namespace synfigapp;
59 using namespace Action;
60
61 /* === M A C R O S ========================================================= */
62
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$");
71
72 /* === G L O B A L S ======================================================= */
73
74 /* === P R O C E D U R E S ================================================= */
75
76 /* === M E T H O D S ======================================================= */
77
78 Action::ValueDescSet::ValueDescSet():
79         time(0)
80 {
81 }
82
83 synfig::String
84 Action::ValueDescSet::get_local_name()const
85 {
86         return strprintf(_("Set %s"),
87                                          value_desc
88                                          ? value_desc.get_description().c_str()
89                                          : _("ValueDesc"));
90 }
91
92 Action::ParamVocab
93 Action::ValueDescSet::get_param_vocab()
94 {
95         ParamVocab ret(Action::CanvasSpecific::get_param_vocab());
96
97         ret.push_back(ParamDesc("value_desc",Param::TYPE_VALUEDESC)
98                 .set_local_name(_("ValueDesc"))
99         );
100
101         ret.push_back(ParamDesc("new_value",Param::TYPE_VALUE)
102                 .set_local_name(_("ValueBase"))
103         );
104
105         ret.push_back(ParamDesc("time",Param::TYPE_TIME)
106                 .set_local_name(_("Time"))
107                 .set_optional()
108         );
109
110         return ret;
111 }
112
113 bool
114 Action::ValueDescSet::is_candidate(const ParamList &x)
115 {
116         return candidate_check(get_param_vocab(),x);
117 }
118
119 bool
120 Action::ValueDescSet::set_param(const synfig::String& name, const Action::Param &param)
121 {
122         if(name=="value_desc" && param.get_type()==Param::TYPE_VALUEDESC)
123         {
124                 value_desc=param.get_value_desc();
125
126                 return true;
127         }
128
129         if(name=="new_value" && param.get_type()==Param::TYPE_VALUE)
130         {
131                 value=param.get_value();
132
133                 return true;
134         }
135
136         if(name=="time" && param.get_type()==Param::TYPE_TIME)
137         {
138                 time=param.get_time();
139
140                 return true;
141         }
142
143         return Action::CanvasSpecific::set_param(name,param);
144 }
145
146 bool
147 Action::ValueDescSet::is_ready()const
148 {
149         if(!value_desc || !value.is_valid())
150                 return false;
151         return Action::CanvasSpecific::is_ready();
152 }
153
154 void
155 Action::ValueDescSet::prepare()
156 {
157         clear();
158
159         // If our tangents are merged, and
160         // our first tangent is being manipulated,
161         // then we also need to adjust the other
162         // tangent.
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)
168         {
169                 {
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);
173
174                         Vector t1((*parent_value_node->get_link("t1"))(time));
175                         Vector t2((*parent_value_node->get_link("t2"))(time));
176                 }
177
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());
182
183                         assert(parent_value_node);
184
185                         Action::Handle action(Action::create("ValueDescSet"));
186
187                         if(!action)
188                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
189
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")));
195
196                         if(!action->is_ready())
197                                 throw Error(Error::TYPE_NOTREADY);
198
199                         add_action(action);
200                 }
201         }
202
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()))
207         {
208                 ValueDesc reference_value_desc(ValueNode_Reference::Handle::cast_dynamic(value_desc.get_value_node()),0);
209
210                 Action::Handle action(Action::create("ValueDescSet"));
211
212                 if(!action)
213                         throw Error(_("Unable to find action ValueDescSet (bug)"));
214
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);
220
221                 if(!action->is_ready())
222                         throw Error(Error::TYPE_NOTREADY);
223
224                 add_action(action);
225
226                 return;
227         }
228
229         // If we are a composite value node, then
230         // we need to distribute the changes to the
231         // individual parts
232         if(value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
233         {
234                 ValueBase components[6];
235                 int n_components(0);
236                 switch(value.get_type())
237                 {
238                 case ValueBase::TYPE_VECTOR:
239                         components[0]=value.get(Vector())[0];
240                         components[1]=value.get(Vector())[1];
241                         n_components=2;
242                         break;
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();
248                         n_components=4;
249                         break;
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;
255                         n_components=4;
256                         break;
257                 case ValueBase::TYPE_BLINEPOINT:
258                 {
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();
266                         n_components=6;
267                         break;
268                 }
269                 default:
270                         throw Error(_("Bad type for composite (%s)"),ValueBase::type_local_name(value.get_type()).c_str());
271                         break;
272                 }
273
274                 for(int i=0;i<n_components;i++)
275                 {
276                         ValueDesc component_value_desc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),i);
277
278                         Action::Handle action(Action::create("ValueDescSet"));
279
280                         if(!action)
281                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
282
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);
288
289                         if(!action->is_ready())
290                                 throw Error(Error::TYPE_NOTREADY);
291
292                         add_action(action);
293                 }
294
295                 return;
296         }
297
298
299         // If we are a RADIAL composite value node, then
300         // we need to distribute the changes to the
301         // individual parts
302         if(value_desc.is_value_node() && ValueNode_RadialComposite::Handle::cast_dynamic(value_desc.get_value_node()))
303         {
304                 ValueBase components[6];
305                 int n_components(0);
306                 switch(value.get_type())
307                 {
308                 case ValueBase::TYPE_VECTOR:
309                 {
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;
318                         n_components=2;
319                 }
320                         break;
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();
326                         n_components=4;
327                         break;
328                 default:
329                         throw Error(_("Bad type for radial composite (%s)"),ValueBase::type_local_name(value.get_type()).c_str());
330                         break;
331                 }
332                 for(int i=0;i<n_components;i++)
333                 {
334                         ValueDesc component_value_desc(ValueNode_RadialComposite::Handle::cast_dynamic(value_desc.get_value_node()),i);
335
336                         Action::Handle action(Action::create("ValueDescSet"));
337
338                         if(!action)
339                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
340
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);
346
347                         if(!action->is_ready())
348                                 throw Error(Error::TYPE_NOTREADY);
349
350                         add_action(action);
351                 }
352
353                 return;
354         }
355
356         // Perform reverse manipulations
357
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()))
361         {
362                 if(! scale_value_node->is_invertible(time))
363                 {
364                         synfig::warning(_("Attempt to edit scale ValueNode with a scale factor of zero."));
365                         return;
366                 }
367
368                 ValueBase new_value;
369
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."));
374                 else
375                         new_value = scale_value_node->get_inverse(time, value.get(Vector()));
376
377                 Action::Handle action(Action::create("ValueDescSet"));
378
379                 if(!action)
380                         throw Error(_("Unable to find action ValueDescSet (bug)"));
381
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")));
387
388                 if(!action->is_ready())
389                         throw Error(Error::TYPE_NOTREADY);
390
391                 add_action(action);
392                 return;
393         }
394
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()))
397         {
398                 ValueBase new_value;
399
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."));
404                 else
405                         new_value = range_value_node->get_inverse(time, value.get(Vector()));
406
407                 Action::Handle action(Action::create("ValueDescSet"));
408
409                 if(!action)
410                         throw Error(_("Unable to find action ValueDescSet (bug)"));
411
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")));
417
418                 if(!action->is_ready())
419                         throw Error(Error::TYPE_NOTREADY);
420
421                 add_action(action);
422                 return;
423         }
424
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()))
428         {
429                 Real old_width((*bline_width)(time).get(Real()));
430                 Real scale((*(bline_width->get_link("scale")))(time).get(Real()));
431
432                 ValueBase new_width(value.get(Real()) * scale / old_width);
433
434                 Action::Handle action(Action::create("ValueDescSet"));
435
436                 if(!action)
437                         throw Error(_("Unable to find action ValueDescSet (bug)"));
438
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")));
444
445                 if(!action->is_ready())
446                         throw Error(Error::TYPE_NOTREADY);
447
448                 add_action(action);
449                 return;
450         }
451
452         // BLineCalcVertex: snap the point to the nearest
453         // allowed position.
454         if (ValueNode_BLineCalcVertex::Handle bline_vertex = ValueNode_BLineCalcVertex::Handle::cast_dynamic(value_desc.get_value_node()))
455         {
456                 ValueNode_BLine::Handle bline = ValueNode_BLine::Handle::cast_dynamic(bline_vertex->get_link("bline"));
457                 Real radius = 0.0;
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;
468
469                         new_amount = amount_old+difference;
470                 } else {
471                         new_amount = synfig::find_closest_point((*bline)(time), value, radius, bline->get_loop());
472                 }
473
474                 Action::Handle action(Action::create("ValueDescSet"));
475
476                 if(!action)
477                         throw Error(_("Unable to find action ValueDescSet (bug)"));
478
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")));
484
485                 if(!action->is_ready())
486                         throw Error(Error::TYPE_NOTREADY);
487
488                 add_action(action);
489                 return;
490         }
491
492
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()))
496         {
497                 ValueBase new_scale;
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"));
500
501                 switch(value_desc.get_value_type())
502                 {
503                 case ValueBase::TYPE_REAL:
504                 {
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()));
509
510                         if (fixed_length)
511                         {
512                                 new_scale = new_length;
513                                 break;
514                         }
515                         if (old_length == 0)
516                                 return;
517                         new_scale = new_length * scale / old_length;
518                 }
519
520                 case ValueBase::TYPE_VECTOR:
521                 {
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()));
530                         if (fixed_length)
531                         {
532                                 new_scale = new_length;
533                                 break;
534                         }
535                         if (old_length != 0)
536                         {
537                                 new_scale = new_length * scale / old_length;
538
539
540                                 Action::Handle action(Action::create("ValueDescSet"));
541
542                                 if(!action)
543                                         throw Error(_("Unable to find action ValueDescSet (bug)"));
544
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);
550
551                                 if(!action->is_ready())
552                                         throw Error(Error::TYPE_NOTREADY);
553
554                                 add_action(action);
555                         }
556                 }
557                 break;
558
559                 case ValueBase::TYPE_ANGLE:
560                 {
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()));
564
565
566                         Action::Handle action(Action::create("ValueDescSet"));
567
568                         if(!action)
569                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
570
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);
576
577                         if(!action->is_ready())
578                                 throw Error(Error::TYPE_NOTREADY);
579
580                         add_action(action);
581                         return;
582                 }
583
584                 default:
585                         break;
586                 }
587
588                 if (new_scale)
589                 {
590                         Action::Handle action(Action::create("ValueDescSet"));
591
592                         if(!action)
593                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
594
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);
600
601                         if(!action->is_ready())
602                                 throw Error(Error::TYPE_NOTREADY);
603
604                         add_action(action);
605                 }
606                 return;
607         }
608         
609         // end reverse manipulations
610
611
612
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)
619         {
620                 ValueNode_Composite::Handle parent_value_node;
621                 parent_value_node=parent_value_node.cast_dynamic(value_desc.get_parent_value_node());
622
623                 assert(parent_value_node);
624
625                 // are we splitting or merging the tangents?
626             if (value.get(bool()))
627             {
628                         // we are splitting tangents
629
630                         Action::Handle action(Action::create("ValueDescSet"));
631
632                         if(!action)
633                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
634
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")));
640
641                         if(!action->is_ready())
642                                 throw Error(Error::TYPE_NOTREADY);
643
644                         add_action(action);
645             }
646             else
647             {
648                         // we are merging tangents
649
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);
653
654                         {
655                                 Action::Handle action(Action::create("ValueDescSet"));
656
657                                 if(!action)
658                                         throw Error(_("Unable to find action ValueDescSet (bug)"));
659
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")));
665
666                                 if(!action->is_ready())
667                                         throw Error(Error::TYPE_NOTREADY);
668
669                                 add_action(action);
670                         }
671
672                         {
673                                 Action::Handle action(Action::create("ValueDescSet"));
674
675                                 if(!action)
676                                         throw Error(_("Unable to find action ValueDescSet (bug)"));
677
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")));
683
684                                 if(!action->is_ready())
685                                         throw Error(Error::TYPE_NOTREADY);
686
687                                 add_action(action);
688                         }
689             }
690
691         }
692
693 /*      DEBUGPOINT();
694         if(     value_desc.parent_is_value_node())
695         {
696                 DEBUGPOINT();
697                 if(value_desc.get_parent_value_node()->get_type()==ValueBase::TYPE_BLINEPOINT)
698                 {
699                         DEBUGPOINT();
700                         if(value_desc.get_index()==4)
701                         {
702                                 DEBUGPOINT();
703                                 if((*value_desc.get_parent_value_node())(time).get(BLinePoint()).get_split_tangent_flag()==false)
704                                 {
705                                         DEBUGPOINT();
706                                 }
707                         }
708                 }
709         }
710 */
711
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()))
715                 {
716                         if(value_desc.is_value_node())
717                                 local_value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
718                         else
719                                 local_value=value_desc.get_value();
720                 }
721         // If we are in animate editing mode
722         if(get_edit_mode()&MODE_ANIMATE && !local_value.get_static())
723         {
724
725                 ValueNode_Animated::Handle& value_node(value_node_animated);
726
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()))
731                 {
732                         ValueBase value;
733                         if(value_desc.is_value_node())
734                                 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
735                         else
736                                 value=value_desc.get_value();
737
738                         if(!value_node)value_node=ValueNode_Animated::create(value,time);
739                         //if(!value_node)value_node=ValueNode_Animated::create(value.get_type());
740
741                         Action::Handle action;
742
743                         if(!value_desc.is_value_node())
744                         {
745                                 action=(ValueDescConnect::create());
746                                 action->set_param("dest",value_desc);
747                                 action->set_param("src",ValueNode::Handle(value_node));
748                         }
749                         else
750                         {
751                                 action=Action::create("ValueNodeReplace");
752                                 action->set_param("dest",value_desc.get_value_node());
753                                 action->set_param("src",ValueNode::Handle(value_node));
754                         }
755
756                         action->set_param("canvas",get_canvas());
757                         action->set_param("canvas_interface",get_canvas_interface());
758
759                         if(!action->is_ready())
760                                 throw Error(Error::TYPE_NOTREADY);
761
762                         add_action_front(action);
763                 }
764                 else
765                 {
766                         value_node=value_node.cast_dynamic(value_desc.get_value_node());
767                 }
768
769                 if(!value_node)
770                         throw Error(_("Direct manipulation of this ValueNode type is not yet supported"));
771
772                 Action::Handle action(WaypointSetSmart::create());
773
774                 //Waypoint waypoint(value,time);
775
776                 Waypoint waypoint(value_node->new_waypoint_at_time(time));
777                 waypoint.set_value(value);
778
779                 waypoint.set_before(synfigapp::Main::get_interpolation());
780                 waypoint.set_after(synfigapp::Main::get_interpolation());
781
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);
786
787                 if(!action->is_ready())
788                         throw Error(Error::TYPE_NOTREADY);
789
790                 add_action(action);
791
792                 return;
793         }
794         else
795         {
796                 if(value_desc.is_value_node())
797                 {
798                         if(ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
799                         {
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);
807
808                                 if(!action->is_ready())
809                                         throw Error(Error::TYPE_NOTREADY);
810
811                                 add_action_front(action);
812                                 return;
813                         }
814                         else
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"));
817                         else
818                                 throw Error(_("Direct manipulation of this ValueNode type is not yet supported"));
819                 }
820                 else
821                 if(value_desc.parent_is_layer_param() && !value_desc.is_value_node())
822                 {
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);
831
832                         if(!layer_param_set->is_ready())
833                                 throw Error(Error::TYPE_NOTREADY);
834
835                         add_action_front(layer_param_set);
836                         return;
837                 }
838
839                 throw Error(_("Unsupported ValueDesc type"));
840         }
841 }