my log
[synfig.git] / synfig-studio / trunk / src / synfigapp / actions / waypointset.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file waypointset.cpp
3 **      \brief Template File
4 **
5 **      $Id: waypointset.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 "waypointset.h"
32 #include <synfigapp/canvasinterface.h>
33
34 #endif
35
36 using namespace std;
37 using namespace etl;
38 using namespace synfig;
39 using namespace synfigapp;
40 using namespace Action;
41
42 /* === M A C R O S ========================================================= */
43
44 ACTION_INIT(Action::WaypointSet);
45 ACTION_SET_NAME(Action::WaypointSet,"waypoint_set");
46 ACTION_SET_LOCAL_NAME(Action::WaypointSet,"Set Waypoint");
47 ACTION_SET_TASK(Action::WaypointSet,"set");
48 ACTION_SET_CATEGORY(Action::WaypointSet,Action::CATEGORY_WAYPOINT);
49 ACTION_SET_PRIORITY(Action::WaypointSet,0);
50 ACTION_SET_VERSION(Action::WaypointSet,"0.0");
51 ACTION_SET_CVS_ID(Action::WaypointSet,"$Id: waypointset.cpp,v 1.1.1.1 2005/01/07 03:34:37 darco Exp $");
52
53 /* === G L O B A L S ======================================================= */
54
55 /* === P R O C E D U R E S ================================================= */
56
57 /* === M E T H O D S ======================================================= */
58
59 Action::WaypointSet::WaypointSet()
60 {
61         set_dirty(true);
62 }
63
64 Action::ParamVocab
65 Action::WaypointSet::get_param_vocab()
66 {
67         ParamVocab ret(Action::CanvasSpecific::get_param_vocab());
68         
69         ret.push_back(ParamDesc("value_node",Param::TYPE_VALUENODE)
70                 .set_local_name(_("Destination ValueNode (Animated)"))
71         );
72
73         ret.push_back(ParamDesc("waypoint",Param::TYPE_WAYPOINT)
74                 .set_local_name(_("Waypoint"))
75                 .set_desc(_("Waypoint to be changed"))
76                 .set_supports_multiple()
77         );
78
79         return ret;
80 }
81
82 bool
83 Action::WaypointSet::is_canidate(const ParamList &x)
84 {
85         return canidate_check(get_param_vocab(),x);
86 }
87
88 bool
89 Action::WaypointSet::set_param(const synfig::String& name, const Action::Param &param)
90 {
91         if(name=="value_node" && param.get_type()==Param::TYPE_VALUENODE)
92         {
93                 value_node=ValueNode_Animated::Handle::cast_dynamic(param.get_value_node());
94                 
95                 return static_cast<bool>(value_node);
96         }
97         if(name=="waypoint" && param.get_type()==Param::TYPE_WAYPOINT)
98         {
99                 //NOTE: at the moment there is no error checking for multiple sets!!!
100                 waypoints.push_back(param.get_waypoint());
101                 
102                 return true;
103         }
104
105         return Action::CanvasSpecific::set_param(name,param);
106 }
107
108 bool
109 Action::WaypointSet::is_ready()const
110 {
111         if(!value_node || waypoints.empty())
112                 return false;
113         return Action::CanvasSpecific::is_ready();
114 }
115
116 void
117 Action::WaypointSet::perform()
118 {       
119         WaypointList::iterator iter;
120
121 #if 1   
122         vector<WaypointList::iterator>  iters;
123         vector<Waypoint>::iterator i = waypoints.begin(), end = waypoints.end();        
124         
125         for(; i != end; ++i)
126         {
127                 try { iters.push_back(value_node->find(*i)); }
128                 catch(synfig::Exception::NotFound)
129                 {
130                         throw Error(_("Unable to find waypoint"));
131                 }
132         }
133         
134         //check to see which valuenodes are going to override because of the time...
135         ValueNode_Animated::findresult timeiter;
136         
137         for(i = waypoints.begin(); i != end; ++i)
138         {
139                 timeiter = value_node->find_time(i->get_time());
140                 
141                 bool candelete = timeiter.second;
142         
143                 //we only want to track overwrites (not waypoints that are also being modified)
144                 if(candelete)
145                 {
146                         for(vector<WaypointList::iterator>::iterator ii = iters.begin(); ii != iters.end(); ++ii)
147                         {
148                                 if(timeiter.first == *ii)
149                                 {
150                                         candelete = false;
151                                         break;
152                                 }
153                         }
154                 }
155                 
156                 //if we can still delete it after checking, record it, and then remove them all later
157                 if(candelete)
158                 {
159                         Waypoint w = *timeiter.first;
160                         overwritten_waypoints.push_back(w);
161                 }
162         }
163         
164         //overwrite all the valuenodes we're supposed to set
165         {
166                 i = waypoints.begin();
167                 for(vector<WaypointList::iterator>::iterator ii = iters.begin(); ii != iters.end() && i != end; ++ii, ++i)
168                 {
169                         old_waypoints.push_back(**ii);
170                         **ii = *i; //set the point to the corresponding point in the normal waypoint list
171                 }
172         }
173         
174         //remove all the points we're supposed to be overwritting
175         {
176                 vector<Waypoint>::iterator      oi = overwritten_waypoints.begin(),
177                                                                         oend = overwritten_waypoints.end();
178                 for(; oi != oend; ++oi)
179                 {
180                         value_node->erase(*oi);
181                 }
182         }
183
184 #else
185         try { iter=value_node->find(waypoint); }
186         catch(synfig::Exception::NotFound)
187         {
188                 throw Error(_("Unable to find waypoint"));
189         }
190
191         //find the value at the old time before we replace it
192         ValueNode_Animated::findresult timeiter;
193         timeiter = value_node->find_time(waypoint.get_time());
194         
195         //we only want to track overwrites (not inplace modifications)
196         if(timeiter.second && waypoint.get_uid() == timeiter.first->get_uid())
197         {
198                 timeiter.second = false;                        
199         }
200                 
201         //copy and overwrite
202         old_waypoint=*iter;
203         *iter=waypoint;
204         
205         //if we've found a unique one then we need to erase it, but store it first
206         if(timeiter.second)
207         {
208                 time_overwrite = true;
209                 overwritten_wp = *timeiter.first;
210                 
211                 value_node->erase(overwritten_wp);
212         }
213 #endif
214         
215         // Signal that a valuenode has been changed
216         value_node->changed();
217 }
218
219 void
220 Action::WaypointSet::undo()
221 {
222         WaypointList::iterator iter;
223         
224 #if 1
225         vector<Waypoint>::iterator i = old_waypoints.begin(), end = old_waypoints.end();        
226         
227         for(; i != end; ++i)
228         {
229                 try { iter = value_node->find(*i); }
230                 catch(synfig::Exception::NotFound)
231                 {
232                         throw Error(_("Unable to find waypoint"));
233                 }
234                 
235                 //overwrite with old one
236                 *iter = *i;
237         }
238                 
239         //add back in all the points that we removed before...
240         {
241                 vector<Waypoint>::iterator      oi = overwritten_waypoints.begin(),
242                                                                         oend = overwritten_waypoints.end();
243                 for(; oi != oend; ++oi)
244                 {
245                         value_node->add(*oi);
246                 }
247         }
248
249 #else
250         try { iter=value_node->find(old_waypoint); }
251         catch(synfig::Exception::NotFound)
252         {
253                 throw Error(_("Unable to find waypoint"));
254         }       
255
256         *iter=old_waypoint;
257         
258         if(time_overwrite)
259         {
260                 value_node->add(overwritten_wp);
261         }
262 #endif
263         
264         // Signal that a valuenode has been changed
265         value_node->changed();
266 }