Revision 1150 changed the way angles work so that 0 degrees and 360 degrees are treat...
[synfig.git] / synfig-core / trunk / src / synfig / node.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file node.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 #define HASH_MAP_H <ext/hash_map>
26
27 #ifdef USING_PCH
28 #       include "pch.h"
29 #else
30 #ifdef HAVE_CONFIG_H
31 #       include <config.h>
32 #endif
33
34 #include "node.h"
35 #include "nodebase.h"
36
37 #ifdef HASH_MAP_H
38 #include HASH_MAP_H
39 using namespace __gnu_cxx;
40 #else
41 #include <map>
42 #endif
43
44 #endif
45
46 /* === U S I N G =========================================================== */
47
48 using namespace std;
49 using namespace etl;
50 using namespace synfig;
51
52 /* === M A C R O S ========================================================= */
53
54 // About BE_FRUGAL_WITH_GUIDS
55 // If this macro is set, then a GUID will NOT
56 // be calculated until the first call to get_guid()
57 // This also means that the node doesn't get
58 // added to the database until get_guid() is called
59 // for the first time, or set_guid() is called.
60 // If it is expensive to calculate GUIDs, then
61 // this can improve performance a tad in
62 // some cases. Otherwise, it doesn't change
63 // much of anything.
64 #define BE_FRUGAL_WITH_GUIDS 1
65
66 #ifndef __sys_clock
67 #ifndef _WIN32
68 # include <time.h>
69 # define __sys_clock    ::clock
70 #else
71 # ifdef __GNUG__
72 #  include <time.h>
73 #  define __sys_clock   ::clock
74 # else
75 typedef int clock_t;
76 extern clock_t _clock();
77 #  define CLOCKS_PER_SEC 1000
78 #  define __sys_clock   _clock
79 # endif
80 #endif
81 #endif
82
83 /* === G L O B A L S ======================================================= */
84
85 #ifdef HASH_MAP_H
86 typedef hash_map<GUID,Node*,GUIDHash> GlobalNodeMap;
87 #else
88 typedef map<GUID,Node*> GlobalNodeMap;
89 #endif
90
91 static GlobalNodeMap* global_node_map_;
92
93 static GlobalNodeMap& global_node_map()
94 {
95         if(!global_node_map_)
96                 global_node_map_=new GlobalNodeMap;
97         return *global_node_map_;
98 }
99
100 /* === P R O C E D U R E S ================================================= */
101
102 synfig::Node*
103 synfig::find_node(const GUID& guid)
104 {
105         if(global_node_map().count(guid)==0)
106                 return 0;
107         return global_node_map()[guid];
108 }
109
110 static void
111 refresh_node(synfig::Node* node, GUID old_guid)
112 {
113         assert(global_node_map().count(old_guid));
114         global_node_map().erase(old_guid);
115         assert(!global_node_map().count(old_guid));
116         global_node_map()[node->get_guid()]=node;
117 }
118
119 /* === M E T H O D S ======================================================= */
120
121 #ifdef _DEBUG
122 const char *
123 TimePoint::c_str()const
124 {
125         return get_time().get_string().c_str();
126 }
127 #endif
128
129 void
130 TimePoint::absorb(const TimePoint& x)
131 {
132         if(get_guid()==x.get_guid())
133                 return;
134         set_guid(get_guid()^x.get_guid());
135
136         if(get_after()==INTERPOLATION_NIL)
137                 set_after(x.get_after());
138         if(get_before()==INTERPOLATION_NIL)
139                 set_before(x.get_before());
140
141         if(get_after()!=x.get_after() && x.get_after()!=INTERPOLATION_NIL)
142                 set_after(INTERPOLATION_UNDEFINED);
143         if(get_before()!=x.get_before() && x.get_before()!=INTERPOLATION_NIL)
144                 set_before(INTERPOLATION_UNDEFINED);
145 }
146
147 TimePointSet::iterator
148 TimePointSet::insert(const TimePoint& x)
149 {
150         iterator iter(find(x));
151         if(iter!=end())
152         {
153                 const_cast<TimePoint&>(*iter).absorb(x);
154                 return iter;
155         }
156         return std::set<TimePoint>::insert(x).first;
157 }
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173 Node::Node():
174         guid_(0),
175         bchanged(true),
176         deleting_(false)
177 {
178 #ifndef BE_FRUGAL_WITH_GUIDS
179         guid_.make_unique();
180         assert(guid_);
181         assert(!global_node_map().count(guid_));
182         global_node_map()[guid_]=this;
183 #endif
184 }
185
186 Node::~Node()
187 {
188         begin_delete();
189
190         if(guid_)
191         {
192                 assert(global_node_map().count(guid_));
193                 global_node_map().erase(guid_);
194                 assert(!global_node_map().count(guid_));
195         }
196 }
197
198 void
199 Node::changed()
200 {
201         time_last_changed_=__sys_clock();
202         on_changed();
203 }
204
205
206 //! Gets the GUID for this value node
207 const GUID&
208 Node::get_guid()const
209 {
210 #ifdef BE_FRUGAL_WITH_GUIDS
211         if(!guid_)
212         {
213                 const_cast<GUID&>(guid_).make_unique();
214                 assert(guid_);
215                 assert(!global_node_map().count(guid_));
216                 global_node_map()[guid_]=const_cast<Node*>(this);
217         }
218 #endif
219
220         return guid_;
221 }
222
223 //! Sets the GUID for this value node
224 void
225 Node::set_guid(const GUID& x)
226 {
227         assert(x);
228
229 #ifdef BE_FRUGAL_WITH_GUIDS
230         if(!guid_)
231         {
232                 guid_=x;
233                 assert(!global_node_map().count(guid_));
234                 global_node_map()[guid_]=this;
235         }
236         else
237 #endif
238         if(guid_!=x)
239         {
240                 GUID oldguid(guid_);
241                 guid_=x;
242                 refresh_node(this, oldguid);
243                 on_guid_changed(oldguid);
244         }
245 }
246
247 int
248 Node::get_time_last_changed()const
249 {
250         return time_last_changed_;
251 }
252
253 void
254 Node::add_child(Node*x)
255 {
256         x->parent_set.insert(this);
257 }
258
259 void
260 Node::remove_child(Node*x)
261 {
262         if(x->parent_set.count(this)) x->parent_set.erase(this);
263 }
264
265 int
266 Node::parent_count()const
267 {
268         return parent_set.size();
269 }
270
271 const Node::time_set &
272 Node::get_times() const
273 {
274         if(bchanged)
275         {
276                 times.clear();
277                 get_times_vfunc(times);
278                 bchanged = false;
279         }
280
281         //set the output set...
282         return times;
283 }
284
285 void
286 Node::begin_delete()
287 {
288         if(!deleting_)
289         {
290                 deleting_=true; signal_deleted()();
291         }
292 }
293
294 void
295 Node::on_changed()
296 {
297         bchanged = true;
298         signal_changed()();
299
300         std::set<Node*>::iterator iter;
301         for(iter=parent_set.begin();iter!=parent_set.end();++iter)
302         {
303                 (*iter)->changed();
304         }
305 }
306
307 void
308 Node::on_guid_changed(GUID guid)
309 {
310         signal_guid_changed()(guid);
311 }