hur
[synfig.git] / synfig-core / trunk / src / synfig / canvas.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file canvas.cpp
3 **      \brief Canvas Class Member Definitions
4 **
5 **      $Id: canvas.cpp,v 1.1.1.1 2005/01/04 01:23:14 darco Exp $
6 **
7 **      \legal
8 **      Copyright (c) 2002 Robert B. Quattlebaum Jr.
9 **
10 **      This software and associated documentation
11 **      are CONFIDENTIAL and PROPRIETARY property of
12 **      the above-mentioned copyright holder.
13 **
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.
18 **      \endlegal
19 */
20 /* ========================================================================= */
21
22 /* === H E A D E R S ======================================================= */
23
24 #define SYNFIG_NO_ANGLE
25
26 #ifdef USING_PCH
27 #       include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 #       include <config.h>
31 #endif
32
33 #include "layer.h"
34 #include "canvas.h"
35 #include <cassert>
36 #include "exception.h"
37 #include "time.h"
38 #include "context.h"
39 #include "layer_pastecanvas.h"
40 #include <sigc++/bind.h>
41
42 #endif
43
44 using namespace synfig;
45 using namespace etl;
46 using namespace std;
47
48 namespace synfig { extern Canvas::Handle open_canvas(const String &filename); };
49
50 /* === M A C R O S ========================================================= */
51
52 struct _CanvasCounter
53 {
54         static int counter;
55         ~_CanvasCounter()
56         {
57                 if(counter)
58                         synfig::error("%d canvases not yet deleted!",counter);
59         }
60 } _canvas_counter;
61
62 int _CanvasCounter::counter(0);
63
64 /* === G L O B A L S ======================================================= */
65
66 /* === P R O C E D U R E S ================================================= */
67
68 /* === M E T H O D S ======================================================= */
69
70 Canvas::Canvas(const string &id):
71         id_                     (id),
72         cur_time_       (0),
73         is_inline_      (false),
74         is_dirty_       (true),
75         op_flag_        (false)
76 {
77         _CanvasCounter::counter++;
78         clear();
79 }
80
81 void
82 Canvas::on_changed()
83 {
84         is_dirty_=true;
85         Node::on_changed();
86 }
87
88 Canvas::~Canvas()
89 {
90         //if(is_inline() && parent_) assert(0);
91         _CanvasCounter::counter--;
92         //DEBUGPOINT();
93         clear();
94         begin_delete();
95 }
96
97 Canvas::iterator
98 Canvas::end()
99 {
100         return CanvasBase::end()-1;
101 }
102
103 Canvas::const_iterator
104 Canvas::end()const
105 {
106         return CanvasBase::end()-1;
107 }
108
109 Canvas::reverse_iterator
110 Canvas::rbegin()
111 {
112         return CanvasBase::rbegin()+1;
113 }
114
115 Canvas::const_reverse_iterator
116 Canvas::rbegin()const
117 {
118         return CanvasBase::rbegin()+1;
119 }
120
121 int
122 Canvas::size()const
123 {
124         return CanvasBase::size()-1;
125 }
126
127 void
128 Canvas::clear()
129 {
130         while(!empty())
131         {
132                 Layer::Handle layer(front());
133                 //if(layer->count()>2)synfig::info("before layer->count()=%d",layer->count());
134                                 
135                 erase(begin());
136                 //if(layer->count()>1)synfig::info("after layer->count()=%d",layer->count());
137         }
138         //CanvasBase::clear();
139
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
144         // for a color.
145         CanvasBase::push_back(Layer::Handle());
146         
147         changed();
148 }
149
150 bool
151 Canvas::empty()const
152 {
153         return CanvasBase::size()<=1;
154 }
155
156 Layer::Handle &
157 Canvas::back()
158 {
159         return *(CanvasBase::end()-1);
160 }
161
162 const Layer::Handle &
163 Canvas::back()const
164 {
165         return *(CanvasBase::end()-1);
166 }
167
168 Context
169 Canvas::get_context()const
170 {
171         return begin();
172 }
173
174 const ValueNodeList &
175 Canvas::value_node_list()const
176 {
177         if(is_inline() && parent_)
178                 return parent_->value_node_list();
179         return value_node_list_;
180 }
181
182 KeyframeList &
183 Canvas::keyframe_list()
184 {
185         if(is_inline() && parent_)
186                 return parent_->keyframe_list();
187         return keyframe_list_;
188 }
189
190 const KeyframeList &
191 Canvas::keyframe_list()const
192 {
193         if(is_inline() && parent_)
194                 return parent_->keyframe_list();
195         return keyframe_list_;
196 }
197
198 etl::handle<Layer>
199 Canvas::find_layer(const Point &pos)
200 {
201         return get_context().hit_check(pos);
202 }
203
204 static bool
205 valid_id(const String &x)
206 {
207         static const char bad_chars[]=" :#@$^&()*";
208         unsigned int i;
209         
210         if(!x.empty() && x[0]>='0' && x[0]<='9')
211                 return false;
212         
213         for(i=0;i<sizeof(bad_chars);i++)
214                 if(x.find_first_of(bad_chars[i])!=string::npos)
215                         return false;
216
217         return true;
218 }
219
220 void
221 Canvas::set_id(const String &x)
222 {
223         if(is_inline() && parent_)
224                 throw runtime_error("Inline Canvas cannot have an ID");
225         
226         if(!valid_id(x))
227                 throw runtime_error("Invalid ID");
228         id_=x;
229         signal_id_changed_();
230 }
231
232 void
233 Canvas::set_name(const String &x)
234 {
235         name_=x;
236         signal_meta_data_changed()("name");
237         signal_meta_data_changed("name")();
238 }
239
240 void
241 Canvas::set_author(const String &x)
242 {
243         author_=x;
244         signal_meta_data_changed()("author");
245         signal_meta_data_changed("author")();
246 }
247
248 void
249 Canvas::set_description(const String &x)
250 {
251         description_=x;
252         signal_meta_data_changed()("description");
253         signal_meta_data_changed("description")();
254 }
255
256 void
257 Canvas::set_time(Time t)const
258 {       
259         if(is_dirty_ || !get_time().is_equal(t))
260         {       
261 #if 0
262                 if(is_root())
263                 {
264                         synfig::info("is_dirty_=%d",is_dirty_);
265                         synfig::info("get_time()=%f",(float)get_time());
266                         synfig::info("t=%f",(float)t);
267                 }
268 #endif
269
270                 // ...questionable
271                 const_cast<Canvas&>(*this).cur_time_=t;
272                 
273                 is_dirty_=false;
274                 get_context().set_time(t);
275         }
276         is_dirty_=false;
277 }
278
279 Canvas::LooseHandle
280 Canvas::get_root()const
281 {
282         return parent_?parent_->get_root().get():const_cast<synfig::Canvas *>(this);
283 }
284
285 int
286 Canvas::get_depth(etl::handle<Layer> layer)const
287 {
288         const_iterator iter;
289         int i(0);
290         for(iter=begin();iter!=end();++iter,i++)
291         {
292                 if(layer==*iter)
293                         return i;
294         }
295         return -1;
296 }
297
298 String
299 Canvas::get_relative_id(etl::loose_handle<const Canvas> x)const
300 {
301         if(x->get_root()==this)
302                 return ":";
303         if(is_inline() && parent_)
304                 return parent_->_get_relative_id(x);
305         return _get_relative_id(x);
306 }
307
308 String
309 Canvas::_get_relative_id(etl::loose_handle<const Canvas> x)const
310 {
311         if(is_inline() && parent_)
312                 return parent_->_get_relative_id(x);
313
314         if(x.get()==this)
315                 return String();
316         
317         if(parent()==x.get())
318                 return get_id();
319         
320         String id;
321         
322         const Canvas* canvas=this;
323         
324         for(;!canvas->is_root();canvas=canvas->parent().get())
325                 id=':'+canvas->get_id()+id;
326         
327         if(x && get_root()!=x->get_root())
328         {
329                 //String file_name=get_file_name();
330                 //String file_path=x->get_file_path();
331                 
332                 String file_name;
333                 if(is_absolute_path(get_file_name()))
334                         file_name=etl::relative_path(x->get_file_path(),get_file_name());
335                 else
336                         file_name=get_file_name();
337                 
338                 // If the path of X is inside of file_name,
339                 // then remove it.
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);
343                         
344                 id=file_name+'#'+id;
345         }
346
347         return id;
348 }
349
350
351 ValueNode::Handle
352 Canvas::find_value_node(const String &id)
353 {
354         return
355                 ValueNode::Handle::cast_const(
356                         const_cast<const Canvas*>(this)->find_value_node(id)
357                 );
358 }
359
360 ValueNode::ConstHandle
361 Canvas::find_value_node(const String &id)const
362 {
363         if(is_inline() && parent_)
364                 return parent_->find_value_node(id);
365                 
366         if(id.empty())
367                 throw Exception::IDNotFound("Empty ID");
368
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);
373
374         String canvas_id(id,0,id.rfind(':'));
375         String value_node_id(id,id.rfind(':')+1);
376         if(canvas_id.empty())
377                 canvas_id=':';
378         //synfig::warning("constfind:value_node_id: "+value_node_id);
379         //synfig::warning("constfind:canvas_id: "+canvas_id);
380
381         return find_canvas(canvas_id)->value_node_list_.find(value_node_id);
382 }
383
384 ValueNode::Handle
385 Canvas::surefind_value_node(const String &id)
386 {
387         if(is_inline() && parent_)
388                 return parent_->surefind_value_node(id);
389
390         if(id.empty())
391                 throw Exception::IDNotFound("Empty ID");
392
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);
397
398         String canvas_id(id,0,id.rfind(':'));
399         String value_node_id(id,id.rfind(':')+1);
400         if(canvas_id.empty())
401                 canvas_id=':';
402                 
403         return surefind_canvas(canvas_id)->value_node_list_.surefind(value_node_id);
404 }
405
406 void
407 Canvas::add_value_node(ValueNode::Handle x, const String &id)
408 {
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");
412
413         //DEBUGPOINT();
414         if(x->is_exported())
415                 throw runtime_error("ValueNode is already exported");
416
417         if(id.empty())
418                 throw Exception::BadLinkName("Empty ID");
419
420         if(id.find_first_of(':',0)!=string::npos)
421                 throw Exception::BadLinkName("Bad character");
422         
423         try
424         {
425                 //DEBUGPOINT();
426                 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
427                         throw Exception::IDNotFound("add_value_node()");
428                 
429                 //DEBUGPOINT();
430                 throw Exception::IDAlreadyExists(id);
431         }
432         catch(Exception::IDNotFound)
433         {
434                 //DEBUGPOINT();
435                 x->set_id(id);
436         
437                 x->set_parent_canvas(this);
438         
439                 if(!value_node_list_.add(x))
440                 {
441                         synfig::error("Unable to add ValueNode");
442                         throw std::runtime_error("Unable to add ValueNode");
443                 }
444                 //DEBUGPOINT();
445                 
446                 return;
447         }
448 }
449
450 /*
451 void
452 Canvas::rename_value_node(ValueNode::Handle x, const String &id)
453 {
454         if(id.empty())
455                 throw Exception::BadLinkName("Empty ID");
456
457         if(id.find_first_of(": ",0)!=string::npos)
458                 throw Exception::BadLinkName("Bad character");
459
460         try
461         {
462                 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
463                         throw Exception::IDNotFound("rename_value_node");
464                 throw Exception::IDAlreadyExists(id);
465         }
466         catch(Exception::IDNotFound)
467         {
468                 x->set_id(id);  
469
470                 return;
471         }
472 }
473 */
474
475 void
476 Canvas::remove_value_node(ValueNode::Handle x)
477 {
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");
481                 
482         if(!x)
483                 throw Exception::IDNotFound("Canvas::remove_value_node() was passed empty handle");
484         
485         if(!value_node_list_.erase(x))
486                 throw Exception::IDNotFound("Canvas::remove_value_node(): ValueNode was not found inside of this canvas");
487
488         //x->set_parent_canvas(0);
489         
490         x->set_id("");
491 }
492
493
494 etl::handle<Canvas>
495 Canvas::surefind_canvas(const String &id)
496 {
497         if(is_inline() && parent_)
498                 return parent_->surefind_canvas(id);
499         
500         if(id.empty())
501                 return this;
502         
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)
506         {
507                 // If '#' is the first character, remove it
508                 // and attempt to parse the ID again.
509                 if(id[0]=='#')
510                         return surefind_canvas(String(id,1));
511                 
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);
515
516                 file_name=unix_to_local_path(file_name);
517                 
518                 Canvas::Handle external_canvas;
519                 
520                 // If the composition is already open, then use it.
521                 if(externals_.count(file_name))
522                         external_canvas=externals_[file_name];
523                 else
524                 {
525                         if(is_absolute_path(file_name))
526                                 external_canvas=open_canvas(file_name);
527                         else
528                                 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPERATOR+file_name);
529
530                         if(!external_canvas)
531                                 throw Exception::FileNotFound(file_name);
532                         externals_[file_name]=external_canvas;
533                 }
534                 
535                 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
536         }
537         
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)
541         {
542                 Children::iterator iter;
543         
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())
548                                 return *iter;
549                         
550                 // Create a new canvas and return it
551                 //synfig::warning("Implicitly creating canvas named "+id);
552                 return new_child_canvas(id);
553         }
554         
555         // If the first character is the seperator, then 
556         // this references the root canvas.
557         if(id[0]==':')
558                 return get_root()->surefind_canvas(string(id,1));
559
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.
563         
564         String canvas_name=string(id,0,id.find_first_of(':'));
565         
566         Canvas::Handle child_canvas=surefind_canvas(canvas_name);
567
568         return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1));
569 }
570
571 Canvas::Handle
572 Canvas::find_canvas(const String &id)
573 {
574         return
575                 Canvas::Handle::cast_const(
576                         const_cast<const Canvas*>(this)->find_canvas(id)
577                 );
578 }
579
580 Canvas::ConstHandle
581 Canvas::find_canvas(const String &id)const
582 {
583         if(is_inline() && parent_)return parent_->find_canvas(id);
584
585         if(id.empty())
586                 return this;
587
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)
591         {
592                 // If '#' is the first character, remove it
593                 // and attempt to parse the ID again.
594                 if(id[0]=='#')
595                         return find_canvas(String(id,1));
596                 
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);
600                 
601                 file_name=unix_to_local_path(file_name);
602                 
603                 Canvas::Handle external_canvas;
604                 
605                 // If the composition is already open, then use it.
606                 if(externals_.count(file_name))
607                         external_canvas=externals_[file_name];
608                 else
609                 {
610                         if(is_absolute_path(file_name))
611                                 external_canvas=open_canvas(file_name);
612                         else
613                                 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPERATOR+file_name);
614
615                         if(!external_canvas)
616                                 throw Exception::FileNotFound(file_name);
617                         externals_[file_name]=external_canvas;
618                 }
619                 
620                 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
621         }
622         
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)
626         {
627                 Children::const_iterator iter;
628         
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())
633                                 return *iter;
634                         
635                 throw Exception::IDNotFound("Child Canvas in Parent Canvas: (child)"+id);
636         }
637         
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));
642
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.
646         
647         String canvas_name=string(id,0,id.find_first_of(':'));
648         
649         Canvas::ConstHandle child_canvas=find_canvas(canvas_name);
650
651         return child_canvas->find_canvas(string(id,id.find_first_of(':')+1));
652 }
653
654
655 Canvas::Handle
656 Canvas::create()
657 {
658         return new Canvas("Untitled");
659 }
660
661 void
662 Canvas::push_back(etl::handle<Layer> x)
663 {
664 //      DEBUGPOINT();
665 //      int i(x->count());
666         insert(end(),x);
667         //if(x->count()!=i+1)synfig::info("push_back before %d, after %d",i,x->count());
668 }
669
670 void
671 Canvas::push_front(etl::handle<Layer> x)
672 {
673 //      DEBUGPOINT();
674 //      int i(x->count());
675         insert(begin(),x);
676         //if(x->count()!=i+1)synfig::error("push_front before %d, after %d",i,x->count());
677 }
678
679 void
680 Canvas::insert(iterator iter,etl::handle<Layer> x)
681 {
682 //      int i(x->count());
683         CanvasBase::insert(iter,x);
684
685         /*if(x->count()!=i+1)
686         {
687                 synfig::error(__FILE__":%d: Canvas::insert(): ***FAILURE*** before %d, after %d",__LINE__,i,x->count());
688                 return;
689                 //throw runtime_error("Canvas Insertion Failed");
690         }*/
691
692         x->set_canvas(this);
693
694
695         add_child(x.get());
696
697         
698         LooseHandle correct_canvas(this);
699         //while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
700         Layer::LooseHandle loose_layer(x);
701         
702         x->signal_added_to_group().connect(
703                 sigc::bind(
704                         sigc::mem_fun(
705                                 *correct_canvas,
706                                 &Canvas::add_group_pair
707                         ),
708                         loose_layer
709                 )
710         );
711         x->signal_removed_from_group().connect(
712                 sigc::bind(
713                         sigc::mem_fun(
714                                 *correct_canvas,
715                                 &Canvas::remove_group_pair
716                         ),
717                         loose_layer
718                 )
719         );
720
721
722         if(!x->get_group().empty())
723                 add_group_pair(x->get_group(),x);
724
725
726         changed();
727 }
728
729 void
730 Canvas::push_back_simple(etl::handle<Layer> x)
731 {
732         CanvasBase::insert(end(),x);
733         changed();
734 }
735
736 void
737 Canvas::erase(Canvas::iterator iter)
738 {
739         if(!(*iter)->get_group().empty())
740                 remove_group_pair((*iter)->get_group(),(*iter));
741         
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();
753
754         if(!op_flag_)remove_child(iter->get());
755                 
756         CanvasBase::erase(iter);
757         if(!op_flag_)changed();
758 }
759
760 Canvas::Handle
761 Canvas::clone(const GUID& deriv_guid)const
762 {
763         synfig::String name;
764         if(is_inline())
765                 name="inline";
766         else
767         {
768                 name=get_id()+"_CLONE";
769                 
770                 throw runtime_error("Cloning of non-inline canvases is not yet suported");
771         }
772         
773         Handle canvas(new Canvas(name));
774         
775         if(is_inline())
776         {
777                 canvas->is_inline_=true;
778                 canvas->parent_=0;
779                 //canvas->set_inline(parent());
780         }
781
782         canvas->set_guid(get_guid()^deriv_guid);
783
784         const_iterator iter;
785         for(iter=begin();iter!=end();++iter)
786         {
787                 Layer::Handle layer((*iter)->clone(deriv_guid));
788                 if(layer)
789                 {
790                         assert(layer.count()==1);
791                         int presize(size());
792                         canvas->push_back(layer);
793                         if(!(layer.count()>1))
794                         {
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());
800                         }
801                         assert(layer.count()>1);
802                 }
803                 else
804                 {
805                         synfig::error("Unable to clone layer");
806                 }
807         }
808
809         canvas->signal_group_pair_removed().clear();
810         canvas->signal_group_pair_added().clear();
811
812         return canvas;
813 }
814
815 void
816 Canvas::set_inline(LooseHandle parent)
817 {
818         if(is_inline_ && parent_)
819         {
820                 
821         }
822         
823         id_="inline";
824         is_inline_=true;
825         parent_=parent;
826
827         // Have the parent inherit all of the group stuff
828
829         std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
830
831         for(iter=group_db_.begin();iter!=group_db_.end();++iter)
832         {
833                 parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
834         }
835         
836         rend_desc()=parent->rend_desc();
837 }
838
839 Canvas::Handle
840 Canvas::create_inline(Handle parent)
841 {
842         assert(parent);
843         //if(parent->is_inline())
844         //      return create_inline(parent->parent());
845         
846         Handle canvas(new Canvas("inline"));
847         canvas->set_inline(parent);
848         return canvas;
849 }
850
851 Canvas::Handle
852 Canvas::new_child_canvas()
853 {
854         if(is_inline() && parent_)
855                 return parent_->new_child_canvas();
856 //              runtime_error("You cannot create a child Canvas in an inline Canvas");
857
858         // Create a new canvas
859         children().push_back(create());
860         Canvas::Handle canvas(children().back());
861
862         canvas->parent_=this;
863
864         canvas->rend_desc()=rend_desc();
865
866         return canvas;
867 }
868
869 Canvas::Handle
870 Canvas::new_child_canvas(const String &id)
871 {
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");
875
876         // Create a new canvas
877         children().push_back(create());
878         Canvas::Handle canvas(children().back());
879         
880         canvas->set_id(id);
881         canvas->parent_=this;
882         canvas->rend_desc()=rend_desc();
883
884         return canvas;
885 }
886
887 Canvas::Handle
888 Canvas::add_child_canvas(Canvas::Handle child_canvas, const synfig::String& id)
889 {
890         if(is_inline() && parent_)
891                 return parent_->add_child_canvas(child_canvas,id);
892
893         if(child_canvas->parent() && !child_canvas->is_inline())
894                 throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
895         
896         if(!valid_id(id))
897                 throw runtime_error("Invalid ID");
898         
899         try
900         {
901                 find_canvas(id);
902                 throw Exception::IDAlreadyExists(id);
903         }
904         catch(Exception::IDNotFound)
905         {
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;
911         }
912         
913         return child_canvas;
914 }
915
916 void
917 Canvas::remove_child_canvas(Canvas::Handle child_canvas)
918 {
919         if(is_inline() && parent_)
920                 return parent_->remove_child_canvas(child_canvas);
921         
922         if(child_canvas->parent_!=this)
923                 throw runtime_error("Given child does not belong to me");
924         
925         if(find(children().begin(),children().end(),child_canvas)==children().end())
926                 throw Exception::IDNotFound(child_canvas->get_id());
927         
928         children().remove(child_canvas);
929
930         child_canvas->parent_=0;
931 }
932
933 void
934 Canvas::set_file_name(const String &file_name)
935 {
936         if(parent())
937                 parent()->set_file_name(file_name);
938         else
939         {
940                 file_name_=file_name;
941                 signal_file_name_changed_();
942         }
943 }
944
945 sigc::signal<void>&
946 Canvas::signal_file_name_changed()
947 {
948         if(parent())
949                 return signal_file_name_changed();
950         else
951                 return signal_file_name_changed_;
952 }
953
954 String
955 Canvas::get_file_name()const
956 {
957         if(parent())
958                 return parent()->get_file_name();
959         return file_name_;
960 }
961
962 String
963 Canvas::get_file_path()const
964 {
965         if(parent())
966                 return parent()->get_file_path();
967         return dirname(file_name_);
968 }
969
970         
971 String
972 Canvas::get_meta_data(const String& key)const
973 {
974         if(!meta_data_.count(key))
975                 return String();
976         return meta_data_.find(key)->second;
977 }
978
979 void
980 Canvas::set_meta_data(const String& key, const String& data)
981 {
982         if(meta_data_[key]!=data)
983         {
984                 meta_data_[key]=data;
985                 signal_meta_data_changed()(key);
986                 signal_meta_data_changed(key)();
987         }
988 }
989
990 void
991 Canvas::erase_meta_data(const String& key)
992 {
993         if(meta_data_.count(key))
994         {
995                 meta_data_.erase(key);
996                 signal_meta_data_changed()(key);
997                 signal_meta_data_changed(key)();
998         }
999 }
1000
1001 std::list<String>
1002 Canvas::get_meta_data_keys()const
1003 {
1004         std::list<String> ret;
1005
1006         std::map<String,String>::const_iterator iter;
1007
1008         for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
1009                 ret.push_back(iter->first);
1010         
1011         return ret;
1012 }
1013
1014 void
1015 synfig::optimize_layers(Context context, Canvas::Handle op_canvas)
1016 {
1017         Context iter;
1018
1019         std::vector< std::pair<float,Layer::Handle> > sort_list;
1020         int i;
1021         
1022         // Go ahead and start romping through the canvas to paste
1023         for(iter=context,i=0;*iter;iter++,i++)
1024         {
1025                 Layer::Handle layer=*iter;
1026                 float z_depth(layer->get_z_depth()*1.0001+i);
1027                 
1028                 // If the layer isn't active, don't worry about it
1029                 if(!layer->active())
1030                         continue;
1031
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)
1035                         continue;
1036
1037                 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1038                 if(layer->get_name()=="PasteCanvas" && paste_canvas->get_time_offset()==0)
1039                 {
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
1043
1044 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS                     
1045                         Canvas::iterator sub_iter;
1046                         // Determine if we can just remove the paste canvas
1047                         // altogether                   
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))
1049                         try{
1050                                 for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1051                                 {
1052                                         Layer* layer=sub_iter->get();
1053                                         
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))
1057                                                 throw int();
1058
1059                                         ValueBase value(layer->get_param("blend_method"));
1060                                         if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1061                                                 throw int();
1062                                 }
1063                                 
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())
1068                                 {
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();
1072                                 }
1073                                 continue;
1074                         }catch(int) { }
1075 #endif
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);
1083                         layer=new_layer;
1084                 }
1085                                                                 
1086                 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1087                 //op_canvas->push_back_simple(layer);   
1088         }
1089         
1090         //sort_list.sort();
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;
1096 }
1097
1098 void
1099 Canvas::get_times_vfunc(Node::time_set &set) const
1100 {
1101         const_iterator  i = begin(),
1102                                 iend = end();
1103         
1104         for(; i != iend; ++i)
1105         {
1106                 const Node::time_set &tset = (*i)->get_times();
1107                 set.insert(tset.begin(),tset.end());
1108         }
1109 }
1110
1111 std::set<etl::handle<Layer> >
1112 Canvas::get_layers_in_group(const String&group)
1113 {
1114         if(is_inline() && parent_)
1115                 return parent_->get_layers_in_group(group);
1116
1117         if(group_db_.count(group)==0)
1118                 return std::set<etl::handle<Layer> >();
1119         return group_db_.find(group)->second;
1120 }
1121
1122 std::set<String>
1123 Canvas::get_groups()const
1124 {
1125         if(is_inline() && parent_)
1126                 return parent_->get_groups();
1127
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);
1132         return ret;
1133 }
1134
1135 int
1136 Canvas::get_group_count()const
1137 {
1138         if(is_inline() && parent_)
1139                 return parent_->get_group_count();
1140
1141         return group_db_.size();
1142 }
1143         
1144 void
1145 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1146 {
1147         group_db_[group].insert(layer);
1148         if(group_db_[group].size()==1)
1149                 signal_group_added()(group);
1150         else
1151                 signal_group_changed()(group);
1152         
1153         signal_group_pair_added()(group,layer);
1154
1155         if(is_inline()  && parent_)
1156                 return parent_->add_group_pair(group,layer);
1157 }
1158
1159 void
1160 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1161 {
1162         group_db_[group].erase(layer);
1163
1164         signal_group_pair_removed()(group,layer);
1165
1166         if(group_db_[group].empty())
1167         {
1168                 group_db_.erase(group);
1169                 signal_group_removed()(group);
1170         }
1171         else
1172                 signal_group_changed()(group);
1173
1174         if(is_inline() && parent_)
1175                 return parent_->remove_group_pair(group,layer);
1176 }
1177
1178 void
1179 Canvas::rename_group(const String&old_name,const String&new_name)
1180 {
1181         if(is_inline() && parent_)
1182                 return parent_->rename_group(old_name,new_name);
1183         
1184         {
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)
1189                 {
1190                         String name(iter->first,old_name.size(),String::npos);
1191                         name=new_name+name;
1192                         rename_group(iter->first,name);
1193                 }
1194         }
1195         
1196         std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1197         std::set<etl::handle<Layer> >::iterator iter;
1198         
1199         for(iter=layers.begin();iter!=layers.end();++iter)
1200         {
1201                 (*iter)->remove_from_group(old_name);
1202                 (*iter)->add_to_group(new_name);
1203         }
1204 }