+++ /dev/null
-/* === S Y N F I G ========================================================= */
-/*! \file valuenode_dynamiclist.cpp
-** \brief Template File
-**
-** $Id$
-**
-** \legal
-** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
-**
-** This package is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License as
-** published by the Free Software Foundation; either version 2 of
-** the License, or (at your option) any later version.
-**
-** This package is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-** General Public License for more details.
-** \endlegal
-*/
-/* ========================================================================= */
-
-/* === H E A D E R S ======================================================= */
-
-#ifdef USING_PCH
-# include "pch.h"
-#else
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "valuenode_dynamiclist.h"
-#include "valuenode_const.h"
-#include "valuenode_composite.h"
-#include "general.h"
-#include "exception.h"
-#include <vector>
-#include <list>
-#include <algorithm>
-#include "canvas.h"
-
-#endif
-
-/* === U S I N G =========================================================== */
-
-using namespace std;
-using namespace etl;
-using namespace synfig;
-
-/* === M A C R O S ========================================================= */
-
-/* === G L O B A L S ======================================================= */
-
-/* === P R O C E D U R E S ================================================= */
-
-/* === M E T H O D S ======================================================= */
-
-ValueNode_DynamicList::ListEntry::ListEntry():
- index(0)
-{
-}
-
-ValueNode_DynamicList::ListEntry::ListEntry(const ValueNode::Handle &value_node):
- value_node(value_node),
- index(0)
-{
-}
-
-ValueNode_DynamicList::ListEntry::ListEntry(const ValueNode::Handle &value_node,Time begin, Time end):
- value_node(value_node)
-{
- add(begin,false);
- add(end,false);
- add((begin+end)*0.5,true);
-}
-
-ValueNode_DynamicList::ListEntry::ActivepointList::iterator
-ValueNode_DynamicList::ListEntry::add(Time time, bool status, int priority)
-{
- typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList::iterator iterator;
-
- //! \optimize
- Activepoint ap(time,status,priority);
- ap.set_parent_index(get_index());
- ap.set_parent_value_node(get_parent_value_node());
- timing_info.push_back(ap);
- iterator iter(--iterator(timing_info.end()));
- timing_info.sort();
-
- return iter;
-}
-
-ValueNode_DynamicList::ListEntry::ActivepointList::iterator
-ValueNode_DynamicList::ListEntry::add(const Activepoint &x)
-{
- typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList::iterator iterator;
-
- //! \optimize
- Activepoint ap(x);
- ap.set_parent_index(get_index());
- ap.set_parent_value_node(get_parent_value_node());
- timing_info.push_back(ap);
- iterator iter(--iterator(timing_info.end()));
- timing_info.sort();
-
- return iter;
-}
-
-void
-ValueNode_DynamicList::reindex()
-{
- int i(0);
-
- std::vector<ListEntry>::iterator iter;
-
- for(iter=list.begin();iter!=list.end();++iter)
- {
- assert(iter->value_node);
- if(iter->index!=i || iter->get_parent_value_node().get()!=this)
- {
- ActivepointList::iterator iter2;
-
- if(iter->timing_info.size()) // is this line really necessary?
- for(iter2=iter->timing_info.begin();iter2!=iter->timing_info.end();++iter2)
- {
- iter2->set_parent_index(i);
- iter2->set_parent_value_node(this);
- }
- iter->index=i;
- iter->set_parent_value_node(this);
- }
- }
-}
-
-ValueNode_DynamicList::ListEntry
-ValueNode_DynamicList::create_list_entry(int index, Time time, Real origin)
-{
- ValueNode_DynamicList::ListEntry ret;
-
-
- synfig::ValueBase prev,next;
-
- index=index%link_count();
-
- assert(index>=0);
-
- ret.index=index;
- ret.set_parent_value_node(this);
-
- next=(*list[index].value_node)(time);
-
- if(index!=0)
- prev=(*list[index-1].value_node)(time);
- else
- {
- if(get_loop())
- prev=(*list[link_count()-1].value_node)(time);
- else
- {
- prev=next;
- }
- }
-
-
- switch(get_contained_type())
- {
- case ValueBase::TYPE_VECTOR:
- {
- Vector a(prev.get(Vector())), b(next.get(Vector()));
- ret.value_node=ValueNode_Const::create((b-a)*origin+a);
- break;
- }
- case ValueBase::TYPE_REAL:
- {
- Real a(prev.get(Real())), b(next.get(Real()));
- ret.value_node=ValueNode_Const::create((b-a)*origin+a);
- break;
- }
- case ValueBase::TYPE_COLOR:
- {
- Color a(prev.get(Color())), b(next.get(Color()));
- ret.value_node=ValueNode_Composite::create((b-a)*origin+a);
- break;
- }
- case ValueBase::TYPE_ANGLE:
- {
- Angle a(prev.get(Angle())), b(next.get(Angle()));
- ret.value_node=ValueNode_Const::create((b-a)*origin+a);
- break;
- }
- case ValueBase::TYPE_TIME:
- {
- Time a(prev.get(Time())), b(next.get(Time()));
- ret.value_node=ValueNode_Const::create((b-a)*origin+a);
- break;
- }
- default:
- ret.value_node=ValueNode_Const::create(get_contained_type());
- break;
- }
-
-
- return ret;
-}
-
-ValueNode_DynamicList::ListEntry::ActivepointList::iterator
-ValueNode_DynamicList::ListEntry::find(const UniqueID& x)
-{
- return std::find(timing_info.begin(),timing_info.end(),x);
-}
-
-ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
-ValueNode_DynamicList::ListEntry::find(const UniqueID& x)const
-{
- return std::find(timing_info.begin(),timing_info.end(),x);
-}
-
-void
-ValueNode_DynamicList::ListEntry::erase(const UniqueID& x)
-{
- timing_info.erase(find(x));
-}
-
-ValueNode_DynamicList::ListEntry::ActivepointList::iterator
-ValueNode_DynamicList::ListEntry::find(const Time& x)
-{
- typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
- ActivepointList::iterator iter;
-
- for(iter=timing_info.begin();iter!=timing_info.end();++iter)
- if(iter->time==x)
- return iter;
-
- throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find():"+x.get_string());
-}
-
-ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
-ValueNode_DynamicList::ListEntry::find(const Time& x)const
-{
- typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
- ActivepointList::const_iterator iter;
-
- for(iter=timing_info.begin();iter!=timing_info.end();++iter)
- if(iter->time==x)
- return iter;
-
- throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find()const:"+x.get_string());
-}
-
-ValueNode_DynamicList::ListEntry::ActivepointList::iterator
-ValueNode_DynamicList::ListEntry::find_next(const Time& x)
-{
- typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
- ActivepointList::iterator iter;
-
- for(iter=timing_info.begin();iter!=timing_info.end();++iter)
- if(iter->time>x)
- return iter;
-
- throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_next():"+x.get_string());
-}
-
-ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
-ValueNode_DynamicList::ListEntry::find_next(const Time& x)const
-{
- typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
- ActivepointList::const_iterator iter;
-
- for(iter=timing_info.begin();iter!=timing_info.end();++iter)
- if(iter->time>x)
- return iter;
-
- throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_next()const:"+x.get_string());
-}
-
-ValueNode_DynamicList::ListEntry::ActivepointList::iterator
-ValueNode_DynamicList::ListEntry::find_prev(const Time& x)
-{
- typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
- ActivepointList::iterator iter;
- iter=timing_info.end();
- do
- {
- --iter;
- if(iter->time<x)
- return iter;
- }
- while(iter!=timing_info.begin());
-
- throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_prev():"+x.get_string());
-}
-
-ValueNode_DynamicList::ListEntry::ActivepointList::const_iterator
-ValueNode_DynamicList::ListEntry::find_prev(const Time& x)const
-{
- typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
- ActivepointList::const_iterator iter;
- iter=timing_info.end();
- do
- {
- --iter;
- if(iter->time<x)
- return iter;
- }
- while(iter!=timing_info.begin());
-
- throw Exception::NotFound("ValueNode_DynamicList::ListEntry::find_prev()const:"+x.get_string());
-}
-
-int
-ValueNode_DynamicList::ListEntry::find(const Time& begin,const Time& end,std::vector<Activepoint*>& selected)
-{
- Time curr_time(begin);
- int ret(0);
-
- // try to grab first waypoint
- try
- {
- ActivepointList::iterator iter;
- iter=find(curr_time);
- selected.push_back(&*iter);
- ret++;
- }
- catch(...) { }
-
- try
- {
- ActivepointList::iterator iter;
- while(true)
- {
- iter=find_next(curr_time);
- curr_time=iter->get_time();
- if(curr_time>=end)
- break;
- selected.push_back(&*iter);
- ret++;
- }
- }
- catch(...) { }
-
- return ret;
-}
-
-float
-ValueNode_DynamicList::ListEntry::amount_at_time(const Time &t,bool *rising)const
-{
- typedef synfig::ValueNode_DynamicList::ListEntry::Activepoint Activepoint;
- typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
- if(timing_info.empty())
- return 1.0f;
-
- try
- {
- ActivepointList::const_iterator iter;
- iter=find(t);
- return iter->state?1.0f:0.0f;
- }
- catch(...) { }
-
- ActivepointList::const_iterator prev_iter;
- ActivepointList::const_iterator next_iter;
-
- try { prev_iter=find_prev(t); }
- catch(...) { return find_next(t)->state?1.0f:0.0f; }
-
- try { next_iter=find_next(t); }
- catch(...) { return prev_iter->state?1.0f:0.0f; }
-
- if(next_iter->state==prev_iter->state)
- return next_iter->state?1.0f:0.0f;
-
- if(rising)*rising=next_iter->state;
-
- if(next_iter->state==true)
- return float((t-prev_iter->time)/(next_iter->time-prev_iter->time));
-
- return float((next_iter->time-t)/(next_iter->time-prev_iter->time));
-}
-
-Activepoint
-ValueNode_DynamicList::ListEntry::new_activepoint_at_time(const Time& time)const
-{
- Activepoint activepoint;
-
- activepoint.set_state(status_at_time(time));
- activepoint.set_priority(0);
-
- return activepoint;
-}
-
-bool
-ValueNode_DynamicList::ListEntry::status_at_time(const Time &t)const
-{
- typedef synfig::ValueNode_DynamicList::ListEntry::Activepoint Activepoint;
- typedef synfig::ValueNode_DynamicList::ListEntry::ActivepointList ActivepointList;
-
- ActivepointList::const_iterator entry_iter;
- ActivepointList::const_iterator prev_iter;
- bool state(true);
-
- // New "symmetric" state mechanism
- if(!timing_info.empty())
- {
- if(timing_info.size()==1)
- state=timing_info.front().state;
- else
- {
- //! \optimize Perhaps we should use a binary search...?
- // This will give us the first activepoint that is after t.
- for(entry_iter=timing_info.begin();entry_iter!=timing_info.end();++entry_iter)
- {
- if(entry_iter->time==t)
- {
- // If we hit the entry right on the nose, then we don't
- // have to do anything more
- return entry_iter->state;
- }
- if(entry_iter->time>t)
- break;
-
- }
- prev_iter=entry_iter;
- prev_iter--;
-
- // ie:
- //
- // |-------|---t---|-------|
- // prev_iter^ ^entry_iter
-
- if(entry_iter==timing_info.end())
- {
- state=prev_iter->state;
- }
- else
- if(entry_iter==timing_info.begin())
- {
- state=entry_iter->state;
- }
- else
- if(entry_iter->priority==prev_iter->priority)
- {
- state=entry_iter->state || prev_iter->state;
- }
- else
- if(entry_iter->priority>prev_iter->priority)
- {
- state=entry_iter->state;
- }
- else
- {
- state=prev_iter->state;
- }
- }
- }
- return state;
-}
-
-
-
-
-void
-ValueNode_DynamicList::add(const ValueNode::Handle &value_node, int index)
-{
- ListEntry list_entry(value_node);
- list_entry.timing_info.size();
-
- if(index<0 || index>=(int)list.size())
- {
- list.push_back(list_entry);
- }
- else
- {
- list.insert(list.begin()+index,list_entry);
- }
-
- add_child(value_node.get());
- reindex();
- //changed();
-
- if(get_parent_canvas())
- get_parent_canvas()->signal_value_node_child_added()(this,value_node);
- else if(get_root_canvas() && get_parent_canvas())
- get_root_canvas()->signal_value_node_child_added()(this,value_node);
-}
-
-void
-ValueNode_DynamicList::add(const ListEntry &list_entry, int index)
-{
- if(index<0 || index>=(int)list.size())
- list.push_back(list_entry);
- else
- list.insert(list.begin()+index,list_entry);
- add_child(list_entry.value_node.get());
-
- reindex();
- //changed();
-
- if(get_parent_canvas())
- get_parent_canvas()->signal_value_node_child_added()(this,list_entry.value_node);
- else if(get_root_canvas() && get_parent_canvas())
- get_root_canvas()->signal_value_node_child_added()(this,list_entry.value_node);
-}
-
-void
-ValueNode_DynamicList::erase(const ValueNode::Handle &value_node_)
-{
- ValueNode::Handle value_node(value_node_);
-
- assert(value_node);
- if(!value_node)
- throw String("ValueNode_DynamicList::erase(): Passed bad value node");
-
- std::vector<ListEntry>::iterator iter;
- for(iter=list.begin();iter!=list.end();++iter)
- if(iter->value_node==value_node)
- {
- list.erase(iter);
- if(value_node)
- {
- remove_child(value_node.get());
- // changed to fix bug 1420091 - it seems that when a .sif file containing a bline layer encapsulated inside
- // another layer, get_parent_canvas() is false and get_root_canvas() is true, but when we come to erase a
- // vertex, both are true. So the signal is sent to the parent, but the signal wasn't sent to the parent
- // when it was added. This probably isn't the right fix, but it seems to work for now. Note that the same
- // strange "if (X) else if (Y && X)" code is also present in the two previous functions, above.
-
- // if(get_parent_canvas())
- // get_parent_canvas()->signal_value_node_child_removed()(this,value_node);
- // else if(get_root_canvas() && get_parent_canvas())
- // get_root_canvas()->signal_value_node_child_removed()(this,value_node);
- if(get_root_canvas())
- get_root_canvas()->signal_value_node_child_removed()(this,value_node);
- }
- break;
- }
- reindex();
-}
-
-
-ValueNode_DynamicList::ValueNode_DynamicList(ValueBase::Type container_type):
- LinkableValueNode(ValueBase::TYPE_LIST),
- container_type (container_type),
- loop_(false)
-{
- DCAST_HACK_ENABLE();
-}
-
-ValueNode_DynamicList::Handle
-ValueNode_DynamicList::create(ValueBase::Type id)
-{
- return new ValueNode_DynamicList(id);
-}
-
-ValueNode_DynamicList::~ValueNode_DynamicList()
-{
- unlink_all();
-}
-
-ValueNode_DynamicList*
-ValueNode_DynamicList::create_from(const ValueBase &value)
-{
- //vector<ValueBase> value_list(value.operator vector<ValueBase>());
- vector<ValueBase> value_list(value.get_list());
-
- vector<ValueBase>::iterator iter;
-
- if(value_list.empty())
- return 0;
-
- ValueNode_DynamicList* value_node(new ValueNode_DynamicList(value_list.front().get_type()));
-
- for(iter=value_list.begin();iter!=value_list.end();++iter)
- {
- ValueNode::Handle item(ValueNode_Const::create(*iter));
- value_node->add(ListEntry(item));
- assert(value_node->list.back().value_node);
- }
- return value_node;
-}
-
-ValueBase
-ValueNode_DynamicList::operator()(Time t)const
-{
- std::vector<ValueBase> ret_list;
- std::vector<ListEntry>::const_iterator iter;
-
- assert(container_type);
-
- for(iter=list.begin();iter!=list.end();++iter)
- {
- bool state(iter->status_at_time(t));
-
- if(state)
- {
- if(iter->value_node->get_type()==container_type)
- ret_list.push_back((*iter->value_node)(t));
- else
- {
- synfig::warning(string("ValueNode_DynamicList::operator()():")+_("List type/item type mismatch, throwing away mismatch"));
- }
- }
- }
-
- if(list.empty())
- synfig::warning(string("ValueNode_DynamicList::operator()():")+_("No entries in list"));
- else
- if(ret_list.empty())
- synfig::warning(string("ValueNode_DynamicList::operator()():")+_("No entries in ret_list"));
-
- return ret_list;
-}
-
-bool
-ValueNode_DynamicList::set_link_vfunc(int i,ValueNode::Handle x)
-{
- assert(i>=0);
- if((unsigned)i>=list.size())
- return false;
- if(x->get_type()!=container_type)
- return false;
- list[i].value_node=x;
- return true;
-}
-
-ValueNode::LooseHandle
-ValueNode_DynamicList::get_link_vfunc(int i)const
-{
- assert(i>=0);
- if((unsigned)i>=list.size())
- return 0;
- return list[i].value_node;
-}
-
-int
-ValueNode_DynamicList::link_count()const
-{
- return list.size();
-}
-
-String
-ValueNode_DynamicList::link_local_name(int i)const
-{
- assert(i>=0 && (unsigned)i<list.size());
- return etl::strprintf(_("Item %03d"),i+1);
-}
-
-ValueNode*
-ValueNode_DynamicList::clone(const GUID& deriv_guid)const
-{
- { ValueNode* x(find_value_node(get_guid()^deriv_guid).get()); if(x)return x; }
-
- ValueNode_DynamicList* ret=new ValueNode_DynamicList(container_type);
- ret->set_guid(get_guid()^deriv_guid);
-
- std::vector<ListEntry>::const_iterator iter;
-
- for(iter=list.begin();iter!=list.end();++iter)
- {
- if(iter->value_node->is_exported())
- ret->add(*iter);
- else
- {
- ListEntry list_entry(*iter);
- //list_entry.value_node=find_value_node(iter->value_node->get_guid()^deriv_guid).get();
- //if(!list_entry.value_node)
- list_entry.value_node=iter->value_node->clone(deriv_guid);
- ret->add(list_entry);
- //ret->list.back().value_node=iter->value_node.clone();
- }
- }
- ret->set_loop(get_loop());
- return ret;
-}
-
-String
-ValueNode_DynamicList::link_name(int i)const
-{
- return strprintf("item%04d",i);
-}
-
-int
-ValueNode_DynamicList::get_link_index_from_name(const String &name)const
-{
- throw Exception::BadLinkName(name);
-}
-
-String
-ValueNode_DynamicList::get_name()const
-{
- return "dynamic_list";
-}
-
-String
-ValueNode_DynamicList::get_local_name()const
-{
- return _("Dynamic List");
-}
-
-bool
-ValueNode_DynamicList::check_type(ValueBase::Type type)
-{
- return type==ValueBase::TYPE_LIST;
-}
-
-ValueBase::Type
-ValueNode_DynamicList::get_contained_type()const
-{
- return container_type;
-}
-
-LinkableValueNode*
-ValueNode_DynamicList::create_new()const
-{
- assert(0);
- return 0;
-}
-
-int
-ValueNode_DynamicList::find_next_valid_entry(int orig_item, Time t)const
-{
- int curr_item;
-
- for(curr_item=orig_item+1;curr_item!=orig_item;curr_item++)
- {
- if(curr_item==(int)list.size())
- {
- curr_item=0;
- continue;
- }
- if(list[curr_item].status_at_time(t))
- return curr_item;
- }
- return curr_item;
-}
-
-int
-ValueNode_DynamicList::find_prev_valid_entry(int orig_item, Time t)const
-{
- int curr_item;
-
- for(curr_item=orig_item-1;curr_item!=orig_item;curr_item--)
- {
- if(curr_item==-1)
- {
- curr_item=list.size();
- continue;
- }
- if(list[curr_item].status_at_time(t))
- return curr_item;
- }
- return curr_item;
-}
-
-const synfig::Node::time_set & ValueNode_DynamicList::ListEntry::get_times() const
-{
- synfig::ActivepointList::const_iterator j = timing_info.begin(),
- end = timing_info.end();
-
- //must remerge with all the other values because we don't know if we've changed...
- times = value_node->get_times();
-
- for(; j != end; ++j)
- {
- TimePoint t;
- t.set_time(j->get_time());
- t.set_guid(j->get_guid());
-
- times.insert(t);
- }
-
- return times;
-}
-
-void ValueNode_DynamicList::get_times_vfunc(Node::time_set &set) const
-{
- //add in the active points
- int size = list.size();
-
- //rebuild all the info...
- for(int i = 0; i < size; ++i)
- {
- const Node::time_set & tset= list[i].get_times();
- set.insert(tset.begin(),tset.end());
- }
-}
-
-
-//new find functions that don't throw
-struct timecmp
-{
- Time t;
-
- timecmp(const Time &c) :t(c) {}
-
- bool operator()(const Activepoint &rhs) const
- {
- return t.is_equal(rhs.get_time());
- }
-};
-
-ValueNode_DynamicList::ListEntry::findresult ValueNode_DynamicList::ListEntry::find_uid(const UniqueID& x)
-{
- findresult f;
- f.second = false;
-
- f.first = std::find(timing_info.begin(),timing_info.end(),x);
-
- if(f.first != timing_info.end())
- {
- f.second = true;
- }
-
- return f;
-}
-
-ValueNode_DynamicList::ListEntry::const_findresult ValueNode_DynamicList::ListEntry::find_uid(const UniqueID& x) const
-{
- const_findresult f;
- f.second = false;
-
- f.first = std::find(timing_info.begin(),timing_info.end(),x);
-
- if(f.first != timing_info.end())
- {
- f.second = true;
- }
-
- return f;
-}
-
-ValueNode_DynamicList::ListEntry::findresult ValueNode_DynamicList::ListEntry::find_time(const Time& x)
-{
- findresult f;
- f.second = false;
-
- f.first = std::find_if(timing_info.begin(),timing_info.end(),timecmp(x));
-
- if(f.first != timing_info.end())
- {
- f.second = true;
- }
-
- return f;
-}
-
-ValueNode_DynamicList::ListEntry::const_findresult ValueNode_DynamicList::ListEntry::find_time(const Time& x)const
-{
- const_findresult f;
- f.second = false;
-
- f.first = std::find_if(timing_info.begin(),timing_info.end(),timecmp(x));
-
- if(f.first != timing_info.end())
- {
- f.second = true;
- }
-
- return f;
-}
-
-void
-ValueNode_DynamicList::insert_time(const Time& location, const Time& delta)
-{
- if(!delta)
- return;
-
- std::vector<ListEntry>::iterator iter(list.begin());
- for(;iter!=list.end();++iter)
- {
- try
- {
- ListEntry& item(*iter);
-
- ActivepointList::iterator iter(item.find_next(location));
- for(;iter!=item.timing_info.end();++iter)
- {
- iter->set_time(iter->get_time()+delta);
- }
- }
- catch(Exception::NotFound) { }
- }
- changed();
-}