1 /* === S Y N F I G ========================================================= */
2 /*! \file valuenode_dynamiclist.cpp
3 ** \brief Template File
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
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.
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.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
32 #include "valuenode_dynamiclist.h"
33 #include "valuenode_const.h"
34 #include "valuenode_composite.h"
36 #include "exception.h"
44 /* === U S I N G =========================================================== */
48 using namespace synfig;
50 /* === M A C R O S ========================================================= */
52 /* === G L O B A L S ======================================================= */
54 /* === P R O C E D U R E S ================================================= */
56 /* === M E T H O D S ======================================================= */
58 ValueNode_DynamicList::ListEntry::ListEntry():
63 ValueNode_DynamicList::ListEntry::ListEntry(const ValueNode::Handle &value_node):
64 value_node(value_node),
69 ValueNode_DynamicList::ListEntry::ListEntry(const ValueNode::Handle &value_node,Time begin, Time end):
70 value_node(value_node)
74 add((begin+end)*0.5,true);
77 ValueNode_DynamicList::ListEntry::ActivepointList::iterator
78 ValueNode_DynamicList::ListEntry::add(Time time, bool status, int priority)
80 typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList::iterator iterator;
83 Activepoint ap(time,status,priority);
84 ap.set_parent_index(get_index());
85 ap.set_parent_value_node(get_parent_value_node());
86 timing_info.push_back(ap);
87 iterator iter(--iterator(timing_info.end()));
93 ValueNode_DynamicList::ListEntry::ActivepointList::iterator
94 ValueNode_DynamicList::ListEntry::add(const Activepoint &x)
96 typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList::iterator iterator;
100 ap.set_parent_index(get_index());
101 ap.set_parent_value_node(get_parent_value_node());
102 timing_info.push_back(ap);
103 iterator iter(--iterator(timing_info.end()));
110 ValueNode_DynamicList::reindex()
114 std::vector<ListEntry>::iterator iter;
116 for(iter=list.begin();iter!=list.end();++iter)
118 assert(iter->value_node);
119 if(iter->index!=i || iter->get_parent_value_node().get()!=this)
121 ActivepointList::iterator iter2;
123 if(iter->timing_info.size()) // is this line really necessary?
124 for(iter2=iter->timing_info.begin();iter2!=iter->timing_info.end();++iter2)
126 iter2->set_parent_index(i);
127 iter2->set_parent_value_node(this);
130 iter->set_parent_value_node(this);
135 ValueNode_DynamicList::ListEntry
136 ValueNode_DynamicList::create_list_entry(int index, Time time, Real origin)
138 ValueNode_DynamicList::ListEntry ret;
141 synfig::ValueBase prev,next;
143 index=index%link_count();
148 ret.set_parent_value_node(this);
150 next=(*list[index].value_node)(time);
153 prev=(*list[index-1].value_node)(time);
157 prev=(*list[link_count()-1].value_node)(time);
165 switch(get_contained_type())
167 case ValueBase::TYPE_VECTOR:
169 Vector a(prev.get(Vector())), b(next.get(Vector()));
170 ret.value_node=ValueNode_Const::create((b-a)*origin+a);
173 case ValueBase::TYPE_REAL:
175 Real a(prev.get(Real())), b(next.get(Real()));
176 ret.value_node=ValueNode_Const::create((b-a)*origin+a);
179 case ValueBase::TYPE_COLOR:
181 Color a(prev.get(Color())), b(next.get(Color()));
182 ret.value_node=ValueNode_Composite::create((b-a)*origin+a);
185 case ValueBase::TYPE_ANGLE:
187 Angle a(prev.get(Angle())), b(next.get(Angle()));
188 ret.value_node=ValueNode_Const::create((b-a)*origin+a);
191 case ValueBase::TYPE_TIME:
193 Time a(prev.get(Time())), b(next.get(Time()));
194 ret.value_node=ValueNode_Const::create((b-a)*origin+a);
198 ret.value_node=ValueNode_Const::create(get_contained_type());
206 ValueNode_DynamicList::ListEntry::ActivepointList::iterator
207 ValueNode_DynamicList::ListEntry::find(const UniqueID& x)
209 return std::find(timing_info.begin(),timing_info.end(),x);
212 ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
213 ValueNode_DynamicList::ListEntry::find(const UniqueID& x)const
215 return std::find(timing_info.begin(),timing_info.end(),x);
219 ValueNode_DynamicList::ListEntry::erase(const UniqueID& x)
221 timing_info.erase(find(x));
224 ValueNode_DynamicList::ListEntry::ActivepointList::iterator
225 ValueNode_DynamicList::ListEntry::find(const Time& x)
227 typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
229 ActivepointList::iterator iter;
231 for(iter=timing_info.begin();iter!=timing_info.end();++iter)
235 throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find():"+x.get_string());
238 ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
239 ValueNode_DynamicList::ListEntry::find(const Time& x)const
241 typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
243 ActivepointList::const_iterator iter;
245 for(iter=timing_info.begin();iter!=timing_info.end();++iter)
249 throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find()const:"+x.get_string());
252 ValueNode_DynamicList::ListEntry::ActivepointList::iterator
253 ValueNode_DynamicList::ListEntry::find_next(const Time& x)
255 typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
257 ActivepointList::iterator iter;
259 for(iter=timing_info.begin();iter!=timing_info.end();++iter)
263 throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_next():"+x.get_string());
266 ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
267 ValueNode_DynamicList::ListEntry::find_next(const Time& x)const
269 typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
271 ActivepointList::const_iterator iter;
273 for(iter=timing_info.begin();iter!=timing_info.end();++iter)
277 throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_next()const:"+x.get_string());
280 ValueNode_DynamicList::ListEntry::ActivepointList::iterator
281 ValueNode_DynamicList::ListEntry::find_prev(const Time& x)
283 typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
285 ActivepointList::iterator iter;
286 iter=timing_info.end();
293 while(iter!=timing_info.begin());
295 throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_prev():"+x.get_string());
298 ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
299 ValueNode_DynamicList::ListEntry::find_prev(const Time& x)const
301 typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
303 ActivepointList::const_iterator iter;
304 iter=timing_info.end();
311 while(iter!=timing_info.begin());
313 throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_prev()const:"+x.get_string());
317 ValueNode_DynamicList::ListEntry::find(const Time& begin,const Time& end,std::vector<Activepoint*>& selected)
319 Time curr_time(begin);
322 // try to grab first waypoint
325 ActivepointList::iterator iter;
326 iter=find(curr_time);
327 selected.push_back(&*iter);
334 ActivepointList::iterator iter;
337 iter=find_next(curr_time);
338 curr_time=iter->get_time();
341 selected.push_back(&*iter);
351 ValueNode_DynamicList::ListEntry::amount_at_time(const Time &t,bool *rising)const
353 typedef synfig::ValueNode_DynamicList::ListEntry::Activepoint Activepoint;
354 typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
356 if(timing_info.empty())
361 ActivepointList::const_iterator iter;
363 return iter->state?1.0f:0.0f;
367 ActivepointList::const_iterator prev_iter;
368 ActivepointList::const_iterator next_iter;
370 try { prev_iter=find_prev(t); }
371 catch(...) { return find_next(t)->state?1.0f:0.0f; }
373 try { next_iter=find_next(t); }
374 catch(...) { return prev_iter->state?1.0f:0.0f; }
376 if(next_iter->state==prev_iter->state)
377 return next_iter->state?1.0f:0.0f;
379 if(rising)*rising=next_iter->state;
381 if(next_iter->state==true)
382 return float((t-prev_iter->time)/(next_iter->time-prev_iter->time));
384 return float((next_iter->time-t)/(next_iter->time-prev_iter->time));
388 ValueNode_DynamicList::ListEntry::new_activepoint_at_time(const Time& time)const
390 Activepoint activepoint;
392 activepoint.set_state(status_at_time(time));
393 activepoint.set_priority(0);
399 ValueNode_DynamicList::ListEntry::status_at_time(const Time &t)const
401 typedef synfig::ValueNode_DynamicList::ListEntry::Activepoint Activepoint;
402 typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
404 ActivepointList::const_iterator entry_iter;
405 ActivepointList::const_iterator prev_iter;
408 // New "symetric" state mechanism
409 if(!timing_info.empty())
411 if(timing_info.size()==1)
412 state=timing_info.front().state;
415 //! \optimize Perhaps we should use a binary search...?
416 // This will give us the first activepoint that is after t.
417 for(entry_iter=timing_info.begin();entry_iter!=timing_info.end();++entry_iter)
419 if(entry_iter->time==t)
421 // If we hit the entry right on the nose, then we don't
422 // have to do anything more
423 return entry_iter->state;
425 if(entry_iter->time>t)
429 prev_iter=entry_iter;
434 // |-------|---t---|-------|
435 // prev_iter^ ^entry_iter
437 if(entry_iter==timing_info.end())
439 state=prev_iter->state;
442 if(entry_iter==timing_info.begin())
444 state=entry_iter->state;
447 if(entry_iter->priority==prev_iter->priority)
449 state=entry_iter->state || prev_iter->state;
452 if(entry_iter->priority>prev_iter->priority)
454 state=entry_iter->state;
458 state=prev_iter->state;
469 ValueNode_DynamicList::add(const ValueNode::Handle &value_node, int index)
471 ListEntry list_entry(value_node);
472 list_entry.timing_info.size();
474 if(index<0 || index>=(int)list.size())
476 list.push_back(list_entry);
480 list.insert(list.begin()+index,list_entry);
483 add_child(value_node.get());
487 if(get_parent_canvas())
488 get_parent_canvas()->signal_value_node_child_added()(this,value_node);
489 else if(get_root_canvas() && get_parent_canvas())
490 get_root_canvas()->signal_value_node_child_added()(this,value_node);
494 ValueNode_DynamicList::add(const ListEntry &list_entry, int index)
496 if(index<0 || index>=(int)list.size())
497 list.push_back(list_entry);
499 list.insert(list.begin()+index,list_entry);
500 add_child(list_entry.value_node.get());
505 if(get_parent_canvas())
506 get_parent_canvas()->signal_value_node_child_added()(this,list_entry.value_node);
507 else if(get_root_canvas() && get_parent_canvas())
508 get_root_canvas()->signal_value_node_child_added()(this,list_entry.value_node);
512 ValueNode_DynamicList::erase(const ValueNode::Handle &value_node_)
514 ValueNode::Handle value_node(value_node_);
518 throw String("ValueNode_DynamicList::erase(): Passed bad value node");
520 std::vector<ListEntry>::iterator iter;
521 for(iter=list.begin();iter!=list.end();++iter)
522 if(iter->value_node==value_node)
527 remove_child(value_node.get());
528 // changed to fix bug 1420091 - it seems that when a .sif file containing a bline layer encapsulated inside
529 // another layer, get_parent_canvas() is false and get_root_canvas() is true, but when we come to erase a
530 // vertex, both are true. So the signal is sent to the parent, but the signal wasn't sent to the parent
531 // when it was added. This probably isn't the right fix, but it seems to work for now. Note that the same
532 // strange "if (X) else if (Y && X)" code is also present in the two previous functions, above.
534 // if(get_parent_canvas())
535 // get_parent_canvas()->signal_value_node_child_removed()(this,value_node);
536 // else if(get_root_canvas() && get_parent_canvas())
537 // get_root_canvas()->signal_value_node_child_removed()(this,value_node);
538 if(get_root_canvas())
539 get_root_canvas()->signal_value_node_child_removed()(this,value_node);
547 ValueNode_DynamicList::ValueNode_DynamicList(ValueBase::Type container_type):
548 LinkableValueNode(ValueBase::TYPE_LIST),
549 container_type (container_type),
555 ValueNode_DynamicList::Handle
556 ValueNode_DynamicList::create(ValueBase::Type id)
558 return new ValueNode_DynamicList(id);
561 ValueNode_DynamicList::~ValueNode_DynamicList()
566 ValueNode_DynamicList*
567 ValueNode_DynamicList::create_from(const ValueBase &value)
569 //vector<ValueBase> value_list(value.operator vector<ValueBase>());
570 vector<ValueBase> value_list(value.get_list());
572 vector<ValueBase>::iterator iter;
574 if(value_list.empty())
577 ValueNode_DynamicList* value_node(new ValueNode_DynamicList(value_list.front().get_type()));
579 for(iter=value_list.begin();iter!=value_list.end();++iter)
581 ValueNode::Handle item(ValueNode_Const::create(*iter));
582 value_node->add(ListEntry(item));
583 assert(value_node->list.back().value_node);
589 ValueNode_DynamicList::operator()(Time t)const
591 std::vector<ValueBase> ret_list;
592 std::vector<ListEntry>::const_iterator iter;
594 assert(container_type);
596 for(iter=list.begin();iter!=list.end();++iter)
598 bool state(iter->status_at_time(t));
602 if(iter->value_node->get_type()==container_type)
603 ret_list.push_back((*iter->value_node)(t));
606 synfig::warning(string("ValueNode_DynamicList::operator()():")+_("List type/item type mismatch, throwing away mismatch"));
612 synfig::warning(string("ValueNode_DynamicList::operator()():")+_("No entries in list"));
615 synfig::warning(string("ValueNode_DynamicList::operator()():")+_("No entries in ret_list"));
621 ValueNode_DynamicList::set_link_vfunc(int i,ValueNode::Handle x)
624 if((unsigned)i>=list.size())
626 if(x->get_type()!=container_type)
628 list[i].value_node=x;
632 ValueNode::LooseHandle
633 ValueNode_DynamicList::get_link_vfunc(int i)const
636 if((unsigned)i>=list.size())
638 return list[i].value_node;
642 ValueNode_DynamicList::link_count()const
648 ValueNode_DynamicList::link_local_name(int i)const
650 assert(i>=0 && (unsigned)i<list.size());
651 return etl::strprintf(_("Item %03d"),i+1);
655 ValueNode_DynamicList::clone(const GUID& deriv_guid)const
657 { ValueNode* x(find_value_node(get_guid()^deriv_guid).get()); if(x)return x; }
659 ValueNode_DynamicList* ret=new ValueNode_DynamicList(container_type);
660 ret->set_guid(get_guid()^deriv_guid);
662 std::vector<ListEntry>::const_iterator iter;
664 for(iter=list.begin();iter!=list.end();++iter)
666 if(iter->value_node->is_exported())
670 ListEntry list_entry(*iter);
671 //list_entry.value_node=find_value_node(iter->value_node->get_guid()^deriv_guid).get();
672 //if(!list_entry.value_node)
673 list_entry.value_node=iter->value_node->clone(deriv_guid);
674 ret->add(list_entry);
675 //ret->list.back().value_node=iter->value_node.clone();
678 ret->set_loop(get_loop());
683 ValueNode_DynamicList::link_name(int i)const
685 return strprintf("item%04d",i);
689 ValueNode_DynamicList::get_link_index_from_name(const String &name)const
691 throw Exception::BadLinkName(name);
695 ValueNode_DynamicList::get_name()const
697 return "dynamic_list";
701 ValueNode_DynamicList::get_local_name()const
703 return _("Dynamic List");
707 ValueNode_DynamicList::check_type(ValueBase::Type type)
709 return type==ValueBase::TYPE_LIST;
713 ValueNode_DynamicList::get_contained_type()const
715 return container_type;
719 ValueNode_DynamicList::create_new()const
726 ValueNode_DynamicList::find_next_valid_entry(int orig_item, Time t)const
730 for(curr_item=orig_item+1;curr_item!=orig_item;curr_item++)
732 if(curr_item==(int)list.size())
737 if(list[curr_item].status_at_time(t))
744 ValueNode_DynamicList::find_prev_valid_entry(int orig_item, Time t)const
748 for(curr_item=orig_item-1;curr_item!=orig_item;curr_item--)
752 curr_item=list.size();
755 if(list[curr_item].status_at_time(t))
761 const synfig::Node::time_set & ValueNode_DynamicList::ListEntry::get_times() const
763 synfig::ActivepointList::const_iterator j = timing_info.begin(),
764 end = timing_info.end();
766 //must remerge with all the other values because we don't know if we've changed...
767 times = value_node->get_times();
772 t.set_time(j->get_time());
773 t.set_guid(j->get_guid());
781 void ValueNode_DynamicList::get_times_vfunc(Node::time_set &set) const
783 //add in the active points
784 int size = list.size();
786 //rebuild all the info...
787 for(int i = 0; i < size; ++i)
789 const Node::time_set & tset= list[i].get_times();
790 set.insert(tset.begin(),tset.end());
795 //new find functions that don't throw
800 timecmp(const Time &c) :t(c) {}
802 bool operator()(const Activepoint &rhs) const
804 return t.is_equal(rhs.get_time());
808 ValueNode_DynamicList::ListEntry::findresult ValueNode_DynamicList::ListEntry::find_uid(const UniqueID& x)
813 f.first = std::find(timing_info.begin(),timing_info.end(),x);
815 if(f.first != timing_info.end())
823 ValueNode_DynamicList::ListEntry::const_findresult ValueNode_DynamicList::ListEntry::find_uid(const UniqueID& x) const
828 f.first = std::find(timing_info.begin(),timing_info.end(),x);
830 if(f.first != timing_info.end())
838 ValueNode_DynamicList::ListEntry::findresult ValueNode_DynamicList::ListEntry::find_time(const Time& x)
843 f.first = std::find_if(timing_info.begin(),timing_info.end(),timecmp(x));
845 if(f.first != timing_info.end())
853 ValueNode_DynamicList::ListEntry::const_findresult ValueNode_DynamicList::ListEntry::find_time(const Time& x)const
858 f.first = std::find_if(timing_info.begin(),timing_info.end(),timecmp(x));
860 if(f.first != timing_info.end())
869 ValueNode_DynamicList::insert_time(const Time& location, const Time& delta)
874 std::vector<ListEntry>::iterator iter(list.begin());
875 for(;iter!=list.end();++iter)
879 ListEntry& item(*iter);
881 ActivepointList::iterator iter(item.find_next(location));
882 for(;iter!=item.timing_info.end();++iter)
884 iter->set_time(iter->get_time()+delta);
887 catch(Exception::NotFound) { }