Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / synfig_0_61_07_rc3 / src / synfig / canvas.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file canvas.cpp
3 **      \brief Canvas Class Member Definitions
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007 Chris Moore
10 **
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.
15 **
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.
20 **      \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #define SYNFIG_NO_ANGLE
27
28 #ifdef USING_PCH
29 #       include "pch.h"
30 #else
31 #ifdef HAVE_CONFIG_H
32 #       include <config.h>
33 #endif
34
35 #include "layer.h"
36 #include "canvas.h"
37 #include <cassert>
38 #include "exception.h"
39 #include "time.h"
40 #include "context.h"
41 #include "layer_pastecanvas.h"
42 #include <sigc++/bind.h>
43
44 #endif
45
46 using namespace synfig;
47 using namespace etl;
48 using namespace std;
49
50 namespace synfig { extern Canvas::Handle open_canvas(const String &filename); };
51
52 /* === M A C R O S ========================================================= */
53
54 struct _CanvasCounter
55 {
56         static int counter;
57         ~_CanvasCounter()
58         {
59                 if(counter)
60                         synfig::error("%d canvases not yet deleted!",counter);
61         }
62 } _canvas_counter;
63
64 int _CanvasCounter::counter(0);
65
66 /* === G L O B A L S ======================================================= */
67
68 /* === P R O C E D U R E S ================================================= */
69
70 /* === M E T H O D S ======================================================= */
71
72 Canvas::Canvas(const string &id):
73         id_                     (id),
74         cur_time_       (0),
75         is_inline_      (false),
76         is_dirty_       (true),
77         op_flag_        (false)
78 {
79         _CanvasCounter::counter++;
80         clear();
81 }
82
83 void
84 Canvas::on_changed()
85 {
86         is_dirty_=true;
87         Node::on_changed();
88 }
89
90 Canvas::~Canvas()
91 {
92         //if(is_inline() && parent_) assert(0);
93         _CanvasCounter::counter--;
94         //DEBUGPOINT();
95         clear();
96         begin_delete();
97 }
98
99 Canvas::iterator
100 Canvas::end()
101 {
102         return CanvasBase::end()-1;
103 }
104
105 Canvas::const_iterator
106 Canvas::end()const
107 {
108         return CanvasBase::end()-1;
109 }
110
111 Canvas::reverse_iterator
112 Canvas::rbegin()
113 {
114         return CanvasBase::rbegin()+1;
115 }
116
117 Canvas::const_reverse_iterator
118 Canvas::rbegin()const
119 {
120         return CanvasBase::rbegin()+1;
121 }
122
123 int
124 Canvas::size()const
125 {
126         return CanvasBase::size()-1;
127 }
128
129 void
130 Canvas::clear()
131 {
132         while(!empty())
133         {
134                 Layer::Handle layer(front());
135                 //if(layer->count()>2)synfig::info("before layer->count()=%d",layer->count());
136
137                 erase(begin());
138                 //if(layer->count()>1)synfig::info("after layer->count()=%d",layer->count());
139         }
140         //CanvasBase::clear();
141
142         // We need to keep a blank handle at the
143         // end of the image list, and acts at
144         // the bottom. Without it, the layers
145         // would just continue going when polled
146         // for a color.
147         CanvasBase::push_back(Layer::Handle());
148
149         changed();
150 }
151
152 bool
153 Canvas::empty()const
154 {
155         return CanvasBase::size()<=1;
156 }
157
158 Layer::Handle &
159 Canvas::back()
160 {
161         return *(CanvasBase::end()-1);
162 }
163
164 const Layer::Handle &
165 Canvas::back()const
166 {
167         return *(CanvasBase::end()-1);
168 }
169
170 Context
171 Canvas::get_context()const
172 {
173         return begin();
174 }
175
176 const ValueNodeList &
177 Canvas::value_node_list()const
178 {
179         if(is_inline() && parent_)
180                 return parent_->value_node_list();
181         return value_node_list_;
182 }
183
184 KeyframeList &
185 Canvas::keyframe_list()
186 {
187         if(is_inline() && parent_)
188                 return parent_->keyframe_list();
189         return keyframe_list_;
190 }
191
192 const KeyframeList &
193 Canvas::keyframe_list()const
194 {
195         if(is_inline() && parent_)
196                 return parent_->keyframe_list();
197         return keyframe_list_;
198 }
199
200 etl::handle<Layer>
201 Canvas::find_layer(const Point &pos)
202 {
203         return get_context().hit_check(pos);
204 }
205
206 static bool
207 valid_id(const String &x)
208 {
209         static const char bad_chars[]=" :#@$^&()*";
210         unsigned int i;
211
212         if(!x.empty() && x[0]>='0' && x[0]<='9')
213                 return false;
214
215         for(i=0;i<sizeof(bad_chars);i++)
216                 if(x.find_first_of(bad_chars[i])!=string::npos)
217                         return false;
218
219         return true;
220 }
221
222 void
223 Canvas::set_id(const String &x)
224 {
225         if(is_inline() && parent_)
226                 throw runtime_error("Inline Canvas cannot have an ID");
227
228         if(!valid_id(x))
229                 throw runtime_error("Invalid ID");
230         id_=x;
231         signal_id_changed_();
232 }
233
234 void
235 Canvas::set_name(const String &x)
236 {
237         name_=x;
238         signal_meta_data_changed()("name");
239         signal_meta_data_changed("name")();
240 }
241
242 void
243 Canvas::set_author(const String &x)
244 {
245         author_=x;
246         signal_meta_data_changed()("author");
247         signal_meta_data_changed("author")();
248 }
249
250 void
251 Canvas::set_description(const String &x)
252 {
253         description_=x;
254         signal_meta_data_changed()("description");
255         signal_meta_data_changed("description")();
256 }
257
258 void
259 Canvas::set_time(Time t)const
260 {
261         if(is_dirty_ || !get_time().is_equal(t))
262         {
263 #if 0
264                 if(is_root())
265                 {
266                         synfig::info("is_dirty_=%d",is_dirty_);
267                         synfig::info("get_time()=%f",(float)get_time());
268                         synfig::info("t=%f",(float)t);
269                 }
270 #endif
271
272                 // ...questionable
273                 const_cast<Canvas&>(*this).cur_time_=t;
274
275                 is_dirty_=false;
276                 get_context().set_time(t);
277         }
278         is_dirty_=false;
279 }
280
281 Canvas::LooseHandle
282 Canvas::get_root()const
283 {
284         return parent_?parent_->get_root().get():const_cast<synfig::Canvas *>(this);
285 }
286
287 int
288 Canvas::get_depth(etl::handle<Layer> layer)const
289 {
290         const_iterator iter;
291         int i(0);
292         for(iter=begin();iter!=end();++iter,i++)
293         {
294                 if(layer==*iter)
295                         return i;
296         }
297         return -1;
298 }
299
300 String
301 Canvas::get_relative_id(etl::loose_handle<const Canvas> x)const
302 {
303         if(x->get_root()==this)
304                 return ":";
305         if(is_inline() && parent_)
306                 return parent_->_get_relative_id(x);
307         return _get_relative_id(x);
308 }
309
310 String
311 Canvas::_get_relative_id(etl::loose_handle<const Canvas> x)const
312 {
313         if(is_inline() && parent_)
314                 return parent_->_get_relative_id(x);
315
316         if(x.get()==this)
317                 return String();
318
319         if(parent()==x.get())
320                 return get_id();
321
322         String id;
323
324         const Canvas* canvas=this;
325
326         for(;!canvas->is_root();canvas=canvas->parent().get())
327                 id=':'+canvas->get_id()+id;
328
329         if(x && get_root()!=x->get_root())
330         {
331                 //String file_name=get_file_name();
332                 //String file_path=x->get_file_path();
333
334                 String file_name;
335                 if(is_absolute_path(get_file_name()))
336                         file_name=etl::relative_path(x->get_file_path(),get_file_name());
337                 else
338                         file_name=get_file_name();
339
340                 // If the path of X is inside of file_name,
341                 // then remove it.
342                 //if(file_name.size()>file_path.size())
343                 //      if(file_path==String(file_name,0,file_path.size()))
344                 //              file_name.erase(0,file_path.size()+1);
345
346                 id=file_name+'#'+id;
347         }
348
349         return id;
350 }
351
352
353 ValueNode::Handle
354 Canvas::find_value_node(const String &id)
355 {
356         return
357                 ValueNode::Handle::cast_const(
358                         const_cast<const Canvas*>(this)->find_value_node(id)
359                 );
360 }
361
362 ValueNode::ConstHandle
363 Canvas::find_value_node(const String &id)const
364 {
365         if(is_inline() && parent_)
366                 return parent_->find_value_node(id);
367
368         if(id.empty())
369                 throw Exception::IDNotFound("Empty ID");
370
371         // If we do not have any resolution, then we assume that the
372         // request is for this immediate canvas
373         if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
374                 return value_node_list_.find(id);
375
376         String canvas_id(id,0,id.rfind(':'));
377         String value_node_id(id,id.rfind(':')+1);
378         if(canvas_id.empty())
379                 canvas_id=':';
380         //synfig::warning("constfind:value_node_id: "+value_node_id);
381         //synfig::warning("constfind:canvas_id: "+canvas_id);
382
383         return find_canvas(canvas_id)->value_node_list_.find(value_node_id);
384 }
385
386 ValueNode::Handle
387 Canvas::surefind_value_node(const String &id)
388 {
389         if(is_inline() && parent_)
390                 return parent_->surefind_value_node(id);
391
392         if(id.empty())
393                 throw Exception::IDNotFound("Empty ID");
394
395         // If we do not have any resolution, then we assume that the
396         // request is for this immediate canvas
397         if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
398                 return value_node_list_.surefind(id);
399
400         String canvas_id(id,0,id.rfind(':'));
401         String value_node_id(id,id.rfind(':')+1);
402         if(canvas_id.empty())
403                 canvas_id=':';
404
405         return surefind_canvas(canvas_id)->value_node_list_.surefind(value_node_id);
406 }
407
408 void
409 Canvas::add_value_node(ValueNode::Handle x, const String &id)
410 {
411         if(is_inline() && parent_)
412                 return parent_->add_value_node(x,id);
413 //              throw runtime_error("You cannot add a ValueNode to an inline Canvas");
414
415         //DEBUGPOINT();
416         if(x->is_exported())
417                 throw runtime_error("ValueNode is already exported");
418
419         if(id.empty())
420                 throw Exception::BadLinkName("Empty ID");
421
422         if(id.find_first_of(':',0)!=string::npos)
423                 throw Exception::BadLinkName("Bad character");
424
425         try
426         {
427                 //DEBUGPOINT();
428                 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
429                         throw Exception::IDNotFound("add_value_node()");
430
431                 //DEBUGPOINT();
432                 throw Exception::IDAlreadyExists(id);
433         }
434         catch(Exception::IDNotFound)
435         {
436                 //DEBUGPOINT();
437                 x->set_id(id);
438
439                 x->set_parent_canvas(this);
440
441                 if(!value_node_list_.add(x))
442                 {
443                         synfig::error("Unable to add ValueNode");
444                         throw std::runtime_error("Unable to add ValueNode");
445                 }
446                 //DEBUGPOINT();
447
448                 return;
449         }
450 }
451
452 /*
453 void
454 Canvas::rename_value_node(ValueNode::Handle x, const String &id)
455 {
456         if(id.empty())
457                 throw Exception::BadLinkName("Empty ID");
458
459         if(id.find_first_of(": ",0)!=string::npos)
460                 throw Exception::BadLinkName("Bad character");
461
462         try
463         {
464                 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
465                         throw Exception::IDNotFound("rename_value_node");
466                 throw Exception::IDAlreadyExists(id);
467         }
468         catch(Exception::IDNotFound)
469         {
470                 x->set_id(id);
471
472                 return;
473         }
474 }
475 */
476
477 void
478 Canvas::remove_value_node(ValueNode::Handle x)
479 {
480         if(is_inline() && parent_)
481                 return parent_->remove_value_node(x);
482 //              throw Exception::IDNotFound("Canvas::remove_value_node() was called from an inline canvas");
483
484         if(!x)
485                 throw Exception::IDNotFound("Canvas::remove_value_node() was passed empty handle");
486
487         if(!value_node_list_.erase(x))
488                 throw Exception::IDNotFound("Canvas::remove_value_node(): ValueNode was not found inside of this canvas");
489
490         //x->set_parent_canvas(0);
491
492         x->set_id("");
493 }
494
495
496 etl::handle<Canvas>
497 Canvas::surefind_canvas(const String &id)
498 {
499         if(is_inline() && parent_)
500                 return parent_->surefind_canvas(id);
501
502         if(id.empty())
503                 return this;
504
505         // If the ID contains a "#" character, then a filename is
506         // expected on the left side.
507         if(id.find_first_of('#')!=string::npos)
508         {
509                 // If '#' is the first character, remove it
510                 // and attempt to parse the ID again.
511                 if(id[0]=='#')
512                         return surefind_canvas(String(id,1));
513
514                 //! \todo This needs a lot more optimization
515                 String file_name(id,0,id.find_first_of('#'));
516                 String external_id(id,id.find_first_of('#')+1);
517
518                 file_name=unix_to_local_path(file_name);
519
520                 Canvas::Handle external_canvas;
521
522                 // If the composition is already open, then use it.
523                 if(externals_.count(file_name))
524                         external_canvas=externals_[file_name];
525                 else
526                 {
527                         if(is_absolute_path(file_name))
528                                 external_canvas=open_canvas(file_name);
529                         else
530                                 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
531
532                         if(!external_canvas)
533                                 throw Exception::FileNotFound(file_name);
534                         externals_[file_name]=external_canvas;
535                 }
536
537                 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
538         }
539
540         // If we do not have any resolution, then we assume that the
541         // request is for this immediate canvas
542         if(id.find_first_of(':')==string::npos)
543         {
544                 Children::iterator iter;
545
546                 // Search for the image in the image list,
547                 // and return it if it is found
548                 for(iter=children().begin();iter!=children().end();iter++)
549                         if(id==(*iter)->get_id())
550                                 return *iter;
551
552                 // Create a new canvas and return it
553                 //synfig::warning("Implicitly creating canvas named "+id);
554                 return new_child_canvas(id);
555         }
556
557         // If the first character is the separator, then
558         // this references the root canvas.
559         if(id[0]==':')
560                 return get_root()->surefind_canvas(string(id,1));
561
562         // Now we know that the requested Canvas is in a child
563         // of this canvas. We have to find that canvas and
564         // call "find_canvas" on it, and return the result.
565
566         String canvas_name=string(id,0,id.find_first_of(':'));
567
568         Canvas::Handle child_canvas=surefind_canvas(canvas_name);
569
570         return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1));
571 }
572
573 Canvas::Handle
574 Canvas::find_canvas(const String &id)
575 {
576         return
577                 Canvas::Handle::cast_const(
578                         const_cast<const Canvas*>(this)->find_canvas(id)
579                 );
580 }
581
582 Canvas::ConstHandle
583 Canvas::find_canvas(const String &id)const
584 {
585         if(is_inline() && parent_)return parent_->find_canvas(id);
586
587         if(id.empty())
588                 return this;
589
590         // If the ID contains a "#" character, then a filename is
591         // expected on the left side.
592         if(id.find_first_of('#')!=string::npos)
593         {
594                 // If '#' is the first character, remove it
595                 // and attempt to parse the ID again.
596                 if(id[0]=='#')
597                         return find_canvas(String(id,1));
598
599                 //! \todo This needs a lot more optimization
600                 String file_name(id,0,id.find_first_of('#'));
601                 String external_id(id,id.find_first_of('#')+1);
602
603                 file_name=unix_to_local_path(file_name);
604
605                 Canvas::Handle external_canvas;
606
607                 // If the composition is already open, then use it.
608                 if(externals_.count(file_name))
609                         external_canvas=externals_[file_name];
610                 else
611                 {
612                         if(is_absolute_path(file_name))
613                                 external_canvas=open_canvas(file_name);
614                         else
615                                 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
616
617                         if(!external_canvas)
618                                 throw Exception::FileNotFound(file_name);
619                         externals_[file_name]=external_canvas;
620                 }
621
622                 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
623         }
624
625         // If we do not have any resolution, then we assume that the
626         // request is for this immediate canvas
627         if(id.find_first_of(':')==string::npos)
628         {
629                 Children::const_iterator iter;
630
631                 // Search for the image in the image list,
632                 // and return it if it is found
633                 for(iter=children().begin();iter!=children().end();iter++)
634                         if(id==(*iter)->get_id())
635                                 return *iter;
636
637                 throw Exception::IDNotFound("Child Canvas in Parent Canvas: (child)"+id);
638         }
639
640         // If the first character is the separator, then
641         // this references the root canvas.
642         if(id.find_first_of(':')==0)
643                 return get_root()->find_canvas(string(id,1));
644
645         // Now we know that the requested Canvas is in a child
646         // of this canvas. We have to find that canvas and
647         // call "find_canvas" on it, and return the result.
648
649         String canvas_name=string(id,0,id.find_first_of(':'));
650
651         Canvas::ConstHandle child_canvas=find_canvas(canvas_name);
652
653         return child_canvas->find_canvas(string(id,id.find_first_of(':')+1));
654 }
655
656
657 Canvas::Handle
658 Canvas::create()
659 {
660         return new Canvas("Untitled");
661 }
662
663 void
664 Canvas::push_back(etl::handle<Layer> x)
665 {
666 //      DEBUGPOINT();
667 //      int i(x->count());
668         insert(end(),x);
669         //if(x->count()!=i+1)synfig::info("push_back before %d, after %d",i,x->count());
670 }
671
672 void
673 Canvas::push_front(etl::handle<Layer> x)
674 {
675 //      DEBUGPOINT();
676 //      int i(x->count());
677         insert(begin(),x);
678         //if(x->count()!=i+1)synfig::error("push_front before %d, after %d",i,x->count());
679 }
680
681 void
682 Canvas::insert(iterator iter,etl::handle<Layer> x)
683 {
684 //      int i(x->count());
685         CanvasBase::insert(iter,x);
686
687         /*if(x->count()!=i+1)
688         {
689                 synfig::error(__FILE__":%d: Canvas::insert(): ***FAILURE*** before %d, after %d",__LINE__,i,x->count());
690                 return;
691                 //throw runtime_error("Canvas Insertion Failed");
692         }*/
693
694         x->set_canvas(this);
695
696
697         add_child(x.get());
698
699
700         LooseHandle correct_canvas(this);
701         //while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
702         Layer::LooseHandle loose_layer(x);
703
704         add_connection(loose_layer,
705                                    sigc::connection::connection(
706                                            x->signal_added_to_group().connect(
707                                                    sigc::bind(
708                                                            sigc::mem_fun(
709                                                                    *correct_canvas,
710                                                                    &Canvas::add_group_pair),
711                                                            loose_layer))));
712         add_connection(loose_layer,
713                                    sigc::connection::connection(
714                                            x->signal_removed_from_group().connect(
715                                                    sigc::bind(
716                                                            sigc::mem_fun(
717                                                                    *correct_canvas,
718                                                                    &Canvas::remove_group_pair),
719                                                            loose_layer))));
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
752         // so don't wipe them out entirely
753         // - dooglus 09-21-2007
754         disconnect_connections(*iter);
755
756         if(!op_flag_)remove_child(iter->get());
757
758         CanvasBase::erase(iter);
759         if(!op_flag_)changed();
760 }
761
762 Canvas::Handle
763 Canvas::clone(const GUID& deriv_guid)const
764 {
765         synfig::String name;
766         if(is_inline())
767                 name="inline";
768         else
769         {
770                 name=get_id()+"_CLONE";
771
772                 throw runtime_error("Cloning of non-inline canvases is not yet suported");
773         }
774
775         Handle canvas(new Canvas(name));
776
777         if(is_inline())
778         {
779                 canvas->is_inline_=true;
780                 canvas->parent_=0;
781                 //canvas->set_inline(parent());
782         }
783
784         canvas->set_guid(get_guid()^deriv_guid);
785
786         const_iterator iter;
787         for(iter=begin();iter!=end();++iter)
788         {
789                 Layer::Handle layer((*iter)->clone(deriv_guid));
790                 if(layer)
791                 {
792                         assert(layer.count()==1);
793                         int presize(size());
794                         canvas->push_back(layer);
795                         if(!(layer.count()>1))
796                         {
797                                 synfig::error("Canvas::clone(): Cloned layer insertion failure!");
798                                 synfig::error("Canvas::clone(): \tlayer.count()=%d",layer.count());
799                                 synfig::error("Canvas::clone(): \tlayer->get_name()=%s",layer->get_name().c_str());
800                                 synfig::error("Canvas::clone(): \tbefore size()=%d",presize);
801                                 synfig::error("Canvas::clone(): \tafter size()=%d",size());
802                         }
803                         assert(layer.count()>1);
804                 }
805                 else
806                 {
807                         synfig::error("Unable to clone layer");
808                 }
809         }
810
811         canvas->signal_group_pair_removed().clear();
812         canvas->signal_group_pair_added().clear();
813
814         return canvas;
815 }
816
817 void
818 Canvas::set_inline(LooseHandle parent)
819 {
820         if(is_inline_ && parent_)
821         {
822
823         }
824
825         id_="inline";
826         is_inline_=true;
827         parent_=parent;
828
829         // Have the parent inherit all of the group stuff
830
831         std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
832
833         for(iter=group_db_.begin();iter!=group_db_.end();++iter)
834         {
835                 parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
836         }
837
838         rend_desc()=parent->rend_desc();
839 }
840
841 Canvas::Handle
842 Canvas::create_inline(Handle parent)
843 {
844         assert(parent);
845         //if(parent->is_inline())
846         //      return create_inline(parent->parent());
847
848         Handle canvas(new Canvas("inline"));
849         canvas->set_inline(parent);
850         return canvas;
851 }
852
853 Canvas::Handle
854 Canvas::new_child_canvas()
855 {
856         if(is_inline() && parent_)
857                 return parent_->new_child_canvas();
858 //              runtime_error("You cannot create a child Canvas in an inline Canvas");
859
860         // Create a new canvas
861         children().push_back(create());
862         Canvas::Handle canvas(children().back());
863
864         canvas->parent_=this;
865
866         canvas->rend_desc()=rend_desc();
867
868         return canvas;
869 }
870
871 Canvas::Handle
872 Canvas::new_child_canvas(const String &id)
873 {
874         if(is_inline() && parent_)
875                 return parent_->new_child_canvas(id);
876 //              runtime_error("You cannot create a child Canvas in an inline Canvas");
877
878         // Create a new canvas
879         children().push_back(create());
880         Canvas::Handle canvas(children().back());
881
882         canvas->set_id(id);
883         canvas->parent_=this;
884         canvas->rend_desc()=rend_desc();
885
886         return canvas;
887 }
888
889 Canvas::Handle
890 Canvas::add_child_canvas(Canvas::Handle child_canvas, const synfig::String& id)
891 {
892         if(is_inline() && parent_)
893                 return parent_->add_child_canvas(child_canvas,id);
894
895         if(child_canvas->parent() && !child_canvas->is_inline())
896                 throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
897
898         if(!valid_id(id))
899                 throw runtime_error("Invalid ID");
900
901         try
902         {
903                 find_canvas(id);
904                 throw Exception::IDAlreadyExists(id);
905         }
906         catch(Exception::IDNotFound)
907         {
908                 if(child_canvas->is_inline())
909                         child_canvas->is_inline_=false;
910                 child_canvas->id_=id;
911                 children().push_back(child_canvas);
912                 child_canvas->parent_=this;
913         }
914
915         return child_canvas;
916 }
917
918 void
919 Canvas::remove_child_canvas(Canvas::Handle child_canvas)
920 {
921         if(is_inline() && parent_)
922                 return parent_->remove_child_canvas(child_canvas);
923
924         if(child_canvas->parent_!=this)
925                 throw runtime_error("Given child does not belong to me");
926
927         if(find(children().begin(),children().end(),child_canvas)==children().end())
928                 throw Exception::IDNotFound(child_canvas->get_id());
929
930         children().remove(child_canvas);
931
932         child_canvas->parent_=0;
933 }
934
935 void
936 Canvas::set_file_name(const String &file_name)
937 {
938         if(parent())
939                 parent()->set_file_name(file_name);
940         else
941         {
942                 file_name_=file_name;
943                 signal_file_name_changed_();
944         }
945 }
946
947 sigc::signal<void>&
948 Canvas::signal_file_name_changed()
949 {
950         if(parent())
951                 return signal_file_name_changed();
952         else
953                 return signal_file_name_changed_;
954 }
955
956 String
957 Canvas::get_file_name()const
958 {
959         if(parent())
960                 return parent()->get_file_name();
961         return file_name_;
962 }
963
964 String
965 Canvas::get_file_path()const
966 {
967         if(parent())
968                 return parent()->get_file_path();
969         return dirname(file_name_);
970 }
971
972
973 String
974 Canvas::get_meta_data(const String& key)const
975 {
976         if(!meta_data_.count(key))
977                 return String();
978         return meta_data_.find(key)->second;
979 }
980
981 void
982 Canvas::set_meta_data(const String& key, const String& data)
983 {
984         if(meta_data_[key]!=data)
985         {
986                 meta_data_[key]=data;
987                 signal_meta_data_changed()(key);
988                 signal_meta_data_changed(key)();
989         }
990 }
991
992 void
993 Canvas::erase_meta_data(const String& key)
994 {
995         if(meta_data_.count(key))
996         {
997                 meta_data_.erase(key);
998                 signal_meta_data_changed()(key);
999                 signal_meta_data_changed(key)();
1000         }
1001 }
1002
1003 std::list<String>
1004 Canvas::get_meta_data_keys()const
1005 {
1006         std::list<String> ret;
1007
1008         std::map<String,String>::const_iterator iter;
1009
1010         for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
1011                 ret.push_back(iter->first);
1012
1013         return ret;
1014 }
1015
1016 void
1017 synfig::optimize_layers(Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
1018 {
1019         Context iter;
1020
1021         std::vector< std::pair<float,Layer::Handle> > sort_list;
1022         int i, motion_blur_i=0; // motion_blur_i is for resolving which layer comes first in the event of a z_depth tie
1023         float motion_blur_z_depth=0; // the z_depth of the least deep motion blur layer in this context
1024         bool seen_motion_blur_locally = false;
1025         bool motion_blurred; // the final result - is this layer blurred or not?
1026
1027         // If the parent didn't cause us to already be motion blurred,
1028         // check whether there's a motion blur in this context,
1029         // and if so, calculate its z_depth.
1030         if (!seen_motion_blur_in_parent)
1031                 for(iter=context,i=0;*iter;iter++,i++)
1032                 {
1033                         Layer::Handle layer=*iter;
1034
1035                         // If the layer isn't active, don't worry about it
1036                         if(!layer->active())
1037                                 continue;
1038
1039                         // Any layer with an amount of zero is implicitly disabled.
1040                         ValueBase value(layer->get_param("amount"));
1041                         if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1042                                 continue;
1043
1044                         if(layer->get_name()=="MotionBlur")
1045                         {
1046                                 float z_depth(layer->get_z_depth()*1.0001+i);
1047
1048                                 // If we've seen a motion blur before in this context...
1049                                 if (seen_motion_blur_locally)
1050                                 {
1051                                         // ... then we're only interested in this one if it's less deep...
1052                                         if (z_depth < motion_blur_z_depth)
1053                                         {
1054                                                 motion_blur_z_depth = z_depth;
1055                                                 motion_blur_i = i;
1056                                         }
1057                                 }
1058                                 // ... otherwise we're always interested in it.
1059                                 else
1060                                 {
1061                                         motion_blur_z_depth = z_depth;
1062                                         motion_blur_i = i;
1063                                         seen_motion_blur_locally = true;
1064                                 }
1065                         }
1066                 }
1067
1068         // Go ahead and start romping through the canvas to paste
1069         for(iter=context,i=0;*iter;iter++,i++)
1070         {
1071                 Layer::Handle layer=*iter;
1072                 float z_depth(layer->get_z_depth()*1.0001+i);
1073
1074                 // If the layer isn't active, don't worry about it
1075                 if(!layer->active())
1076                         continue;
1077
1078                 // Any layer with an amount of zero is implicitly disabled.
1079                 ValueBase value(layer->get_param("amount"));
1080                 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1081                         continue;
1082
1083                 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1084
1085                 // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
1086                 //               time-shifted layers weren't being sorted by z-depth (bug #1806852)
1087                 if(layer->get_name()=="PasteCanvas")
1088                 {
1089                         // we need to blur the sub canvas if:
1090                         // our parent is blurred,
1091                         // or the child is lower than a local blur,
1092                         // or the child is at the same z_depth as a local blur, but later in the context
1093
1094 #if 0 // DEBUG
1095                         if (seen_motion_blur_in_parent)                                 synfig::info("seen BLUR in parent\n");
1096                         else if (seen_motion_blur_locally)
1097                                 if (z_depth > motion_blur_z_depth)                      synfig::info("paste is deeper than BLUR\n");
1098                                 else if (z_depth == motion_blur_z_depth) {      synfig::info("paste is same depth as BLUR\n");
1099                                         if (i > motion_blur_i)                                  synfig::info("paste is physically deeper than BLUR\n");
1100                                         else                                                                    synfig::info("paste is less physically deep than BLUR\n");
1101                                 } else                                                                          synfig::info("paste is less deep than BLUR\n");
1102                         else                                                                                    synfig::info("no BLUR at all\n");
1103 #endif  // DEBUG
1104
1105                         motion_blurred = (seen_motion_blur_in_parent ||
1106                                                           (seen_motion_blur_locally &&
1107                                                            (z_depth > motion_blur_z_depth ||
1108                                                                 (z_depth == motion_blur_z_depth && i > motion_blur_i))));
1109
1110                         Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1111                         Canvas::Handle paste_sub_canvas = paste_canvas->get_sub_canvas();
1112                         if(paste_sub_canvas)
1113                                 optimize_layers(paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
1114 //#define SYNFIG_OPTIMIZE_PASTE_CANVAS 1
1115
1116 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
1117                         Canvas::iterator sub_iter;
1118                         // Determine if we can just remove the paste canvas
1119                         // altogether
1120                         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))
1121                         try{
1122                                 for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1123                                 {
1124                                         Layer* layer=sub_iter->get();
1125
1126                                         // any layers that deform end up breaking things
1127                                         // so do things the old way if we run into anything like this
1128                                         if(!dynamic_cast<Layer_NoDeform*>(layer))
1129                                                 throw int();
1130
1131                                         ValueBase value(layer->get_param("blend_method"));
1132                                         if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1133                                                 throw int();
1134                                 }
1135
1136                                 // It has turned out that we don't need a paste canvas
1137                                 // layer, so just go ahead and add all the layers onto
1138                                 // the current stack and be done with it
1139                                 while(sub_canvas->size())
1140                                 {
1141                                         sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,sub_canvas->front()));
1142                                         //op_canvas->push_back_simple(sub_canvas->front());
1143                                         sub_canvas->pop_front();
1144                                 }
1145                                 continue;
1146                         }catch(int) { }
1147 #endif
1148                         Layer::Handle new_layer(Layer::create("PasteCanvas"));
1149                         dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(false);
1150                         if (motion_blurred)
1151                         {
1152                                 Layer::DynamicParamList dynamic_param_list(paste_canvas->dynamic_param_list());
1153                                 for(Layer::DynamicParamList::const_iterator iter(dynamic_param_list.begin()); iter != dynamic_param_list.end(); ++iter)
1154                                         new_layer->connect_dynamic_param(iter->first, iter->second);
1155                         }
1156                         Layer::ParamList param_list(paste_canvas->get_param_list());
1157                         //param_list.erase("canvas");
1158                         new_layer->set_param_list(param_list);
1159                         dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_sub_canvas(sub_canvas);
1160                         dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
1161                         layer=new_layer;
1162                 }
1163
1164                 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1165                 //op_canvas->push_back_simple(layer);
1166         }
1167
1168         //sort_list.sort();
1169         stable_sort(sort_list.begin(),sort_list.end());
1170         std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
1171         for(iter2=sort_list.begin();iter2!=sort_list.end();++iter2)
1172                 op_canvas->push_back_simple(iter2->second);
1173         op_canvas->op_flag_=true;
1174 }
1175
1176 void
1177 Canvas::get_times_vfunc(Node::time_set &set) const
1178 {
1179         const_iterator  i = begin(),
1180                                 iend = end();
1181
1182         for(; i != iend; ++i)
1183         {
1184                 const Node::time_set &tset = (*i)->get_times();
1185                 set.insert(tset.begin(),tset.end());
1186         }
1187 }
1188
1189 std::set<etl::handle<Layer> >
1190 Canvas::get_layers_in_group(const String&group)
1191 {
1192         if(is_inline() && parent_)
1193                 return parent_->get_layers_in_group(group);
1194
1195         if(group_db_.count(group)==0)
1196                 return std::set<etl::handle<Layer> >();
1197         return group_db_.find(group)->second;
1198 }
1199
1200 std::set<String>
1201 Canvas::get_groups()const
1202 {
1203         if(is_inline() && parent_)
1204                 return parent_->get_groups();
1205
1206         std::set<String> ret;
1207         std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
1208         for(iter=group_db_.begin();iter!=group_db_.end();++iter)
1209                 ret.insert(iter->first);
1210         return ret;
1211 }
1212
1213 int
1214 Canvas::get_group_count()const
1215 {
1216         if(is_inline() && parent_)
1217                 return parent_->get_group_count();
1218
1219         return group_db_.size();
1220 }
1221
1222 void
1223 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1224 {
1225         group_db_[group].insert(layer);
1226         if(group_db_[group].size()==1)
1227                 signal_group_added()(group);
1228         else
1229                 signal_group_changed()(group);
1230
1231         signal_group_pair_added()(group,layer);
1232
1233         if(is_inline()  && parent_)
1234                 return parent_->add_group_pair(group,layer);
1235 }
1236
1237 void
1238 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1239 {
1240         group_db_[group].erase(layer);
1241
1242         signal_group_pair_removed()(group,layer);
1243
1244         if(group_db_[group].empty())
1245         {
1246                 group_db_.erase(group);
1247                 signal_group_removed()(group);
1248         }
1249         else
1250                 signal_group_changed()(group);
1251
1252         if(is_inline() && parent_)
1253                 return parent_->remove_group_pair(group,layer);
1254 }
1255
1256 void
1257 Canvas::add_connection(Layer::LooseHandle layer, sigc::connection connection)
1258 {
1259         connections_[layer].push_back(connection);
1260 }
1261
1262 void
1263 Canvas::disconnect_connections(Layer::LooseHandle layer)
1264 {
1265         std::vector<sigc::connection>::iterator iter;
1266         for(iter=connections_[layer].begin();iter!=connections_[layer].end();++iter)
1267                 iter->disconnect();
1268         connections_[layer].clear();
1269 }
1270
1271 void
1272 Canvas::rename_group(const String&old_name,const String&new_name)
1273 {
1274         if(is_inline() && parent_)
1275                 return parent_->rename_group(old_name,new_name);
1276
1277         {
1278                 std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
1279                 iter=group_db_.find(old_name);
1280                 if(iter!=group_db_.end())
1281                 for(++iter;iter!=group_db_.end() && iter->first.find(old_name)==0;iter=group_db_.find(old_name),++iter)
1282                 {
1283                         String name(iter->first,old_name.size(),String::npos);
1284                         name=new_name+name;
1285                         rename_group(iter->first,name);
1286                 }
1287         }
1288
1289         std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1290         std::set<etl::handle<Layer> >::iterator iter;
1291
1292         for(iter=layers.begin();iter!=layers.end();++iter)
1293         {
1294                 (*iter)->remove_from_group(old_name);
1295                 (*iter)->add_to_group(new_name);
1296         }
1297 }