1 /* === S Y N F I G ========================================================= */
3 ** \brief Canvas Class Member Definitions
5 ** $Id: canvas.cpp,v 1.1.1.1 2005/01/04 01:23:14 darco Exp $
8 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
10 ** This software and associated documentation
11 ** are CONFIDENTIAL and PROPRIETARY property of
12 ** the above-mentioned copyright holder.
14 ** You may not copy, print, publish, or in any
15 ** other way distribute this software without
16 ** a prior written agreement with
17 ** the copyright holder.
20 /* ========================================================================= */
22 /* === H E A D E R S ======================================================= */
24 #define SYNFIG_NO_ANGLE
36 #include "exception.h"
39 #include "layer_pastecanvas.h"
40 #include <sigc++/bind.h>
44 using namespace synfig;
48 namespace synfig { extern Canvas::Handle open_canvas(const String &filename); };
50 /* === M A C R O S ========================================================= */
58 synfig::error("%d canvases not yet deleted!",counter);
62 int _CanvasCounter::counter(0);
64 /* === G L O B A L S ======================================================= */
66 /* === P R O C E D U R E S ================================================= */
68 /* === M E T H O D S ======================================================= */
70 Canvas::Canvas(const string &id):
77 _CanvasCounter::counter++;
90 //if(is_inline() && parent_) assert(0);
91 _CanvasCounter::counter--;
100 return CanvasBase::end()-1;
103 Canvas::const_iterator
106 return CanvasBase::end()-1;
109 Canvas::reverse_iterator
112 return CanvasBase::rbegin()+1;
115 Canvas::const_reverse_iterator
116 Canvas::rbegin()const
118 return CanvasBase::rbegin()+1;
124 return CanvasBase::size()-1;
132 Layer::Handle layer(front());
133 //if(layer->count()>2)synfig::info("before layer->count()=%d",layer->count());
136 //if(layer->count()>1)synfig::info("after layer->count()=%d",layer->count());
138 //CanvasBase::clear();
140 // We need to keep a blank handle at the
141 // end of the image list, and acts at
142 // the bottom. Without it, the layers
143 // would just continue going when polled
145 CanvasBase::push_back(Layer::Handle());
153 return CanvasBase::size()<=1;
159 return *(CanvasBase::end()-1);
162 const Layer::Handle &
165 return *(CanvasBase::end()-1);
169 Canvas::get_context()const
174 const ValueNodeList &
175 Canvas::value_node_list()const
177 if(is_inline() && parent_)
178 return parent_->value_node_list();
179 return value_node_list_;
183 Canvas::keyframe_list()
185 if(is_inline() && parent_)
186 return parent_->keyframe_list();
187 return keyframe_list_;
191 Canvas::keyframe_list()const
193 if(is_inline() && parent_)
194 return parent_->keyframe_list();
195 return keyframe_list_;
199 Canvas::find_layer(const Point &pos)
201 return get_context().hit_check(pos);
205 valid_id(const String &x)
207 static const char bad_chars[]=" :#@$^&()*";
210 if(!x.empty() && x[0]>='0' && x[0]<='9')
213 for(i=0;i<sizeof(bad_chars);i++)
214 if(x.find_first_of(bad_chars[i])!=string::npos)
221 Canvas::set_id(const String &x)
223 if(is_inline() && parent_)
224 throw runtime_error("Inline Canvas cannot have an ID");
227 throw runtime_error("Invalid ID");
229 signal_id_changed_();
233 Canvas::set_name(const String &x)
236 signal_meta_data_changed()("name");
237 signal_meta_data_changed("name")();
241 Canvas::set_author(const String &x)
244 signal_meta_data_changed()("author");
245 signal_meta_data_changed("author")();
249 Canvas::set_description(const String &x)
252 signal_meta_data_changed()("description");
253 signal_meta_data_changed("description")();
257 Canvas::set_time(Time t)const
259 if(is_dirty_ || !get_time().is_equal(t))
264 synfig::info("is_dirty_=%d",is_dirty_);
265 synfig::info("get_time()=%f",(float)get_time());
266 synfig::info("t=%f",(float)t);
271 const_cast<Canvas&>(*this).cur_time_=t;
274 get_context().set_time(t);
280 Canvas::get_root()const
282 return parent_?parent_->get_root().get():const_cast<synfig::Canvas *>(this);
286 Canvas::get_depth(etl::handle<Layer> layer)const
290 for(iter=begin();iter!=end();++iter,i++)
299 Canvas::get_relative_id(etl::loose_handle<const Canvas> x)const
301 if(x->get_root()==this)
303 if(is_inline() && parent_)
304 return parent_->_get_relative_id(x);
305 return _get_relative_id(x);
309 Canvas::_get_relative_id(etl::loose_handle<const Canvas> x)const
311 if(is_inline() && parent_)
312 return parent_->_get_relative_id(x);
317 if(parent()==x.get())
322 const Canvas* canvas=this;
324 for(;!canvas->is_root();canvas=canvas->parent().get())
325 id=':'+canvas->get_id()+id;
327 if(x && get_root()!=x->get_root())
329 //String file_name=get_file_name();
330 //String file_path=x->get_file_path();
333 if(is_absolute_path(get_file_name()))
334 file_name=etl::relative_path(x->get_file_path(),get_file_name());
336 file_name=get_file_name();
338 // If the path of X is inside of file_name,
340 //if(file_name.size()>file_path.size())
341 // if(file_path==String(file_name,0,file_path.size()))
342 // file_name.erase(0,file_path.size()+1);
352 Canvas::find_value_node(const String &id)
355 ValueNode::Handle::cast_const(
356 const_cast<const Canvas*>(this)->find_value_node(id)
360 ValueNode::ConstHandle
361 Canvas::find_value_node(const String &id)const
363 if(is_inline() && parent_)
364 return parent_->find_value_node(id);
367 throw Exception::IDNotFound("Empty ID");
369 // If we do not have any resolution, then we assume that the
370 // request is for this immediate canvas
371 if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
372 return value_node_list_.find(id);
374 String canvas_id(id,0,id.rfind(':'));
375 String value_node_id(id,id.rfind(':')+1);
376 if(canvas_id.empty())
378 //synfig::warning("constfind:value_node_id: "+value_node_id);
379 //synfig::warning("constfind:canvas_id: "+canvas_id);
381 return find_canvas(canvas_id)->value_node_list_.find(value_node_id);
385 Canvas::surefind_value_node(const String &id)
387 if(is_inline() && parent_)
388 return parent_->surefind_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_.surefind(id);
398 String canvas_id(id,0,id.rfind(':'));
399 String value_node_id(id,id.rfind(':')+1);
400 if(canvas_id.empty())
403 return surefind_canvas(canvas_id)->value_node_list_.surefind(value_node_id);
407 Canvas::add_value_node(ValueNode::Handle x, const String &id)
409 if(is_inline() && parent_)
410 return parent_->add_value_node(x,id);
411 // throw runtime_error("You cannot add a ValueNode to an inline Canvas");
415 throw runtime_error("ValueNode is already exported");
418 throw Exception::BadLinkName("Empty ID");
420 if(id.find_first_of(':',0)!=string::npos)
421 throw Exception::BadLinkName("Bad character");
426 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
427 throw Exception::IDNotFound("add_value_node()");
430 throw Exception::IDAlreadyExists(id);
432 catch(Exception::IDNotFound)
437 x->set_parent_canvas(this);
439 if(!value_node_list_.add(x))
441 synfig::error("Unable to add ValueNode");
442 throw std::runtime_error("Unable to add ValueNode");
452 Canvas::rename_value_node(ValueNode::Handle x, const String &id)
455 throw Exception::BadLinkName("Empty ID");
457 if(id.find_first_of(": ",0)!=string::npos)
458 throw Exception::BadLinkName("Bad character");
462 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
463 throw Exception::IDNotFound("rename_value_node");
464 throw Exception::IDAlreadyExists(id);
466 catch(Exception::IDNotFound)
476 Canvas::remove_value_node(ValueNode::Handle x)
478 if(is_inline() && parent_)
479 return parent_->remove_value_node(x);
480 // throw Exception::IDNotFound("Canvas::remove_value_node() was called from an inline canvas");
483 throw Exception::IDNotFound("Canvas::remove_value_node() was passed empty handle");
485 if(!value_node_list_.erase(x))
486 throw Exception::IDNotFound("Canvas::remove_value_node(): ValueNode was not found inside of this canvas");
488 //x->set_parent_canvas(0);
495 Canvas::surefind_canvas(const String &id)
497 if(is_inline() && parent_)
498 return parent_->surefind_canvas(id);
503 // If the ID contains a "#" character, then a filename is
504 // expected on the left side.
505 if(id.find_first_of('#')!=string::npos)
507 // If '#' is the first character, remove it
508 // and attempt to parse the ID again.
510 return surefind_canvas(String(id,1));
512 //! \todo This needs alot more optimization
513 String file_name(id,0,id.find_first_of('#'));
514 String external_id(id,id.find_first_of('#')+1);
516 file_name=unix_to_local_path(file_name);
518 Canvas::Handle external_canvas;
520 // If the composition is already open, then use it.
521 if(externals_.count(file_name))
522 external_canvas=externals_[file_name];
525 if(is_absolute_path(file_name))
526 external_canvas=open_canvas(file_name);
528 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPERATOR+file_name);
531 throw Exception::FileNotFound(file_name);
532 externals_[file_name]=external_canvas;
535 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
538 // If we do not have any resolution, then we assume that the
539 // request is for this immediate canvas
540 if(id.find_first_of(':')==string::npos)
542 Children::iterator iter;
544 // Search for the image in the image list,
545 // and return it if it is found
546 for(iter=children().begin();iter!=children().end();iter++)
547 if(id==(*iter)->get_id())
550 // Create a new canvas and return it
551 //synfig::warning("Implicitly creating canvas named "+id);
552 return new_child_canvas(id);
555 // If the first character is the seperator, then
556 // this references the root canvas.
558 return get_root()->surefind_canvas(string(id,1));
560 // Now we know that the requested Canvas is in a child
561 // of this canvas. We have to find that canvas and
562 // call "find_canvas" on it, and return the result.
564 String canvas_name=string(id,0,id.find_first_of(':'));
566 Canvas::Handle child_canvas=surefind_canvas(canvas_name);
568 return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1));
572 Canvas::find_canvas(const String &id)
575 Canvas::Handle::cast_const(
576 const_cast<const Canvas*>(this)->find_canvas(id)
581 Canvas::find_canvas(const String &id)const
583 if(is_inline() && parent_)return parent_->find_canvas(id);
588 // If the ID contains a "#" character, then a filename is
589 // expected on the left side.
590 if(id.find_first_of('#')!=string::npos)
592 // If '#' is the first character, remove it
593 // and attempt to parse the ID again.
595 return find_canvas(String(id,1));
597 //! \todo This needs alot more optimization
598 String file_name(id,0,id.find_first_of('#'));
599 String external_id(id,id.find_first_of('#')+1);
601 file_name=unix_to_local_path(file_name);
603 Canvas::Handle external_canvas;
605 // If the composition is already open, then use it.
606 if(externals_.count(file_name))
607 external_canvas=externals_[file_name];
610 if(is_absolute_path(file_name))
611 external_canvas=open_canvas(file_name);
613 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPERATOR+file_name);
616 throw Exception::FileNotFound(file_name);
617 externals_[file_name]=external_canvas;
620 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
623 // If we do not have any resolution, then we assume that the
624 // request is for this immediate canvas
625 if(id.find_first_of(':')==string::npos)
627 Children::const_iterator iter;
629 // Search for the image in the image list,
630 // and return it if it is found
631 for(iter=children().begin();iter!=children().end();iter++)
632 if(id==(*iter)->get_id())
635 throw Exception::IDNotFound("Child Canvas in Parent Canvas: (child)"+id);
638 // If the first character is the seperator, then
639 // this references the root canvas.
640 if(id.find_first_of(':')==0)
641 return get_root()->find_canvas(string(id,1));
643 // Now we know that the requested Canvas is in a child
644 // of this canvas. We have to find that canvas and
645 // call "find_canvas" on it, and return the result.
647 String canvas_name=string(id,0,id.find_first_of(':'));
649 Canvas::ConstHandle child_canvas=find_canvas(canvas_name);
651 return child_canvas->find_canvas(string(id,id.find_first_of(':')+1));
658 return new Canvas("Untitled");
662 Canvas::push_back(etl::handle<Layer> x)
665 // int i(x->count());
667 //if(x->count()!=i+1)synfig::info("push_back before %d, after %d",i,x->count());
671 Canvas::push_front(etl::handle<Layer> x)
674 // int i(x->count());
676 //if(x->count()!=i+1)synfig::error("push_front before %d, after %d",i,x->count());
680 Canvas::insert(iterator iter,etl::handle<Layer> x)
682 // int i(x->count());
683 CanvasBase::insert(iter,x);
685 /*if(x->count()!=i+1)
687 synfig::error(__FILE__":%d: Canvas::insert(): ***FAILURE*** before %d, after %d",__LINE__,i,x->count());
689 //throw runtime_error("Canvas Insertion Failed");
698 LooseHandle correct_canvas(this);
699 //while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
700 Layer::LooseHandle loose_layer(x);
702 x->signal_added_to_group().connect(
706 &Canvas::add_group_pair
711 x->signal_removed_from_group().connect(
715 &Canvas::remove_group_pair
722 if(!x->get_group().empty())
723 add_group_pair(x->get_group(),x);
730 Canvas::push_back_simple(etl::handle<Layer> x)
732 CanvasBase::insert(end(),x);
737 Canvas::erase(Canvas::iterator iter)
739 if(!(*iter)->get_group().empty())
740 remove_group_pair((*iter)->get_group(),(*iter));
742 // HACK: We really shouldn't be wiping
743 // out these signals entirely. We should
744 // only be removing the specific connections
745 // that we made. At the moment, I'm too
746 // lazy to add the code to keep track
747 // of those connections, and no one else
748 // is using these signals, so I'll just
749 // leave these next two lines like they
750 // are for now - darco 07-30-2004
751 (*iter)->signal_added_to_group().clear();
752 (*iter)->signal_removed_from_group().clear();
754 if(!op_flag_)remove_child(iter->get());
756 CanvasBase::erase(iter);
757 if(!op_flag_)changed();
761 Canvas::clone(const GUID& deriv_guid)const
768 name=get_id()+"_CLONE";
770 throw runtime_error("Cloning of non-inline canvases is not yet suported");
773 Handle canvas(new Canvas(name));
777 canvas->is_inline_=true;
779 //canvas->set_inline(parent());
782 canvas->set_guid(get_guid()^deriv_guid);
785 for(iter=begin();iter!=end();++iter)
787 Layer::Handle layer((*iter)->clone(deriv_guid));
790 assert(layer.count()==1);
792 canvas->push_back(layer);
793 if(!(layer.count()>1))
795 synfig::error("Canvas::clone(): Cloned layer insertion failure!");
796 synfig::error("Canvas::clone(): \tlayer.count()=%d",layer.count());
797 synfig::error("Canvas::clone(): \tlayer->get_name()=%s",layer->get_name().c_str());
798 synfig::error("Canvas::clone(): \tbefore size()=%d",presize);
799 synfig::error("Canvas::clone(): \tafter size()=%d",size());
801 assert(layer.count()>1);
805 synfig::error("Unable to clone layer");
809 canvas->signal_group_pair_removed().clear();
810 canvas->signal_group_pair_added().clear();
816 Canvas::set_inline(LooseHandle parent)
818 if(is_inline_ && parent_)
827 // Have the parent inherit all of the group stuff
829 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
831 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
833 parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
836 rend_desc()=parent->rend_desc();
840 Canvas::create_inline(Handle parent)
843 //if(parent->is_inline())
844 // return create_inline(parent->parent());
846 Handle canvas(new Canvas("inline"));
847 canvas->set_inline(parent);
852 Canvas::new_child_canvas()
854 if(is_inline() && parent_)
855 return parent_->new_child_canvas();
856 // runtime_error("You cannot create a child Canvas in an inline Canvas");
858 // Create a new canvas
859 children().push_back(create());
860 Canvas::Handle canvas(children().back());
862 canvas->parent_=this;
864 canvas->rend_desc()=rend_desc();
870 Canvas::new_child_canvas(const String &id)
872 if(is_inline() && parent_)
873 return parent_->new_child_canvas(id);
874 // runtime_error("You cannot create a child Canvas in an inline Canvas");
876 // Create a new canvas
877 children().push_back(create());
878 Canvas::Handle canvas(children().back());
881 canvas->parent_=this;
882 canvas->rend_desc()=rend_desc();
888 Canvas::add_child_canvas(Canvas::Handle child_canvas, const synfig::String& id)
890 if(is_inline() && parent_)
891 return parent_->add_child_canvas(child_canvas,id);
893 if(child_canvas->parent() && !child_canvas->is_inline())
894 throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
897 throw runtime_error("Invalid ID");
902 throw Exception::IDAlreadyExists(id);
904 catch(Exception::IDNotFound)
906 if(child_canvas->is_inline())
907 child_canvas->is_inline_=false;
908 child_canvas->id_=id;
909 children().push_back(child_canvas);
910 child_canvas->parent_=this;
917 Canvas::remove_child_canvas(Canvas::Handle child_canvas)
919 if(is_inline() && parent_)
920 return parent_->remove_child_canvas(child_canvas);
922 if(child_canvas->parent_!=this)
923 throw runtime_error("Given child does not belong to me");
925 if(find(children().begin(),children().end(),child_canvas)==children().end())
926 throw Exception::IDNotFound(child_canvas->get_id());
928 children().remove(child_canvas);
930 child_canvas->parent_=0;
934 Canvas::set_file_name(const String &file_name)
937 parent()->set_file_name(file_name);
940 file_name_=file_name;
941 signal_file_name_changed_();
946 Canvas::signal_file_name_changed()
949 return signal_file_name_changed();
951 return signal_file_name_changed_;
955 Canvas::get_file_name()const
958 return parent()->get_file_name();
963 Canvas::get_file_path()const
966 return parent()->get_file_path();
967 return dirname(file_name_);
972 Canvas::get_meta_data(const String& key)const
974 if(!meta_data_.count(key))
976 return meta_data_.find(key)->second;
980 Canvas::set_meta_data(const String& key, const String& data)
982 if(meta_data_[key]!=data)
984 meta_data_[key]=data;
985 signal_meta_data_changed()(key);
986 signal_meta_data_changed(key)();
991 Canvas::erase_meta_data(const String& key)
993 if(meta_data_.count(key))
995 meta_data_.erase(key);
996 signal_meta_data_changed()(key);
997 signal_meta_data_changed(key)();
1002 Canvas::get_meta_data_keys()const
1004 std::list<String> ret;
1006 std::map<String,String>::const_iterator iter;
1008 for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
1009 ret.push_back(iter->first);
1015 synfig::optimize_layers(Context context, Canvas::Handle op_canvas)
1019 std::vector< std::pair<float,Layer::Handle> > sort_list;
1022 // Go ahead and start romping through the canvas to paste
1023 for(iter=context,i=0;*iter;iter++,i++)
1025 Layer::Handle layer=*iter;
1026 float z_depth(layer->get_z_depth()*1.0001+i);
1028 // If the layer isn't active, don't worry about it
1029 if(!layer->active())
1032 // Any layer with an amount of zero is implicitly disabled.
1033 ValueBase value(layer->get_param("amount"));
1034 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1037 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1038 if(layer->get_name()=="PasteCanvas" && paste_canvas->get_time_offset()==0)
1040 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1041 optimize_layers(paste_canvas->get_sub_canvas()->get_context(),sub_canvas);
1042 //#define SYNFIG_OPTIMIZE_PASTE_CANVAS 1
1044 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
1045 Canvas::iterator sub_iter;
1046 // Determine if we can just remove the paste canvas
1048 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))
1050 for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1052 Layer* layer=sub_iter->get();
1054 // any layers that deform end up breaking things
1055 // so do things the old way if we run into anything like this
1056 if(!dynamic_cast<Layer_NoDeform*>(layer))
1059 ValueBase value(layer->get_param("blend_method"));
1060 if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1064 // It has turned out that we don't need a paste canvas
1065 // layer, so just go ahead and add all the layers onto
1066 // the current stack and be done with it
1067 while(sub_canvas->size())
1069 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,sub_canvas->front()));
1070 //op_canvas->push_back_simple(sub_canvas->front());
1071 sub_canvas->pop_front();
1076 Layer::Handle new_layer(Layer::create("PasteCanvas"));
1077 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_do_not_muck_with_time(true);
1078 Layer::ParamList param_list(paste_canvas->get_param_list());
1079 //param_list.erase("canvas");
1080 new_layer->set_param_list(param_list);
1081 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_sub_canvas(sub_canvas);
1082 dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_do_not_muck_with_time(false);
1086 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1087 //op_canvas->push_back_simple(layer);
1091 stable_sort(sort_list.begin(),sort_list.end());
1092 std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
1093 for(iter2=sort_list.begin();iter2!=sort_list.end();++iter2)
1094 op_canvas->push_back_simple(iter2->second);
1095 op_canvas->op_flag_=true;
1099 Canvas::get_times_vfunc(Node::time_set &set) const
1101 const_iterator i = begin(),
1104 for(; i != iend; ++i)
1106 const Node::time_set &tset = (*i)->get_times();
1107 set.insert(tset.begin(),tset.end());
1111 std::set<etl::handle<Layer> >
1112 Canvas::get_layers_in_group(const String&group)
1114 if(is_inline() && parent_)
1115 return parent_->get_layers_in_group(group);
1117 if(group_db_.count(group)==0)
1118 return std::set<etl::handle<Layer> >();
1119 return group_db_.find(group)->second;
1123 Canvas::get_groups()const
1125 if(is_inline() && parent_)
1126 return parent_->get_groups();
1128 std::set<String> ret;
1129 std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
1130 for(iter=group_db_.begin();iter!=group_db_.end();++iter)
1131 ret.insert(iter->first);
1136 Canvas::get_group_count()const
1138 if(is_inline() && parent_)
1139 return parent_->get_group_count();
1141 return group_db_.size();
1145 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1147 group_db_[group].insert(layer);
1148 if(group_db_[group].size()==1)
1149 signal_group_added()(group);
1151 signal_group_changed()(group);
1153 signal_group_pair_added()(group,layer);
1155 if(is_inline() && parent_)
1156 return parent_->add_group_pair(group,layer);
1160 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1162 group_db_[group].erase(layer);
1164 signal_group_pair_removed()(group,layer);
1166 if(group_db_[group].empty())
1168 group_db_.erase(group);
1169 signal_group_removed()(group);
1172 signal_group_changed()(group);
1174 if(is_inline() && parent_)
1175 return parent_->remove_group_pair(group,layer);
1179 Canvas::rename_group(const String&old_name,const String&new_name)
1181 if(is_inline() && parent_)
1182 return parent_->rename_group(old_name,new_name);
1185 std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
1186 iter=group_db_.find(old_name);
1187 if(iter!=group_db_.end())
1188 for(++iter;iter!=group_db_.end() && iter->first.find(old_name)==0;iter=group_db_.find(old_name),++iter)
1190 String name(iter->first,old_name.size(),String::npos);
1192 rename_group(iter->first,name);
1196 std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1197 std::set<etl::handle<Layer> >::iterator iter;
1199 for(iter=layers.begin();iter!=layers.end();++iter)
1201 (*iter)->remove_from_group(old_name);
1202 (*iter)->add_to_group(new_name);