Rename get_param_vocab to get_children_vocab and use a wrapper for the pure virtual...
[synfig.git] / synfig-core / src / synfig / valuenode_dynamiclist.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file valuenode_dynamiclist.cpp
3 **      \brief Implementation of the "Dynamic List" valuenode conversion.
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 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 "valuenode_dynamiclist.h"
34 #include "valuenode_const.h"
35 #include "valuenode_composite.h"
36 #include "general.h"
37 #include "exception.h"
38 #include <vector>
39 #include <list>
40 #include <algorithm>
41 #include "canvas.h"
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 /* === G L O B A L S ======================================================= */
54
55 /* === P R O C E D U R E S ================================================= */
56
57 /* === M E T H O D S ======================================================= */
58
59 ValueNode_DynamicList::ListEntry::ListEntry():
60         index(0)
61 {
62 }
63
64 ValueNode_DynamicList::ListEntry::ListEntry(const ValueNode::Handle &value_node):
65         value_node(value_node),
66         index(0)
67 {
68 }
69
70 ValueNode_DynamicList::ListEntry::ListEntry(const ValueNode::Handle &value_node,Time begin, Time end):
71         value_node(value_node)
72 {
73         add(begin,false);
74         add(end,false);
75         add((begin+end)*0.5,true);
76 }
77
78 ValueNode_DynamicList::ListEntry::ActivepointList::iterator
79 ValueNode_DynamicList::ListEntry::add(Time time, bool status, int priority)
80 {
81         typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList::iterator iterator;
82
83         //! \optimize
84         Activepoint ap(time,status,priority);
85         ap.set_parent_index(get_index());
86         ap.set_parent_value_node(get_parent_value_node());
87         timing_info.push_back(ap);
88         iterator iter(--iterator(timing_info.end()));
89         timing_info.sort();
90
91         return iter;
92 }
93
94 ValueNode_DynamicList::ListEntry::ActivepointList::iterator
95 ValueNode_DynamicList::ListEntry::add(const Activepoint &x)
96 {
97         typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList::iterator iterator;
98
99         //! \optimize
100         Activepoint ap(x);
101         ap.set_parent_index(get_index());
102         ap.set_parent_value_node(get_parent_value_node());
103         timing_info.push_back(ap);
104         iterator iter(--iterator(timing_info.end()));
105         timing_info.sort();
106
107         return iter;
108 }
109
110 void
111 ValueNode_DynamicList::reindex()
112 {
113         int i(0);
114
115         std::vector<ListEntry>::iterator iter;
116
117         for(iter=list.begin();iter!=list.end();++iter)
118         {
119                 assert(iter->value_node);
120                 if(iter->index!=i || iter->get_parent_value_node().get()!=this)
121                 {
122                         ActivepointList::iterator iter2;
123
124                         if(iter->timing_info.size()) // is this line really necessary?
125                         for(iter2=iter->timing_info.begin();iter2!=iter->timing_info.end();++iter2)
126                         {
127                                 iter2->set_parent_index(i);
128                                 iter2->set_parent_value_node(this);
129                         }
130                         iter->index=i;
131                         iter->set_parent_value_node(this);
132                 }
133         }
134 }
135
136 ValueNode_DynamicList::ListEntry
137 ValueNode_DynamicList::create_list_entry(int index, Time time, Real origin)
138 {
139         ValueNode_DynamicList::ListEntry ret;
140
141
142         synfig::ValueBase prev,next;
143
144         index=index%link_count();
145
146         assert(index>=0);
147
148         ret.index=index;
149         ret.set_parent_value_node(this);
150
151         next=(*list[index].value_node)(time);
152
153         if(index!=0)
154                 prev=(*list[index-1].value_node)(time);
155         else
156         {
157                 if(get_loop())
158                         prev=(*list[link_count()-1].value_node)(time);
159                 else
160                 {
161                         prev=next;
162                 }
163         }
164
165
166         switch(get_contained_type())
167         {
168         case ValueBase::TYPE_VECTOR:
169         {
170                 Vector a(prev.get(Vector())), b(next.get(Vector()));
171                 ret.value_node=ValueNode_Const::create((b-a)*origin+a);
172                 break;
173         }
174         case ValueBase::TYPE_REAL:
175         {
176                 Real a(prev.get(Real())), b(next.get(Real()));
177                 ret.value_node=ValueNode_Const::create((b-a)*origin+a);
178                 break;
179         }
180         case ValueBase::TYPE_COLOR:
181         {
182                 Color a(prev.get(Color())), b(next.get(Color()));
183                 ret.value_node=ValueNode_Composite::create((b-a)*origin+a);
184                 break;
185         }
186         case ValueBase::TYPE_ANGLE:
187         {
188                 Angle a(prev.get(Angle())), b(next.get(Angle()));
189                 ret.value_node=ValueNode_Const::create((b-a)*origin+a);
190                 break;
191         }
192         case ValueBase::TYPE_TIME:
193         {
194                 Time a(prev.get(Time())), b(next.get(Time()));
195                 ret.value_node=ValueNode_Const::create((b-a)*origin+a);
196                 break;
197         }
198         default:
199                 ret.value_node=ValueNode_Const::create(get_contained_type());
200                 break;
201         }
202
203
204         return ret;
205 }
206
207 ValueNode_DynamicList::ListEntry::ActivepointList::iterator
208 ValueNode_DynamicList::ListEntry::find(const UniqueID& x)
209 {
210         return std::find(timing_info.begin(),timing_info.end(),x);
211 }
212
213 ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
214 ValueNode_DynamicList::ListEntry::find(const UniqueID& x)const
215 {
216         return std::find(timing_info.begin(),timing_info.end(),x);
217 }
218
219 void
220 ValueNode_DynamicList::ListEntry::erase(const UniqueID& x)
221 {
222         timing_info.erase(find(x));
223 }
224
225 ValueNode_DynamicList::ListEntry::ActivepointList::iterator
226 ValueNode_DynamicList::ListEntry::find(const Time& x)
227 {
228         typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
229
230         ActivepointList::iterator iter;
231
232         for(iter=timing_info.begin();iter!=timing_info.end();++iter)
233                 if(iter->time==x)
234                         return iter;
235
236         throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find():"+x.get_string());
237 }
238
239 ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
240 ValueNode_DynamicList::ListEntry::find(const Time& x)const
241 {
242         typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
243
244         ActivepointList::const_iterator iter;
245
246         for(iter=timing_info.begin();iter!=timing_info.end();++iter)
247                 if(iter->time==x)
248                         return iter;
249
250         throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find()const:"+x.get_string());
251 }
252
253 ValueNode_DynamicList::ListEntry::ActivepointList::iterator
254 ValueNode_DynamicList::ListEntry::find_next(const Time& x)
255 {
256         typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
257
258         ActivepointList::iterator iter;
259
260         for(iter=timing_info.begin();iter!=timing_info.end();++iter)
261                 if(iter->time>x)
262                         return iter;
263
264         throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_next():"+x.get_string());
265 }
266
267 ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
268 ValueNode_DynamicList::ListEntry::find_next(const Time& x)const
269 {
270         typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
271
272         ActivepointList::const_iterator iter;
273
274         for(iter=timing_info.begin();iter!=timing_info.end();++iter)
275                 if(iter->time>x)
276                         return iter;
277
278         throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_next()const:"+x.get_string());
279 }
280
281 ValueNode_DynamicList::ListEntry::ActivepointList::iterator
282 ValueNode_DynamicList::ListEntry::find_prev(const Time& x)
283 {
284         typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
285
286         ActivepointList::iterator iter;
287         iter=timing_info.end();
288         do
289         {
290                 --iter;
291                 if(iter->time<x)
292                         return iter;
293         }
294         while(iter!=timing_info.begin());
295
296         throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_prev():"+x.get_string());
297 }
298
299 ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
300 ValueNode_DynamicList::ListEntry::find_prev(const Time& x)const
301 {
302         typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
303
304         ActivepointList::const_iterator iter;
305         iter=timing_info.end();
306         do
307         {
308                 --iter;
309                 if(iter->time<x)
310                         return iter;
311         }
312         while(iter!=timing_info.begin());
313
314         throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_prev()const:"+x.get_string());
315 }
316
317 int
318 ValueNode_DynamicList::ListEntry::find(const Time& begin,const Time& end,std::vector<Activepoint*>& selected)
319 {
320         Time curr_time(begin);
321         int ret(0);
322
323         // try to grab first waypoint
324         try
325         {
326                 ActivepointList::iterator iter;
327                 iter=find(curr_time);
328                 selected.push_back(&*iter);
329                 ret++;
330         }
331         catch(...) { }
332
333         try
334         {
335                 ActivepointList::iterator iter;
336                 while(true)
337                 {
338                         iter=find_next(curr_time);
339                         curr_time=iter->get_time();
340                         if(curr_time>=end)
341                                 break;
342                         selected.push_back(&*iter);
343                         ret++;
344                 }
345         }
346         catch(...) { }
347
348         return ret;
349 }
350
351 float
352 ValueNode_DynamicList::ListEntry::amount_at_time(const Time &t,bool *rising)const
353 {
354         typedef synfig::ValueNode_DynamicList::ListEntry::Activepoint Activepoint;
355         typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
356
357         if(timing_info.empty())
358                 return 1.0f;
359
360         try
361         {
362                 ActivepointList::const_iterator iter;
363                 iter=find(t);
364                 return iter->state?1.0f:0.0f;
365         }
366         catch(...) { }
367
368         ActivepointList::const_iterator prev_iter;
369         ActivepointList::const_iterator next_iter;
370
371         try     { prev_iter=find_prev(t); }
372         catch(...) { return find_next(t)->state?1.0f:0.0f; }
373
374         try     { next_iter=find_next(t); }
375         catch(...) { return prev_iter->state?1.0f:0.0f; }
376
377         if(next_iter->state==prev_iter->state)
378                 return next_iter->state?1.0f:0.0f;
379
380         if(rising)*rising=next_iter->state;
381
382         if(next_iter->state==true)
383                 return float((t-prev_iter->time)/(next_iter->time-prev_iter->time));
384
385         return float((next_iter->time-t)/(next_iter->time-prev_iter->time));
386 }
387
388 Activepoint
389 ValueNode_DynamicList::ListEntry::new_activepoint_at_time(const Time& time)const
390 {
391         Activepoint activepoint;
392
393         activepoint.set_state(status_at_time(time));
394         activepoint.set_priority(0);
395
396         return activepoint;
397 }
398
399 bool
400 ValueNode_DynamicList::ListEntry::status_at_time(const Time &t)const
401 {
402         typedef synfig::ValueNode_DynamicList::ListEntry::Activepoint Activepoint;
403         typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
404
405         ActivepointList::const_iterator entry_iter;
406         ActivepointList::const_iterator prev_iter;
407         bool state(true);
408
409         // New "symmetric" state mechanism
410         if(!timing_info.empty())
411         {
412                 if(timing_info.size()==1)
413                         state=timing_info.front().state;
414                 else
415                 {
416                         //! \optimize Perhaps we should use a binary search...?
417                         // This will give us the first activepoint that is after t.
418                         for(entry_iter=timing_info.begin();entry_iter!=timing_info.end();++entry_iter)
419                         {
420                                 if(entry_iter->time==t)
421                                 {
422                                         // If we hit the entry right on the nose, then we don't
423                                         // have to do anything more
424                                         return entry_iter->state;
425                                 }
426                                 if(entry_iter->time>t)
427                                         break;
428
429                         }
430                         prev_iter=entry_iter;
431                         prev_iter--;
432
433                         // ie:
434                         //
435                         //              |-------|---t---|-------|
436                         //         prev_iter^           ^entry_iter
437
438                         if(entry_iter==timing_info.end())
439                         {
440                                 state=prev_iter->state;
441                         }
442                         else
443                         if(entry_iter==timing_info.begin())
444                         {
445                                 state=entry_iter->state;
446                         }
447                         else
448                         if(entry_iter->priority==prev_iter->priority)
449                         {
450                                 state=entry_iter->state || prev_iter->state;
451                         }
452                         else
453                         if(entry_iter->priority>prev_iter->priority)
454                         {
455                                 state=entry_iter->state;
456                         }
457                         else
458                         {
459                                 state=prev_iter->state;
460                         }
461                 }
462         }
463         return state;
464 }
465
466
467
468
469 void
470 ValueNode_DynamicList::add(const ValueNode::Handle &value_node, int index)
471 {
472         ListEntry list_entry(value_node);
473         list_entry.timing_info.size();
474
475         if(index<0 || index>=(int)list.size())
476         {
477                 list.push_back(list_entry);
478         }
479         else
480         {
481                 list.insert(list.begin()+index,list_entry);
482         }
483
484         add_child(value_node.get());
485         reindex();
486         //changed();
487
488         if(get_parent_canvas())
489                 get_parent_canvas()->signal_value_node_child_added()(this,value_node);
490         else if(get_root_canvas() && get_parent_canvas())
491                 get_root_canvas()->signal_value_node_child_added()(this,value_node);
492 }
493
494 void
495 ValueNode_DynamicList::add(const ListEntry &list_entry, int index)
496 {
497         if(index<0 || index>=(int)list.size())
498                 list.push_back(list_entry);
499         else
500                 list.insert(list.begin()+index,list_entry);
501         add_child(list_entry.value_node.get());
502
503         reindex();
504         //changed();
505
506         if(get_parent_canvas())
507                 get_parent_canvas()->signal_value_node_child_added()(this,list_entry.value_node);
508         else if(get_root_canvas() && get_parent_canvas())
509                 get_root_canvas()->signal_value_node_child_added()(this,list_entry.value_node);
510 }
511
512 void
513 ValueNode_DynamicList::erase(const ValueNode::Handle &value_node_)
514 {
515         ValueNode::Handle value_node(value_node_);
516
517         assert(value_node);
518         if(!value_node)
519                 throw String("ValueNode_DynamicList::erase(): Passed bad value node");
520
521         std::vector<ListEntry>::iterator iter;
522         for(iter=list.begin();iter!=list.end();++iter)
523                 if(iter->value_node==value_node)
524                 {
525                         list.erase(iter);
526                         if(value_node)
527                         {
528                                 remove_child(value_node.get());
529                                 // changed to fix bug 1420091 - it seems that when a .sif file containing a bline layer encapsulated inside
530                                 // another layer, get_parent_canvas() is false and get_root_canvas() is true, but when we come to erase a
531                                 // vertex, both are true.  So the signal is sent to the parent, but the signal wasn't sent to the parent
532                                 // when it was added.  This probably isn't the right fix, but it seems to work for now.  Note that the same
533                                 // strange "if (X) else if (Y && X)" code is also present in the two previous functions, above.
534
535                                 // if(get_parent_canvas())
536                                 //      get_parent_canvas()->signal_value_node_child_removed()(this,value_node);
537                                 // else if(get_root_canvas() && get_parent_canvas())
538                                 //      get_root_canvas()->signal_value_node_child_removed()(this,value_node);
539                                 if(get_root_canvas())
540                                         get_root_canvas()->signal_value_node_child_removed()(this,value_node);
541                         }
542                         break;
543                 }
544         reindex();
545 }
546
547
548 ValueNode_DynamicList::ValueNode_DynamicList(ValueBase::Type container_type):
549         LinkableValueNode(ValueBase::TYPE_LIST),
550         container_type  (container_type),
551         loop_(false)
552 {
553 }
554
555 ValueNode_DynamicList::Handle
556 ValueNode_DynamicList::create(ValueBase::Type id)
557 {
558         return new ValueNode_DynamicList(id);
559 }
560
561 ValueNode_DynamicList::~ValueNode_DynamicList()
562 {
563         unlink_all();
564 }
565
566 ValueNode_DynamicList*
567 ValueNode_DynamicList::create_from(const ValueBase &value)
568 {
569         //vector<ValueBase> value_list(value.operator vector<ValueBase>());
570         vector<ValueBase> value_list(value.get_list());
571
572         vector<ValueBase>::iterator iter;
573
574         if(value_list.empty())
575                 return 0;
576
577         ValueNode_DynamicList* value_node(new ValueNode_DynamicList(value_list.front().get_type()));
578
579         // when creating a list of vectors, start it off being looped.
580         // I think the only time this is used if for creating polygons,
581         // and we want them to be looped by default
582         if (value_node->get_contained_type() == ValueBase::TYPE_VECTOR)
583                 value_node->set_loop(true);
584
585         for(iter=value_list.begin();iter!=value_list.end();++iter)
586         {
587                 ValueNode::Handle item(ValueNode_Const::create(*iter));
588                 value_node->add(ListEntry(item));
589                 assert(value_node->list.back().value_node);
590         }
591         return value_node;
592 }
593
594 ValueBase
595 ValueNode_DynamicList::operator()(Time t)const
596 {
597         if (getenv("SYNFIG_DEBUG_VALUENODE_OPERATORS"))
598                 printf("%s:%d operator()\n", __FILE__, __LINE__);
599
600         std::vector<ValueBase> ret_list;
601         std::vector<ListEntry>::const_iterator iter;
602
603         assert(container_type);
604
605         for(iter=list.begin();iter!=list.end();++iter)
606         {
607                 bool state(iter->status_at_time(t));
608
609                 if(state)
610                 {
611                         if(iter->value_node->get_type()==container_type)
612                                 ret_list.push_back((*iter->value_node)(t));
613                         else
614                         {
615                                 synfig::warning(string("ValueNode_DynamicList::operator()():")+_("List type/item type mismatch, throwing away mismatch"));
616                         }
617                 }
618         }
619
620         if(list.empty())
621                 synfig::warning(string("ValueNode_DynamicList::operator()():")+_("No entries in list"));
622         else
623         if(ret_list.empty())
624                 synfig::warning(string("ValueNode_DynamicList::operator()():")+_("No entries in ret_list"));
625
626         return ret_list;
627 }
628
629 bool
630 ValueNode_DynamicList::set_link_vfunc(int i,ValueNode::Handle x)
631 {
632         assert(i>=0);
633
634         if((unsigned)i>=list.size())
635                 return false;
636         if(x->get_type()!=container_type)
637                 return false;
638         list[i].value_node=x;
639         return true;
640 }
641
642 ValueNode::LooseHandle
643 ValueNode_DynamicList::get_link_vfunc(int i)const
644 {
645         assert(i>=0);
646
647         if((unsigned)i>=list.size())
648                 return 0;
649         return list[i].value_node;
650 }
651
652 int
653 ValueNode_DynamicList::link_count()const
654 {
655         return list.size();
656 }
657
658 String
659 ValueNode_DynamicList::link_local_name(int i)const
660 {
661         assert(i>=0 && i<link_count());
662
663         return etl::strprintf(_("Item %03d"),i+1);
664 }
665
666 ValueNode*
667 ValueNode_DynamicList::clone(const GUID& deriv_guid)const
668 {
669         { ValueNode* x(find_value_node(get_guid()^deriv_guid).get()); if(x)return x; }
670
671         ValueNode_DynamicList* ret=dynamic_cast<ValueNode_DynamicList*>(create_new());
672         ret->set_guid(get_guid()^deriv_guid);
673
674         std::vector<ListEntry>::const_iterator iter;
675
676         for(iter=list.begin();iter!=list.end();++iter)
677         {
678                 if(iter->value_node->is_exported())
679                         ret->add(*iter);
680                 else
681                 {
682                         ListEntry list_entry(*iter);
683                         //list_entry.value_node=find_value_node(iter->value_node->get_guid()^deriv_guid).get();
684                         //if(!list_entry.value_node)
685                         list_entry.value_node=iter->value_node->clone(deriv_guid);
686                         ret->add(list_entry);
687                         //ret->list.back().value_node=iter->value_node.clone();
688                 }
689         }
690         ret->set_loop(get_loop());
691         return ret;
692 }
693
694 String
695 ValueNode_DynamicList::link_name(int i)const
696 {
697         return strprintf("item%04d",i);
698 }
699
700 int
701 ValueNode_DynamicList::get_link_index_from_name(const String &name)const
702 {
703         throw Exception::BadLinkName(name);
704 }
705
706 String
707 ValueNode_DynamicList::get_name()const
708 {
709         return "dynamic_list";
710 }
711
712 String
713 ValueNode_DynamicList::get_local_name()const
714 {
715         return _("Dynamic List");
716 }
717
718 bool
719 ValueNode_DynamicList::check_type(ValueBase::Type type)
720 {
721         return type==ValueBase::TYPE_LIST;
722 }
723
724 void
725 ValueNode_DynamicList::set_member_canvas(etl::loose_handle<Canvas> canvas)
726 {
727         for (vector<ListEntry>::iterator iter = list.begin(); iter != list.end(); iter++)
728                 iter->value_node->set_parent_canvas(canvas);
729 }
730
731 ValueBase::Type
732 ValueNode_DynamicList::get_contained_type()const
733 {
734         return container_type;
735 }
736
737 LinkableValueNode*
738 ValueNode_DynamicList::create_new()const
739 {
740         return new ValueNode_DynamicList(container_type);
741 }
742
743 int
744 ValueNode_DynamicList::find_next_valid_entry(int orig_item, Time t)const
745 {
746         int curr_item;
747
748         for(curr_item=orig_item+1;curr_item!=orig_item;curr_item++)
749         {
750                 if(curr_item==(int)list.size())
751                 {
752                         curr_item=0;
753                         continue;
754                 }
755                 if(list[curr_item].status_at_time(t))
756                         return curr_item;
757         }
758         return curr_item;
759 }
760
761 int
762 ValueNode_DynamicList::find_prev_valid_entry(int orig_item, Time t)const
763 {
764         int curr_item;
765
766         for(curr_item=orig_item-1;curr_item!=orig_item;curr_item--)
767         {
768                 if(curr_item==-1)
769                 {
770                         curr_item=list.size();
771                         continue;
772                 }
773                 if(list[curr_item].status_at_time(t))
774                         return curr_item;
775         }
776         return curr_item;
777 }
778
779 const synfig::Node::time_set    & ValueNode_DynamicList::ListEntry::get_times() const
780 {
781         synfig::ActivepointList::const_iterator         j = timing_info.begin(),
782                                                                                         end = timing_info.end();
783
784         //must remerge with all the other values because we don't know if we've changed...
785         times = value_node->get_times();
786
787         for(; j != end; ++j)
788         {
789                 TimePoint t;
790                 t.set_time(j->get_time());
791                 t.set_guid(j->get_guid());
792
793                 times.insert(t);
794         }
795
796         return times;
797 }
798
799 void ValueNode_DynamicList::get_times_vfunc(Node::time_set &set) const
800 {
801         //add in the active points
802         int size = list.size();
803
804         //rebuild all the info...
805         for(int i = 0; i < size; ++i)
806         {
807                 const Node::time_set & tset= list[i].get_times();
808                 set.insert(tset.begin(),tset.end());
809         }
810 }
811
812
813 //new find functions that don't throw
814 struct timecmp
815 {
816         Time t;
817
818         timecmp(const Time &c) :t(c) {}
819
820         bool operator()(const Activepoint &rhs) const
821         {
822                 return t.is_equal(rhs.get_time());
823         }
824 };
825
826 ValueNode_DynamicList::ListEntry::findresult ValueNode_DynamicList::ListEntry::find_uid(const UniqueID& x)
827 {
828         findresult f;
829         f.second = false;
830
831         f.first = std::find(timing_info.begin(),timing_info.end(),x);
832
833         if(f.first != timing_info.end())
834         {
835                 f.second = true;
836         }
837
838         return f;
839 }
840
841 ValueNode_DynamicList::ListEntry::const_findresult ValueNode_DynamicList::ListEntry::find_uid(const UniqueID& x) const
842 {
843         const_findresult f;
844         f.second = false;
845
846         f.first = std::find(timing_info.begin(),timing_info.end(),x);
847
848         if(f.first != timing_info.end())
849         {
850                 f.second = true;
851         }
852
853         return f;
854 }
855
856 ValueNode_DynamicList::ListEntry::findresult ValueNode_DynamicList::ListEntry::find_time(const Time& x)
857 {
858         findresult f;
859         f.second = false;
860
861         f.first = std::find_if(timing_info.begin(),timing_info.end(),timecmp(x));
862
863         if(f.first != timing_info.end())
864         {
865                 f.second = true;
866         }
867
868         return f;
869 }
870
871 ValueNode_DynamicList::ListEntry::const_findresult ValueNode_DynamicList::ListEntry::find_time(const Time& x)const
872 {
873         const_findresult f;
874         f.second = false;
875
876         f.first = std::find_if(timing_info.begin(),timing_info.end(),timecmp(x));
877
878         if(f.first != timing_info.end())
879         {
880                 f.second = true;
881         }
882
883         return f;
884 }
885
886 void
887 ValueNode_DynamicList::insert_time(const Time& location, const Time& delta)
888 {
889         if(!delta)
890                 return;
891
892         std::vector<ListEntry>::iterator iter(list.begin());
893         for(;iter!=list.end();++iter)
894         {
895                 try
896                 {
897                         ListEntry& item(*iter);
898
899                         ActivepointList::iterator iter(item.find_next(location));
900                         for(;iter!=item.timing_info.end();++iter)
901                         {
902                                 iter->set_time(iter->get_time()+delta);
903                         }
904                 }
905                 catch(Exception::NotFound) { }
906         }
907         changed();
908 }
909
910 LinkableValueNode::Vocab
911 ValueNode_DynamicList::get_children_vocab_vfunc()const
912 {
913         LinkableValueNode::Vocab ret;
914         for(unsigned int i=0; i<list.size();i++)
915         {
916                 ret.push_back(ParamDesc(ValueBase(),strprintf("item%04d",i))
917                         .set_local_name(etl::strprintf(_("Item %03d"),i+1))
918                 );
919         }
920
921         return ret;
922 }