Remove ancient trunk folder from svn repository
[synfig.git] / synfig-core / src / synfig / node.cpp
diff --git a/synfig-core/src/synfig/node.cpp b/synfig-core/src/synfig/node.cpp
new file mode 100644 (file)
index 0000000..6524109
--- /dev/null
@@ -0,0 +1,310 @@
+/* === S Y N F I G ========================================================= */
+/*!    \file node.cpp
+**     \brief Template File
+**
+**     $Id$
+**
+**     \legal
+**     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+**     Copyright (c) 2007, 2008 Chris Moore
+**
+**     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 "node.h"
+// #include "nodebase.h"               // this defines a bunch of sigc::slots that are never used
+
+#ifdef HASH_MAP_H
+#include HASH_MAP_H
+#else
+#include <map>
+#endif
+
+#endif
+
+/* === U S I N G =========================================================== */
+
+using namespace std;
+using namespace etl;
+using namespace synfig;
+
+/* === M A C R O S ========================================================= */
+
+// About BE_FRUGAL_WITH_GUIDS
+// If this macro is set, then a GUID will NOT
+// be calculated until the first call to get_guid()
+// This also means that the node doesn't get
+// added to the database until get_guid() is called
+// for the first time, or set_guid() is called.
+// If it is expensive to calculate GUIDs, then
+// this can improve performance a tad in
+// some cases. Otherwise, it doesn't change
+// much of anything.
+#define BE_FRUGAL_WITH_GUIDS 1
+
+#ifndef __sys_clock
+#ifndef _WIN32
+# include <time.h>
+# define __sys_clock   ::clock
+#else
+# ifdef __GNUG__
+#  include <time.h>
+#  define __sys_clock  ::clock
+# else
+typedef int clock_t;
+extern clock_t _clock();
+#  define CLOCKS_PER_SEC 1000
+#  define __sys_clock  _clock
+# endif
+#endif
+#endif
+
+/* === G L O B A L S ======================================================= */
+
+#ifdef HASH_MAP_H
+typedef HASH_MAP_CLASS<synfig::GUID,Node*,GUIDHash> GlobalNodeMap;
+#else
+typedef map<synfig::GUID,Node*> GlobalNodeMap;
+#endif
+
+static GlobalNodeMap* global_node_map_;
+
+static GlobalNodeMap& global_node_map()
+{
+       if(!global_node_map_)
+               global_node_map_=new GlobalNodeMap;
+       return *global_node_map_;
+}
+
+/* === P R O C E D U R E S ================================================= */
+
+synfig::Node*
+synfig::find_node(const synfig::GUID& guid)
+{
+       if(global_node_map().count(guid)==0)
+               return 0;
+       return global_node_map()[guid];
+}
+
+static void
+refresh_node(synfig::Node* node, synfig::GUID old_guid)
+{
+       assert(global_node_map().count(old_guid));
+       global_node_map().erase(old_guid);
+       assert(!global_node_map().count(old_guid));
+       global_node_map()[node->get_guid()]=node;
+}
+
+/* === M E T H O D S ======================================================= */
+
+#ifdef _DEBUG
+const char *
+TimePoint::c_str()const
+{
+       return get_time().get_string().c_str();
+}
+#endif
+
+void
+TimePoint::absorb(const TimePoint& x)
+{
+       if(get_guid()==x.get_guid())
+               return;
+       set_guid(get_guid()^x.get_guid());
+
+       if(get_after()==INTERPOLATION_NIL)
+               set_after(x.get_after());
+       if(get_before()==INTERPOLATION_NIL)
+               set_before(x.get_before());
+
+       if(get_after()!=x.get_after() && x.get_after()!=INTERPOLATION_NIL)
+               set_after(INTERPOLATION_UNDEFINED);
+       if(get_before()!=x.get_before() && x.get_before()!=INTERPOLATION_NIL)
+               set_before(INTERPOLATION_UNDEFINED);
+}
+
+TimePointSet::iterator
+TimePointSet::insert(const TimePoint& x)
+{
+       iterator iter(find(x));
+       if(iter!=end())
+       {
+               const_cast<TimePoint&>(*iter).absorb(x);
+               return iter;
+       }
+       return std::set<TimePoint>::insert(x).first;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Node::Node():
+       guid_(0),
+       bchanged(true),
+       time_last_changed_(__sys_clock()),
+       deleting_(false)
+{
+#ifndef BE_FRUGAL_WITH_GUIDS
+       guid_.make_unique();
+       assert(guid_);
+       assert(!global_node_map().count(guid_));
+       global_node_map()[guid_]=this;
+#endif
+}
+
+Node::~Node()
+{
+       begin_delete();
+
+       if(guid_)
+       {
+               assert(global_node_map().count(guid_));
+               global_node_map().erase(guid_);
+               assert(!global_node_map().count(guid_));
+       }
+}
+
+void
+Node::changed()
+{
+       time_last_changed_=__sys_clock();
+       on_changed();
+}
+
+
+//! Gets the GUID for this value node
+const synfig::GUID&
+Node::get_guid()const
+{
+#ifdef BE_FRUGAL_WITH_GUIDS
+       if(!guid_)
+       {
+               const_cast<synfig::GUID&>(guid_).make_unique();
+               assert(guid_);
+               assert(!global_node_map().count(guid_));
+               global_node_map()[guid_]=const_cast<Node*>(this);
+       }
+#endif
+
+       return guid_;
+}
+
+//! Sets the GUID for this value node
+void
+Node::set_guid(const synfig::GUID& x)
+{
+       assert(x);
+
+#ifdef BE_FRUGAL_WITH_GUIDS
+       if(!guid_)
+       {
+               guid_=x;
+               assert(!global_node_map().count(guid_));
+               global_node_map()[guid_]=this;
+       }
+       else
+#endif
+       if(guid_!=x)
+       {
+               synfig::GUID oldguid(guid_);
+               guid_=x;
+               refresh_node(this, oldguid);
+               on_guid_changed(oldguid);
+       }
+}
+
+int
+Node::get_time_last_changed()const
+{
+       return time_last_changed_;
+}
+
+void
+Node::add_child(Node*x)
+{
+       x->parent_set.insert(this);
+}
+
+void
+Node::remove_child(Node*x)
+{
+       if(x->parent_set.count(this)) x->parent_set.erase(this);
+}
+
+int
+Node::parent_count()const
+{
+       return parent_set.size();
+}
+
+const Node::time_set &
+Node::get_times() const
+{
+       if(bchanged)
+       {
+               times.clear();
+               get_times_vfunc(times);
+               bchanged = false;
+       }
+
+       //set the output set...
+       return times;
+}
+
+void
+Node::begin_delete()
+{
+       if(!deleting_)
+       {
+               deleting_=true; signal_deleted()();
+       }
+}
+
+void
+Node::on_changed()
+{
+       bchanged = true;
+       signal_changed()();
+
+       std::set<Node*>::iterator iter;
+       for(iter=parent_set.begin();iter!=parent_set.end();++iter)
+       {
+               (*iter)->changed();
+       }
+}
+
+void
+Node::on_guid_changed(synfig::GUID guid)
+{
+       signal_guid_changed()(guid);
+}