23a0ea2afea85094043fb99e9d33bf9a4f368dbe
[synfig.git] /
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         return (candidate_check(get_param_vocab(),x) &&
112                         // We need an animated valuenode.
113                         ValueNode_Animated::Handle::cast_dynamic(x.find("value_node")->second.get_value_node()) &&
114                         // We need either a waypoint or a time.
115                         (x.count("waypoint") || x.count("time")));
116 }
117
118 bool
119 Action::WaypointSetSmart::set_param(const synfig::String& name, const Action::Param &param)
120 {
121         if(name=="value_node" && param.get_type()==Param::TYPE_VALUENODE)
122         {
123                 value_node=ValueNode_Animated::Handle::cast_dynamic(param.get_value_node());
124                 if(time_set)
125                         calc_waypoint();
126
127                 return static_cast<bool>(value_node);
128         }
129         if(name=="waypoint" && param.get_type()==Param::TYPE_WAYPOINT && !time_set)
130         {
131                 waypoint=param.get_waypoint();
132
133                 return true;
134         }
135
136         if(name=="time" && param.get_type()==Param::TYPE_TIME && waypoint.get_time()==(Time::begin()-1))
137         {
138                 waypoint.set_time(param.get_time());
139                 time_set=true;
140
141                 if(value_node)
142                         calc_waypoint();
143
144                 return true;
145         }
146
147         if(name=="model" && param.get_type()==Param::TYPE_WAYPOINTMODEL)
148         {
149                 if(value_node)
150                         calc_waypoint();
151
152                 waypoint.apply_model(param.get_waypoint_model());
153
154                 return true;
155         }
156
157         return Action::CanvasSpecific::set_param(name,param);
158 }
159
160 bool
161 Action::WaypointSetSmart::is_ready()const
162 {
163         if(!value_node)
164                 synfig::error("Missing value_node");
165
166         if(waypoint.get_time()==(Time::begin()-1))
167                 synfig::error("Missing waypoint");
168
169         if(!value_node || waypoint.get_time()==(Time::begin()-1))
170                 return false;
171         return Action::CanvasSpecific::is_ready();
172 }
173
174 // This function is called if a time is specified, but not
175 // a waypoint. In this case, we need to calculate the value
176 // of the waypoint
177 void
178 Action::WaypointSetSmart::calc_waypoint()
179 {
180         Time time=waypoint.get_time();
181         try
182         {
183                 // Trivial case, we are sitting on a waypoint
184                 waypoint=*value_node->find(waypoint.get_time());
185         }
186         catch(...)
187         {
188                 waypoint=value_node->new_waypoint_at_time(time);
189                 waypoint.set_before(synfigapp::Main::get_interpolation());
190                 waypoint.set_after(synfigapp::Main::get_interpolation());
191         }
192 /*
193         Time time=waypoint.get_time();
194         ValueNode_Animated::WaypointList &waypoint_list(value_node->waypoint_list());
195         ValueNode_Animated::WaypointList::iterator iter;
196
197         if(waypoint_list.empty())
198         {
199                 waypoint.set_value((*value_node)(time));
200                 return;
201         }
202
203         ValueNode_Animated::WaypointList::iterator closest=waypoint_list.begin();
204
205         for(iter=waypoint_list.begin();iter!=waypoint_list.end();++iter)
206         {
207                 const Real dist(abs(iter->get_time()-time));
208                 if(dist<abs(closest->get_time()-time))
209                         closest=iter;
210         }
211         if(!closest->is_static())
212                 waypoint.set_value_node(closest->get_value_node());
213         else
214                 waypoint.set_value((*value_node)(time));
215 */
216 }
217
218 void
219 Action::WaypointSetSmart::enclose_waypoint(const synfig::Waypoint& waypoint)
220 {
221         times.insert(waypoint.get_time());
222
223         try {
224                 times.insert(value_node->find(waypoint)->get_time());
225 //              synfig::info(__FILE__":%d: value_node->find(waypoint)->get_time()=%s",__LINE__,value_node->find(waypoint)->get_time().get_string().c_str());
226         }catch (...) { }
227
228         // First we need to add any waypoints necessary to
229         // maintain the integrity of the keyframes.
230         if(get_edit_mode()&MODE_ANIMATE_PAST) try
231         {
232                 Time curr_time(waypoint.get_time());
233
234                 //while(value_node->waypoint_list().front().get_time()<=curr_time)
235                 {
236                         // Try to find prev keyframe
237                         Keyframe keyframe(*get_canvas()->keyframe_list().find_prev(curr_time));
238                         curr_time=keyframe.get_time();
239
240 //                      synfig::info(__FILE__":%d: prev_keyframe->time=%s",__LINE__,keyframe.get_time().get_string().c_str());
241 //                      synfig::info(__FILE__":%d: waypoint->time=%s",__LINE__,waypoint.get_time().get_string().c_str());
242
243                         if(times.count(keyframe.get_time()))
244                         {
245                                 throw int();
246                         }
247                         if(waypoint.get_time().is_equal(keyframe.get_time()))
248                         {
249                                 throw int();
250                         }
251
252                         times.insert(keyframe.get_time());
253                         try
254                         {
255                                 value_node->find(keyframe.get_time());
256 //                              synfig::info(__FILE__":%d: waypointtime=%s",__LINE__,value_node->find(keyframe.get_time())->get_time().get_string().c_str());
257                         }
258                         catch(synfig::Exception::NotFound)
259                         {
260                                 Action::Handle action(WaypointAdd::create());
261
262                                 action->set_param("canvas",get_canvas());
263                                 action->set_param("canvas_interface",get_canvas_interface());
264                                 action->set_param("value_node",ValueNode::Handle(value_node));
265
266                                 if(!value_node->waypoint_list().empty())
267                                 {
268                                         action->set_param("time",keyframe.get_time());
269                                 }
270                                 else
271                                 {
272                                         synfig::Waypoint tmp;
273
274                                         tmp.set_value(waypoint.get_value());
275                                         tmp.set_time(keyframe.get_time());
276                                         action->set_param("waypoint",tmp);
277                                 }
278
279                                 assert(action->is_ready());
280                                 if(!action->is_ready())
281                                         throw Error(Error::TYPE_NOTREADY);
282
283                                 add_action(action);
284                         }
285                 }
286         }
287         catch(Error x) { throw x; }
288         catch(synfig::Exception::NotFound) { }
289         catch(int) { }
290         catch(...) { }
291
292         if(get_edit_mode()&MODE_ANIMATE_FUTURE)try
293         {
294                 Time curr_time(waypoint.get_time());
295
296                 //while(value_node->waypoint_list().back().get_time()>=curr_time)
297                 {
298
299                         // Try to find next keyframe
300                         //synfig::info("FUTURE waypoint.get_time()=%s",waypoint.get_time().get_string().c_str());
301                         Keyframe keyframe(*get_canvas()->keyframe_list().find_next(curr_time));
302                         //synfig::info("FUTURE keyframe.get_time()=%s",keyframe.get_time().get_string().c_str());
303                         curr_time=keyframe.get_time();
304
305                         if(times.count(keyframe.get_time())|| waypoint.get_time().is_equal(keyframe.get_time()))
306                                 throw int();
307                         else
308                                 times.insert(keyframe.get_time());
309
310                         try
311                         {
312                                 value_node->find(keyframe.get_time());
313                                 synfig::info(__FILE__":%d: time=%s",__LINE__,keyframe.get_time().get_string().c_str());
314                                 synfig::info(__FILE__":%d: waypointtime=%s",__LINE__,value_node->find(keyframe.get_time())->get_time().get_string().c_str());
315
316                         }
317                         catch(synfig::Exception::NotFound)
318                         {
319                                 Action::Handle action(WaypointAdd::create());
320
321                                 action->set_param("canvas",get_canvas());
322                                 action->set_param("canvas_interface",get_canvas_interface());
323                                 action->set_param("value_node",ValueNode::Handle(value_node));
324
325                                 if(!value_node->waypoint_list().empty())
326                                 {
327                                         action->set_param("time",keyframe.get_time());
328                                 }
329                                 else
330                                 {
331                                         synfig::Waypoint tmp;
332
333                                         tmp.set_value(waypoint.get_value());
334                                         tmp.set_time(keyframe.get_time());
335                                         action->set_param("waypoint",tmp);
336                                 }
337
338                                 assert(action->is_ready());
339                                 if(!action->is_ready())
340                                         throw Error(Error::TYPE_NOTREADY);
341
342                                 add_action(action);
343                         }
344                 }
345         }
346         catch(Error x) { throw x; }
347         catch(synfig::Exception::NotFound) { }
348         catch(int) { }
349         catch(...) { }
350 }
351
352 void
353 Action::WaypointSetSmart::prepare()
354 {
355         clear();
356         times.clear();
357
358         // First we need to add any waypoints necessary to
359         // maintain the integrity of the keyframes.
360         enclose_waypoint(waypoint);
361
362         try
363         {
364                 //synfig::info("WaypointSetSmart: Move/Update?");
365                 // Let's try to replace the old waypoint, if it exists
366                 WaypointList::iterator iter(value_node->find(waypoint));
367
368                 if(iter == value_node->waypoint_list().end())
369                         throw int();
370
371                 enclose_waypoint(*iter);
372
373                 Action::Handle action(WaypointSet::create());
374
375                 action->set_param("canvas",get_canvas());
376                 action->set_param("canvas_interface",get_canvas_interface());
377                 action->set_param("value_node",ValueNode::Handle(value_node));
378                 action->set_param("waypoint",waypoint);
379
380                 assert(action->is_ready());
381                 if(!action->is_ready())
382                         throw Error(Error::TYPE_NOTREADY);
383
384                 add_action(action);
385
386                 return;
387         }
388         catch(synfig::Exception::NotFound){ } catch(int){ }
389
390         try
391         {
392                 //synfig::info("WaypointSetSmart: Replace?");
393                 // Check to see if a waypoint exists at this point in time
394                 WaypointList::iterator iter=value_node->find(waypoint.get_time());
395
396                 waypoint.mimic(*iter);
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: Add?");
420                 // At this point we know that the old waypoint doesn't exist,
421                 // so we need to create it.
422                 Action::Handle action(WaypointAdd::create());
423
424                 action->set_param("canvas",get_canvas());
425                 action->set_param("canvas_interface",get_canvas_interface());
426                 action->set_param("value_node",ValueNode::Handle(value_node));
427                 action->set_param("waypoint",waypoint);
428
429                 assert(action->is_ready());
430                 if(!action->is_ready())
431                         throw Error(Error::TYPE_NOTREADY);
432
433                 add_action(action);
434
435                 return;
436         }
437         catch(synfig::Exception::NotFound){ } catch(int){ }
438
439         throw Error(_("Unable to determine how to proceed. This is a bug."));
440 }