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, 2008 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 "loadcanvas.h"
43 #include <sigc++/bind.h>
47 using namespace synfig;
51 namespace synfig { extern Canvas::Handle open_canvas(const String &filename, String &errors, String &warnings); };
53 /* === M A C R O S ========================================================= */
55 #define ALLOW_CLONE_NON_INLINE_CANVASES
63 synfig::error("%d canvases not yet deleted!",counter);
67 int _CanvasCounter::counter(0);
69 /* === G L O B A L S ======================================================= */
71 /* === P R O C E D U R E S ================================================= */
73 /* === M E T H O D S ======================================================= */
75 Canvas::Canvas(const String &id):
77 version_ (CURRENT_CANVAS_VERSION),
83 _CanvasCounter::counter++;
96 // we were having a crash where pastecanvas layers were still
97 // refering to a canvas after it had been destroyed; this code
98 // will stop the pastecanvas layers from refering to the canvas
99 // before the canvas is destroyed
101 // the set_sub_canvas(0) ends up deleting the parent-child link,
102 // which deletes the current element from the set we're iterating
103 // through, so we have to make sure we've incremented the iterator
104 // before we mess with the pastecanvas
105 std::set<Node*>::iterator iter = parent_set.begin();
106 while (iter != parent_set.end())
108 Layer_PasteCanvas* paste_canvas = dynamic_cast<Layer_PasteCanvas*>(*iter);
111 paste_canvas->set_sub_canvas(0);
113 warning("destroyed canvas has a parent that is not a pastecanvas - please report if repeatable");
116 //if(is_inline() && parent_) assert(0);
117 _CanvasCounter::counter--;
125 return CanvasBase::end()-1;
128 Canvas::const_iterator
131 return CanvasBase::end()-1;
134 Canvas::reverse_iterator
137 return CanvasBase::rbegin()+1;
140 Canvas::const_reverse_iterator
141 Canvas::rbegin()const
143 return CanvasBase::rbegin()+1;
149 return CanvasBase::size()-1;
157 Layer::Handle layer(front());
158 //if(layer->count()>2)synfig::info("before layer->count()=%d",layer->count());
161 //if(layer->count()>1)synfig::info("after layer->count()=%d",layer->count());
163 //CanvasBase::clear();
165 // We need to keep a blank handle at the
166 // end of the image list, and acts at
167 // the bottom. Without it, the layers
168 // would just continue going when polled
170 CanvasBase::push_back(Layer::Handle());
178 return CanvasBase::size()<=1;
184 return *(CanvasBase::end()-1);
187 const Layer::Handle &
190 return *(CanvasBase::end()-1);
194 Canvas::get_context()const
199 const ValueNodeList &
200 Canvas::value_node_list()const
202 if(is_inline() && parent_)
203 return parent_->value_node_list();
204 return value_node_list_;
208 Canvas::keyframe_list()
210 if(is_inline() && parent_)
211 return parent_->keyframe_list();
212 return keyframe_list_;
216 Canvas::keyframe_list()const
218 if(is_inline() && parent_)
219 return parent_->keyframe_list();
220 return keyframe_list_;
224 Canvas::find_layer(const Point &pos)
226 return get_context().hit_check(pos);
230 valid_id(const String &x)
232 static const char bad_chars[]=" :#@$^&()*";
235 if(!x.empty() && x[0]>='0' && x[0]<='9')
238 for(i=0;i<sizeof(bad_chars);i++)
239 if(x.find_first_of(bad_chars[i])!=string::npos)
246 Canvas::set_id(const String &x)
248 if(is_inline() && parent_)
249 throw runtime_error("Inline Canvas cannot have an ID");
252 throw runtime_error("Invalid ID");
254 signal_id_changed_();
258 Canvas::set_name(const String &x)
261 signal_meta_data_changed()("name");
262 signal_meta_data_changed("name")();
266 Canvas::set_author(const String &x)
269 signal_meta_data_changed()("author");
270 signal_meta_data_changed("author")();
274 Canvas::set_description(const String &x)
277 signal_meta_data_changed()("description");
278 signal_meta_data_changed("description")();
282 Canvas::set_time(Time t)const
284 if(is_dirty_ || !get_time().is_equal(t))
289 synfig::info("is_dirty_=%d",is_dirty_);
290 synfig::info("get_time()=%f",(float)get_time());
291 synfig::info("t=%f",(float)t);
296 const_cast<Canvas&>(*this).cur_time_=t;
299 get_context().set_time(t);
305 Canvas::get_root()const
307 return parent_?parent_->get_root().get():const_cast<synfig::Canvas *>(this);
311 Canvas::get_depth(etl::handle<Layer> layer)const
315 for(iter=begin();iter!=end();++iter,i++)
324 Canvas::get_relative_id(etl::loose_handle<const Canvas> x)const
326 if(x->get_root()==this)
328 if(is_inline() && parent_)
329 return parent_->_get_relative_id(x);
330 return _get_relative_id(x);
334 Canvas::_get_relative_id(etl::loose_handle<const Canvas> x)const
336 if(is_inline() && parent_)
337 return parent_->_get_relative_id(x);
342 if(parent()==x.get())
347 const Canvas* canvas=this;
349 for(;!canvas->is_root();canvas=canvas->parent().get())
350 id=':'+canvas->get_id()+id;
352 if(x && get_root()!=x->get_root())
354 //String file_name=get_file_name();
355 //String file_path=x->get_file_path();
358 if(is_absolute_path(get_file_name()))
359 file_name=etl::relative_path(x->get_file_path(),get_file_name());
361 file_name=get_file_name();
363 // If the path of X is inside of file_name,
365 //if(file_name.size()>file_path.size())
366 // if(file_path==String(file_name,0,file_path.size()))
367 // file_name.erase(0,file_path.size()+1);
376 Canvas::find_value_node(const String &id)
379 ValueNode::Handle::cast_const(
380 const_cast<const Canvas*>(this)->find_value_node(id)
384 ValueNode::ConstHandle
385 Canvas::find_value_node(const String &id)const
387 if(is_inline() && parent_)
388 return parent_->find_value_node(id);
391 throw Exception::IDNotFound("Empty ID");
393 // If we do not have any resolution, then we assume that the
394 // request is for this immediate canvas
395 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
396 return value_node_list_.find(id);
398 String canvas_id(id,0,id.rfind(':'));
399 String value_node_id(id,id.rfind(':')+1);
400 if(canvas_id.empty())
402 //synfig::warning("constfind:value_node_id: "+value_node_id);
403 //synfig::warning("constfind:canvas_id: "+canvas_id);
406 return find_canvas(canvas_id, warnings)->value_node_list_.find(value_node_id);
410 Canvas::surefind_value_node(const String &id)
412 if(is_inline() && parent_)
413 return parent_->surefind_value_node(id);
416 throw Exception::IDNotFound("Empty ID");
418 // If we do not have any resolution, then we assume that the
419 // request is for this immediate canvas
420 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
421 return value_node_list_.surefind(id);
423 String canvas_id(id,0,id.rfind(':'));
424 String value_node_id(id,id.rfind(':')+1);
425 if(canvas_id.empty())
429 return surefind_canvas(canvas_id,warnings)->value_node_list_.surefind(value_node_id);
433 Canvas::add_value_node(ValueNode::Handle x, const String &id)
435 if(is_inline() && parent_)
436 return parent_->add_value_node(x,id);
437 // throw runtime_error("You cannot add a ValueNode to an inline Canvas");
440 throw runtime_error("ValueNode is already exported");
443 throw Exception::BadLinkName("Empty ID");
445 if(id.find_first_of(':',0)!=string::npos)
446 throw Exception::BadLinkName("Bad character");
450 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
451 throw Exception::IDNotFound("add_value_node()");
453 throw Exception::IDAlreadyExists(id);
455 catch(Exception::IDNotFound)
459 x->set_parent_canvas(this);
461 if(!value_node_list_.add(x))
463 synfig::error("Unable to add ValueNode");
464 throw std::runtime_error("Unable to add ValueNode");
473 Canvas::rename_value_node(ValueNode::Handle x, const String &id)
476 throw Exception::BadLinkName("Empty ID");
478 if(id.find_first_of(": ",0)!=string::npos)
479 throw Exception::BadLinkName("Bad character");
483 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
484 throw Exception::IDNotFound("rename_value_node");
485 throw Exception::IDAlreadyExists(id);
487 catch(Exception::IDNotFound)
497 Canvas::remove_value_node(ValueNode::Handle x)
499 if(is_inline() && parent_)
500 return parent_->remove_value_node(x);
501 // throw Exception::IDNotFound("Canvas::remove_value_node() was called from an inline canvas");
504 throw Exception::IDNotFound("Canvas::remove_value_node() was passed empty handle");
506 if(!value_node_list_.erase(x))
507 throw Exception::IDNotFound("Canvas::remove_value_node(): ValueNode was not found inside of this canvas");
509 //x->set_parent_canvas(0);
515 Canvas::surefind_canvas(const String &id, String &warnings)
517 if(is_inline() && parent_)
518 return parent_->surefind_canvas(id,warnings);
523 // If the ID contains a "#" character, then a filename is
524 // expected on the left side.
525 if(id.find_first_of('#')!=string::npos)
527 // If '#' is the first character, remove it
528 // and attempt to parse the ID again.
530 return surefind_canvas(String(id,1),warnings);
532 //! \todo This needs a lot more optimization
533 String file_name(id,0,id.find_first_of('#'));
534 String external_id(id,id.find_first_of('#')+1);
536 file_name=unix_to_local_path(file_name);
538 Canvas::Handle external_canvas;
540 if(!is_absolute_path(file_name))
541 file_name = get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name;
543 // If the composition is already open, then use it.
544 if(externals_.count(file_name))
545 external_canvas=externals_[file_name];
549 external_canvas=open_canvas(file_name, errors, warnings);
551 throw runtime_error(errors);
552 externals_[file_name]=external_canvas;
555 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id, warnings));
558 // If we do not have any resolution, then we assume that the
559 // request is for this immediate canvas
560 if(id.find_first_of(':')==string::npos)
562 Children::iterator iter;
564 // Search for the image in the image list,
565 // and return it if it is found
566 for(iter=children().begin();iter!=children().end();iter++)
567 if(id==(*iter)->get_id())
570 // Create a new canvas and return it
571 //synfig::warning("Implicitly creating canvas named "+id);
572 return new_child_canvas(id);
575 // If the first character is the separator, then
576 // this references the root canvas.
578 return get_root()->surefind_canvas(string(id,1),warnings);
580 // Now we know that the requested Canvas is in a child
581 // of this canvas. We have to find that canvas and
582 // call "find_canvas" on it, and return the result.
584 String canvas_name=string(id,0,id.find_first_of(':'));
586 Canvas::Handle child_canvas=surefind_canvas(canvas_name,warnings);
588 return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1),warnings);
592 Canvas::find_canvas(const String &id, String &warnings)
595 Canvas::Handle::cast_const(
596 const_cast<const Canvas*>(this)->find_canvas(id, warnings)
601 Canvas::find_canvas(const String &id, String &warnings)const
603 if(is_inline() && parent_)
604 return parent_->find_canvas(id, warnings);
609 // If the ID contains a "#" character, then a filename is
610 // expected on the left side.
611 if(id.find_first_of('#')!=string::npos)
613 // If '#' is the first character, remove it
614 // and attempt to parse the ID again.
616 return find_canvas(String(id,1), warnings);
618 //! \todo This needs a lot more optimization
619 String file_name(id,0,id.find_first_of('#'));
620 String external_id(id,id.find_first_of('#')+1);
622 file_name=unix_to_local_path(file_name);
624 Canvas::Handle external_canvas;
626 if(!is_absolute_path(file_name))
627 file_name = get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name;
629 // If the composition is already open, then use it.
630 if(externals_.count(file_name))
631 external_canvas=externals_[file_name];
634 String errors, warnings;
635 external_canvas=open_canvas(file_name, errors, warnings);
637 throw runtime_error(errors);
638 externals_[file_name]=external_canvas;
641 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id, warnings));
644 // If we do not have any resolution, then we assume that the
645 // request is for this immediate canvas
646 if(id.find_first_of(':')==string::npos)
648 Children::const_iterator iter;
650 // Search for the image in the image list,
651 // and return it if it is found
652 for(iter=children().begin();iter!=children().end();iter++)
653 if(id==(*iter)->get_id())
656 throw Exception::IDNotFound("Child Canvas in Parent Canvas: (child)"+id);
659 // If the first character is the separator, then
660 // this references the root canvas.
662 return get_root()->find_canvas(string(id,1), warnings);
664 // Now we know that the requested Canvas is in a child
665 // of this canvas. We have to find that canvas and
666 // call "find_canvas" on it, and return the result.
668 String canvas_name=string(id,0,id.find_first_of(':'));
670 Canvas::ConstHandle child_canvas=find_canvas(canvas_name, warnings);
672 return child_canvas->find_canvas(string(id,id.find_first_of(':')+1), warnings);
678 return new Canvas("Untitled");
682 Canvas::push_back(etl::handle<Layer> x)
684 // int i(x->count());
686 //if(x->count()!=i+1)synfig::info("push_back before %d, after %d",i,x->count());
690 Canvas::push_front(etl::handle<Layer> x)
692 // int i(x->count());
694 //if(x->count()!=i+1)synfig::error("push_front before %d, after %d",i,x->count());
698 Canvas::insert(iterator iter,etl::handle<Layer> x)
700 // int i(x->count());
701 CanvasBase::insert(iter,x);
703 /*if(x->count()!=i+1)
705 synfig::error(__FILE__":%d: Canvas::insert(): ***FAILURE*** before %d, after %d",__LINE__,i,x->count());
707 //throw runtime_error("Canvas Insertion Failed");
714 LooseHandle correct_canvas(this);
715 //while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
716 Layer::LooseHandle loose_layer(x);
718 add_connection(loose_layer,
719 sigc::connection::connection(
720 x->signal_added_to_group().connect(
724 &Canvas::add_group_pair),
726 add_connection(loose_layer,
727 sigc::connection::connection(
728 x->signal_removed_from_group().connect(
732 &Canvas::remove_group_pair),
735 if(!x->get_group().empty())
736 add_group_pair(x->get_group(),x);
742 Canvas::push_back_simple(etl::handle<Layer> x)
744 CanvasBase::insert(end(),x);
749 Canvas::erase(iterator iter)
751 if(!(*iter)->get_group().empty())
752 remove_group_pair((*iter)->get_group(),(*iter));
754 // HACK: We really shouldn't be wiping
755 // out these signals entirely. We should
756 // only be removing the specific connections
757 // that we made. At the moment, I'm too
758 // lazy to add the code to keep track
759 // of those connections, and no one else
760 // is using these signals, so I'll just
761 // leave these next two lines like they
762 // are for now - darco 07-30-2004
764 // so don't wipe them out entirely
765 // - dooglus 09-21-2007
766 disconnect_connections(*iter);
768 if(!op_flag_)remove_child(iter->get());
770 CanvasBase::erase(iter);
771 if(!op_flag_)changed();
775 Canvas::clone(const GUID& deriv_guid)const
782 name=get_id()+"_CLONE";
784 #ifndef ALLOW_CLONE_NON_INLINE_CANVASES
785 throw runtime_error("Cloning of non-inline canvases is not yet supported");
786 #endif // ALLOW_CLONE_NON_INLINE_CANVASES
789 Handle canvas(new Canvas(name));
793 canvas->is_inline_=true;
794 // \todo this was setting parent_=0 - is there a reason for that?
795 // this was causing bug 1838132, where cloning an inline canvas that contains an imported image fails
796 // it was failing to ascertain the absolute pathname of the imported image, since it needs the pathname
797 // of the canvas to get that, which is stored in the parent canvas
798 canvas->parent_=parent();
799 canvas->rend_desc() = rend_desc();
800 //canvas->set_inline(parent());
803 canvas->set_guid(get_guid()^deriv_guid);
806 for(iter=begin();iter!=end();++iter)
808 Layer::Handle layer((*iter)->clone(deriv_guid));
811 assert(layer.count()==1);
813 canvas->push_back(layer);
814 if(!(layer.count()>1))
816 synfig::error("Canvas::clone(): Cloned layer insertion failure!");
817 synfig::error("Canvas::clone(): \tlayer.count()=%d",layer.count());
818 synfig::error("Canvas::clone(): \tlayer->get_name()=%s",layer->get_name().c_str());
819 synfig::error("Canvas::clone(): \tbefore size()=%d",presize);
820 synfig::error("Canvas::clone(): \tafter size()=%d",size());
822 assert(layer.count()>1);
826 synfig::error("Unable to clone layer");
830 canvas->signal_group_pair_removed().clear();
831 canvas->signal_group_pair_added().clear();
837 Canvas::set_inline(LooseHandle parent)
839 if(is_inline_ && parent_)
848 // Have the parent inherit all of the group stuff
850 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
852 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
854 parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
857 rend_desc()=parent->rend_desc();
861 Canvas::create_inline(Handle parent)
864 //if(parent->is_inline())
865 // return create_inline(parent->parent());
867 Handle canvas(new Canvas("inline"));
868 canvas->set_inline(parent);
873 Canvas::new_child_canvas()
875 if(is_inline() && parent_)
876 return parent_->new_child_canvas();
877 // runtime_error("You cannot create a child Canvas in an inline Canvas");
879 // Create a new canvas
880 children().push_back(create());
881 Canvas::Handle canvas(children().back());
883 canvas->parent_=this;
885 canvas->rend_desc()=rend_desc();
891 Canvas::new_child_canvas(const String &id)
893 if(is_inline() && parent_)
894 return parent_->new_child_canvas(id);
895 // runtime_error("You cannot create a child Canvas in an inline Canvas");
897 // Create a new canvas
898 children().push_back(create());
899 Canvas::Handle canvas(children().back());
902 canvas->parent_=this;
903 canvas->rend_desc()=rend_desc();
909 Canvas::add_child_canvas(Canvas::Handle child_canvas, const synfig::String& id)
911 if(is_inline() && parent_)
912 return parent_->add_child_canvas(child_canvas,id);
914 if(child_canvas->parent() && !child_canvas->is_inline())
915 throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
918 throw runtime_error("Invalid ID");
923 find_canvas(id, warnings);
924 throw Exception::IDAlreadyExists(id);
926 catch(Exception::IDNotFound)
928 if(child_canvas->is_inline())
929 child_canvas->is_inline_=false;
930 child_canvas->id_=id;
931 children().push_back(child_canvas);
932 child_canvas->parent_=this;
939 Canvas::remove_child_canvas(Canvas::Handle child_canvas)
941 if(is_inline() && parent_)
942 return parent_->remove_child_canvas(child_canvas);
944 if(child_canvas->parent_!=this)
945 throw runtime_error("Given child does not belong to me");
947 if(find(children().begin(),children().end(),child_canvas)==children().end())
948 throw Exception::IDNotFound(child_canvas->get_id());
950 children().remove(child_canvas);
952 child_canvas->parent_=0;
956 Canvas::set_file_name(const String &file_name)
959 parent()->set_file_name(file_name);
962 String old_name(file_name_);
963 file_name_=file_name;
965 // when a canvas is made, its name is ""
966 // then, before it's saved or even edited, it gets a name like "Synfig Animation 23", in the local language
967 // we don't want to register the canvas' filename in the canvas map until it gets a real filename
970 file_name_=file_name;
971 std::map<synfig::String, etl::loose_handle<Canvas> >::iterator iter;
972 for(iter=get_open_canvas_map().begin();iter!=get_open_canvas_map().end();++iter)
973 if(iter->second==this)
975 if (iter == get_open_canvas_map().end())
976 CanvasParser::register_canvas_in_map(this, file_name);
978 signal_file_name_changed_();
984 Canvas::signal_file_name_changed()
987 return parent()->signal_file_name_changed();
989 return signal_file_name_changed_;
993 Canvas::get_file_name()const
996 return parent()->get_file_name();
1001 Canvas::get_file_path()const
1004 return parent()->get_file_path();
1005 return dirname(file_name_);
1009 Canvas::get_meta_data(const String& key)const
1011 if(!meta_data_.count(key))
1013 return meta_data_.find(key)->second;
1017 Canvas::set_meta_data(const String& key, const String& data)
1019 if(meta_data_[key]!=data)
1021 meta_data_[key]=data;
1022 signal_meta_data_changed()(key);
1023 signal_meta_data_changed(key)();
1028 Canvas::erase_meta_data(const String& key)
1030 if(meta_data_.count(key))
1032 meta_data_.erase(key);
1033 signal_meta_data_changed()(key);
1034 signal_meta_data_changed(key)();
1039 Canvas::get_meta_data_keys()const
1041 std::list<String> ret;
1043 std::map<String,String>::const_iterator iter;
1045 for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
1046 ret.push_back(iter->first);
1051 /* note - the "Motion Blur" and "Duplicate" layers need the dynamic
1052 parameters of any PasteCanvas layers they loop over to be
1053 maintained. When the variables in the following function
1054 refer to "motion blur", they mean either of these two
1057 synfig::optimize_layers(Time time, Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
1061 std::vector< std::pair<float,Layer::Handle> > sort_list;
1062 int i, motion_blur_i=0; // motion_blur_i is for resolving which layer comes first in the event of a z_depth tie
1063 float motion_blur_z_depth=0; // the z_depth of the least deep motion blur layer in this context
1064 bool seen_motion_blur_locally = false;
1065 bool motion_blurred; // the final result - is this layer blurred or not?
1067 // If the parent didn't cause us to already be motion blurred,
1068 // check whether there's a motion blur in this context,
1069 // and if so, calculate its z_depth.
1070 if (!seen_motion_blur_in_parent)
1071 for(iter=context,i=0;*iter;iter++,i++)
1073 Layer::Handle layer=*iter;
1075 // If the layer isn't active, don't worry about it
1076 if(!layer->active())
1079 // Any layer with an amount of zero is implicitly disabled.
1080 ValueBase value(layer->get_param("amount"));
1081 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1084 if(layer->get_name()=="MotionBlur" || layer->get_name()=="duplicate")
1086 float z_depth(layer->get_z_depth()*1.0001+i);
1088 // If we've seen a motion blur before in this context...
1089 if (seen_motion_blur_locally)
1091 // ... then we're only interested in this one if it's less deep...
1092 if (z_depth < motion_blur_z_depth)
1094 motion_blur_z_depth = z_depth;
1098 // ... otherwise we're always interested in it.
1101 motion_blur_z_depth = z_depth;
1103 seen_motion_blur_locally = true;
1108 // Go ahead and start romping through the canvas to paste
1109 for(iter=context,i=0;*iter;iter++,i++)
1111 Layer::Handle layer=*iter;
1112 float z_depth(layer->get_z_depth()*1.0001+i);
1114 // If the layer isn't active, don't worry about it
1115 if(!layer->active())
1118 // Any layer with an amount of zero is implicitly disabled.
1119 ValueBase value(layer->get_param("amount"));
1120 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1123 // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
1124 // time-shifted layers weren't being sorted by z-depth (bug #1806852)
1125 if(layer->get_name()=="PasteCanvas")
1127 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1129 // we need to blur the sub canvas if:
1130 // our parent is blurred,
1131 // or the child is lower than a local blur,
1132 // or the child is at the same z_depth as a local blur, but later in the context
1135 if (seen_motion_blur_in_parent) synfig::info("seen BLUR in parent\n");
1136 else if (seen_motion_blur_locally)
1137 if (z_depth > motion_blur_z_depth) synfig::info("paste is deeper than BLUR\n");
1138 else if (z_depth == motion_blur_z_depth) { synfig::info("paste is same depth as BLUR\n");
1139 if (i > motion_blur_i) synfig::info("paste is physically deeper than BLUR\n");
1140 else synfig::info("paste is less physically deep than BLUR\n");
1141 } else synfig::info("paste is less deep than BLUR\n");
1142 else synfig::info("no BLUR at all\n");
1145 motion_blurred = (seen_motion_blur_in_parent ||
1146 (seen_motion_blur_locally &&
1147 (z_depth > motion_blur_z_depth ||
1148 (z_depth == motion_blur_z_depth && i > motion_blur_i))));
1150 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1151 Canvas::Handle paste_sub_canvas = paste_canvas->get_sub_canvas();
1152 if(paste_sub_canvas)
1153 optimize_layers(time, paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
1155 // \todo: uncommenting the following breaks the rendering of at least examples/backdrop.sifz quite severely
1156 // #define SYNFIG_OPTIMIZE_PASTE_CANVAS
1157 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
1158 Canvas::iterator sub_iter;
1160 // Determine if we can just remove the paste canvas altogether
1161 if (paste_canvas->get_blend_method() == Color::BLEND_COMPOSITE &&
1162 paste_canvas->get_amount() == 1.0f &&
1163 paste_canvas->get_zoom() == 0 &&
1164 paste_canvas->get_time_offset() == 0 &&
1165 paste_canvas->get_origin() == Point(0,0) )
1167 for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1169 Layer* layer=sub_iter->get();
1171 // any layers that deform end up breaking things
1172 // so do things the old way if we run into anything like this
1173 if(!dynamic_cast<Layer_NoDeform*>(layer))
1176 ValueBase value(layer->get_param("blend_method"));
1177 if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1181 // It has turned out that we don't need a paste canvas
1182 // layer, so just go ahead and add all the layers onto
1183 // the current stack and be done with it
1184 while(sub_canvas->size())
1186 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,sub_canvas->front()));
1187 //op_canvas->push_back_simple(sub_canvas->front());
1188 sub_canvas->pop_front();
1194 #endif // SYNFIG_OPTIMIZE_PASTE_CANVAS
1196 Layer::Handle new_layer(Layer::create("PasteCanvas"));
1197 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(false);
1200 Layer::DynamicParamList dynamic_param_list(paste_canvas->dynamic_param_list());
1201 for(Layer::DynamicParamList::const_iterator iter(dynamic_param_list.begin()); iter != dynamic_param_list.end(); ++iter)
1202 new_layer->connect_dynamic_param(iter->first, iter->second);
1204 Layer::ParamList param_list(paste_canvas->get_param_list());
1205 //param_list.erase("canvas");
1206 new_layer->set_param_list(param_list);
1207 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_sub_canvas(sub_canvas);
1208 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
1211 else // not a PasteCanvas - does it use blend method 'Straight'?
1213 /* when we use the 'straight' blend method, every pixel on the layer affects the layers underneath,
1214 * not just the non-transparent pixels; the following workarea wraps non-pastecanvas layers in a
1215 * new pastecanvas to ensure that the straight blend affects the full plane, not just the area
1216 * within the layer's bounding box
1219 // \todo: this code probably needs modification to work properly with motionblur and duplicate
1220 etl::handle<Layer_Composite> composite = etl::handle<Layer_Composite>::cast_dynamic(layer);
1222 /* some layers (such as circle) don't touch pixels that aren't
1223 * part of the circle, so they don't get blended correctly when
1224 * using a straight blend. so we encapsulate the circle, and the
1225 * encapsulation layer takes care of the transparent pixels
1226 * for us. if we do that for all layers, however, then the
1227 * distortion layers no longer work, since they have no
1228 * context to work on. the Layer::reads_context() method
1229 * returns true for layers which need to be able to see
1230 * their context. we can't encapsulate those.
1233 Color::is_straight(composite->get_blend_method()) &&
1234 !composite->reads_context())
1236 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1237 // don't use clone() because it re-randomizes the seeds of any random valuenodes
1238 sub_canvas->push_back(composite = composite->simple_clone());
1239 layer = Layer::create("PasteCanvas");
1240 composite->set_description(strprintf("Wrapped clone of '%s'", composite->get_non_empty_description().c_str()));
1241 layer->set_description(strprintf("PasteCanvas wrapper for '%s'", composite->get_non_empty_description().c_str()));
1242 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1243 paste_canvas->set_blend_method(composite->get_blend_method());
1244 paste_canvas->set_amount(composite->get_amount());
1245 sub_canvas->set_time(time); // region and outline don't calculate their bounding rects until their time is set
1246 composite->set_blend_method(Color::BLEND_STRAIGHT); // do this before calling set_sub_canvas(), but after set_time()
1247 composite->set_amount(1.0f); // after set_time()
1248 paste_canvas->set_sub_canvas(sub_canvas);
1252 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1253 //op_canvas->push_back_simple(layer);
1257 stable_sort(sort_list.begin(),sort_list.end());
1258 std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
1259 for(iter2=sort_list.begin();iter2!=sort_list.end();++iter2)
1260 op_canvas->push_back_simple(iter2->second);
1261 op_canvas->op_flag_=true;
1265 Canvas::get_times_vfunc(Node::time_set &set) const
1267 const_iterator i = begin(),
1270 for(; i != iend; ++i)
1272 const Node::time_set &tset = (*i)->get_times();
1273 set.insert(tset.begin(),tset.end());
1277 std::set<etl::handle<Layer> >
1278 Canvas::get_layers_in_group(const String&group)
1280 if(is_inline() && parent_)
1281 return parent_->get_layers_in_group(group);
1283 if(group_db_.count(group)==0)
1284 return std::set<etl::handle<Layer> >();
1285 return group_db_.find(group)->second;
1289 Canvas::get_groups()const
1291 if(is_inline() && parent_)
1292 return parent_->get_groups();
1294 std::set<String> ret;
1295 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
1296 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
1297 ret.insert(iter->first);
1302 Canvas::get_group_count()const
1304 if(is_inline() && parent_)
1305 return parent_->get_group_count();
1307 return group_db_.size();
1311 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1313 group_db_[group].insert(layer);
1314 if(group_db_[group].size()==1)
1315 signal_group_added()(group);
1317 signal_group_changed()(group);
1319 signal_group_pair_added()(group,layer);
1321 if(is_inline() && parent_)
1322 return parent_->add_group_pair(group,layer);
1326 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1328 group_db_[group].erase(layer);
1330 signal_group_pair_removed()(group,layer);
1332 if(group_db_[group].empty())
1334 group_db_.erase(group);
1335 signal_group_removed()(group);
1338 signal_group_changed()(group);
1340 if(is_inline() && parent_)
1341 return parent_->remove_group_pair(group,layer);
1345 Canvas::add_connection(etl::loose_handle<Layer> layer, sigc::connection connection)
1347 connections_[layer].push_back(connection);
1351 Canvas::disconnect_connections(etl::loose_handle<Layer> layer)
1353 std::vector<sigc::connection>::iterator iter;
1354 for(iter=connections_[layer].begin();iter!=connections_[layer].end();++iter)
1356 connections_[layer].clear();
1360 Canvas::rename_group(const String&old_name,const String&new_name)
1362 if(is_inline() && parent_)
1363 return parent_->rename_group(old_name,new_name);
1366 std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
1367 iter=group_db_.find(old_name);
1368 if(iter!=group_db_.end())
1369 for(++iter;iter!=group_db_.end() && iter->first.find(old_name)==0;iter=group_db_.find(old_name),++iter)
1371 String name(iter->first,old_name.size(),String::npos);
1373 rename_group(iter->first,name);
1377 std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1378 std::set<etl::handle<Layer> >::iterator iter;
1380 for(iter=layers.begin();iter!=layers.end();++iter)
1382 (*iter)->remove_from_group(old_name);
1383 (*iter)->add_to_group(new_name);
1388 Canvas::register_external_canvas(String file_name, Handle canvas)
1390 if(!is_absolute_path(file_name)) file_name = get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name;
1391 externals_[file_name] = canvas;
1396 Canvas::show_externals(String file, int line, String text) const
1398 printf(" .----- (externals for %lx '%s')\n | %s:%d %s\n", ulong(this), get_name().c_str(), file.c_str(), line, text.c_str());
1399 std::map<String, Handle>::iterator iter;
1400 for (iter = externals_.begin(); iter != externals_.end(); iter++)
1402 synfig::String first(iter->first);
1403 etl::loose_handle<Canvas> second(iter->second);
1404 printf(" | %40s : %lx (%d)\n", first.c_str(), ulong(&*second), second->count());
1406 printf(" `-----\n\n");