Do not use get_param_vocab().size() as link counter. It is too slow.
[synfig.git] / synfig-core / 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 **      Copyright (c) 2007, 2008 Chris Moore
10 **
11 **      This package is free software; you can redistribute it and/or
12 **      modify it under the terms of the GNU General Public License as
13 **      published by the Free Software Foundation; either version 2 of
14 **      the License, or (at your option) any later version.
15 **
16 **      This package is distributed in the hope that it will be useful,
17 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **      General Public License for more details.
20 **      \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
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 "nodebase.h"                // this defines a bunch of sigc::slots that are never used
35
36 #ifdef HASH_MAP_H
37 #include HASH_MAP_H
38 #else
39 #include <map>
40 #endif
41
42 #endif
43
44 /* === U S I N G =========================================================== */
45
46 using namespace std;
47 using namespace etl;
48 using namespace synfig;
49
50 /* === M A C R O S ========================================================= */
51
52 // About BE_FRUGAL_WITH_GUIDS
53 // If this macro is set, then a GUID will NOT
54 // be calculated until the first call to get_guid()
55 // This also means that the node doesn't get
56 // added to the database until get_guid() is called
57 // for the first time, or set_guid() is called.
58 // If it is expensive to calculate GUIDs, then
59 // this can improve performance a tad in
60 // some cases. Otherwise, it doesn't change
61 // much of anything.
62 #define BE_FRUGAL_WITH_GUIDS 1
63
64 #ifndef __sys_clock
65         #ifndef _WIN32
66                 # include <time.h>
67                 # define __sys_clock    ::clock
68         #else
69                 # ifdef __GNUG__
70                         #  include <time.h>
71                         #  define __sys_clock   ::clock
72                 # else
73                         typedef int clock_t;
74                         extern clock_t _clock();
75                         #  define CLOCKS_PER_SEC 1000
76                         #  define __sys_clock   _clock
77                 # endif // __GNUG__
78         #endif // _WIN_32
79 #endif // __sys_clock
80
81 /* === G L O B A L S ======================================================= */
82
83 #ifdef HASH_MAP_H
84 typedef HASH_MAP_CLASS<synfig::GUID,Node*,GUIDHash> GlobalNodeMap;
85 #else
86 typedef map<synfig::GUID,Node*> GlobalNodeMap;
87 #endif
88
89 //! A map to store all the GUIDs with a pointer to the Node.
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 synfig::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, synfig::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 #ifdef _DEBUG
121 const char *
122 TimePoint::c_str()const
123 {
124         return get_time().get_string().c_str();
125 }
126 #endif
127
128 void
129 TimePoint::absorb(const TimePoint& x)
130 {
131         //! If the Time Point to absorb is itself then bail out
132         if(get_guid()==x.get_guid())
133                 return;
134         //! Creates a new GUID with the old and the new one using XOR operator
135         set_guid(get_guid()^x.get_guid());
136         //! If the current before/after interpolation is NIL use the interpolation
137         //! provided by the TimePoint to absorb
138         if(get_after()==INTERPOLATION_NIL)
139                 set_after(x.get_after());
140         if(get_before()==INTERPOLATION_NIL)
141                 set_before(x.get_before());
142         //! If the interpolation of the Time Point to absorb is not the same
143         //! than the interpolation from the Time Point to absorb then
144         //! use UNDEFINED interpolation
145         if(get_after()!=x.get_after() && x.get_after()!=INTERPOLATION_NIL)
146                 set_after(INTERPOLATION_UNDEFINED);
147         if(get_before()!=x.get_before() && x.get_before()!=INTERPOLATION_NIL)
148                 set_before(INTERPOLATION_UNDEFINED);
149 }
150
151 TimePointSet::iterator
152 TimePointSet::insert(const TimePoint& x)
153 {
154         //! finds a iterator to a Time Point with the same time
155         //! \see inline bool operator==(const TimePoint& lhs,const TimePoint& rhs)
156         iterator iter(find(x));
157         //! If iter is not a the end of the set (we found one Time Point)
158         if(iter!=end())
159         {
160                 //! Absorb the time point
161                 const_cast<TimePoint&>(*iter).absorb(x);
162                 return iter;
163         }
164         //! Else, insert it at the first of the set
165         return std::set<TimePoint>::insert(x).first;
166 }
167
168
169 Node::Node():
170         guid_(0),
171         bchanged(true),
172         time_last_changed_(__sys_clock()),
173         deleting_(false)
174 {
175 #ifndef BE_FRUGAL_WITH_GUIDS
176         guid_.make_unique();
177         assert(guid_);
178         assert(!global_node_map().count(guid_));
179         global_node_map()[guid_]=this;
180 #endif
181 }
182
183 Node::~Node()
184 {
185         begin_delete();
186
187         if(guid_)
188         {
189                 assert(global_node_map().count(guid_));
190                 global_node_map().erase(guid_);
191                 assert(!global_node_map().count(guid_));
192         }
193 }
194
195 void
196 Node::changed()
197 {
198         time_last_changed_=__sys_clock();
199         on_changed();
200 }
201
202
203 //! Gets the GUID for this value node
204 const synfig::GUID&
205 Node::get_guid()const
206 {
207 #ifdef BE_FRUGAL_WITH_GUIDS
208         if(!guid_)
209         {
210                 const_cast<synfig::GUID&>(guid_).make_unique();
211                 assert(guid_);
212                 assert(!global_node_map().count(guid_));
213                 global_node_map()[guid_]=const_cast<Node*>(this);
214         }
215 #endif
216
217         return guid_;
218 }
219
220 //! Sets the GUID for this value node
221 void
222 Node::set_guid(const synfig::GUID& x)
223 {
224         assert(x);
225
226 #ifdef BE_FRUGAL_WITH_GUIDS
227         if(!guid_)
228         {
229                 guid_=x;
230                 assert(!global_node_map().count(guid_));
231                 global_node_map()[guid_]=this;
232         }
233         else
234 #endif
235         if(guid_!=x)
236         {
237                 synfig::GUID oldguid(guid_);
238                 guid_=x;
239                 refresh_node(this, oldguid);
240                 on_guid_changed(oldguid);
241         }
242 }
243
244 int
245 Node::get_time_last_changed()const
246 {
247         return time_last_changed_;
248 }
249
250 void
251 Node::add_child(Node*x)
252 {
253         x->parent_set.insert(this);
254 }
255
256 void
257 Node::remove_child(Node*x)
258 {
259         if(x->parent_set.count(this)) x->parent_set.erase(this);
260 }
261
262 int
263 Node::parent_count()const
264 {
265         return parent_set.size();
266 }
267
268 const Node::time_set &
269 Node::get_times() const
270 {
271         if(bchanged)
272         {
273                 times.clear();
274                 get_times_vfunc(times);
275                 bchanged = false;
276         }
277
278         //set the output set...
279         return times;
280 }
281
282 void
283 Node::begin_delete()
284 {
285         if(!deleting_)
286         {
287                 deleting_=true; signal_deleted()();
288         }
289 }
290
291 void
292 Node::on_changed()
293 {
294         bchanged = true;
295         signal_changed()();
296
297         std::set<Node*>::iterator iter;
298         for(iter=parent_set.begin();iter!=parent_set.end();++iter)
299         {
300                 (*iter)->changed();
301         }
302 }
303
304 void
305 Node::on_guid_changed(synfig::GUID guid)
306 {
307         signal_guid_changed()(guid);
308 }