35f6d26ea0d996eb744095db1c8690bbdbc21ece
[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_composite.h>
41 #include <synfig/valuenode_radialcomposite.h>
42 #include <synfig/valuenode_reference.h>
43 #include <synfigapp/main.h>
44
45 #include <synfigapp/general.h>
46
47 #endif
48
49 using namespace std;
50 using namespace etl;
51 using namespace synfig;
52 using namespace synfigapp;
53 using namespace Action;
54
55 /* === M A C R O S ========================================================= */
56
57 ACTION_INIT_NO_GET_LOCAL_NAME(Action::ValueDescSet);
58 ACTION_SET_NAME(Action::ValueDescSet,"ValueDescSet");
59 ACTION_SET_LOCAL_NAME(Action::ValueDescSet,N_("Set ValueDesc"));
60 ACTION_SET_TASK(Action::ValueDescSet,"set");
61 ACTION_SET_CATEGORY(Action::ValueDescSet,Action::CATEGORY_VALUEDESC);
62 ACTION_SET_PRIORITY(Action::ValueDescSet,0);
63 ACTION_SET_VERSION(Action::ValueDescSet,"0.0");
64 ACTION_SET_CVS_ID(Action::ValueDescSet,"$Id$");
65
66 /* === G L O B A L S ======================================================= */
67
68 /* === P R O C E D U R E S ================================================= */
69
70 /* === M E T H O D S ======================================================= */
71
72 Action::ValueDescSet::ValueDescSet():
73         time(0)
74 {
75 }
76
77 synfig::String
78 Action::ValueDescSet::get_local_name()const
79 {
80         return strprintf(_("Set %s"),
81                                          value_desc
82                                          ? value_desc.get_description().c_str()
83                                          : _("ValueDesc"));
84 }
85
86 Action::ParamVocab
87 Action::ValueDescSet::get_param_vocab()
88 {
89         ParamVocab ret(Action::CanvasSpecific::get_param_vocab());
90
91         ret.push_back(ParamDesc("value_desc",Param::TYPE_VALUEDESC)
92                 .set_local_name(_("ValueDesc"))
93         );
94
95         ret.push_back(ParamDesc("new_value",Param::TYPE_VALUE)
96                 .set_local_name(_("ValueBase"))
97         );
98
99         ret.push_back(ParamDesc("time",Param::TYPE_TIME)
100                 .set_local_name(_("Time"))
101                 .set_optional()
102         );
103
104         return ret;
105 }
106
107 bool
108 Action::ValueDescSet::is_candidate(const ParamList &x)
109 {
110         return candidate_check(get_param_vocab(),x);
111 }
112
113 bool
114 Action::ValueDescSet::set_param(const synfig::String& name, const Action::Param &param)
115 {
116         if(name=="value_desc" && param.get_type()==Param::TYPE_VALUEDESC)
117         {
118                 value_desc=param.get_value_desc();
119
120                 return true;
121         }
122
123         if(name=="new_value" && param.get_type()==Param::TYPE_VALUE)
124         {
125                 value=param.get_value();
126
127                 return true;
128         }
129
130         if(name=="time" && param.get_type()==Param::TYPE_TIME)
131         {
132                 time=param.get_time();
133
134                 return true;
135         }
136
137         return Action::CanvasSpecific::set_param(name,param);
138 }
139
140 bool
141 Action::ValueDescSet::is_ready()const
142 {
143         if(!value_desc || !value.is_valid())
144                 return false;
145         return Action::CanvasSpecific::is_ready();
146 }
147
148 void
149 Action::ValueDescSet::prepare()
150 {
151         clear();
152
153         // If our tangents are merged, and
154         // our first tangent is being manipulated,
155         // then we also need to adjust the other
156         // tangent.
157         if(     value_desc.parent_is_value_node() &&
158                 value_desc.get_parent_value_node()->get_type()==ValueBase::TYPE_BLINEPOINT &&
159                 (value_desc.get_name()=="t1" || value_desc.get_name()=="t2") &&
160                 //(value_desc.get_index()==4 || value_desc.get_index()==5) &&
161                 (*value_desc.get_parent_value_node())(time).get(BLinePoint()).get_split_tangent_flag()==false)
162         {
163                 {
164                         ValueNode_Composite::Handle parent_value_node;
165                         parent_value_node=parent_value_node.cast_dynamic(value_desc.get_parent_value_node());
166                         assert(parent_value_node);
167
168                         Vector t1((*parent_value_node->get_link("t1"))(time));
169                         Vector t2((*parent_value_node->get_link("t2"))(time));
170                 }
171
172                 //if (value_desc.get_index()==4) {
173                 if (value_desc.get_name()=="t1") {
174                         ValueNode_Composite::Handle parent_value_node;
175                         parent_value_node=parent_value_node.cast_dynamic(value_desc.get_parent_value_node());
176
177                         assert(parent_value_node);
178
179                         Action::Handle action(Action::create("ValueDescSet"));
180
181                         if(!action)
182                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
183
184                         action->set_param("canvas",get_canvas());
185                         action->set_param("canvas_interface",get_canvas_interface());
186                         action->set_param("time",time);
187                         action->set_param("new_value",value);
188                         action->set_param("value_desc",ValueDesc(parent_value_node, parent_value_node->get_link_index_from_name("t2")));
189
190                         if(!action->is_ready())
191                                 throw Error(Error::TYPE_NOTREADY);
192
193                         add_action(action);
194                 }
195         }
196
197         // If we are a reference value node, then
198         // we need to distribute the changes to the
199         // referenced value node
200         if(value_desc.is_value_node() && ValueNode_Reference::Handle::cast_dynamic(value_desc.get_value_node()))
201         {
202                 ValueDesc reference_value_desc(ValueNode_Reference::Handle::cast_dynamic(value_desc.get_value_node()),0);
203
204                 Action::Handle action(Action::create("ValueDescSet"));
205
206                 if(!action)
207                         throw Error(_("Unable to find action ValueDescSet (bug)"));
208
209                 action->set_param("canvas",get_canvas());
210                 action->set_param("canvas_interface",get_canvas_interface());
211                 action->set_param("time",time);
212                 action->set_param("new_value",value);
213                 action->set_param("value_desc",reference_value_desc);
214
215                 if(!action->is_ready())
216                         throw Error(Error::TYPE_NOTREADY);
217
218                 add_action(action);
219
220                 return;
221         }
222
223         // If we are a composite value node, then
224         // we need to distribute the changes to the
225         // individual parts
226         if(value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
227         {
228                 ValueBase components[6];
229                 int n_components(0);
230                 switch(value.get_type())
231                 {
232                 case ValueBase::TYPE_VECTOR:
233                         components[0]=value.get(Vector())[0];
234                         components[1]=value.get(Vector())[1];
235                         n_components=2;
236                         break;
237                 case ValueBase::TYPE_COLOR:
238                         components[0]=value.get(Color()).get_r();
239                         components[1]=value.get(Color()).get_g();
240                         components[2]=value.get(Color()).get_b();
241                         components[3]=value.get(Color()).get_a();
242                         n_components=4;
243                         break;
244                 case ValueBase::TYPE_SEGMENT:
245                         components[0]=value.get(Segment()).p1;
246                         components[1]=value.get(Segment()).t1;
247                         components[2]=value.get(Segment()).p2;
248                         components[3]=value.get(Segment()).t2;
249                         n_components=4;
250                         break;
251                 case ValueBase::TYPE_BLINEPOINT:
252                 {
253                         BLinePoint bline_point(value);
254                         components[0]=bline_point.get_vertex();
255                         components[1]=bline_point.get_width();
256                         components[2]=bline_point.get_origin();
257                         components[3]=bline_point.get_split_tangent_flag();
258                         components[4]=bline_point.get_tangent1();
259                         components[5]=bline_point.get_tangent2();
260                         n_components=6;
261                         break;
262                 }
263                 default:
264                         throw Error(_("Bad type for composite (%s)"),ValueBase::type_local_name(value.get_type()).c_str());
265                         break;
266                 }
267
268                 for(int i=0;i<n_components;i++)
269                 {
270                         ValueDesc component_value_desc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),i);
271
272                         Action::Handle action(Action::create("ValueDescSet"));
273
274                         if(!action)
275                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
276
277                         action->set_param("canvas",get_canvas());
278                         action->set_param("canvas_interface",get_canvas_interface());
279                         action->set_param("time",time);
280                         action->set_param("new_value",components[i]);
281                         action->set_param("value_desc",component_value_desc);
282
283                         if(!action->is_ready())
284                                 throw Error(Error::TYPE_NOTREADY);
285
286                         add_action(action);
287                 }
288
289                 return;
290         }
291
292
293         // If we are a RADIAL composite value node, then
294         // we need to distribute the changes to the
295         // individual parts
296         if(value_desc.is_value_node() && ValueNode_RadialComposite::Handle::cast_dynamic(value_desc.get_value_node()))
297         {
298                 ValueBase components[6];
299                 int n_components(0);
300                 switch(value.get_type())
301                 {
302                 case ValueBase::TYPE_VECTOR:
303                 {
304                         Angle old_angle = (*(ValueNode_RadialComposite::Handle::cast_dynamic(
305                                                                          value_desc.get_value_node())->get_link("theta")))(time).get(Angle());
306                         Vector vect(value.get(Vector()));
307                         components[0]=vect.mag();
308                         Angle change = Angle(Angle::tan(vect[1],vect[0])) - old_angle;
309                         while (change < Angle::deg(-180)) change += Angle::deg(360);
310                         while (change > Angle::deg(180)) change -= Angle::deg(360);
311                         components[1]=old_angle + change;
312                         n_components=2;
313                 }
314                         break;
315                 case ValueBase::TYPE_COLOR:
316                         components[0]=value.get(Color()).get_y();
317                         components[1]=value.get(Color()).get_s();
318                         components[2]=value.get(Color()).get_hue();
319                         components[3]=value.get(Color()).get_a();
320                         n_components=4;
321                         break;
322                 default:
323                         throw Error(_("Bad type for radial composite (%s)"),ValueBase::type_local_name(value.get_type()).c_str());
324                         break;
325                 }
326                 for(int i=0;i<n_components;i++)
327                 {
328                         ValueDesc component_value_desc(ValueNode_RadialComposite::Handle::cast_dynamic(value_desc.get_value_node()),i);
329
330                         Action::Handle action(Action::create("ValueDescSet"));
331
332                         if(!action)
333                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
334
335                         action->set_param("canvas",get_canvas());
336                         action->set_param("canvas_interface",get_canvas_interface());
337                         action->set_param("time",time);
338                         action->set_param("new_value",components[i]);
339                         action->set_param("value_desc",component_value_desc);
340
341                         if(!action->is_ready())
342                                 throw Error(Error::TYPE_NOTREADY);
343
344                         add_action(action);
345                 }
346
347                 return;
348         }
349
350         // If we are merging the tangents of a BLinePoint,
351         // we must also set the second tangent for things
352         // to interpolate properly
353         if (value_desc.parent_is_value_node() &&
354             value_desc.get_parent_value_node()->get_type()==ValueBase::TYPE_BLINEPOINT &&
355             value_desc.get_index()==3)
356         {
357                 ValueNode_Composite::Handle parent_value_node;
358                 parent_value_node=parent_value_node.cast_dynamic(value_desc.get_parent_value_node());
359
360                 assert(parent_value_node);
361
362                 // are we splitting or merging the tangents?
363             if (value.get(bool()))
364             {
365                         // we are splitting tangents
366
367                         Action::Handle action(Action::create("ValueDescSet"));
368
369                         if(!action)
370                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
371
372                         action->set_param("canvas",get_canvas());
373                         action->set_param("canvas_interface",get_canvas_interface());
374                         action->set_param("time",time);
375                         action->set_param("new_value",(*parent_value_node->get_link("t1"))(time));
376                         action->set_param("value_desc",ValueDesc(parent_value_node,parent_value_node->get_link_index_from_name("t2")));
377
378                         if(!action->is_ready())
379                                 throw Error(Error::TYPE_NOTREADY);
380
381                         add_action(action);
382             }
383             else
384             {
385                         // we are merging tangents
386
387                         // the merged tangent should be the average of the 2 tangents we're merging
388                         ValueBase average(((Vector)((*parent_value_node->get_link("t1"))(time)) +
389                                                            (Vector)((*parent_value_node->get_link("t2"))(time))) / 2);
390
391                         {
392                                 Action::Handle action(Action::create("ValueDescSet"));
393
394                                 if(!action)
395                                         throw Error(_("Unable to find action ValueDescSet (bug)"));
396
397                                 action->set_param("canvas",get_canvas());
398                                 action->set_param("canvas_interface",get_canvas_interface());
399                                 action->set_param("time",time);
400                                 action->set_param("new_value",average);
401                                 action->set_param("value_desc",ValueDesc(parent_value_node,parent_value_node->get_link_index_from_name("t1")));
402
403                                 if(!action->is_ready())
404                                         throw Error(Error::TYPE_NOTREADY);
405
406                                 add_action(action);
407                         }
408
409                         {
410                                 Action::Handle action(Action::create("ValueDescSet"));
411
412                                 if(!action)
413                                         throw Error(_("Unable to find action ValueDescSet (bug)"));
414
415                                 action->set_param("canvas",get_canvas());
416                                 action->set_param("canvas_interface",get_canvas_interface());
417                                 action->set_param("time",time);
418                                 action->set_param("new_value",average);
419                                 action->set_param("value_desc",ValueDesc(parent_value_node,parent_value_node->get_link_index_from_name("t2")));
420
421                                 if(!action->is_ready())
422                                         throw Error(Error::TYPE_NOTREADY);
423
424                                 add_action(action);
425                         }
426             }
427
428         }
429
430 /*      DEBUGPOINT();
431         if(     value_desc.parent_is_value_node())
432         {
433                 DEBUGPOINT();
434                 if(value_desc.get_parent_value_node()->get_type()==ValueBase::TYPE_BLINEPOINT)
435                 {
436                         DEBUGPOINT();
437                         if(value_desc.get_index()==4)
438                         {
439                                 DEBUGPOINT();
440                                 if((*value_desc.get_parent_value_node())(time).get(BLinePoint()).get_split_tangent_flag()==false)
441                                 {
442                                         DEBUGPOINT();
443                                 }
444                         }
445                 }
446         }
447 */
448
449         ValueBase local_value;
450         local_value.set_static(false);
451                 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
452                 {
453                         if(value_desc.is_value_node())
454                                 local_value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
455                         else
456                                 local_value=value_desc.get_value();
457                 }
458         // If we are in animate editing mode
459         if(get_edit_mode()&MODE_ANIMATE && !local_value.get_static())
460         {
461
462                 ValueNode_Animated::Handle& value_node(value_node_animated);
463
464                 // If this value isn't a ValueNode_Animated, but
465                 // it is somewhat constant, then go ahead and convert
466                 // it to a ValueNode_Animated.
467                 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
468                 {
469                         ValueBase value;
470                         if(value_desc.is_value_node())
471                                 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
472                         else
473                                 value=value_desc.get_value();
474
475                         if(!value_node)value_node=ValueNode_Animated::create(value,time);
476                         //if(!value_node)value_node=ValueNode_Animated::create(value.get_type());
477
478                         Action::Handle action;
479
480                         if(!value_desc.is_value_node())
481                         {
482                                 action=(ValueDescConnect::create());
483                                 action->set_param("dest",value_desc);
484                                 action->set_param("src",ValueNode::Handle(value_node));
485                         }
486                         else
487                         {
488                                 action=Action::create("ValueNodeReplace");
489                                 action->set_param("dest",value_desc.get_value_node());
490                                 action->set_param("src",ValueNode::Handle(value_node));
491                         }
492
493                         action->set_param("canvas",get_canvas());
494                         action->set_param("canvas_interface",get_canvas_interface());
495
496                         if(!action->is_ready())
497                                 throw Error(Error::TYPE_NOTREADY);
498
499                         add_action_front(action);
500                 }
501                 else
502                 {
503                         value_node=value_node.cast_dynamic(value_desc.get_value_node());
504                 }
505
506                 if(!value_node)
507                         throw Error(_("Direct manipulation of this ValueNode type is not yet supported"));
508
509                 Action::Handle action(WaypointSetSmart::create());
510
511                 //Waypoint waypoint(value,time);
512
513                 Waypoint waypoint(value_node->new_waypoint_at_time(time));
514                 waypoint.set_value(value);
515
516                 waypoint.set_before(synfigapp::Main::get_interpolation());
517                 waypoint.set_after(synfigapp::Main::get_interpolation());
518
519                 action->set_param("canvas",get_canvas());
520                 action->set_param("canvas_interface",get_canvas_interface());
521                 action->set_param("value_node",ValueNode::Handle(value_node));
522                 action->set_param("waypoint",waypoint);
523
524                 if(!action->is_ready())
525                         throw Error(Error::TYPE_NOTREADY);
526
527                 add_action(action);
528
529                 return;
530         }
531         else
532         {
533                 if(value_desc.is_value_node())
534                 {
535                         if(ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
536                         {
537                                 Action::Handle action(ValueNodeConstSet::create());
538                                 synfig::ValueNode_Const::Handle localvaluenode(ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()));
539                                 value.set_static(localvaluenode->get_static());
540                                 action->set_param("canvas",get_canvas());
541                                 action->set_param("canvas_interface",get_canvas_interface());
542                                 action->set_param("value_node",value_desc.get_value_node());
543                                 action->set_param("new_value",value);
544
545                                 if(!action->is_ready())
546                                         throw Error(Error::TYPE_NOTREADY);
547
548                                 add_action_front(action);
549                                 return;
550                         }
551                         else
552                         if(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
553                                 throw Error(_("You must be in Animate-Editing-Mode to directly manipulate this value"));
554                         else
555                                 throw Error(_("Direct manipulation of this ValueNode type is not yet supported"));
556                 }
557                 else
558                 if(value_desc.parent_is_layer_param() && !value_desc.is_value_node())
559                 {
560                         Action::Handle layer_param_set(LayerParamSet::create());
561                         synfig::ValueBase localvalue(value_desc.get_value());
562                         value.set_static(local_value.get_static());
563                         layer_param_set->set_param("canvas",get_canvas());
564                         layer_param_set->set_param("canvas_interface",get_canvas_interface());
565                         layer_param_set->set_param("layer",value_desc.get_layer());
566                         layer_param_set->set_param("param",value_desc.get_param_name());
567                         layer_param_set->set_param("new_value",value);
568
569                         if(!layer_param_set->is_ready())
570                                 throw Error(Error::TYPE_NOTREADY);
571
572                         add_action_front(layer_param_set);
573                         return;
574                 }
575
576                 throw Error(_("Unsupported ValueDesc type"));
577         }
578 }