1 /* === S Y N F I G ========================================================= */
3 ** \brief Canvas Class Member Definitions
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
26 #define SYNFIG_NO_ANGLE
38 #include "exception.h"
41 #include "layer_pastecanvas.h"
42 #include <sigc++/bind.h>
46 using namespace synfig;
50 namespace synfig { extern Canvas::Handle open_canvas(const String &filename); };
52 /* === M A C R O S ========================================================= */
60 synfig::error("%d canvases not yet deleted!",counter);
64 int _CanvasCounter::counter(0);
66 /* === G L O B A L S ======================================================= */
68 /* === P R O C E D U R E S ================================================= */
70 /* === M E T H O D S ======================================================= */
72 Canvas::Canvas(const String &id):
74 version_ (CURRENT_CANVAS_VERSION),
80 _CanvasCounter::counter++;
93 //if(is_inline() && parent_) assert(0);
94 _CanvasCounter::counter--;
103 return CanvasBase::end()-1;
106 Canvas::const_iterator
109 return CanvasBase::end()-1;
112 Canvas::reverse_iterator
115 return CanvasBase::rbegin()+1;
118 Canvas::const_reverse_iterator
119 Canvas::rbegin()const
121 return CanvasBase::rbegin()+1;
127 return CanvasBase::size()-1;
135 Layer::Handle layer(front());
136 //if(layer->count()>2)synfig::info("before layer->count()=%d",layer->count());
139 //if(layer->count()>1)synfig::info("after layer->count()=%d",layer->count());
141 //CanvasBase::clear();
143 // We need to keep a blank handle at the
144 // end of the image list, and acts at
145 // the bottom. Without it, the layers
146 // would just continue going when polled
148 CanvasBase::push_back(Layer::Handle());
156 return CanvasBase::size()<=1;
162 return *(CanvasBase::end()-1);
165 const Layer::Handle &
168 return *(CanvasBase::end()-1);
172 Canvas::get_context()const
177 const ValueNodeList &
178 Canvas::value_node_list()const
180 if(is_inline() && parent_)
181 return parent_->value_node_list();
182 return value_node_list_;
186 Canvas::keyframe_list()
188 if(is_inline() && parent_)
189 return parent_->keyframe_list();
190 return keyframe_list_;
194 Canvas::keyframe_list()const
196 if(is_inline() && parent_)
197 return parent_->keyframe_list();
198 return keyframe_list_;
202 Canvas::find_layer(const Point &pos)
204 return get_context().hit_check(pos);
208 valid_id(const String &x)
210 static const char bad_chars[]=" :#@$^&()*";
213 if(!x.empty() && x[0]>='0' && x[0]<='9')
216 for(i=0;i<sizeof(bad_chars);i++)
217 if(x.find_first_of(bad_chars[i])!=string::npos)
224 Canvas::set_id(const String &x)
226 if(is_inline() && parent_)
227 throw runtime_error("Inline Canvas cannot have an ID");
230 throw runtime_error("Invalid ID");
232 signal_id_changed_();
236 Canvas::set_name(const String &x)
239 signal_meta_data_changed()("name");
240 signal_meta_data_changed("name")();
244 Canvas::set_author(const String &x)
247 signal_meta_data_changed()("author");
248 signal_meta_data_changed("author")();
252 Canvas::set_description(const String &x)
255 signal_meta_data_changed()("description");
256 signal_meta_data_changed("description")();
260 Canvas::set_time(Time t)const
262 if(is_dirty_ || !get_time().is_equal(t))
267 synfig::info("is_dirty_=%d",is_dirty_);
268 synfig::info("get_time()=%f",(float)get_time());
269 synfig::info("t=%f",(float)t);
274 const_cast<Canvas&>(*this).cur_time_=t;
277 get_context().set_time(t);
283 Canvas::get_root()const
285 return parent_?parent_->get_root().get():const_cast<synfig::Canvas *>(this);
289 Canvas::get_depth(etl::handle<Layer> layer)const
293 for(iter=begin();iter!=end();++iter,i++)
302 Canvas::get_relative_id(etl::loose_handle<const Canvas> x)const
304 if(x->get_root()==this)
306 if(is_inline() && parent_)
307 return parent_->_get_relative_id(x);
308 return _get_relative_id(x);
312 Canvas::_get_relative_id(etl::loose_handle<const Canvas> x)const
314 if(is_inline() && parent_)
315 return parent_->_get_relative_id(x);
320 if(parent()==x.get())
325 const Canvas* canvas=this;
327 for(;!canvas->is_root();canvas=canvas->parent().get())
328 id=':'+canvas->get_id()+id;
330 if(x && get_root()!=x->get_root())
332 //String file_name=get_file_name();
333 //String file_path=x->get_file_path();
336 if(is_absolute_path(get_file_name()))
337 file_name=etl::relative_path(x->get_file_path(),get_file_name());
339 file_name=get_file_name();
341 // If the path of X is inside of file_name,
343 //if(file_name.size()>file_path.size())
344 // if(file_path==String(file_name,0,file_path.size()))
345 // file_name.erase(0,file_path.size()+1);
355 Canvas::find_value_node(const String &id)
358 ValueNode::Handle::cast_const(
359 const_cast<const Canvas*>(this)->find_value_node(id)
363 ValueNode::ConstHandle
364 Canvas::find_value_node(const String &id)const
366 if(is_inline() && parent_)
367 return parent_->find_value_node(id);
370 throw Exception::IDNotFound("Empty ID");
372 // If we do not have any resolution, then we assume that the
373 // request is for this immediate canvas
374 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
375 return value_node_list_.find(id);
377 String canvas_id(id,0,id.rfind(':'));
378 String value_node_id(id,id.rfind(':')+1);
379 if(canvas_id.empty())
381 //synfig::warning("constfind:value_node_id: "+value_node_id);
382 //synfig::warning("constfind:canvas_id: "+canvas_id);
384 return find_canvas(canvas_id)->value_node_list_.find(value_node_id);
388 Canvas::surefind_value_node(const String &id)
390 if(is_inline() && parent_)
391 return parent_->surefind_value_node(id);
394 throw Exception::IDNotFound("Empty ID");
396 // If we do not have any resolution, then we assume that the
397 // request is for this immediate canvas
398 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
399 return value_node_list_.surefind(id);
401 String canvas_id(id,0,id.rfind(':'));
402 String value_node_id(id,id.rfind(':')+1);
403 if(canvas_id.empty())
406 return surefind_canvas(canvas_id)->value_node_list_.surefind(value_node_id);
410 Canvas::add_value_node(ValueNode::Handle x, const String &id)
412 if(is_inline() && parent_)
413 return parent_->add_value_node(x,id);
414 // throw runtime_error("You cannot add a ValueNode to an inline Canvas");
418 throw runtime_error("ValueNode is already exported");
421 throw Exception::BadLinkName("Empty ID");
423 if(id.find_first_of(':',0)!=string::npos)
424 throw Exception::BadLinkName("Bad character");
429 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
430 throw Exception::IDNotFound("add_value_node()");
433 throw Exception::IDAlreadyExists(id);
435 catch(Exception::IDNotFound)
440 x->set_parent_canvas(this);
442 if(!value_node_list_.add(x))
444 synfig::error("Unable to add ValueNode");
445 throw std::runtime_error("Unable to add ValueNode");
455 Canvas::rename_value_node(ValueNode::Handle x, const String &id)
458 throw Exception::BadLinkName("Empty ID");
460 if(id.find_first_of(": ",0)!=string::npos)
461 throw Exception::BadLinkName("Bad character");
465 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
466 throw Exception::IDNotFound("rename_value_node");
467 throw Exception::IDAlreadyExists(id);
469 catch(Exception::IDNotFound)
479 Canvas::remove_value_node(ValueNode::Handle x)
481 if(is_inline() && parent_)
482 return parent_->remove_value_node(x);
483 // throw Exception::IDNotFound("Canvas::remove_value_node() was called from an inline canvas");
486 throw Exception::IDNotFound("Canvas::remove_value_node() was passed empty handle");
488 if(!value_node_list_.erase(x))
489 throw Exception::IDNotFound("Canvas::remove_value_node(): ValueNode was not found inside of this canvas");
491 //x->set_parent_canvas(0);
498 Canvas::surefind_canvas(const String &id)
500 if(is_inline() && parent_)
501 return parent_->surefind_canvas(id);
506 // If the ID contains a "#" character, then a filename is
507 // expected on the left side.
508 if(id.find_first_of('#')!=string::npos)
510 // If '#' is the first character, remove it
511 // and attempt to parse the ID again.
513 return surefind_canvas(String(id,1));
515 //! \todo This needs a lot more optimization
516 String file_name(id,0,id.find_first_of('#'));
517 String external_id(id,id.find_first_of('#')+1);
519 file_name=unix_to_local_path(file_name);
521 Canvas::Handle external_canvas;
523 // If the composition is already open, then use it.
524 if(externals_.count(file_name))
525 external_canvas=externals_[file_name];
528 if(is_absolute_path(file_name))
529 external_canvas=open_canvas(file_name);
531 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
534 throw Exception::FileNotFound(file_name);
535 externals_[file_name]=external_canvas;
538 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
541 // If we do not have any resolution, then we assume that the
542 // request is for this immediate canvas
543 if(id.find_first_of(':')==string::npos)
545 Children::iterator iter;
547 // Search for the image in the image list,
548 // and return it if it is found
549 for(iter=children().begin();iter!=children().end();iter++)
550 if(id==(*iter)->get_id())
553 // Create a new canvas and return it
554 //synfig::warning("Implicitly creating canvas named "+id);
555 return new_child_canvas(id);
558 // If the first character is the separator, then
559 // this references the root canvas.
561 return get_root()->surefind_canvas(string(id,1));
563 // Now we know that the requested Canvas is in a child
564 // of this canvas. We have to find that canvas and
565 // call "find_canvas" on it, and return the result.
567 String canvas_name=string(id,0,id.find_first_of(':'));
569 Canvas::Handle child_canvas=surefind_canvas(canvas_name);
571 return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1));
575 Canvas::find_canvas(const String &id)
578 Canvas::Handle::cast_const(
579 const_cast<const Canvas*>(this)->find_canvas(id)
584 Canvas::find_canvas(const String &id)const
586 if(is_inline() && parent_)return parent_->find_canvas(id);
591 // If the ID contains a "#" character, then a filename is
592 // expected on the left side.
593 if(id.find_first_of('#')!=string::npos)
595 // If '#' is the first character, remove it
596 // and attempt to parse the ID again.
598 return find_canvas(String(id,1));
600 //! \todo This needs a lot more optimization
601 String file_name(id,0,id.find_first_of('#'));
602 String external_id(id,id.find_first_of('#')+1);
604 file_name=unix_to_local_path(file_name);
606 Canvas::Handle external_canvas;
608 // If the composition is already open, then use it.
609 if(externals_.count(file_name))
610 external_canvas=externals_[file_name];
613 if(is_absolute_path(file_name))
614 external_canvas=open_canvas(file_name);
616 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
619 throw Exception::FileNotFound(file_name);
620 externals_[file_name]=external_canvas;
623 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
626 // If we do not have any resolution, then we assume that the
627 // request is for this immediate canvas
628 if(id.find_first_of(':')==string::npos)
630 Children::const_iterator iter;
632 // Search for the image in the image list,
633 // and return it if it is found
634 for(iter=children().begin();iter!=children().end();iter++)
635 if(id==(*iter)->get_id())
638 throw Exception::IDNotFound("Child Canvas in Parent Canvas: (child)"+id);
641 // If the first character is the separator, then
642 // this references the root canvas.
643 if(id.find_first_of(':')==0)
644 return get_root()->find_canvas(string(id,1));
646 // Now we know that the requested Canvas is in a child
647 // of this canvas. We have to find that canvas and
648 // call "find_canvas" on it, and return the result.
650 String canvas_name=string(id,0,id.find_first_of(':'));
652 Canvas::ConstHandle child_canvas=find_canvas(canvas_name);
654 return child_canvas->find_canvas(string(id,id.find_first_of(':')+1));
661 return new Canvas("Untitled");
665 Canvas::push_back(etl::handle<Layer> x)
668 // int i(x->count());
670 //if(x->count()!=i+1)synfig::info("push_back before %d, after %d",i,x->count());
674 Canvas::push_front(etl::handle<Layer> x)
677 // int i(x->count());
679 //if(x->count()!=i+1)synfig::error("push_front before %d, after %d",i,x->count());
683 Canvas::insert(iterator iter,etl::handle<Layer> x)
685 // int i(x->count());
686 CanvasBase::insert(iter,x);
688 /*if(x->count()!=i+1)
690 synfig::error(__FILE__":%d: Canvas::insert(): ***FAILURE*** before %d, after %d",__LINE__,i,x->count());
692 //throw runtime_error("Canvas Insertion Failed");
701 LooseHandle correct_canvas(this);
702 //while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
703 Layer::LooseHandle loose_layer(x);
705 add_connection(loose_layer,
706 sigc::connection::connection(
707 x->signal_added_to_group().connect(
711 &Canvas::add_group_pair),
713 add_connection(loose_layer,
714 sigc::connection::connection(
715 x->signal_removed_from_group().connect(
719 &Canvas::remove_group_pair),
723 if(!x->get_group().empty())
724 add_group_pair(x->get_group(),x);
731 Canvas::push_back_simple(etl::handle<Layer> x)
733 CanvasBase::insert(end(),x);
738 Canvas::erase(iterator iter)
740 if(!(*iter)->get_group().empty())
741 remove_group_pair((*iter)->get_group(),(*iter));
743 // HACK: We really shouldn't be wiping
744 // out these signals entirely. We should
745 // only be removing the specific connections
746 // that we made. At the moment, I'm too
747 // lazy to add the code to keep track
748 // of those connections, and no one else
749 // is using these signals, so I'll just
750 // leave these next two lines like they
751 // are for now - darco 07-30-2004
753 // so don't wipe them out entirely
754 // - dooglus 09-21-2007
755 disconnect_connections(*iter);
757 if(!op_flag_)remove_child(iter->get());
759 CanvasBase::erase(iter);
760 if(!op_flag_)changed();
764 Canvas::clone(const GUID& deriv_guid)const
771 name=get_id()+"_CLONE";
773 throw runtime_error("Cloning of non-inline canvases is not yet supported");
776 Handle canvas(new Canvas(name));
780 canvas->is_inline_=true;
781 // \todo this was setting parent_=0 - is there a reason for that?
782 // this was causing bug 1838132, where cloning an inline canvas that contains an imported image fails
783 // it was failing to ascertain the absolute pathname of the imported image, since it needs the pathname
784 // of the canvas to get that, which is stored in the parent canvas
785 canvas->parent_=parent();
786 //canvas->set_inline(parent());
789 canvas->set_guid(get_guid()^deriv_guid);
792 for(iter=begin();iter!=end();++iter)
794 Layer::Handle layer((*iter)->clone(deriv_guid));
797 assert(layer.count()==1);
799 canvas->push_back(layer);
800 if(!(layer.count()>1))
802 synfig::error("Canvas::clone(): Cloned layer insertion failure!");
803 synfig::error("Canvas::clone(): \tlayer.count()=%d",layer.count());
804 synfig::error("Canvas::clone(): \tlayer->get_name()=%s",layer->get_name().c_str());
805 synfig::error("Canvas::clone(): \tbefore size()=%d",presize);
806 synfig::error("Canvas::clone(): \tafter size()=%d",size());
808 assert(layer.count()>1);
812 synfig::error("Unable to clone layer");
816 canvas->signal_group_pair_removed().clear();
817 canvas->signal_group_pair_added().clear();
823 Canvas::set_inline(LooseHandle parent)
825 if(is_inline_ && parent_)
834 // Have the parent inherit all of the group stuff
836 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
838 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
840 parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
843 rend_desc()=parent->rend_desc();
847 Canvas::create_inline(Handle parent)
850 //if(parent->is_inline())
851 // return create_inline(parent->parent());
853 Handle canvas(new Canvas("inline"));
854 canvas->set_inline(parent);
859 Canvas::new_child_canvas()
861 if(is_inline() && parent_)
862 return parent_->new_child_canvas();
863 // runtime_error("You cannot create a child Canvas in an inline Canvas");
865 // Create a new canvas
866 children().push_back(create());
867 Canvas::Handle canvas(children().back());
869 canvas->parent_=this;
871 canvas->rend_desc()=rend_desc();
877 Canvas::new_child_canvas(const String &id)
879 if(is_inline() && parent_)
880 return parent_->new_child_canvas(id);
881 // runtime_error("You cannot create a child Canvas in an inline Canvas");
883 // Create a new canvas
884 children().push_back(create());
885 Canvas::Handle canvas(children().back());
888 canvas->parent_=this;
889 canvas->rend_desc()=rend_desc();
895 Canvas::add_child_canvas(Canvas::Handle child_canvas, const synfig::String& id)
897 if(is_inline() && parent_)
898 return parent_->add_child_canvas(child_canvas,id);
900 if(child_canvas->parent() && !child_canvas->is_inline())
901 throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
904 throw runtime_error("Invalid ID");
909 throw Exception::IDAlreadyExists(id);
911 catch(Exception::IDNotFound)
913 if(child_canvas->is_inline())
914 child_canvas->is_inline_=false;
915 child_canvas->id_=id;
916 children().push_back(child_canvas);
917 child_canvas->parent_=this;
924 Canvas::remove_child_canvas(Canvas::Handle child_canvas)
926 if(is_inline() && parent_)
927 return parent_->remove_child_canvas(child_canvas);
929 if(child_canvas->parent_!=this)
930 throw runtime_error("Given child does not belong to me");
932 if(find(children().begin(),children().end(),child_canvas)==children().end())
933 throw Exception::IDNotFound(child_canvas->get_id());
935 children().remove(child_canvas);
937 child_canvas->parent_=0;
941 Canvas::set_file_name(const String &file_name)
944 parent()->set_file_name(file_name);
947 file_name_=file_name;
948 signal_file_name_changed_();
953 Canvas::signal_file_name_changed()
956 return signal_file_name_changed();
958 return signal_file_name_changed_;
962 Canvas::get_file_name()const
965 return parent()->get_file_name();
970 Canvas::get_file_path()const
973 return parent()->get_file_path();
974 return dirname(file_name_);
979 Canvas::get_meta_data(const String& key)const
981 if(!meta_data_.count(key))
983 return meta_data_.find(key)->second;
987 Canvas::set_meta_data(const String& key, const String& data)
989 if(meta_data_[key]!=data)
991 meta_data_[key]=data;
992 signal_meta_data_changed()(key);
993 signal_meta_data_changed(key)();
998 Canvas::erase_meta_data(const String& key)
1000 if(meta_data_.count(key))
1002 meta_data_.erase(key);
1003 signal_meta_data_changed()(key);
1004 signal_meta_data_changed(key)();
1009 Canvas::get_meta_data_keys()const
1011 std::list<String> ret;
1013 std::map<String,String>::const_iterator iter;
1015 for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
1016 ret.push_back(iter->first);
1021 /* note - the "Motion Blur" and "Duplicate" layers need the dynamic
1022 parameters of any PasteCanvas layers they loop over to be
1023 maintained. When the variables in the following function
1024 refer to "motion blur", they mean either of these two
1027 synfig::optimize_layers(Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
1031 std::vector< std::pair<float,Layer::Handle> > sort_list;
1032 int i, motion_blur_i=0; // motion_blur_i is for resolving which layer comes first in the event of a z_depth tie
1033 float motion_blur_z_depth=0; // the z_depth of the least deep motion blur layer in this context
1034 bool seen_motion_blur_locally = false;
1035 bool motion_blurred; // the final result - is this layer blurred or not?
1037 // If the parent didn't cause us to already be motion blurred,
1038 // check whether there's a motion blur in this context,
1039 // and if so, calculate its z_depth.
1040 if (!seen_motion_blur_in_parent)
1041 for(iter=context,i=0;*iter;iter++,i++)
1043 Layer::Handle layer=*iter;
1045 // If the layer isn't active, don't worry about it
1046 if(!layer->active())
1049 // Any layer with an amount of zero is implicitly disabled.
1050 ValueBase value(layer->get_param("amount"));
1051 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1054 if(layer->get_name()=="MotionBlur" || layer->get_name()=="duplicate")
1056 float z_depth(layer->get_z_depth()*1.0001+i);
1058 // If we've seen a motion blur before in this context...
1059 if (seen_motion_blur_locally)
1061 // ... then we're only interested in this one if it's less deep...
1062 if (z_depth < motion_blur_z_depth)
1064 motion_blur_z_depth = z_depth;
1068 // ... otherwise we're always interested in it.
1071 motion_blur_z_depth = z_depth;
1073 seen_motion_blur_locally = true;
1078 // Go ahead and start romping through the canvas to paste
1079 for(iter=context,i=0;*iter;iter++,i++)
1081 Layer::Handle layer=*iter;
1082 float z_depth(layer->get_z_depth()*1.0001+i);
1084 // If the layer isn't active, don't worry about it
1085 if(!layer->active())
1088 // Any layer with an amount of zero is implicitly disabled.
1089 ValueBase value(layer->get_param("amount"));
1090 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1093 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1095 // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
1096 // time-shifted layers weren't being sorted by z-depth (bug #1806852)
1097 if(layer->get_name()=="PasteCanvas")
1099 // we need to blur the sub canvas if:
1100 // our parent is blurred,
1101 // or the child is lower than a local blur,
1102 // or the child is at the same z_depth as a local blur, but later in the context
1105 if (seen_motion_blur_in_parent) synfig::info("seen BLUR in parent\n");
1106 else if (seen_motion_blur_locally)
1107 if (z_depth > motion_blur_z_depth) synfig::info("paste is deeper than BLUR\n");
1108 else if (z_depth == motion_blur_z_depth) { synfig::info("paste is same depth as BLUR\n");
1109 if (i > motion_blur_i) synfig::info("paste is physically deeper than BLUR\n");
1110 else synfig::info("paste is less physically deep than BLUR\n");
1111 } else synfig::info("paste is less deep than BLUR\n");
1112 else synfig::info("no BLUR at all\n");
1115 motion_blurred = (seen_motion_blur_in_parent ||
1116 (seen_motion_blur_locally &&
1117 (z_depth > motion_blur_z_depth ||
1118 (z_depth == motion_blur_z_depth && i > motion_blur_i))));
1120 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1121 Canvas::Handle paste_sub_canvas = paste_canvas->get_sub_canvas();
1122 if(paste_sub_canvas)
1123 optimize_layers(paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
1124 //#define SYNFIG_OPTIMIZE_PASTE_CANVAS 1
1126 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
1127 Canvas::iterator sub_iter;
1128 // Determine if we can just remove the paste canvas
1130 if(paste_canvas->get_blend_method()==Color::BLEND_COMPOSITE && paste_canvas->get_amount()==1.0f && paste_canvas->get_zoom()==0 && paste_canvas->get_time_offset()==0 && paste_canvas->get_origin()==Point(0,0))
1132 for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1134 Layer* layer=sub_iter->get();
1136 // any layers that deform end up breaking things
1137 // so do things the old way if we run into anything like this
1138 if(!dynamic_cast<Layer_NoDeform*>(layer))
1141 ValueBase value(layer->get_param("blend_method"));
1142 if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1146 // It has turned out that we don't need a paste canvas
1147 // layer, so just go ahead and add all the layers onto
1148 // the current stack and be done with it
1149 while(sub_canvas->size())
1151 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,sub_canvas->front()));
1152 //op_canvas->push_back_simple(sub_canvas->front());
1153 sub_canvas->pop_front();
1158 Layer::Handle new_layer(Layer::create("PasteCanvas"));
1159 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(false);
1162 Layer::DynamicParamList dynamic_param_list(paste_canvas->dynamic_param_list());
1163 for(Layer::DynamicParamList::const_iterator iter(dynamic_param_list.begin()); iter != dynamic_param_list.end(); ++iter)
1164 new_layer->connect_dynamic_param(iter->first, iter->second);
1166 Layer::ParamList param_list(paste_canvas->get_param_list());
1167 //param_list.erase("canvas");
1168 new_layer->set_param_list(param_list);
1169 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_sub_canvas(sub_canvas);
1170 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
1174 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1175 //op_canvas->push_back_simple(layer);
1179 stable_sort(sort_list.begin(),sort_list.end());
1180 std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
1181 for(iter2=sort_list.begin();iter2!=sort_list.end();++iter2)
1182 op_canvas->push_back_simple(iter2->second);
1183 op_canvas->op_flag_=true;
1187 Canvas::get_times_vfunc(Node::time_set &set) const
1189 const_iterator i = begin(),
1192 for(; i != iend; ++i)
1194 const Node::time_set &tset = (*i)->get_times();
1195 set.insert(tset.begin(),tset.end());
1199 std::set<etl::handle<Layer> >
1200 Canvas::get_layers_in_group(const String&group)
1202 if(is_inline() && parent_)
1203 return parent_->get_layers_in_group(group);
1205 if(group_db_.count(group)==0)
1206 return std::set<etl::handle<Layer> >();
1207 return group_db_.find(group)->second;
1211 Canvas::get_groups()const
1213 if(is_inline() && parent_)
1214 return parent_->get_groups();
1216 std::set<String> ret;
1217 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
1218 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
1219 ret.insert(iter->first);
1224 Canvas::get_group_count()const
1226 if(is_inline() && parent_)
1227 return parent_->get_group_count();
1229 return group_db_.size();
1233 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1235 group_db_[group].insert(layer);
1236 if(group_db_[group].size()==1)
1237 signal_group_added()(group);
1239 signal_group_changed()(group);
1241 signal_group_pair_added()(group,layer);
1243 if(is_inline() && parent_)
1244 return parent_->add_group_pair(group,layer);
1248 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1250 group_db_[group].erase(layer);
1252 signal_group_pair_removed()(group,layer);
1254 if(group_db_[group].empty())
1256 group_db_.erase(group);
1257 signal_group_removed()(group);
1260 signal_group_changed()(group);
1262 if(is_inline() && parent_)
1263 return parent_->remove_group_pair(group,layer);
1267 Canvas::add_connection(etl::loose_handle<Layer> layer, sigc::connection connection)
1269 connections_[layer].push_back(connection);
1273 Canvas::disconnect_connections(etl::loose_handle<Layer> layer)
1275 std::vector<sigc::connection>::iterator iter;
1276 for(iter=connections_[layer].begin();iter!=connections_[layer].end();++iter)
1278 connections_[layer].clear();
1282 Canvas::rename_group(const String&old_name,const String&new_name)
1284 if(is_inline() && parent_)
1285 return parent_->rename_group(old_name,new_name);
1288 std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
1289 iter=group_db_.find(old_name);
1290 if(iter!=group_db_.end())
1291 for(++iter;iter!=group_db_.end() && iter->first.find(old_name)==0;iter=group_db_.find(old_name),++iter)
1293 String name(iter->first,old_name.size(),String::npos);
1295 rename_group(iter->first,name);
1299 std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1300 std::set<etl::handle<Layer> >::iterator iter;
1302 for(iter=layers.begin();iter!=layers.end();++iter)
1304 (*iter)->remove_from_group(old_name);
1305 (*iter)->add_to_group(new_name);