Removed a bunch more DEBUGPOINT()s.
[synfig.git] / synfig-core / trunk / src / synfig / canvas.cpp
index e98b301..ede9501 100644 (file)
@@ -6,6 +6,7 @@
 **
 **     \legal
 **     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+**     Copyright (c) 2007 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
@@ -68,8 +69,9 @@ int _CanvasCounter::counter(0);
 
 /* === M E T H O D S ======================================================= */
 
-Canvas::Canvas(const string &id):
+Canvas::Canvas(const String &id):
        id_                     (id),
+       version_        (CURRENT_CANVAS_VERSION),
        cur_time_       (0),
        is_inline_      (false),
        is_dirty_       (true),
@@ -90,7 +92,6 @@ Canvas::~Canvas()
 {
        //if(is_inline() && parent_) assert(0);
        _CanvasCounter::counter--;
-       //DEBUGPOINT();
        clear();
        begin_delete();
 }
@@ -411,7 +412,6 @@ Canvas::add_value_node(ValueNode::Handle x, const String &id)
                return parent_->add_value_node(x,id);
 //             throw runtime_error("You cannot add a ValueNode to an inline Canvas");
 
-       //DEBUGPOINT();
        if(x->is_exported())
                throw runtime_error("ValueNode is already exported");
 
@@ -423,16 +423,13 @@ Canvas::add_value_node(ValueNode::Handle x, const String &id)
 
        try
        {
-               //DEBUGPOINT();
                if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
                        throw Exception::IDNotFound("add_value_node()");
 
-               //DEBUGPOINT();
                throw Exception::IDAlreadyExists(id);
        }
        catch(Exception::IDNotFound)
        {
-               //DEBUGPOINT();
                x->set_id(id);
 
                x->set_parent_canvas(this);
@@ -442,7 +439,6 @@ Canvas::add_value_node(ValueNode::Handle x, const String &id)
                        synfig::error("Unable to add ValueNode");
                        throw std::runtime_error("Unable to add ValueNode");
                }
-               //DEBUGPOINT();
 
                return;
        }
@@ -662,7 +658,6 @@ Canvas::create()
 void
 Canvas::push_back(etl::handle<Layer> x)
 {
-//     DEBUGPOINT();
 //     int i(x->count());
        insert(end(),x);
        //if(x->count()!=i+1)synfig::info("push_back before %d, after %d",i,x->count());
@@ -671,7 +666,6 @@ Canvas::push_back(etl::handle<Layer> x)
 void
 Canvas::push_front(etl::handle<Layer> x)
 {
-//     DEBUGPOINT();
 //     int i(x->count());
        insert(begin(),x);
        //if(x->count()!=i+1)synfig::error("push_front before %d, after %d",i,x->count());
@@ -700,24 +694,22 @@ Canvas::insert(iterator iter,etl::handle<Layer> x)
        //while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
        Layer::LooseHandle loose_layer(x);
 
-       x->signal_added_to_group().connect(
-               sigc::bind(
-                       sigc::mem_fun(
-                               *correct_canvas,
-                               &Canvas::add_group_pair
-                       ),
-                       loose_layer
-               )
-       );
-       x->signal_removed_from_group().connect(
-               sigc::bind(
-                       sigc::mem_fun(
-                               *correct_canvas,
-                               &Canvas::remove_group_pair
-                       ),
-                       loose_layer
-               )
-       );
+       add_connection(loose_layer,
+                                  sigc::connection::connection(
+                                          x->signal_added_to_group().connect(
+                                                  sigc::bind(
+                                                          sigc::mem_fun(
+                                                                  *correct_canvas,
+                                                                  &Canvas::add_group_pair),
+                                                          loose_layer))));
+       add_connection(loose_layer,
+                                  sigc::connection::connection(
+                                          x->signal_removed_from_group().connect(
+                                                  sigc::bind(
+                                                          sigc::mem_fun(
+                                                                  *correct_canvas,
+                                                                  &Canvas::remove_group_pair),
+                                                          loose_layer))));
 
 
        if(!x->get_group().empty())
@@ -735,7 +727,7 @@ Canvas::push_back_simple(etl::handle<Layer> x)
 }
 
 void
-Canvas::erase(Canvas::iterator iter)
+Canvas::erase(iterator iter)
 {
        if(!(*iter)->get_group().empty())
                remove_group_pair((*iter)->get_group(),(*iter));
@@ -749,8 +741,10 @@ Canvas::erase(Canvas::iterator iter)
        // is using these signals, so I'll just
        // leave these next two lines like they
        // are for now - darco 07-30-2004
-       (*iter)->signal_added_to_group().clear();
-       (*iter)->signal_removed_from_group().clear();
+
+       // so don't wipe them out entirely
+       // - dooglus 09-21-2007
+       disconnect_connections(*iter);
 
        if(!op_flag_)remove_child(iter->get());
 
@@ -768,7 +762,7 @@ Canvas::clone(const GUID& deriv_guid)const
        {
                name=get_id()+"_CLONE";
 
-               throw runtime_error("Cloning of non-inline canvases is not yet suported");
+               throw runtime_error("Cloning of non-inline canvases is not yet supported");
        }
 
        Handle canvas(new Canvas(name));
@@ -776,7 +770,11 @@ Canvas::clone(const GUID& deriv_guid)const
        if(is_inline())
        {
                canvas->is_inline_=true;
-               canvas->parent_=0;
+               // \todo this was setting parent_=0 - is there a reason for that?
+               // this was causing bug 1838132, where cloning an inline canvas that contains an imported image fails
+               // it was failing to ascertain the absolute pathname of the imported image, since it needs the pathname
+               // of the canvas to get that, which is stored in the parent canvas
+               canvas->parent_=parent();
                //canvas->set_inline(parent());
        }
 
@@ -1012,13 +1010,62 @@ Canvas::get_meta_data_keys()const
        return ret;
 }
 
+/* note - the "Motion Blur" and "Duplicate" layers need the dynamic
+                 parameters of any PasteCanvas layers they loop over to be
+                 maintained.  When the variables in the following function
+                 refer to "motion blur", they mean either of these two
+                 layers. */
 void
-synfig::optimize_layers(Context context, Canvas::Handle op_canvas)
+synfig::optimize_layers(Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
 {
        Context iter;
 
        std::vector< std::pair<float,Layer::Handle> > sort_list;
-       int i;
+       int i, motion_blur_i=0; // motion_blur_i is for resolving which layer comes first in the event of a z_depth tie
+       float motion_blur_z_depth=0; // the z_depth of the least deep motion blur layer in this context
+       bool seen_motion_blur_locally = false;
+       bool motion_blurred; // the final result - is this layer blurred or not?
+
+       // If the parent didn't cause us to already be motion blurred,
+       // check whether there's a motion blur in this context,
+       // and if so, calculate its z_depth.
+       if (!seen_motion_blur_in_parent)
+               for(iter=context,i=0;*iter;iter++,i++)
+               {
+                       Layer::Handle layer=*iter;
+
+                       // If the layer isn't active, don't worry about it
+                       if(!layer->active())
+                               continue;
+
+                       // Any layer with an amount of zero is implicitly disabled.
+                       ValueBase value(layer->get_param("amount"));
+                       if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
+                               continue;
+
+                       if(layer->get_name()=="MotionBlur" || layer->get_name()=="duplicate")
+                       {
+                               float z_depth(layer->get_z_depth()*1.0001+i);
+
+                               // If we've seen a motion blur before in this context...
+                               if (seen_motion_blur_locally)
+                               {
+                                       // ... then we're only interested in this one if it's less deep...
+                                       if (z_depth < motion_blur_z_depth)
+                                       {
+                                               motion_blur_z_depth = z_depth;
+                                               motion_blur_i = i;
+                                       }
+                               }
+                               // ... otherwise we're always interested in it.
+                               else
+                               {
+                                       motion_blur_z_depth = z_depth;
+                                       motion_blur_i = i;
+                                       seen_motion_blur_locally = true;
+                               }
+                       }
+               }
 
        // Go ahead and start romping through the canvas to paste
        for(iter=context,i=0;*iter;iter++,i++)
@@ -1036,12 +1083,36 @@ synfig::optimize_layers(Context context, Canvas::Handle op_canvas)
                        continue;
 
                Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
-               if(layer->get_name()=="PasteCanvas" && paste_canvas->get_time_offset()==0)
+
+               // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
+               //               time-shifted layers weren't being sorted by z-depth (bug #1806852)
+               if(layer->get_name()=="PasteCanvas")
                {
+                       // we need to blur the sub canvas if:
+                       // our parent is blurred,
+                       // or the child is lower than a local blur,
+                       // or the child is at the same z_depth as a local blur, but later in the context
+
+#if 0 // DEBUG
+                       if (seen_motion_blur_in_parent)                                 synfig::info("seen BLUR in parent\n");
+                       else if (seen_motion_blur_locally)
+                               if (z_depth > motion_blur_z_depth)                      synfig::info("paste is deeper than BLUR\n");
+                               else if (z_depth == motion_blur_z_depth) {      synfig::info("paste is same depth as BLUR\n");
+                                       if (i > motion_blur_i)                                  synfig::info("paste is physically deeper than BLUR\n");
+                                       else                                                                    synfig::info("paste is less physically deep than BLUR\n");
+                               } else                                                                          synfig::info("paste is less deep than BLUR\n");
+                       else                                                                                    synfig::info("no BLUR at all\n");
+#endif // DEBUG
+
+                       motion_blurred = (seen_motion_blur_in_parent ||
+                                                         (seen_motion_blur_locally &&
+                                                          (z_depth > motion_blur_z_depth ||
+                                                               (z_depth == motion_blur_z_depth && i > motion_blur_i))));
+
                        Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
                        Canvas::Handle paste_sub_canvas = paste_canvas->get_sub_canvas();
                        if(paste_sub_canvas)
-                               optimize_layers(paste_sub_canvas->get_context(),sub_canvas);
+                               optimize_layers(paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
 //#define SYNFIG_OPTIMIZE_PASTE_CANVAS 1
 
 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
@@ -1078,6 +1149,12 @@ synfig::optimize_layers(Context context, Canvas::Handle op_canvas)
 #endif
                        Layer::Handle new_layer(Layer::create("PasteCanvas"));
                        dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(false);
+                       if (motion_blurred)
+                       {
+                               Layer::DynamicParamList dynamic_param_list(paste_canvas->dynamic_param_list());
+                               for(Layer::DynamicParamList::const_iterator iter(dynamic_param_list.begin()); iter != dynamic_param_list.end(); ++iter)
+                                       new_layer->connect_dynamic_param(iter->first, iter->second);
+                       }
                        Layer::ParamList param_list(paste_canvas->get_param_list());
                        //param_list.erase("canvas");
                        new_layer->set_param_list(param_list);
@@ -1179,6 +1256,21 @@ Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
 }
 
 void
+Canvas::add_connection(etl::loose_handle<Layer> layer, sigc::connection connection)
+{
+       connections_[layer].push_back(connection);
+}
+
+void
+Canvas::disconnect_connections(etl::loose_handle<Layer> layer)
+{
+       std::vector<sigc::connection>::iterator iter;
+       for(iter=connections_[layer].begin();iter!=connections_[layer].end();++iter)
+               iter->disconnect();
+       connections_[layer].clear();
+}
+
+void
 Canvas::rename_group(const String&old_name,const String&new_name)
 {
        if(is_inline() && parent_)