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