Use an enumeration type rather than unnamed integers to specify the different types...
[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 "proto/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 void
122 TimePoint::absorb(const TimePoint& x)
123 {
124         if(get_guid()==x.get_guid())
125                 return;
126         set_guid(get_guid()^x.get_guid());
127
128         if(get_after()==INTERPOLATION_NIL)
129                 set_after(x.get_after());
130         if(get_before()==INTERPOLATION_NIL)
131                 set_before(x.get_before());
132
133         if(get_after()!=x.get_after() && x.get_after()!=INTERPOLATION_NIL)
134                 set_after(INTERPOLATION_UNDEFINED);
135         if(get_before()!=x.get_before() && x.get_before()!=INTERPOLATION_NIL)
136                 set_before(INTERPOLATION_UNDEFINED);
137 }
138
139 TimePointSet::iterator
140 TimePointSet::insert(const TimePoint& x)
141 {
142         iterator iter(find(x));
143         if(iter!=end())
144         {
145                 const_cast<TimePoint&>(*iter).absorb(x);
146                 return iter;
147         }
148         return std::set<TimePoint>::insert(x).first;
149 }
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 Node::Node():
166         guid_(0),
167         bchanged(true),
168         deleting_(false)
169 {
170 #ifndef BE_FRUGAL_WITH_GUIDS
171         guid_.make_unique();
172         assert(guid_);
173         assert(!global_node_map().count(guid_));
174         global_node_map()[guid_]=this;
175 #endif
176 }
177
178 Node::~Node()
179 {
180         begin_delete();
181
182         if(guid_)
183         {
184                 assert(global_node_map().count(guid_));
185                 global_node_map().erase(guid_);
186                 assert(!global_node_map().count(guid_));
187         }
188 }
189
190 void
191 Node::changed()
192 {
193         time_last_changed_=__sys_clock();
194         on_changed();
195 }
196
197
198 //! Gets the GUID for this value node
199 const GUID&
200 Node::get_guid()const
201 {
202 #ifdef BE_FRUGAL_WITH_GUIDS
203         if(!guid_)
204         {
205                 const_cast<GUID&>(guid_).make_unique();
206                 assert(guid_);
207                 assert(!global_node_map().count(guid_));
208                 global_node_map()[guid_]=const_cast<Node*>(this);
209         }
210 #endif
211
212         return guid_;
213 }
214
215 //! Sets the GUID for this value node
216 void
217 Node::set_guid(const GUID& x)
218 {
219         assert(x);
220
221 #ifdef BE_FRUGAL_WITH_GUIDS
222         if(!guid_)
223         {
224                 guid_=x;
225                 assert(!global_node_map().count(guid_));
226                 global_node_map()[guid_]=this;
227         }
228         else
229 #endif
230         if(guid_!=x)
231         {
232                 GUID oldguid(guid_);
233                 guid_=x;
234                 refresh_node(this, oldguid);
235                 on_guid_changed(oldguid);
236         }
237 }
238
239 int
240 Node::get_time_last_changed()const
241 {
242         return time_last_changed_;
243 }
244
245 void
246 Node::add_child(Node*x)
247 {
248         x->parent_set.insert(this);
249 }
250
251 void
252 Node::remove_child(Node*x)
253 {
254         if(x->parent_set.count(this)) x->parent_set.erase(this);
255 }
256
257 int
258 Node::parent_count()const
259 {
260         return parent_set.size();
261 }
262
263 const Node::time_set &
264 Node::get_times() const
265 {
266         if(bchanged)
267         {
268                 times.clear();
269                 get_times_vfunc(times);
270                 bchanged = false;
271         }
272
273         //set the output set...
274         return times;
275 }
276
277 void
278 Node::begin_delete()
279 {
280         if(!deleting_)
281         {
282                 deleting_=true; signal_deleted()();
283         }
284 }
285
286 void
287 Node::on_changed()
288 {
289         bchanged = true;
290         signal_changed()();
291
292         std::set<Node*>::iterator iter;
293         for(iter=parent_set.begin();iter!=parent_set.end();++iter)
294         {
295                 (*iter)->changed();
296         }
297 }
298
299 void
300 Node::on_guid_changed(GUID guid)
301 {
302         signal_guid_changed()(guid);
303 }