Better translation for 'Metaballs'
[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_index()==4 || value_desc.get_index()==5) &&
160                 (*value_desc.get_parent_value_node())(time).get(BLinePoint()).get_split_tangent_flag()==false)
161         {
162                 {
163                         ValueNode_Composite::Handle parent_value_node;
164                         parent_value_node=parent_value_node.cast_dynamic(value_desc.get_parent_value_node());
165                         assert(parent_value_node);
166
167                         Vector t1((*parent_value_node->get_link("t1"))(time));
168                         Vector t2((*parent_value_node->get_link("t2"))(time));
169                 }
170
171                 if (value_desc.get_index()==4) {
172                         ValueNode_Composite::Handle parent_value_node;
173                         parent_value_node=parent_value_node.cast_dynamic(value_desc.get_parent_value_node());
174
175                         assert(parent_value_node);
176
177                         Action::Handle action(Action::create("ValueDescSet"));
178
179                         if(!action)
180                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
181
182                         action->set_param("canvas",get_canvas());
183                         action->set_param("canvas_interface",get_canvas_interface());
184                         action->set_param("time",time);
185                         action->set_param("new_value",value);
186                         action->set_param("value_desc",ValueDesc(parent_value_node,5));
187
188                         if(!action->is_ready())
189                                 throw Error(Error::TYPE_NOTREADY);
190
191                         add_action(action);
192                 }
193         }
194
195         // If we are a reference value node, then
196         // we need to distribute the changes to the
197         // referenced value node
198         if(value_desc.is_value_node() && ValueNode_Reference::Handle::cast_dynamic(value_desc.get_value_node()))
199         {
200                 ValueDesc reference_value_desc(ValueNode_Reference::Handle::cast_dynamic(value_desc.get_value_node()),0);
201
202                 Action::Handle action(Action::create("ValueDescSet"));
203
204                 if(!action)
205                         throw Error(_("Unable to find action ValueDescSet (bug)"));
206
207                 action->set_param("canvas",get_canvas());
208                 action->set_param("canvas_interface",get_canvas_interface());
209                 action->set_param("time",time);
210                 action->set_param("new_value",value);
211                 action->set_param("value_desc",reference_value_desc);
212
213                 if(!action->is_ready())
214                         throw Error(Error::TYPE_NOTREADY);
215
216                 add_action(action);
217
218                 return;
219         }
220
221         // If we are a composite value node, then
222         // we need to distribute the changes to the
223         // individual parts
224         if(value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
225         {
226                 ValueBase components[6];
227                 int n_components(0);
228                 switch(value.get_type())
229                 {
230                 case ValueBase::TYPE_VECTOR:
231                         components[0]=value.get(Vector())[0];
232                         components[1]=value.get(Vector())[1];
233                         n_components=2;
234                         break;
235                 case ValueBase::TYPE_COLOR:
236                         components[0]=value.get(Color()).get_r();
237                         components[1]=value.get(Color()).get_g();
238                         components[2]=value.get(Color()).get_b();
239                         components[3]=value.get(Color()).get_a();
240                         n_components=4;
241                         break;
242                 case ValueBase::TYPE_SEGMENT:
243                         components[0]=value.get(Segment()).p1;
244                         components[1]=value.get(Segment()).t1;
245                         components[2]=value.get(Segment()).p2;
246                         components[3]=value.get(Segment()).t2;
247                         n_components=4;
248                         break;
249                 case ValueBase::TYPE_BLINEPOINT:
250                 {
251                         BLinePoint bline_point(value);
252                         components[0]=bline_point.get_vertex();
253                         components[1]=bline_point.get_width();
254                         components[2]=bline_point.get_origin();
255                         components[3]=bline_point.get_split_tangent_flag();
256                         components[4]=bline_point.get_tangent1();
257                         components[5]=bline_point.get_tangent2();
258                         n_components=6;
259                         break;
260                 }
261                 default:
262                         throw Error(_("Bad type for composite (%s)"),ValueBase::type_local_name(value.get_type()).c_str());
263                         break;
264                 }
265
266                 for(int i=0;i<n_components;i++)
267                 {
268                         ValueDesc component_value_desc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),i);
269
270                         Action::Handle action(Action::create("ValueDescSet"));
271
272                         if(!action)
273                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
274
275                         action->set_param("canvas",get_canvas());
276                         action->set_param("canvas_interface",get_canvas_interface());
277                         action->set_param("time",time);
278                         action->set_param("new_value",components[i]);
279                         action->set_param("value_desc",component_value_desc);
280
281                         if(!action->is_ready())
282                                 throw Error(Error::TYPE_NOTREADY);
283
284                         add_action(action);
285                 }
286
287                 return;
288         }
289
290
291         // If we are a RADIAL composite value node, then
292         // we need to distribute the changes to the
293         // individual parts
294         if(value_desc.is_value_node() && ValueNode_RadialComposite::Handle::cast_dynamic(value_desc.get_value_node()))
295         {
296                 ValueBase components[6];
297                 int n_components(0);
298                 switch(value.get_type())
299                 {
300                 case ValueBase::TYPE_VECTOR:
301                 {
302                         Angle old_angle = (*(ValueNode_RadialComposite::Handle::cast_dynamic(
303                                                                          value_desc.get_value_node())->get_link_vfunc(1)))(time).get(Angle());
304                         Vector vect(value.get(Vector()));
305                         components[0]=vect.mag();
306                         Angle change = Angle(Angle::tan(vect[1],vect[0])) - old_angle;
307                         while (change < Angle::deg(-180)) change += Angle::deg(360);
308                         while (change > Angle::deg(180)) change -= Angle::deg(360);
309                         components[1]=old_angle + change;
310                         n_components=2;
311                 }
312                         break;
313                 case ValueBase::TYPE_COLOR:
314                         components[0]=value.get(Color()).get_y();
315                         components[1]=value.get(Color()).get_s();
316                         components[2]=value.get(Color()).get_hue();
317                         components[3]=value.get(Color()).get_a();
318                         n_components=4;
319                         break;
320                 default:
321                         throw Error(_("Bad type for radial composite (%s)"),ValueBase::type_local_name(value.get_type()).c_str());
322                         break;
323                 }
324                 for(int i=0;i<n_components;i++)
325                 {
326                         ValueDesc component_value_desc(ValueNode_RadialComposite::Handle::cast_dynamic(value_desc.get_value_node()),i);
327
328                         Action::Handle action(Action::create("ValueDescSet"));
329
330                         if(!action)
331                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
332
333                         action->set_param("canvas",get_canvas());
334                         action->set_param("canvas_interface",get_canvas_interface());
335                         action->set_param("time",time);
336                         action->set_param("new_value",components[i]);
337                         action->set_param("value_desc",component_value_desc);
338
339                         if(!action->is_ready())
340                                 throw Error(Error::TYPE_NOTREADY);
341
342                         add_action(action);
343                 }
344
345                 return;
346         }
347
348         // If we are merging the tangents of a BLinePoint,
349         // we must also set the second tangent for things
350         // to interpolate properly
351         if (value_desc.parent_is_value_node() &&
352             value_desc.get_parent_value_node()->get_type()==ValueBase::TYPE_BLINEPOINT &&
353             value_desc.get_index()==3)
354         {
355                 ValueNode_Composite::Handle parent_value_node;
356                 parent_value_node=parent_value_node.cast_dynamic(value_desc.get_parent_value_node());
357
358                 assert(parent_value_node);
359
360                 // are we splitting or merging the tangents?
361             if (value.get(bool()))
362             {
363                         // we are splitting tangents
364
365                         Action::Handle action(Action::create("ValueDescSet"));
366
367                         if(!action)
368                                 throw Error(_("Unable to find action ValueDescSet (bug)"));
369
370                         action->set_param("canvas",get_canvas());
371                         action->set_param("canvas_interface",get_canvas_interface());
372                         action->set_param("time",time);
373                         action->set_param("new_value",(*parent_value_node->get_link(4))(time));
374                         action->set_param("value_desc",ValueDesc(parent_value_node,5));
375
376                         if(!action->is_ready())
377                                 throw Error(Error::TYPE_NOTREADY);
378
379                         add_action(action);
380             }
381             else
382             {
383                         // we are merging tangents
384
385                         // the merged tangent should be the average of the 2 tangents we're merging
386                         ValueBase average(((Vector)((*parent_value_node->get_link("t1"))(time)) +
387                                                            (Vector)((*parent_value_node->get_link("t2"))(time))) / 2);
388
389                         {
390                                 Action::Handle action(Action::create("ValueDescSet"));
391
392                                 if(!action)
393                                         throw Error(_("Unable to find action ValueDescSet (bug)"));
394
395                                 action->set_param("canvas",get_canvas());
396                                 action->set_param("canvas_interface",get_canvas_interface());
397                                 action->set_param("time",time);
398                                 action->set_param("new_value",average);
399                                 action->set_param("value_desc",ValueDesc(parent_value_node,4));
400
401                                 if(!action->is_ready())
402                                         throw Error(Error::TYPE_NOTREADY);
403
404                                 add_action(action);
405                         }
406
407                         {
408                                 Action::Handle action(Action::create("ValueDescSet"));
409
410                                 if(!action)
411                                         throw Error(_("Unable to find action ValueDescSet (bug)"));
412
413                                 action->set_param("canvas",get_canvas());
414                                 action->set_param("canvas_interface",get_canvas_interface());
415                                 action->set_param("time",time);
416                                 action->set_param("new_value",average);
417                                 action->set_param("value_desc",ValueDesc(parent_value_node,5));
418
419                                 if(!action->is_ready())
420                                         throw Error(Error::TYPE_NOTREADY);
421
422                                 add_action(action);
423                         }
424             }
425
426         }
427
428 /*      DEBUGPOINT();
429         if(     value_desc.parent_is_value_node())
430         {
431                 DEBUGPOINT();
432                 if(value_desc.get_parent_value_node()->get_type()==ValueBase::TYPE_BLINEPOINT)
433                 {
434                         DEBUGPOINT();
435                         if(value_desc.get_index()==4)
436                         {
437                                 DEBUGPOINT();
438                                 if((*value_desc.get_parent_value_node())(time).get(BLinePoint()).get_split_tangent_flag()==false)
439                                 {
440                                         DEBUGPOINT();
441                                 }
442                         }
443                 }
444         }
445 */
446
447
448         // If we are in animate editing mode
449         if(get_edit_mode()&MODE_ANIMATE)
450         {
451
452                 ValueNode_Animated::Handle& value_node(value_node_animated);
453
454                 // If this value isn't a ValueNode_Animated, but
455                 // it is somewhat constant, then go ahead and convert
456                 // it to a ValueNode_Animated.
457                 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
458                 {
459                         ValueBase value;
460                         if(value_desc.is_value_node())
461                                 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
462                         else
463                                 value=value_desc.get_value();
464
465                         if(!value_node)value_node=ValueNode_Animated::create(value,time);
466                         //if(!value_node)value_node=ValueNode_Animated::create(value.get_type());
467
468                         Action::Handle action;
469
470                         if(!value_desc.is_value_node())
471                         {
472                                 action=(ValueDescConnect::create());
473                                 action->set_param("dest",value_desc);
474                                 action->set_param("src",ValueNode::Handle(value_node));
475                         }
476                         else
477                         {
478                                 action=Action::create("ValueNodeReplace");
479                                 action->set_param("dest",value_desc.get_value_node());
480                                 action->set_param("src",ValueNode::Handle(value_node));
481                         }
482
483                         action->set_param("canvas",get_canvas());
484                         action->set_param("canvas_interface",get_canvas_interface());
485
486                         if(!action->is_ready())
487                                 throw Error(Error::TYPE_NOTREADY);
488
489                         add_action_front(action);
490                 }
491                 else
492                 {
493                         value_node=value_node.cast_dynamic(value_desc.get_value_node());
494                 }
495
496                 if(!value_node)
497                         throw Error(_("Direct manipulation of this ValueNode type is not yet supported"));
498
499                 Action::Handle action(WaypointSetSmart::create());
500
501                 //Waypoint waypoint(value,time);
502
503                 Waypoint waypoint(value_node->new_waypoint_at_time(time));
504                 waypoint.set_value(value);
505
506                 waypoint.set_before(synfigapp::Main::get_interpolation());
507                 waypoint.set_after(synfigapp::Main::get_interpolation());
508
509                 action->set_param("canvas",get_canvas());
510                 action->set_param("canvas_interface",get_canvas_interface());
511                 action->set_param("value_node",ValueNode::Handle(value_node));
512                 action->set_param("waypoint",waypoint);
513
514                 if(!action->is_ready())
515                         throw Error(Error::TYPE_NOTREADY);
516
517                 add_action(action);
518
519                 return;
520         }
521         else
522         {
523                 if(value_desc.is_value_node())
524                 {
525                         if(ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
526                         {
527                                 Action::Handle action(ValueNodeConstSet::create());
528
529                                 action->set_param("canvas",get_canvas());
530                                 action->set_param("canvas_interface",get_canvas_interface());
531                                 action->set_param("value_node",value_desc.get_value_node());
532                                 action->set_param("new_value",value);
533
534                                 if(!action->is_ready())
535                                         throw Error(Error::TYPE_NOTREADY);
536
537                                 add_action_front(action);
538                                 return;
539                         }
540                         else
541                         if(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
542                                 throw Error(_("You must be in Animate-Editing-Mode to directly manipulate this value"));
543                         else
544                                 throw Error(_("Direct manipulation of this ValueNode type is not yet supported"));
545                 }
546                 else
547                 if(value_desc.parent_is_layer_param() && !value_desc.is_value_node())
548                 {
549                         Action::Handle layer_param_set(LayerParamSet::create());
550
551                         layer_param_set->set_param("canvas",get_canvas());
552                         layer_param_set->set_param("canvas_interface",get_canvas_interface());
553                         layer_param_set->set_param("layer",value_desc.get_layer());
554                         layer_param_set->set_param("param",value_desc.get_param_name());
555                         layer_param_set->set_param("new_value",value);
556
557                         if(!layer_param_set->is_ready())
558                                 throw Error(Error::TYPE_NOTREADY);
559
560                         add_action_front(layer_param_set);
561                         return;
562                 }
563
564                 throw Error(_("Unsupported ValueDesc type"));
565         }
566 }