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