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