1 /* === S Y N F I G ========================================================= */
2 /*! \file valuenode_dynamiclist.cpp
3 ** \brief Template File
5 ** $Id: valuenode_dynamiclist.cpp,v 1.1.1.1 2005/01/04 01:23:15 darco Exp $
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 if(get_parent_canvas())
529 get_parent_canvas()->signal_value_node_child_removed()(this,value_node);
530 else if(get_root_canvas() && get_parent_canvas())
531 get_root_canvas()->signal_value_node_child_removed()(this,value_node);
539 ValueNode_DynamicList::ValueNode_DynamicList(ValueBase::Type container_type):
540 LinkableValueNode(ValueBase::TYPE_LIST),
541 container_type (container_type),
547 ValueNode_DynamicList::Handle
548 ValueNode_DynamicList::create(ValueBase::Type id)
550 return new ValueNode_DynamicList(id);
553 ValueNode_DynamicList::~ValueNode_DynamicList()
558 ValueNode_DynamicList*
559 ValueNode_DynamicList::create_from(const ValueBase &value)
561 //vector<ValueBase> value_list(value.operator vector<ValueBase>());
562 vector<ValueBase> value_list(value.get_list());
564 vector<ValueBase>::iterator iter;
566 if(value_list.empty())
569 ValueNode_DynamicList* value_node(new ValueNode_DynamicList(value_list.front().get_type()));
571 for(iter=value_list.begin();iter!=value_list.end();++iter)
573 ValueNode::Handle item(ValueNode_Const::create(*iter));
574 value_node->add(ListEntry(item));
575 assert(value_node->list.back().value_node);
581 ValueNode_DynamicList::operator()(Time t)const
583 std::vector<ValueBase> ret_list;
584 std::vector<ListEntry>::const_iterator iter;
586 assert(container_type);
588 for(iter=list.begin();iter!=list.end();++iter)
590 bool state(iter->status_at_time(t));
594 if(iter->value_node->get_type()==container_type)
595 ret_list.push_back((*iter->value_node)(t));
598 synfig::warning(string("ValueNode_DynamicList::operator()():")+_("List type/item type mismatch, throwing away mismatch"));
604 synfig::warning(string("ValueNode_DynamicList::operator()():")+_("No entries in list"));
607 synfig::warning(string("ValueNode_DynamicList::operator()():")+_("No entries in ret_list"));
613 ValueNode_DynamicList::set_link_vfunc(int i,ValueNode::Handle x)
616 if((unsigned)i>=list.size())
618 if(x->get_type()!=container_type)
620 list[i].value_node=x;
624 ValueNode::LooseHandle
625 ValueNode_DynamicList::get_link_vfunc(int i)const
628 if((unsigned)i>=list.size())
630 return list[i].value_node;
634 ValueNode_DynamicList::link_count()const
640 ValueNode_DynamicList::link_local_name(int i)const
642 assert(i>=0 && (unsigned)i<list.size());
643 return etl::strprintf(_("Item %03d"),i+1);
647 ValueNode_DynamicList::clone(const GUID& deriv_guid)const
649 { ValueNode* x(find_value_node(get_guid()^deriv_guid).get()); if(x)return x; }
651 ValueNode_DynamicList* ret=new ValueNode_DynamicList(container_type);
652 ret->set_guid(get_guid()^deriv_guid);
654 std::vector<ListEntry>::const_iterator iter;
656 for(iter=list.begin();iter!=list.end();++iter)
658 if(iter->value_node->is_exported())
662 ListEntry list_entry(*iter);
663 //list_entry.value_node=find_value_node(iter->value_node->get_guid()^deriv_guid).get();
664 //if(!list_entry.value_node)
665 list_entry.value_node=iter->value_node->clone(deriv_guid);
666 ret->add(list_entry);
667 //ret->list.back().value_node=iter->value_node.clone();
670 ret->set_loop(get_loop());
675 ValueNode_DynamicList::link_name(int i)const
677 return strprintf("item%04d",i);
681 ValueNode_DynamicList::get_link_index_from_name(const String &name)const
683 throw Exception::BadLinkName(name);
687 ValueNode_DynamicList::get_name()const
689 return "dynamic_list";
693 ValueNode_DynamicList::get_local_name()const
695 return _("Dynamic List");
699 ValueNode_DynamicList::check_type(ValueBase::Type type)
701 return type==ValueBase::TYPE_LIST;
705 ValueNode_DynamicList::get_contained_type()const
707 return container_type;
711 ValueNode_DynamicList::create_new()const
718 ValueNode_DynamicList::find_next_valid_entry(int orig_item, Time t)const
722 for(curr_item=orig_item+1;curr_item!=orig_item;curr_item++)
724 if(curr_item==(int)list.size())
729 if(list[curr_item].status_at_time(t))
736 ValueNode_DynamicList::find_prev_valid_entry(int orig_item, Time t)const
740 for(curr_item=orig_item-1;curr_item!=orig_item;curr_item--)
744 curr_item=list.size();
747 if(list[curr_item].status_at_time(t))
753 const synfig::Node::time_set & ValueNode_DynamicList::ListEntry::get_times() const
755 synfig::ActivepointList::const_iterator j = timing_info.begin(),
756 end = timing_info.end();
758 //must remerge with all the other values because we don't know if we've changed...
759 times = value_node->get_times();
764 t.set_time(j->get_time());
765 t.set_guid(j->get_guid());
773 void ValueNode_DynamicList::get_times_vfunc(Node::time_set &set) const
775 //add in the active points
776 int size = list.size();
778 //rebuild all the info...
779 for(int i = 0; i < size; ++i)
781 const Node::time_set & tset= list[i].get_times();
782 set.insert(tset.begin(),tset.end());
787 //new find functions that don't throw
792 timecmp(const Time &c) :t(c) {}
794 bool operator()(const Activepoint &rhs) const
796 return t.is_equal(rhs.get_time());
800 ValueNode_DynamicList::ListEntry::findresult ValueNode_DynamicList::ListEntry::find_uid(const UniqueID& x)
805 f.first = std::find(timing_info.begin(),timing_info.end(),x);
807 if(f.first != timing_info.end())
815 ValueNode_DynamicList::ListEntry::const_findresult ValueNode_DynamicList::ListEntry::find_uid(const UniqueID& x) const
820 f.first = std::find(timing_info.begin(),timing_info.end(),x);
822 if(f.first != timing_info.end())
830 ValueNode_DynamicList::ListEntry::findresult ValueNode_DynamicList::ListEntry::find_time(const Time& x)
835 f.first = std::find_if(timing_info.begin(),timing_info.end(),timecmp(x));
837 if(f.first != timing_info.end())
845 ValueNode_DynamicList::ListEntry::const_findresult ValueNode_DynamicList::ListEntry::find_time(const Time& x)const
850 f.first = std::find_if(timing_info.begin(),timing_info.end(),timecmp(x));
852 if(f.first != timing_info.end())
861 ValueNode_DynamicList::insert_time(const Time& location, const Time& delta)
866 std::vector<ListEntry>::iterator iter(list.begin());
867 for(;iter!=list.end();++iter)
871 ListEntry& item(*iter);
873 ActivepointList::iterator iter(item.find_next(location));
874 for(;iter!=item.timing_info.end();++iter)
876 iter->set_time(iter->get_time()+delta);
879 catch(Exception::NotFound) { }