Changed the "tagrelease" and "tagstable" make targets to use subversion. Also increme...
[synfig.git] / synfig-studio / tags / stable / src / sinfgapp / actions / keyframeset.cpp
1 /* === S I N F G =========================================================== */
2 /*!     \file keyframeset.cpp
3 **      \brief Template File
4 **
5 **      $Id: keyframeset.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 "keyframeset.h"
32 #include <sinfgapp/canvasinterface.h>
33 #include <sinfg/valuenode_dynamiclist.h>
34 #include <sinfg/valuenode_animated.h>
35 #include "activepointsetsmart.h"
36 #include "waypointsetsmart.h"
37
38 #endif
39
40 using namespace std;
41 using namespace etl;
42 using namespace sinfg;
43 using namespace sinfgapp;
44 using namespace Action;
45
46 /* === M A C R O S ========================================================= */
47
48 ACTION_INIT(Action::KeyframeSet);
49 ACTION_SET_NAME(Action::KeyframeSet,"keyframe_set");
50 ACTION_SET_LOCAL_NAME(Action::KeyframeSet,"Set Keyframe");
51 ACTION_SET_TASK(Action::KeyframeSet,"set");
52 ACTION_SET_CATEGORY(Action::KeyframeSet,Action::CATEGORY_KEYFRAME|Action::CATEGORY_HIDDEN);
53 ACTION_SET_PRIORITY(Action::KeyframeSet,0);
54 ACTION_SET_VERSION(Action::KeyframeSet,"0.0");
55 ACTION_SET_CVS_ID(Action::KeyframeSet,"$Id: keyframeset.cpp,v 1.1.1.1 2005/01/07 03:34:37 darco Exp $");
56
57 /* === G L O B A L S ======================================================= */
58
59 /* === P R O C E D U R E S ================================================= */
60
61 /* === M E T H O D S ======================================================= */
62
63 Action::KeyframeSet::KeyframeSet()
64 {
65         keyframe.set_time(Time::begin()-1);
66         set_dirty(false);
67 }
68
69 Action::ParamVocab
70 Action::KeyframeSet::get_param_vocab()
71 {
72         ParamVocab ret(Action::CanvasSpecific::get_param_vocab());
73         
74         ret.push_back(ParamDesc("keyframe",Param::TYPE_KEYFRAME)
75                 .set_local_name(_("New Keyframe"))
76                 .set_desc(_("Keyframe to be added"))
77         );
78
79         return ret;
80 }
81
82 bool
83 Action::KeyframeSet::is_canidate(const ParamList &x)
84 {
85         return canidate_check(get_param_vocab(),x);
86 }
87
88 bool
89 Action::KeyframeSet::set_param(const sinfg::String& name, const Action::Param &param)
90 {
91         if(name=="keyframe" && param.get_type()==Param::TYPE_KEYFRAME)
92         {
93                 sinfg::info("KeyframeSet::set_param():old_time: %s",keyframe.get_time().get_string().c_str());
94                 keyframe=param.get_keyframe();
95                 sinfg::info("KeyframeSet::set_param():new_time: %s",keyframe.get_time().get_string().c_str());
96                 sinfg::info("KeyframeSet::set_param():get_keyframe(): %s",param.get_keyframe().get_time().get_string().c_str());
97                 
98                 return true;
99         }
100
101         return Action::CanvasSpecific::set_param(name,param);
102 }
103
104 bool
105 Action::KeyframeSet::is_ready()const
106 {
107         if(keyframe.get_time()==(Time::begin()-1))
108                 return false;
109         return Action::CanvasSpecific::is_ready();
110 }
111
112 void
113 Action::KeyframeSet::prepare()
114 {
115         clear();
116         guid_set.clear();
117         
118         
119
120         
121         
122         //sinfg::info("new_time: %s",new_time.get_string().c_str());
123         //sinfg::info("old_time: %s",old_time.get_string().c_str());
124         
125         try { if(get_canvas()->keyframe_list().find(new_time)!=get_canvas()->keyframe_list().end()) throw Error(_("A Keyframe already exists at this point in time"));}
126         catch(...) { }  
127
128
129         // If the times are different, then we 
130         // will need to romp through the valuenodes
131         // and add actions to update their values.
132         if(new_time!=old_time)
133         {
134                 std::vector<sinfgapp::ValueDesc> value_desc_list;
135                 get_canvas_interface()->find_important_value_descs(value_desc_list);
136                 while(!value_desc_list.empty())
137                 {
138                         process_value_desc(value_desc_list.back());
139                         value_desc_list.pop_back();
140                 }
141         }
142 }
143
144 #define old_2_new(x)    (((x)-old_begin)/(old_end-old_begin)*(new_end-new_begin)+new_begin)
145
146 int
147 Action::KeyframeSet::scale_activepoints(const sinfgapp::ValueDesc& value_desc,const Time& old_begin,const Time& old_end,const Time& new_begin,const Time& new_end)
148 {
149         ValueNode_DynamicList::Handle value_node(ValueNode_DynamicList::Handle::cast_static(value_desc.get_parent_value_node()));
150         ValueNode_DynamicList::ListEntry& list_entry(value_node->list[value_desc.get_index()]);
151         
152         std::vector<Activepoint*> selected;
153         std::vector<Activepoint*>::iterator iter;
154         
155         if(list_entry.find(old_begin,old_end,selected))
156         {
157                 // check to make sure this operation is OK
158                 for(iter=selected.begin();iter!=selected.end();++iter)
159                 {
160                         try
161                         {
162                                 Time new_time(old_2_new((*iter)->get_time()));
163                                 if(new_time>=old_begin && new_time<old_end)
164                                         continue;
165                                 list_entry.find(new_time);
166                                 // If we found a activepoint already at that time, then
167                                 // we need to abort
168                                 //throw Exception::BadTime(_("Activepoint Conflict"));
169                         }
170                         catch(Exception::NotFound) { }
171                 }
172                 
173                 int ret(0);
174                 while(!selected.empty())
175                 {
176                         if(selected.back()->get_time()!=old_2_new(selected.back()->get_time()))
177                         {
178                                 Action::Handle action(Action::create("activepoint_set"));
179                                 
180                                 action->set_param("canvas",get_canvas());
181                                 action->set_param("canvas_interface",get_canvas_interface());
182                                 action->set_param("value_desc",value_desc);
183                                 
184                                 Activepoint activepoint(*selected.back());
185                                 activepoint.set_time(old_2_new(selected.back()->get_time()));
186
187                                 action->set_param("activepoint",activepoint);
188
189                                 assert(action->is_ready());
190                                 if(!action->is_ready())
191                                         throw Error(Error::TYPE_NOTREADY);
192                         
193                                 add_action_front(action);                                               
194
195                                 ret++;
196                         }
197                         selected.pop_back();
198                 }
199                 return ret;
200         }
201         return 0;
202 }
203
204 int
205 Action::KeyframeSet::scale_waypoints(const sinfgapp::ValueDesc& value_desc,const Time& old_begin,const Time& old_end,const Time& new_begin,const Time& new_end)
206 {
207         ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_static(value_desc.get_value_node()));
208         
209         std::vector<Waypoint*> selected;
210         std::vector<Waypoint*>::iterator iter;
211         
212         if(value_node->find(old_begin,old_end,selected))
213         {
214                 // check to make sure this operation is OK
215                 for(iter=selected.begin();iter!=selected.end();++iter)
216                 {
217                         try
218                         {
219                                 Time new_time(old_2_new((*iter)->get_time()));
220                                 if(new_time>=old_begin && new_time<old_end)
221                                         continue;
222                                 value_node->find(new_time);
223                                 // If we found a waypoint point already at that time, then
224                                 // we need to abort
225                                 //sinfg::info(_("old_begin: %s, old_end: %s"),old_begin.get_string().c_str(),old_end.get_string().c_str());
226                                 //sinfg::info(_("new_begin: %s, new_end: %s"),new_begin.get_string().c_str(),new_end.get_string().c_str());
227                                 //throw Exception::BadTime(strprintf(_("Waypoint Conflict, old: %s, new: %s"),(*iter)->get_time().get_string().c_str(),new_time.get_string().c_str()));
228                         }
229                         catch(Exception::NotFound) { }
230                 }
231                 
232                 int ret(0);
233                 while(!selected.empty())
234                 {
235                         if(selected.back()->get_time()!=old_2_new(selected.back()->get_time()))
236                         {
237                                 Action::Handle action(Action::create("waypoint_set"));
238                                 
239                                 action->set_param("canvas",get_canvas());
240                                 action->set_param("canvas_interface",get_canvas_interface());
241                                 action->set_param("value_node",ValueNode::Handle::cast_static(value_node));
242                                 
243                                 Waypoint waypoint(*selected.back());
244                                 waypoint.set_time(old_2_new(selected.back()->get_time()));
245
246                                 action->set_param("waypoint",waypoint);
247
248                                 assert(action->is_ready());
249                                 if(!action->is_ready())
250                                         throw Error(Error::TYPE_NOTREADY);
251                         
252                                 add_action_front(action);                                               
253
254                                 ret++;
255                         }
256                         selected.pop_back();
257                 }
258                 return ret;
259         }
260         return 0;
261 }
262
263 void
264 Action::KeyframeSet::process_value_desc(const sinfgapp::ValueDesc& value_desc)
265 {       
266         if(value_desc.is_value_node())
267         {               
268                 ValueNode::Handle value_node(value_desc.get_value_node());
269
270                 //if(guid_set.count(value_node->get_guid()))
271                 //      return;
272                 //guid_set.insert(value_node->get_guid());
273
274                 // If we are a dynamic list, then we need to update the ActivePoints
275                 if(ValueNode_DynamicList::Handle::cast_dynamic(value_node))
276                 {
277                         ValueNode_DynamicList::Handle value_node(ValueNode_DynamicList::Handle::cast_dynamic(value_node));
278                         int i;
279                         for(i=0;i<value_node->link_count();i++)
280                         {
281                                 sinfgapp::ValueDesc value_desc(value_node,i);
282                                 if(new_time>keyframe_prev && new_time<keyframe_next)
283                                 {
284                                         // In this circumstance, we need to adjust any
285                                         // activepoints between the previous and next
286                                         // keyframes
287                                         scale_activepoints(value_desc,keyframe_prev,old_time,keyframe_prev,new_time);
288                                         scale_activepoints(value_desc,old_time,keyframe_next,new_time,keyframe_next);
289                                 }
290                                 //else
291                                 {       
292                                         Action::Handle action(ActivepointSetSmart::create());
293                                         
294                                         action->set_param("canvas",get_canvas());
295                                         action->set_param("canvas_interface",get_canvas_interface());
296                                         action->set_param("value_desc",value_desc);
297                                         
298                                         Activepoint activepoint;
299                                         try
300                                         {
301                                                 activepoint=*value_node->list[i].find(old_time);
302                                                 activepoint.set_time(new_time);
303                                         }
304                                         catch(...)
305                                         {
306                                                 activepoint.set_time(new_time);
307                                                 activepoint.set_state(value_node->list[i].status_at_time(old_time));
308                                                 activepoint.set_priority(0);
309                                         }
310                                         action->set_param("activepoint",activepoint);
311         
312                                         assert(action->is_ready());
313                                         if(!action->is_ready())
314                                                 throw Error(Error::TYPE_NOTREADY);
315                                 
316                                         add_action_front(action);
317                                 }
318                         }
319                 }
320                 else if(ValueNode_Animated::Handle::cast_dynamic(value_node))
321                 {
322                         if(new_time>keyframe_prev && new_time<keyframe_next)
323                         {
324                                         // In this circumstance, we need to adjust any
325                                         // waypoints between the previous and next
326                                         // keyframes
327                                         scale_waypoints(value_desc,keyframe_prev,old_time,keyframe_prev,new_time);
328                                         scale_waypoints(value_desc,old_time,keyframe_next,new_time,keyframe_next);
329                         }
330                         //else
331                         {
332                                 ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_dynamic(value_node));
333                                 
334                                 Action::Handle action(WaypointSetSmart::create());
335                                 
336                                 action->set_param("canvas",get_canvas());
337                                 action->set_param("canvas_interface",get_canvas_interface());
338                                 action->set_param("value_node",ValueNode::Handle(value_node));
339                                 
340                                 Waypoint waypoint;
341                                 try
342                                 {
343                                         waypoint=*value_node->find(old_time);
344                                         waypoint.set_time(new_time);
345                                 }
346                                 catch(...)
347                                 {
348                                         waypoint.set_time(new_time);
349                                         waypoint.set_value((*value_node)(old_time));
350                                 }
351                                 action->set_param("waypoint",waypoint);
352                 
353                                 assert(action->is_ready());
354                                 if(!action->is_ready())
355                                         throw Error(Error::TYPE_NOTREADY);
356                         
357                                 add_action_front(action);
358                         }
359                 }
360         }
361 }
362
363
364 void
365 Action::KeyframeSet::perform()
366 {
367
368         old_time=get_canvas()->keyframe_list().find(keyframe)->get_time();
369         new_time=keyframe.get_time();
370         
371         try { get_canvas()->keyframe_list().find(keyframe);}
372         catch(sinfg::Exception::NotFound)
373         {
374                 throw Error(_("Unable to find the given keyframe"));
375         }       
376         
377         // Check for colisions
378         if(old_time!=new_time)
379         {
380                 try {
381                         get_canvas()->keyframe_list().find(new_time);
382                         throw Error(_("Cannot change keyframe time because another keyframe already exists with that time."));
383                 }
384                 catch(Exception::NotFound) { }
385         }
386         try { keyframe_next=get_canvas()->keyframe_list().find_next(old_time)->get_time(); }
387         catch(...) { keyframe_next=Time::end(); }
388         try { keyframe_prev=get_canvas()->keyframe_list().find_prev(old_time)->get_time(); }
389         catch(...) { keyframe_prev=Time::begin(); }
390
391         old_keyframe=*get_canvas()->keyframe_list().find(keyframe);
392         *get_canvas()->keyframe_list().find(keyframe)=keyframe;
393         
394         get_canvas()->keyframe_list().sync();
395
396         try{
397                 Action::Super::perform();
398         } catch(...)
399         {
400                 *get_canvas()->keyframe_list().find(old_keyframe)=old_keyframe;
401
402                 get_canvas()->keyframe_list().sync();
403                 throw;
404         }
405         
406         // Signal that a layer has been inserted
407         if(get_canvas_interface())
408         {
409                 get_canvas_interface()->signal_keyframe_changed()(keyframe);
410         }
411         else sinfg::warning("CanvasInterface not set on action");
412 }
413
414 void
415 Action::KeyframeSet::undo()
416 {
417         Action::Super::undo();
418
419         *get_canvas()->keyframe_list().find(old_keyframe)=old_keyframe;
420
421         get_canvas()->keyframe_list().sync();
422         
423         // Signal that a layer has been inserted
424         if(get_canvas_interface())
425         {
426                 get_canvas_interface()->signal_keyframe_changed()(keyframe);
427         }
428         else sinfg::warning("CanvasInterface not set on action");
429 }