3713e0482721e8da44effabf50050d8e42b71c4c
[synfig.git] / synfig-studio / trunk / src / synfigapp / actions / activepointsetsmart.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file activepointsetsmart.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "activepointsetsmart.h"
33 #include "valuenodelinkconnect.h"
34 #include "valuenodereplace.h"
35
36 #include "activepointset.h"
37 #include "activepointadd.h"
38
39 #include "valuedescconnect.h"
40 #include <synfigapp/canvasinterface.h>
41
42 #include <synfigapp/general.h>
43
44 #endif
45
46 using namespace std;
47 using namespace etl;
48 using namespace synfig;
49 using namespace synfigapp;
50 using namespace Action;
51
52 /* === M A C R O S ========================================================= */
53
54 ACTION_INIT(Action::ActivepointSetSmart);
55 ACTION_SET_NAME(Action::ActivepointSetSmart,"activepoint_set_smart");
56 ACTION_SET_LOCAL_NAME(Action::ActivepointSetSmart,N_("Set Activepoint (Smart)"));
57 ACTION_SET_TASK(Action::ActivepointSetSmart,"set");
58 ACTION_SET_CATEGORY(Action::ActivepointSetSmart,Action::CATEGORY_ACTIVEPOINT);
59 ACTION_SET_PRIORITY(Action::ActivepointSetSmart,0);
60 ACTION_SET_VERSION(Action::ActivepointSetSmart,"0.0");
61 ACTION_SET_CVS_ID(Action::ActivepointSetSmart,"$Id$");
62
63 /* === G L O B A L S ======================================================= */
64
65 /* === P R O C E D U R E S ================================================= */
66
67 /* === M E T H O D S ======================================================= */
68
69 Action::ActivepointSetSmart::ActivepointSetSmart()
70 {
71         activepoint.set_time(Time::begin()-1);
72         time_set=false;
73         set_dirty(true);
74 }
75
76 Action::ParamVocab
77 Action::ActivepointSetSmart::get_param_vocab()
78 {
79         ParamVocab ret(Action::CanvasSpecific::get_param_vocab());
80
81         ret.push_back(ParamDesc("value_desc",Param::TYPE_VALUEDESC)
82                 .set_local_name(_("ValueDesc"))
83         );
84
85         ret.push_back(ParamDesc("activepoint",Param::TYPE_ACTIVEPOINT)
86                 .set_local_name(_("New Activepoint"))
87                 .set_desc(_("Activepoint to be added"))
88                 .set_optional()
89         );
90
91         ret.push_back(ParamDesc("time",Param::TYPE_TIME)
92                 .set_local_name(_("Time"))
93                 .set_desc(_("Time where activepoint is to be added"))
94                 .set_optional()
95         );
96
97         return ret;
98 }
99
100 bool
101 Action::ActivepointSetSmart::is_candidate(const ParamList &x)
102 {
103         if (!candidate_check(get_param_vocab(),x))
104                 return false;
105
106         ValueDesc value_desc(x.find("value_desc")->second.get_value_desc());
107
108         return (value_desc.parent_is_value_node() &&
109                         // We need a dynamic list.
110                         ValueNode_DynamicList::Handle::cast_dynamic(value_desc.get_parent_value_node()) &&
111                         // We need either an activepoint or a time.
112                         (x.count("activepoint") || x.count("time")));
113 }
114
115 bool
116 Action::ActivepointSetSmart::set_param(const synfig::String& name, const Action::Param &param)
117 {
118         if(name=="value_desc" && param.get_type()==Param::TYPE_VALUEDESC)
119         {
120                 value_desc=param.get_value_desc();
121
122                 if(!value_desc.parent_is_value_node())
123                         return false;
124
125                 value_node=ValueNode_DynamicList::Handle::cast_dynamic(value_desc.get_parent_value_node());
126
127                 if(!value_node)
128                         return false;
129
130                 index=value_desc.get_index();
131
132                 if(time_set)
133                         calc_activepoint();
134
135                 return true;
136         }
137         if(name=="activepoint" && param.get_type()==Param::TYPE_ACTIVEPOINT && !time_set)
138         {
139                 activepoint=param.get_activepoint();
140
141                 return true;
142         }
143         if(name=="time" && param.get_type()==Param::TYPE_TIME && activepoint.get_time()==Time::begin()-1)
144         {
145                 activepoint.set_time(param.get_time());
146                 time_set=true;
147
148                 if(value_node)
149                         calc_activepoint();
150
151                 return true;
152         }
153
154         return Action::CanvasSpecific::set_param(name,param);
155
156         return Action::CanvasSpecific::set_param(name,param);
157 }
158
159 bool
160 Action::ActivepointSetSmart::is_ready()const
161 {
162         if(!value_node)
163                 synfig::error("Missing value_node");
164
165         if(activepoint.get_time()==(Time::begin()-1))
166                 synfig::error("Missing activepoint");
167
168         if(!value_node || activepoint.get_time()==(Time::begin()-1))
169                 return false;
170         return Action::CanvasSpecific::is_ready();
171 }
172
173 // This function is called if a time is specified, but not
174 // a activepoint. In this case, we need to calculate the value
175 // of the activepoint
176 void
177 Action::ActivepointSetSmart::calc_activepoint()
178 {
179 /*
180         const Time time(activepoint.get_time());
181         activepoint.set_state(value_node->list[index].status_at_time(time));
182         activepoint.set_priority(0);
183 */
184
185         activepoint=value_node->list[index].new_activepoint_at_time(activepoint.get_time());
186
187         // In this case, nothing is really changing, so there will be
188         // no need to redraw the window
189         set_dirty(false);
190 }
191
192 void
193 Action::ActivepointSetSmart::enclose_activepoint(const synfig::Activepoint& activepoint)
194 {
195         times.insert(activepoint.get_time());
196
197         if(get_edit_mode()&MODE_ANIMATE_PAST) try
198         {
199                 // Try to find prev keyframe
200                 Keyframe keyframe(*get_canvas()->keyframe_list().find_prev(activepoint.get_time()));
201
202                 if(times.count(keyframe.get_time()))
203                         throw int();
204                 else
205                         times.insert(keyframe.get_time());
206
207                 try { value_node->list[index].find(keyframe.get_time()); }
208                 catch(synfig::Exception::NotFound)
209                 {
210                         Action::Handle action(ActivepointAdd::create());
211
212                         action->set_param("canvas",get_canvas());
213                         action->set_param("canvas_interface",get_canvas_interface());
214                         action->set_param("value_desc",value_desc);
215
216                         if(!value_node->list[index].timing_info.empty())
217                         {
218                                 action->set_param("time",keyframe.get_time());
219                         }
220                         else
221                         {
222                                 synfig::Activepoint tmp;
223
224                                 tmp.set_state(true);
225                                 tmp.set_time(keyframe.get_time());
226                                 action->set_param("activepoint",tmp);
227                         }
228
229                         assert(action->is_ready());
230                         if(!action->is_ready())
231                                 throw Error(Error::TYPE_NOTREADY);
232
233                         add_action_front(action);
234                 }
235         }
236         catch(int) { }
237         catch(synfig::Exception::NotFound) { }
238
239         if(get_edit_mode()&MODE_ANIMATE_FUTURE)try
240         {
241                 // Try to find next keyframe
242                 Keyframe keyframe(*get_canvas()->keyframe_list().find_next(activepoint.get_time()));
243
244                 if(times.count(keyframe.get_time()))
245                         throw int();
246                 else
247                         times.insert(keyframe.get_time());
248
249                 try { value_node->list[index].find(keyframe.get_time()); }
250                 catch(synfig::Exception::NotFound)
251                 {
252                         Action::Handle action(ActivepointAdd::create());
253
254                         action->set_param("canvas",get_canvas());
255                         action->set_param("canvas_interface",get_canvas_interface());
256                         action->set_param("value_desc",value_desc);
257
258                         if(!value_node->list[index].timing_info.empty())
259                         {
260                                 action->set_param("time",keyframe.get_time());
261                         }
262                         else
263                         {
264                                 synfig::Activepoint tmp;
265
266                                 tmp.set_state(true);
267                                 tmp.set_time(keyframe.get_time());
268                                 action->set_param("activepoint",tmp);
269                         }
270
271                         assert(action->is_ready());
272                         if(!action->is_ready())
273                                 throw Error(Error::TYPE_NOTREADY);
274
275                         add_action_front(action);
276                 }
277         }
278         catch(int) { }
279         catch(synfig::Exception::NotFound) { }
280 }
281
282 void
283 Action::ActivepointSetSmart::prepare()
284 {
285         clear();
286         times.clear();
287
288         // First, we need to add any activepoints necessary to
289         // maintain the integrity of the keyframes.
290         enclose_activepoint(activepoint);
291
292         try
293         {
294                 if(value_node->list[index].find(activepoint)==value_node->list[index].timing_info.end())
295                         throw int();
296
297                 // Then, let's try to replace the old activepoint, if it exists
298                 enclose_activepoint(*value_node->list[index].find(activepoint));
299
300                 Action::Handle action(ActivepointSet::create());
301
302                 action->set_param("canvas",get_canvas());
303                 action->set_param("canvas_interface",get_canvas_interface());
304                 action->set_param("value_desc",value_desc);
305                 action->set_param("activepoint",activepoint);
306
307                 assert(action->is_ready());
308                 if(!action->is_ready())
309                         throw Error(Error::TYPE_NOTREADY);
310
311                 add_action_front(action);
312
313                 return;
314         }
315         catch(int){}
316         catch(Exception::NotFound){}
317
318         try
319         {
320                 // Check to see if a activepoint exists at this point in time
321                 activepoint.mimic(*value_node->list[index].find(activepoint.get_time()));
322
323                 enclose_activepoint(*value_node->list[index].find(activepoint.get_time()));
324
325                 Action::Handle action(ActivepointSet::create());
326
327                 action->set_param("canvas",get_canvas());
328                 action->set_param("canvas_interface",get_canvas_interface());
329                 action->set_param("value_desc",value_desc);
330                 action->set_param("activepoint",activepoint);
331
332                 assert(action->is_ready());
333                 if(!action->is_ready())
334                         throw Error(Error::TYPE_NOTREADY);
335
336                 add_action_front(action);
337
338                 return;
339         }
340         catch(int){}
341         catch(Exception::NotFound){}
342
343         try
344         {
345                 // At this point we know that the old activepoint doesn't exist,
346                 // so we need to create it.
347                 Action::Handle action(ActivepointAdd::create());
348
349                 action->set_param("canvas",get_canvas());
350                 action->set_param("canvas_interface",get_canvas_interface());
351                 action->set_param("value_desc",value_desc);
352                 action->set_param("activepoint",activepoint);
353
354                 assert(action->is_ready());
355                 if(!action->is_ready())
356                         throw Error(Error::TYPE_NOTREADY);
357
358                 add_action_front(action);
359
360                 return;
361         }
362         catch(int){}
363         catch(Exception::NotFound){}
364
365         throw Error(_("Unable to determine how to proceed. This is a bug."));
366 }