moreupdates
[synfig.git] / synfig-core / trunk / src / synfig / valuenode.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file value_node.cpp
3 **      \brief Template File
4 **
5 **      $Id: valuenode.cpp,v 1.1.1.1 2005/01/04 01:23:15 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 SYNFIG_NO_ANGLE
25
26 //#define HAS_HASH_MAP 1
27
28 #ifdef USING_PCH
29 #       include "pch.h"
30 #else
31 #ifdef HAVE_CONFIG_H
32 #       include <config.h>
33 #endif
34
35 #include "valuenode.h"
36 #include "general.h"
37 #include "canvas.h"
38
39 #include "valuenode_const.h"
40 #include "valuenode_linear.h"
41 #include "valuenode_composite.h"
42 #include "valuenode_reference.h"
43 #include "valuenode_scale.h"
44 #include "valuenode_segcalctangent.h"
45 #include "valuenode_segcalcvertex.h"
46 #include "valuenode_stripes.h"
47 #include "valuenode_subtract.h"
48 #include "valuenode_timedswap.h"
49 #include "valuenode_twotone.h"
50 #include "valuenode_bline.h"
51 #include "valuenode_dynamiclist.h"
52 #include "valuenode_radialcomposite.h"
53 #include "valuenode_gradientrotate.h"
54 #include "valuenode_sine.h"
55
56 #include "layer.h"
57
58 #endif
59
60 /* === U S I N G =========================================================== */
61
62 using namespace std;
63 using namespace etl;
64 using namespace synfig;
65
66 /* === M A C R O S ========================================================= */
67
68 /* === G L O B A L S ======================================================= */
69
70 static int value_node_count(0);
71
72 static LinkableValueNode::Book *book_;
73
74
75 ValueNode::LooseHandle
76 synfig::find_value_node(const GUID& guid)
77 {
78         return guid_cast<ValueNode>(guid);
79 }
80
81 /* === P R O C E D U R E S ================================================= */
82
83 /* === M E T H O D S ======================================================= */
84
85 bool
86 ValueNode::subsys_init()
87 {
88         book_=new LinkableValueNode::Book();
89
90 #define ADD_VALUENODE(c,n) (*book_)[n].factory=reinterpret_cast<LinkableValueNode::Factory>(&c::create); (*book_)[n].check_type=&c::check_type;(*book_)[n].local_name=n
91 #define ADD_VALUENODE2(c,n) (*book_)[n].factory=reinterpret_cast<LinkableValueNode::Factory>(&c::create_from); (*book_)[n].check_type=&c::check_type;(*book_)[n].local_name=n
92
93         ADD_VALUENODE(ValueNode_Linear,"linear");
94         ADD_VALUENODE(ValueNode_Composite,"composite");
95         ADD_VALUENODE(ValueNode_RadialComposite,"radial_composite");
96         ADD_VALUENODE(ValueNode_Reference,"reference");
97         ADD_VALUENODE(ValueNode_Scale,"scale");
98         ADD_VALUENODE(ValueNode_SegCalcTangent,"segcalctangent");
99         ADD_VALUENODE(ValueNode_SegCalcVertex,"segcalcvertex");
100         ADD_VALUENODE(ValueNode_Stripes,"stripes");
101         ADD_VALUENODE(ValueNode_Subtract,"subtract");
102         //ADD_VALUENODE(ValueNode_TimedSwap,"timed_swap");
103         ADD_VALUENODE(ValueNode_TwoTone,"twotone");
104         ADD_VALUENODE(ValueNode_BLine,"bline");
105         ADD_VALUENODE2(ValueNode_DynamicList,"dynamic_list");
106         ADD_VALUENODE(ValueNode_GradientRotate,"gradient_rotate");
107         ADD_VALUENODE(ValueNode_Sine,"sine");
108         
109 #undef ADD_VALUENODE
110         return true;
111 }
112
113 bool
114 ValueNode::subsys_stop()
115 {
116         delete book_;
117 /*      if(global_value_node_map.size() || value_node_count)
118         {
119                 if(value_node_count)
120                         synfig::error("%d ValueNodes haven't been destroyed yet!",value_node_count);
121
122                 if(global_value_node_map.size()!=value_node_count)
123                         synfig::error("value node count mismatch! map.size()!=value_node_count (%d!=%d)",global_value_node_map.size(),value_node_count);
124                 
125                 GlobalValueNodeMap::iterator iter;              
126                 for(iter=global_value_node_map.begin();iter!=global_value_node_map.end();++iter)
127                 {
128                         if(!iter->second->is_exported())
129                                 synfig::info("%s: count:%d name:%s type:%s",
130                                         iter->first.get_string().c_str(),
131                                         iter->second->count(),
132                                         iter->second->get_name().c_str(),
133                                         ValueBase::type_name(iter->second->get_type()).c_str()
134                                 );
135                         else
136                                 synfig::info("%s: id:%s count:%d name:%s type:%s",
137                                         iter->first.get_string().c_str(),
138                                         iter->second->get_id().c_str(),
139                                         iter->second->count(),
140                                         iter->second->get_name().c_str(),
141                                         ValueBase::type_name(iter->second->get_type()).c_str()
142                                 );
143                 }
144         }
145 */
146         return true;
147 }
148
149 ValueNode::ValueNode(ValueBase::Type type):type(type)
150 {
151         value_node_count++;
152 }
153
154 LinkableValueNode::Book&
155 LinkableValueNode::book()
156 {
157         return *book_;
158 }
159
160 LinkableValueNode::Handle
161 LinkableValueNode::create(const String &name, const ValueBase& x)
162 {
163         if(!book().count(name))
164                 return 0;
165         return book()[name].factory(x);
166 }
167
168 bool
169 LinkableValueNode::check_type(const String &name, ValueBase::Type x)
170 {
171         if(!book().count(name) || !book()[name].check_type)
172                 return false;
173         return book()[name].check_type(x);
174 }
175
176 bool
177 LinkableValueNode::set_link(int i,ValueNode::Handle x)
178 {
179         ValueNode::Handle previous(get_link(i));
180         
181         if(set_link_vfunc(i,x))
182         {
183                 if(previous)
184                         remove_child(previous.get());
185                 add_child(x.get());
186                 
187                 if(!x->is_exported() && get_parent_canvas())
188                 {
189                         x->set_parent_canvas(get_parent_canvas());
190                 }
191                 changed();
192                 return true;
193         }
194         return false;
195 }
196
197 ValueNode::LooseHandle
198 LinkableValueNode::get_link(int i)const
199 {
200         return get_link_vfunc(i);
201 }
202
203 void
204 LinkableValueNode::unlink_all()
205 {
206         for(int i=0;i<link_count();i++)
207         {
208                 ValueNode::LooseHandle value_node(get_link(i));
209                 if(value_node)
210                         value_node->parent_set.erase(this);
211         }
212 }
213
214 ValueNode::~ValueNode()
215 {
216         value_node_count--;
217         
218         begin_delete();
219
220         //DEBUGPOINT();
221 }
222
223 void
224 ValueNode::on_changed()
225 {
226         if(get_parent_canvas())
227                 get_parent_canvas()->signal_value_node_changed()(this);
228         else if(get_root_canvas() && get_parent_canvas())
229                 get_root_canvas()->signal_value_node_changed()(this);
230         
231         Node::on_changed();
232 }
233
234 int
235 ValueNode::replace(etl::handle<ValueNode> x)
236 {
237         if(x.get()==this)
238                 return 0;
239         
240         while(parent_set.size())
241         {
242                 (*parent_set.begin())->add_child(x.get());
243                 (*parent_set.begin())->remove_child(this);
244                 //x->parent_set.insert(*parent_set.begin());
245                 //parent_set.erase(parent_set.begin());
246         }
247         int r(RHandle(this).replace(x));
248         x->changed();
249         return r;
250 }
251
252 void
253 ValueNode::set_id(const String &x)
254 {
255         if(name!=x)
256         {
257                 name=x;
258                 signal_id_changed_();
259         }
260 }
261
262 ValueNodeList::ValueNodeList():
263         placeholder_count_(0)
264 {
265 }
266
267 bool
268 ValueNodeList::count(const String &id)const
269 {
270         const_iterator iter;
271
272         if(id.empty())
273                 return false;
274
275         for(iter=begin();iter!=end() && id!=(*iter)->get_id();++iter);
276
277         if(iter==end())
278                 return false;
279
280         return true;
281 }
282
283 ValueNode::Handle
284 ValueNodeList::find(const String &id)
285 {
286         iterator iter;
287
288         if(id.empty())
289                 throw Exception::IDNotFound("Empty ID");
290
291         for(iter=begin();iter!=end() && id!=(*iter)->get_id();++iter);
292
293         if(iter==end())
294                 throw Exception::IDNotFound("ValueNode in ValueNodeList: "+id);
295
296         return *iter;
297 }
298
299 ValueNode::ConstHandle
300 ValueNodeList::find(const String &id)const
301 {
302         const_iterator iter;
303
304         if(id.empty())
305                 throw Exception::IDNotFound("Empty ID");
306
307         for(iter=begin();iter!=end() && id!=(*iter)->get_id();++iter);
308
309         if(iter==end())
310                 throw Exception::IDNotFound("ValueNode in ValueNodeList: "+id);
311
312         return *iter;
313 }
314
315 ValueNode::Handle
316 ValueNodeList::surefind(const String &id)
317 {
318         if(id.empty())
319                 throw Exception::IDNotFound("Empty ID");
320         
321         ValueNode::Handle value_node;
322         
323         try
324         {
325                 value_node=find(id);
326         }
327         catch(Exception::IDNotFound)
328         {
329                 value_node=PlaceholderValueNode::create();
330                 value_node->set_id(id);
331                 push_back(value_node);
332                 placeholder_count_++;
333         }
334
335         return value_node;
336 }
337
338 bool
339 ValueNodeList::erase(ValueNode::Handle value_node)
340 {
341         assert(value_node);
342
343         iterator iter;
344
345         for(iter=begin();iter!=end();++iter)
346                 if(value_node.get()==iter->get())
347                 {
348                         std::list<ValueNode::RHandle>::erase(iter);
349                         if(PlaceholderValueNode::Handle::cast_dynamic(value_node))
350                                 placeholder_count_--;
351                         return true;
352                 }
353         return false;
354 }
355
356 bool
357 ValueNodeList::add(ValueNode::Handle value_node)
358 {
359         if(!value_node)
360                 return false;
361         if(value_node->get_id().empty())
362                 return false;
363
364         try
365         {
366                 ValueNode::RHandle other_value_node=find(value_node->get_id());
367                 if(PlaceholderValueNode::Handle::cast_dynamic(other_value_node))
368                 {
369                         other_value_node->replace(value_node);
370                         placeholder_count_--;
371                         return true;
372                 }
373
374                 return false;
375         }
376         catch(Exception::IDNotFound)
377         {       
378                 push_back(value_node);
379                 return true;
380         }
381         
382         return false;
383 }
384
385 void
386 ValueNodeList::audit()
387 {
388         iterator iter,next;
389
390         for(next=begin(),iter=next++;iter!=end();iter=next++)
391                 if(iter->count()==1)
392                         std::list<ValueNode::RHandle>::erase(iter);
393 }
394
395
396 String
397 PlaceholderValueNode::get_name()const
398 {
399         return "placeholder";
400 }
401
402 String
403 PlaceholderValueNode::get_local_name()const
404 {
405         return _("Placeholder");
406 }
407
408 ValueNode*
409 PlaceholderValueNode::clone(const GUID& deriv_guid)const
410 {
411         ValueNode* ret(new PlaceholderValueNode());
412         ret->set_guid(get_guid()^deriv_guid);
413         return ret;
414 }
415
416 PlaceholderValueNode::Handle
417 PlaceholderValueNode::create(ValueBase::Type type)
418 {
419         return new PlaceholderValueNode(type);
420 }
421
422 ValueBase
423 PlaceholderValueNode::operator()(Time t)const
424 {
425         assert(0);
426         return ValueBase();
427 }
428
429 PlaceholderValueNode::PlaceholderValueNode(ValueBase::Type type):
430         ValueNode(type)
431 {
432 }
433
434 ValueNode*
435 LinkableValueNode::clone(const GUID& deriv_guid)const
436 {
437         { ValueNode* x(find_value_node(get_guid()^deriv_guid).get()); if(x)return x; }
438
439         int i;
440         LinkableValueNode *ret=create_new();
441         ret->set_guid(get_guid()^deriv_guid);
442         
443         for(i=0;i<link_count();i++)
444         {
445                 ValueNode::Handle link=get_link_vfunc(i);
446                 if(!link->is_exported())
447                 {
448                         ValueNode::LooseHandle value_node(find_value_node(link->get_guid()^deriv_guid));
449                         if(!value_node)
450                                 value_node=link->clone(deriv_guid);
451                         ret->set_link(i,value_node);
452                 }
453                 else
454                         ret->set_link(i,link);
455         }
456
457         return ret;
458 }
459
460 String
461 ValueNode::get_relative_id(etl::loose_handle<const Canvas> x)const
462 {
463         assert(is_exported());
464         assert(canvas_);
465         
466         if(x.get()==canvas_.get())
467                 return get_id();
468         
469         return canvas_->_get_relative_id(x)+':'+get_id();
470 }
471
472 void
473 ValueNode::set_parent_canvas(etl::loose_handle<Canvas> x)
474 {
475         canvas_=x; if(x) root_canvas_=x->get_root();
476 }
477
478 void
479 ValueNode::set_root_canvas(etl::loose_handle<Canvas> x)
480 {
481         root_canvas_=x->get_root();
482 }
483
484 void LinkableValueNode::get_times_vfunc(Node::time_set &set) const
485 {
486         ValueNode::LooseHandle  h;
487         
488         int size = link_count();
489                 
490         //just add it to the set...
491         for(int i=0; i < size; ++i)
492         {
493                 h = get_link(i);
494
495                 if(h)
496                 {
497                         const Node::time_set &tset = h->get_times();
498                         set.insert(tset.begin(),tset.end());
499                 }
500         }
501 }