Blame synfig-core/src/synfig/node.cpp

Carlos Lopez a09598
/* === S Y N F I G ========================================================= */
Carlos Lopez a09598
/*!	\file node.cpp
Carlos Lopez a09598
**	\brief Template File
Carlos Lopez a09598
**
Carlos Lopez a09598
**	$Id$
Carlos Lopez a09598
**
Carlos Lopez a09598
**	\legal
Carlos Lopez a09598
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
Carlos Lopez a09598
**	Copyright (c) 2007, 2008 Chris Moore
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is free software; you can redistribute it and/or
Carlos Lopez a09598
**	modify it under the terms of the GNU General Public License as
Carlos Lopez a09598
**	published by the Free Software Foundation; either version 2 of
Carlos Lopez a09598
**	the License, or (at your option) any later version.
Carlos Lopez a09598
**
Carlos Lopez a09598
**	This package is distributed in the hope that it will be useful,
Carlos Lopez a09598
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
Carlos Lopez a09598
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Carlos Lopez a09598
**	General Public License for more details.
Carlos Lopez a09598
**	\endlegal
Carlos Lopez a09598
*/
Carlos Lopez a09598
/* ========================================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
/* === H E A D E R S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef USING_PCH
Carlos Lopez a09598
#	include "pch.h"
Carlos Lopez a09598
#else
Carlos Lopez a09598
#ifdef HAVE_CONFIG_H
Carlos Lopez a09598
#	include <config.h></config.h>
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Nikita Kitaev dc5e35
#include <cstdlib></cstdlib>
Nikita Kitaev dc5e35
#include <cstdio></cstdio>
Carlos Lopez a09598
#include "node.h"
Carlos Lopez a09598
// #include "nodebase.h"		// this defines a bunch of sigc::slots that are never used
Carlos Lopez a09598
67f1c5
#include <map></map>
Carlos Lopez a09598
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
/* === U S I N G =========================================================== */
Carlos Lopez a09598
Carlos Lopez a09598
using namespace std;
Carlos Lopez a09598
using namespace etl;
Carlos Lopez a09598
using namespace synfig;
Carlos Lopez a09598
Carlos Lopez a09598
/* === M A C R O S ========================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#ifndef __sys_clock
Carlos Lopez 1dd5df
	#ifndef _WIN32
Carlos Lopez 1dd5df
		# include <time.h></time.h>
Carlos Lopez 1dd5df
		# define __sys_clock	::clock
Carlos Lopez 1dd5df
	#else
Carlos Lopez 1dd5df
		# ifdef __GNUG__
Carlos Lopez 1dd5df
			#  include <time.h></time.h>
Carlos Lopez 1dd5df
			#  define __sys_clock	::clock
Carlos Lopez 1dd5df
		# else
Carlos Lopez 1dd5df
			typedef int clock_t;
Carlos Lopez 1dd5df
			extern clock_t _clock();
Carlos Lopez 1dd5df
			#  define CLOCKS_PER_SEC 1000
Carlos Lopez 1dd5df
			#  define __sys_clock	_clock
Carlos Lopez 1dd5df
		# endif // __GNUG__
Carlos Lopez 1dd5df
	#endif // _WIN_32
Carlos Lopez 1dd5df
#endif // __sys_clock
Carlos Lopez a09598
Carlos Lopez a09598
/* === G L O B A L S ======================================================= */
Carlos Lopez a09598
bfe3d9
namespace {
bfe3d9
	class GlobalNodeMap {
bfe3d9
	public:
bfe3d9
		typedef std::map<guid, node*=""> Map;</guid,>
bfe3d9
	
bfe3d9
	private:
Rodolfo Ribeiro Gomes d18249
		std::mutex mutex_;
bfe3d9
		Map map;
bfe3d9
	
bfe3d9
	public:
bfe3d9
		Node* get(const GUID &guid) {
Rodolfo Ribeiro Gomes d18249
			std::lock_guard<std::mutex> lock(mutex_);</std::mutex>
bfe3d9
			Map::iterator i = map.find(guid);
Rodolfo Ribeiro Gomes d18249
			return i == map.end() ? nullptr : i->second;
bfe3d9
		}
bfe3d9
bfe3d9
		void add(const GUID &guid, Node *node) {
bfe3d9
			assert(guid);
bfe3d9
			assert(node);
bfe3d9
			
Rodolfo Ribeiro Gomes d18249
			std::lock_guard<std::mutex> lock(mutex_);</std::mutex>
bfe3d9
			assert(!map.count(guid));
bfe3d9
			map[guid] = node;
bfe3d9
		}
bfe3d9
bfe3d9
		void remove(const GUID &guid, Node *node) {
bfe3d9
			assert(guid);
bfe3d9
			assert(node);
bfe3d9
			
Rodolfo Ribeiro Gomes d18249
			std::lock_guard<std::mutex> lock(mutex_);</std::mutex>
bfe3d9
			Map::iterator i = map.find(guid);
bfe3d9
			assert(i != map.end() && i->second == node);
bfe3d9
			map.erase(i);
bfe3d9
		}
bfe3d9
bfe3d9
		void move(const GUID &guid, const GUID &oldguid, Node *node) {
bfe3d9
			assert(guid);
bfe3d9
			assert(node);
bfe3d9
			if (guid == oldguid) {
bfe3d9
				assert(get(guid) == node);
bfe3d9
				return;
bfe3d9
			}
bfe3d9
			assert(oldguid);
bfe3d9
			
Rodolfo Ribeiro Gomes d18249
			std::lock_guard<std::mutex> lock(mutex_);</std::mutex>
d6407d
			Map::iterator i = map.find(oldguid);
bfe3d9
			assert(i != map.end() && i->second == node);
bfe3d9
			map.erase(i);
bfe3d9
			
bfe3d9
			assert(!map.count(guid));
bfe3d9
			map[guid] = node;
bfe3d9
		}
bfe3d9
	};
bfe3d9
}
Carlos Lopez a09598
Carlos Lopez 874797
//! A map to store all the GUIDs with a pointer to the Node.
Carlos Lopez a09598
static GlobalNodeMap& global_node_map()
Carlos Lopez a09598
{
bfe3d9
	static GlobalNodeMap map;
bfe3d9
	return map;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
/* === P R O C E D U R E S ================================================= */
Carlos Lopez a09598
bfe3d9
Node* synfig::find_node(const GUID &guid) {
bfe3d9
	return global_node_map().get(guid);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
/* === M E T H O D S ======================================================= */
Carlos Lopez a09598
Carlos Lopez a09598
#ifdef _DEBUG
Carlos Lopez a09598
const char *
Carlos Lopez a09598
TimePoint::c_str()const
Carlos Lopez a09598
{
Carlos Lopez a09598
	return get_time().get_string().c_str();
Carlos Lopez a09598
}
Carlos Lopez a09598
#endif
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
TimePoint::absorb(const TimePoint& x)
Carlos Lopez a09598
{
Carlos Lopez 874797
	//! If the Time Point to absorb is itself then bail out
Carlos Lopez a09598
	if(get_guid()==x.get_guid())
Carlos Lopez a09598
		return;
Carlos Lopez 874797
	//! Creates a new GUID with the old and the new one using XOR operator
Carlos Lopez a09598
	set_guid(get_guid()^x.get_guid());
Carlos Lopez 874797
	//! If the current before/after interpolation is NIL use the interpolation
Carlos Lopez 874797
	//! provided by the TimePoint to absorb
Carlos Lopez a09598
	if(get_after()==INTERPOLATION_NIL)
Carlos Lopez a09598
		set_after(x.get_after());
Carlos Lopez a09598
	if(get_before()==INTERPOLATION_NIL)
Carlos Lopez a09598
		set_before(x.get_before());
Carlos Lopez 874797
	//! If the interpolation of the Time Point to absorb is not the same
Carlos Lopez 874797
	//! than the interpolation from the Time Point to absorb then
Carlos Lopez 874797
	//! use UNDEFINED interpolation
Carlos Lopez a09598
	if(get_after()!=x.get_after() && x.get_after()!=INTERPOLATION_NIL)
Carlos Lopez a09598
		set_after(INTERPOLATION_UNDEFINED);
Carlos Lopez a09598
	if(get_before()!=x.get_before() && x.get_before()!=INTERPOLATION_NIL)
Carlos Lopez a09598
		set_before(INTERPOLATION_UNDEFINED);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
TimePointSet::iterator
Carlos Lopez a09598
TimePointSet::insert(const TimePoint& x)
Carlos Lopez a09598
{
Carlos Lopez 874797
	//! finds a iterator to a Time Point with the same time
Carlos Lopez 874797
	//! \see inline bool operator==(const TimePoint& lhs,const TimePoint& rhs)
Carlos Lopez a09598
	iterator iter(find(x));
Carlos Lopez 874797
	//! If iter is not a the end of the set (we found one Time Point)
Carlos Lopez a09598
	if(iter!=end())
Carlos Lopez a09598
	{
Carlos Lopez 874797
		//! Absorb the time point
Carlos Lopez a09598
		const_cast<timepoint&>(*iter).absorb(x);</timepoint&>
Carlos Lopez a09598
		return iter;
Carlos Lopez a09598
	}
Carlos Lopez 874797
	//! Else, insert it at the first of the set
Carlos Lopez a09598
	return std::set<timepoint>::insert(x).first;</timepoint>
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
Node::Node():
Carlos Lopez a09598
	guid_(0),
Carlos Lopez a09598
	bchanged(true),
Carlos Lopez a09598
	time_last_changed_(__sys_clock()),
Carlos Lopez a09598
	deleting_(false)
Carlos Lopez a09598
{
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
Node::~Node()
Carlos Lopez a09598
{
Carlos Lopez a09598
	begin_delete();
Carlos Lopez a09598
	if(guid_)
bfe3d9
		global_node_map().remove(guid_, this);
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
Node::changed()
Carlos Lopez a09598
{
Carlos Lopez a09598
	time_last_changed_=__sys_clock();
Carlos Lopez a09598
	on_changed();
Carlos Lopez a09598
}
Carlos Lopez a09598
eef648
void
eef648
Node::child_changed(const Node *x)
eef648
{
eef648
	on_child_changed(x);
eef648
}
eef648
Carlos Lopez a09598
Carlos Lopez a09598
//! Gets the GUID for this value node
Carlos Lopez a09598
const synfig::GUID&
Carlos Lopez a09598
Node::get_guid()const
Carlos Lopez a09598
{
Rodolfo Ribeiro Gomes d18249
	std::lock_guard<std::mutex> lock(guid_mutex_);</std::mutex>
Carlos Lopez a09598
	if(!guid_)
Carlos Lopez a09598
	{
bfe3d9
		guid_.make_unique();
bfe3d9
		global_node_map().add(guid_, const_cast<node*>(this));</node*>
Carlos Lopez a09598
	}
Carlos Lopez a09598
	return guid_;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
//! Sets the GUID for this value node
Carlos Lopez a09598
void
Carlos Lopez a09598
Node::set_guid(const synfig::GUID& x)
Carlos Lopez a09598
{
Carlos Lopez a09598
	assert(x);
Rodolfo Ribeiro Gomes d18249
	std::lock_guard<std::mutex> lock(guid_mutex_);</std::mutex>
bfe3d9
	if (guid_ == x) return;
bfe3d9
	
bfe3d9
	if (!guid_) {
bfe3d9
		guid_ = x;
bfe3d9
		global_node_map().add(guid_, const_cast<node*>(this));</node*>
bfe3d9
	} else
bfe3d9
	if (guid_ != x) {
bfe3d9
		GUID old(guid_);
bfe3d9
		guid_ = x;
bfe3d9
		global_node_map().move(guid_, old, this);
bfe3d9
		on_guid_changed(old);
Carlos Lopez a09598
	}
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
int
Carlos Lopez a09598
Node::get_time_last_changed()const
Carlos Lopez a09598
{
Carlos Lopez a09598
	return time_last_changed_;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
Node::add_child(Node*x)
Carlos Lopez a09598
{
Nikita Kitaev dc5e35
	if (getenv("SYNFIG_DEBUG_NODE_PARENT_SET"))
Nikita Kitaev dc5e35
		printf("%s:%d adding %lx (%s) as parent of %lx (%s) (%zd -> ", __FILE__, __LINE__,
Carlos López 9608fb
			   uintptr_t(this), get_string().c_str(),
Carlos López 9608fb
			   uintptr_t(x), x->get_string().c_str(),
Nikita Kitaev dc5e35
			   x->parent_set.size());
Nikita Kitaev dc5e35
Carlos Lopez a09598
	x->parent_set.insert(this);
Nikita Kitaev dc5e35
Nikita Kitaev dc5e35
	if (getenv("SYNFIG_DEBUG_NODE_PARENT_SET"))
Nikita Kitaev dc5e35
		printf("%zd)\n", x->parent_set.size());
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
Node::remove_child(Node*x)
Carlos Lopez a09598
{
Nikita Kitaev dc5e35
	if(x->parent_set.count(this) == 0)
Nikita Kitaev dc5e35
	{
Nikita Kitaev dc5e35
		if (getenv("SYNFIG_DEBUG_NODE_PARENT_SET"))
Nikita Kitaev dc5e35
			printf("%s:%d %lx (%s) isn't in parent set of %lx (%s)\n", __FILE__, __LINE__,
Carlos López 9608fb
				   uintptr_t(this), get_string().c_str(),
Carlos López 9608fb
				   uintptr_t(x), x->get_string().c_str());
Nikita Kitaev dc5e35
Nikita Kitaev dc5e35
		return;
Nikita Kitaev dc5e35
	}
Nikita Kitaev dc5e35
Nikita Kitaev dc5e35
	if (getenv("SYNFIG_DEBUG_NODE_PARENT_SET"))
Nikita Kitaev dc5e35
		printf("%s:%d removing %lx (%s) from parent set of %lx (%s) (%zd -> ", __FILE__, __LINE__,
Carlos López 9608fb
			   uintptr_t(this), get_string().c_str(),
Carlos López 9608fb
			   uintptr_t(x), x->get_string().c_str(),
Nikita Kitaev dc5e35
			   x->parent_set.size());
Nikita Kitaev dc5e35
Nikita Kitaev dc5e35
	x->parent_set.erase(this);
Nikita Kitaev dc5e35
Nikita Kitaev dc5e35
	if (getenv("SYNFIG_DEBUG_NODE_PARENT_SET"))
Nikita Kitaev dc5e35
		printf("%zd)\n", x->parent_set.size());
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
int
Carlos Lopez a09598
Node::parent_count()const
Carlos Lopez a09598
{
Carlos Lopez a09598
	return parent_set.size();
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
const Node::time_set &
Carlos Lopez a09598
Node::get_times() const
Carlos Lopez a09598
{
Carlos Lopez a09598
	if(bchanged)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		times.clear();
Carlos Lopez a09598
		get_times_vfunc(times);
Carlos Lopez a09598
		bchanged = false;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	//set the output set...
Carlos Lopez a09598
	return times;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
Node::begin_delete()
Carlos Lopez a09598
{
Carlos Lopez a09598
	if(!deleting_)
Carlos Lopez a09598
	{
Carlos Lopez a09598
		deleting_=true; signal_deleted()();
Carlos Lopez a09598
	}
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
Carlos Lopez a09598
Node::on_changed()
Carlos Lopez a09598
{
Nikita Kitaev dc5e35
	if (getenv("SYNFIG_DEBUG_ON_CHANGED"))
Nikita Kitaev dc5e35
	{
Carlos López 9608fb
		printf("%s:%d Node::on_changed() for %lx (%s); signalling these %zd parents:\n", __FILE__, __LINE__, uintptr_t(this), get_string().c_str(), parent_set.size());
Carlos López 9608fb
		for (set<node*>::iterator iter = parent_set.begin(); iter != parent_set.end(); iter++) printf(" %lx (%s)\n", uintptr_t(*iter), (*iter)->get_string().c_str());</node*>
Nikita Kitaev dc5e35
		printf("\n");
Nikita Kitaev dc5e35
	}
Nikita Kitaev dc5e35
Carlos Lopez a09598
	bchanged = true;
Carlos Lopez a09598
	signal_changed()();
Carlos Lopez a09598
Carlos Lopez a09598
	std::set<node*>::iterator iter;</node*>
Carlos Lopez a09598
	for(iter=parent_set.begin();iter!=parent_set.end();++iter)
Carlos Lopez a09598
	{
eef648
		(*iter)->child_changed(this);
Carlos Lopez a09598
	}
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
void
eef648
Node::on_child_changed(const Node *x)
eef648
{
eef648
	signal_child_changed()(x);
eef648
	changed();
eef648
}
eef648
eef648
void
Carlos Lopez a09598
Node::on_guid_changed(synfig::GUID guid)
Carlos Lopez a09598
{
Carlos Lopez a09598
	signal_guid_changed()(guid);
Carlos Lopez a09598
}