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