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