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