Add an option "Browser Command" to allow the user to specify which web browser to...
[synfig.git] / synfig-studio / trunk / src / synfigapp / actions / waypointsetsmart.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file waypointsetsmart.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 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 "waypointsetsmart.h"
34 #include "valuenodelinkconnect.h"
35 #include "valuenodereplace.h"
36
37 #include "waypointset.h"
38 #include "waypointadd.h"
39
40 #include "valuedescconnect.h"
41 #include <synfigapp/canvasinterface.h>
42 #include <synfig/exception.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(Action::WaypointSetSmart);
58 ACTION_SET_NAME(Action::WaypointSetSmart,"waypoint_set_smart");
59 ACTION_SET_LOCAL_NAME(Action::WaypointSetSmart,N_("Add Waypoint"));
60 ACTION_SET_TASK(Action::WaypointSetSmart,"set");
61 ACTION_SET_CATEGORY(Action::WaypointSetSmart,Action::CATEGORY_WAYPOINT|Action::CATEGORY_VALUEDESC|Action::CATEGORY_VALUENODE);
62 ACTION_SET_PRIORITY(Action::WaypointSetSmart,0);
63 ACTION_SET_VERSION(Action::WaypointSetSmart,"0.0");
64 ACTION_SET_CVS_ID(Action::WaypointSetSmart,"$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::WaypointSetSmart::WaypointSetSmart()
73 {
74         waypoint.set_time(Time::begin()-1);
75         time_set=false;
76         set_dirty(true);
77 }
78
79 Action::ParamVocab
80 Action::WaypointSetSmart::get_param_vocab()
81 {
82         ParamVocab ret(Action::CanvasSpecific::get_param_vocab());
83
84         ret.push_back(ParamDesc("value_node",Param::TYPE_VALUENODE)
85                 .set_local_name(_("Destination ValueNode (Animated)"))
86         );
87
88         ret.push_back(ParamDesc("waypoint",Param::TYPE_WAYPOINT)
89                 .set_local_name(_("New Waypoint"))
90                 .set_desc(_("Waypoint to be added"))
91                 .set_optional()
92         );
93
94         ret.push_back(ParamDesc("waypoint_model",Param::TYPE_WAYPOINTMODEL)
95                 .set_local_name(_("Waypoint Model"))
96                 .set_optional()
97         );
98
99         ret.push_back(ParamDesc("time",Param::TYPE_TIME)
100                 .set_local_name(_("Time"))
101                 .set_desc(_("Time where waypoint is to be added"))
102                 .set_optional()
103         );
104
105         return ret;
106 }
107
108 bool
109 Action::WaypointSetSmart::is_candidate(const ParamList &x)
110 {
111         if(candidate_check(get_param_vocab(),x))
112         {
113                 if(!ValueNode_Animated::Handle::cast_dynamic(x.find("value_node")->second.get_value_node()))
114                         return false;
115                 // We need either a waypoint or a time.
116                 if(x.count("waypoint") || x.count("time"))
117                         return true;
118                 return false;
119         }
120         return false;
121 }
122
123 bool
124 Action::WaypointSetSmart::set_param(const synfig::String& name, const Action::Param &param)
125 {
126         if(name=="value_node" && param.get_type()==Param::TYPE_VALUENODE)
127         {
128                 value_node=ValueNode_Animated::Handle::cast_dynamic(param.get_value_node());
129                 if(time_set)
130                         calc_waypoint();
131
132                 return static_cast<bool>(value_node);
133         }
134         if(name=="waypoint" && param.get_type()==Param::TYPE_WAYPOINT && !time_set)
135         {
136                 waypoint=param.get_waypoint();
137
138                 return true;
139         }
140
141         if(name=="time" && param.get_type()==Param::TYPE_TIME && waypoint.get_time()==(Time::begin()-1))
142         {
143                 waypoint.set_time(param.get_time());
144                 time_set=true;
145
146                 if(value_node)
147                         calc_waypoint();
148
149                 return true;
150         }
151
152         if(name=="model" && param.get_type()==Param::TYPE_WAYPOINTMODEL)
153         {
154                 if(value_node)
155                         calc_waypoint();
156
157                 waypoint.apply_model(param.get_waypoint_model());
158
159                 return true;
160         }
161
162         return Action::CanvasSpecific::set_param(name,param);
163 }
164
165 bool
166 Action::WaypointSetSmart::is_ready()const
167 {
168         if(!value_node)
169                 synfig::error("Missing value_node");
170
171         if(waypoint.get_time()==(Time::begin()-1))
172                 synfig::error("Missing waypoint");
173
174         if(!value_node || waypoint.get_time()==(Time::begin()-1))
175                 return false;
176         return Action::CanvasSpecific::is_ready();
177 }
178
179 // This function is called if a time is specified, but not
180 // a waypoint. In this case, we need to calculate the value
181 // of the waypoint
182 void
183 Action::WaypointSetSmart::calc_waypoint()
184 {
185         Time time=waypoint.get_time();
186         try
187         {
188                 // Trivial case, we are sitting on a waypoint
189                 waypoint=*value_node->find(waypoint.get_time());
190         }
191         catch(...)
192         {
193                 waypoint=value_node->new_waypoint_at_time(time);
194                 waypoint.set_before(synfigapp::Main::get_interpolation());
195                 waypoint.set_after(synfigapp::Main::get_interpolation());
196         }
197 /*
198         Time time=waypoint.get_time();
199         ValueNode_Animated::WaypointList &waypoint_list(value_node->waypoint_list());
200         ValueNode_Animated::WaypointList::iterator iter;
201
202         if(waypoint_list.empty())
203         {
204                 waypoint.set_value((*value_node)(time));
205                 return;
206         }
207
208         ValueNode_Animated::WaypointList::iterator closest=waypoint_list.begin();
209
210         for(iter=waypoint_list.begin();iter!=waypoint_list.end();++iter)
211         {
212                 const Real dist(abs(iter->get_time()-time));
213                 if(dist<abs(closest->get_time()-time))
214                         closest=iter;
215         }
216         if(!closest->is_static())
217                 waypoint.set_value_node(closest->get_value_node());
218         else
219                 waypoint.set_value((*value_node)(time));
220 */
221 }
222
223 void
224 Action::WaypointSetSmart::enclose_waypoint(const synfig::Waypoint& waypoint)
225 {
226         times.insert(waypoint.get_time());
227
228         try {
229                 times.insert(value_node->find(waypoint)->get_time());
230 //              synfig::info(__FILE__":%d: value_node->find(waypoint)->get_time()=%s",__LINE__,value_node->find(waypoint)->get_time().get_string().c_str());
231         }catch (...) { }
232
233         // First we need to to add any waypoints necessary to
234         // maintain the integrity of the keyframes.
235         if(get_edit_mode()&MODE_ANIMATE_PAST) try
236         {
237                 Time curr_time(waypoint.get_time());
238
239                 //while(value_node->waypoint_list().front().get_time()<=curr_time)
240                 {
241                         // Try to find prev keyframe
242                         Keyframe keyframe(*get_canvas()->keyframe_list().find_prev(curr_time));
243                         curr_time=keyframe.get_time();
244
245 //                      synfig::info(__FILE__":%d: prev_keyframe->time=%s",__LINE__,keyframe.get_time().get_string().c_str());
246 //                      synfig::info(__FILE__":%d: waypoint->time=%s",__LINE__,waypoint.get_time().get_string().c_str());
247
248                         if(times.count(keyframe.get_time()))
249                         {
250                                 throw int();
251                         }
252                         if(waypoint.get_time().is_equal(keyframe.get_time()))
253                         {
254                                 throw int();
255                         }
256
257                         times.insert(keyframe.get_time());
258                         try
259                         {
260                                 value_node->find(keyframe.get_time());
261 //                              synfig::info(__FILE__":%d: waypointtime=%s",__LINE__,value_node->find(keyframe.get_time())->get_time().get_string().c_str());
262                         }
263                         catch(synfig::Exception::NotFound)
264                         {
265                                 Action::Handle action(WaypointAdd::create());
266
267                                 action->set_param("canvas",get_canvas());
268                                 action->set_param("canvas_interface",get_canvas_interface());
269                                 action->set_param("value_node",ValueNode::Handle(value_node));
270
271                                 if(!value_node->waypoint_list().empty())
272                                 {
273                                         action->set_param("time",keyframe.get_time());
274                                 }
275                                 else
276                                 {
277                                         synfig::Waypoint tmp;
278
279                                         tmp.set_value(waypoint.get_value());
280                                         tmp.set_time(keyframe.get_time());
281                                         action->set_param("waypoint",tmp);
282                                 }
283
284                                 assert(action->is_ready());
285                                 if(!action->is_ready())
286                                         throw Error(Error::TYPE_NOTREADY);
287
288                                 add_action(action);
289                         }
290                 }
291         }
292         catch(Error x) { throw x; }
293         catch(synfig::Exception::NotFound) { }
294         catch(int) { }
295         catch(...) { }
296
297         if(get_edit_mode()&MODE_ANIMATE_FUTURE)try
298         {
299                 Time curr_time(waypoint.get_time());
300
301                 //while(value_node->waypoint_list().back().get_time()>=curr_time)
302                 {
303
304                         // Try to find next keyframe
305                         //synfig::info("FUTURE waypoint.get_time()=%s",waypoint.get_time().get_string().c_str());
306                         Keyframe keyframe(*get_canvas()->keyframe_list().find_next(curr_time));
307                         //synfig::info("FUTURE keyframe.get_time()=%s",keyframe.get_time().get_string().c_str());
308                         curr_time=keyframe.get_time();
309
310                         if(times.count(keyframe.get_time())|| waypoint.get_time().is_equal(keyframe.get_time()))
311                                 throw int();
312                         else
313                                 times.insert(keyframe.get_time());
314
315                         try
316                         {
317                                 value_node->find(keyframe.get_time());
318                                 synfig::info(__FILE__":%d: time=%s",__LINE__,keyframe.get_time().get_string().c_str());
319                                 synfig::info(__FILE__":%d: waypointtime=%s",__LINE__,value_node->find(keyframe.get_time())->get_time().get_string().c_str());
320
321                         }
322                         catch(synfig::Exception::NotFound)
323                         {
324                                 Action::Handle action(WaypointAdd::create());
325
326                                 action->set_param("canvas",get_canvas());
327                                 action->set_param("canvas_interface",get_canvas_interface());
328                                 action->set_param("value_node",ValueNode::Handle(value_node));
329
330                                 if(!value_node->waypoint_list().empty())
331                                 {
332                                         action->set_param("time",keyframe.get_time());
333                                 }
334                                 else
335                                 {
336                                         synfig::Waypoint tmp;
337
338                                         tmp.set_value(waypoint.get_value());
339                                         tmp.set_time(keyframe.get_time());
340                                         action->set_param("waypoint",tmp);
341                                 }
342
343                                 assert(action->is_ready());
344                                 if(!action->is_ready())
345                                         throw Error(Error::TYPE_NOTREADY);
346
347                                 add_action(action);
348                         }
349                 }
350         }
351         catch(Error x) { throw x; }
352         catch(synfig::Exception::NotFound) { }
353         catch(int) { }
354         catch(...) { }
355 }
356
357 void
358 Action::WaypointSetSmart::prepare()
359 {
360         clear();
361         times.clear();
362
363         // First we need to to add any waypoints necessary to
364         // maintain the integrity of the keyframes.
365         enclose_waypoint(waypoint);
366
367         try
368         {
369                 //synfig::info("WaypointSetSmart: Move/Update?");
370                 // Lets try to replace the old waypoint, if it exists
371                 WaypointList::iterator iter(value_node->find(waypoint));
372
373                 if(iter == value_node->waypoint_list().end())
374                         throw int();
375
376                 enclose_waypoint(*iter);
377
378                 Action::Handle action(WaypointSet::create());
379
380                 action->set_param("canvas",get_canvas());
381                 action->set_param("canvas_interface",get_canvas_interface());
382                 action->set_param("value_node",ValueNode::Handle(value_node));
383                 action->set_param("waypoint",waypoint);
384
385                 assert(action->is_ready());
386                 if(!action->is_ready())
387                         throw Error(Error::TYPE_NOTREADY);
388
389                 add_action(action);
390
391                 return;
392         }
393         catch(synfig::Exception::NotFound){ } catch(int){ }
394
395         try
396         {
397                 //synfig::info("WaypointSetSmart: Replace?");
398                 // Check to see if a waypoint exists at this point in time
399                 WaypointList::iterator iter=value_node->find(waypoint.get_time());
400
401                 waypoint.mimic(*iter);
402
403                 enclose_waypoint(*iter);
404
405                 Action::Handle action(WaypointSet::create());
406
407                 action->set_param("canvas",get_canvas());
408                 action->set_param("canvas_interface",get_canvas_interface());
409                 action->set_param("value_node",ValueNode::Handle(value_node));
410                 action->set_param("waypoint",waypoint);
411
412                 assert(action->is_ready());
413                 if(!action->is_ready())
414                         throw Error(Error::TYPE_NOTREADY);
415
416                 add_action(action);
417
418                 return;
419         }
420         catch(synfig::Exception::NotFound){ } catch(int){ }
421
422         try
423         {
424                 //synfig::info("WaypointSetSmart: Add?");
425                 // At this point we know that the old waypoint doesn't exist,
426                 // so we need to create it.
427                 Action::Handle action(WaypointAdd::create());
428
429                 action->set_param("canvas",get_canvas());
430                 action->set_param("canvas_interface",get_canvas_interface());
431                 action->set_param("value_node",ValueNode::Handle(value_node));
432                 action->set_param("waypoint",waypoint);
433
434                 assert(action->is_ready());
435                 if(!action->is_ready())
436                         throw Error(Error::TYPE_NOTREADY);
437
438                 add_action(action);
439
440                 return;
441         }
442         catch(synfig::Exception::NotFound){ } catch(int){ }
443
444         throw Error(_("Unable to determine how to proceed. This is a bug."));
445 }