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