Added copyright lines for files I've edited this year.
[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); };
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
373 ValueNode::Handle
374 Canvas::find_value_node(const String &id)
375 {
376         return
377                 ValueNode::Handle::cast_const(
378                         const_cast<const Canvas*>(this)->find_value_node(id)
379                 );
380 }
381
382 ValueNode::ConstHandle
383 Canvas::find_value_node(const String &id)const
384 {
385         if(is_inline() && parent_)
386                 return parent_->find_value_node(id);
387
388         if(id.empty())
389                 throw Exception::IDNotFound("Empty ID");
390
391         // If we do not have any resolution, then we assume that the
392         // request is for this immediate canvas
393         if(id.find_first_of(':')==string::npos && id.find_first_of('#')==string::npos)
394                 return value_node_list_.find(id);
395
396         String canvas_id(id,0,id.rfind(':'));
397         String value_node_id(id,id.rfind(':')+1);
398         if(canvas_id.empty())
399                 canvas_id=':';
400         //synfig::warning("constfind:value_node_id: "+value_node_id);
401         //synfig::warning("constfind:canvas_id: "+canvas_id);
402
403         return find_canvas(canvas_id)->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         return surefind_canvas(canvas_id)->value_node_list_.surefind(value_node_id);
426 }
427
428 void
429 Canvas::add_value_node(ValueNode::Handle x, const String &id)
430 {
431         if(is_inline() && parent_)
432                 return parent_->add_value_node(x,id);
433 //              throw runtime_error("You cannot add a ValueNode to an inline Canvas");
434
435         if(x->is_exported())
436                 throw runtime_error("ValueNode is already exported");
437
438         if(id.empty())
439                 throw Exception::BadLinkName("Empty ID");
440
441         if(id.find_first_of(':',0)!=string::npos)
442                 throw Exception::BadLinkName("Bad character");
443
444         try
445         {
446                 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
447                         throw Exception::IDNotFound("add_value_node()");
448
449                 throw Exception::IDAlreadyExists(id);
450         }
451         catch(Exception::IDNotFound)
452         {
453                 x->set_id(id);
454
455                 x->set_parent_canvas(this);
456
457                 if(!value_node_list_.add(x))
458                 {
459                         synfig::error("Unable to add ValueNode");
460                         throw std::runtime_error("Unable to add ValueNode");
461                 }
462
463                 return;
464         }
465 }
466
467 /*
468 void
469 Canvas::rename_value_node(ValueNode::Handle x, const String &id)
470 {
471         if(id.empty())
472                 throw Exception::BadLinkName("Empty ID");
473
474         if(id.find_first_of(": ",0)!=string::npos)
475                 throw Exception::BadLinkName("Bad character");
476
477         try
478         {
479                 if(PlaceholderValueNode::Handle::cast_dynamic(value_node_list_.find(id)))
480                         throw Exception::IDNotFound("rename_value_node");
481                 throw Exception::IDAlreadyExists(id);
482         }
483         catch(Exception::IDNotFound)
484         {
485                 x->set_id(id);
486
487                 return;
488         }
489 }
490 */
491
492 void
493 Canvas::remove_value_node(ValueNode::Handle x)
494 {
495         if(is_inline() && parent_)
496                 return parent_->remove_value_node(x);
497 //              throw Exception::IDNotFound("Canvas::remove_value_node() was called from an inline canvas");
498
499         if(!x)
500                 throw Exception::IDNotFound("Canvas::remove_value_node() was passed empty handle");
501
502         if(!value_node_list_.erase(x))
503                 throw Exception::IDNotFound("Canvas::remove_value_node(): ValueNode was not found inside of this canvas");
504
505         //x->set_parent_canvas(0);
506
507         x->set_id("");
508 }
509
510
511 etl::handle<Canvas>
512 Canvas::surefind_canvas(const String &id)
513 {
514         if(is_inline() && parent_)
515                 return parent_->surefind_canvas(id);
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));
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                         if(is_absolute_path(file_name))
543                                 external_canvas=open_canvas(file_name);
544                         else
545                                 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
546
547                         if(!external_canvas)
548                                 throw Exception::FileNotFound(file_name);
549                         externals_[file_name]=external_canvas;
550                 }
551
552                 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
553         }
554
555         // If we do not have any resolution, then we assume that the
556         // request is for this immediate canvas
557         if(id.find_first_of(':')==string::npos)
558         {
559                 Children::iterator iter;
560
561                 // Search for the image in the image list,
562                 // and return it if it is found
563                 for(iter=children().begin();iter!=children().end();iter++)
564                         if(id==(*iter)->get_id())
565                                 return *iter;
566
567                 // Create a new canvas and return it
568                 //synfig::warning("Implicitly creating canvas named "+id);
569                 return new_child_canvas(id);
570         }
571
572         // If the first character is the separator, then
573         // this references the root canvas.
574         if(id[0]==':')
575                 return get_root()->surefind_canvas(string(id,1));
576
577         // Now we know that the requested Canvas is in a child
578         // of this canvas. We have to find that canvas and
579         // call "find_canvas" on it, and return the result.
580
581         String canvas_name=string(id,0,id.find_first_of(':'));
582
583         Canvas::Handle child_canvas=surefind_canvas(canvas_name);
584
585         return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1));
586 }
587
588 Canvas::Handle
589 Canvas::find_canvas(const String &id)
590 {
591         return
592                 Canvas::Handle::cast_const(
593                         const_cast<const Canvas*>(this)->find_canvas(id)
594                 );
595 }
596
597 Canvas::ConstHandle
598 Canvas::find_canvas(const String &id)const
599 {
600         if(is_inline() && parent_)return parent_->find_canvas(id);
601
602         if(id.empty())
603                 return this;
604
605         // If the ID contains a "#" character, then a filename is
606         // expected on the left side.
607         if(id.find_first_of('#')!=string::npos)
608         {
609                 // If '#' is the first character, remove it
610                 // and attempt to parse the ID again.
611                 if(id[0]=='#')
612                         return find_canvas(String(id,1));
613
614                 //! \todo This needs a lot more optimization
615                 String file_name(id,0,id.find_first_of('#'));
616                 String external_id(id,id.find_first_of('#')+1);
617
618                 file_name=unix_to_local_path(file_name);
619
620                 Canvas::Handle external_canvas;
621
622                 // If the composition is already open, then use it.
623                 if(externals_.count(file_name))
624                         external_canvas=externals_[file_name];
625                 else
626                 {
627                         if(is_absolute_path(file_name))
628                                 external_canvas=open_canvas(file_name);
629                         else
630                                 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name);
631
632                         if(!external_canvas)
633                                 throw Exception::FileNotFound(file_name);
634                         externals_[file_name]=external_canvas;
635                 }
636
637                 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
638         }
639
640         // If we do not have any resolution, then we assume that the
641         // request is for this immediate canvas
642         if(id.find_first_of(':')==string::npos)
643         {
644                 Children::const_iterator iter;
645
646                 // Search for the image in the image list,
647                 // and return it if it is found
648                 for(iter=children().begin();iter!=children().end();iter++)
649                         if(id==(*iter)->get_id())
650                                 return *iter;
651
652                 throw Exception::IDNotFound("Child Canvas in Parent Canvas: (child)"+id);
653         }
654
655         // If the first character is the separator, then
656         // this references the root canvas.
657         if(id.find_first_of(':')==0)
658                 return get_root()->find_canvas(string(id,1));
659
660         // Now we know that the requested Canvas is in a child
661         // of this canvas. We have to find that canvas and
662         // call "find_canvas" on it, and return the result.
663
664         String canvas_name=string(id,0,id.find_first_of(':'));
665
666         Canvas::ConstHandle child_canvas=find_canvas(canvas_name);
667
668         return child_canvas->find_canvas(string(id,id.find_first_of(':')+1));
669 }
670
671
672 Canvas::Handle
673 Canvas::create()
674 {
675         return new Canvas("Untitled");
676 }
677
678 void
679 Canvas::push_back(etl::handle<Layer> x)
680 {
681 //      int i(x->count());
682         insert(end(),x);
683         //if(x->count()!=i+1)synfig::info("push_back before %d, after %d",i,x->count());
684 }
685
686 void
687 Canvas::push_front(etl::handle<Layer> x)
688 {
689 //      int i(x->count());
690         insert(begin(),x);
691         //if(x->count()!=i+1)synfig::error("push_front before %d, after %d",i,x->count());
692 }
693
694 void
695 Canvas::insert(iterator iter,etl::handle<Layer> x)
696 {
697 //      int i(x->count());
698         CanvasBase::insert(iter,x);
699
700         /*if(x->count()!=i+1)
701         {
702                 synfig::error(__FILE__":%d: Canvas::insert(): ***FAILURE*** before %d, after %d",__LINE__,i,x->count());
703                 return;
704                 //throw runtime_error("Canvas Insertion Failed");
705         }*/
706
707         x->set_canvas(this);
708
709
710         add_child(x.get());
711
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
735         if(!x->get_group().empty())
736                 add_group_pair(x->get_group(),x);
737
738
739         changed();
740 }
741
742 void
743 Canvas::push_back_simple(etl::handle<Layer> x)
744 {
745         CanvasBase::insert(end(),x);
746         changed();
747 }
748
749 void
750 Canvas::erase(iterator iter)
751 {
752         if(!(*iter)->get_group().empty())
753                 remove_group_pair((*iter)->get_group(),(*iter));
754
755         // HACK: We really shouldn't be wiping
756         // out these signals entirely. We should
757         // only be removing the specific connections
758         // that we made. At the moment, I'm too
759         // lazy to add the code to keep track
760         // of those connections, and no one else
761         // is using these signals, so I'll just
762         // leave these next two lines like they
763         // are for now - darco 07-30-2004
764
765         // so don't wipe them out entirely
766         // - dooglus 09-21-2007
767         disconnect_connections(*iter);
768
769         if(!op_flag_)remove_child(iter->get());
770
771         CanvasBase::erase(iter);
772         if(!op_flag_)changed();
773 }
774
775 Canvas::Handle
776 Canvas::clone(const GUID& deriv_guid)const
777 {
778         synfig::String name;
779         if(is_inline())
780                 name="inline";
781         else
782         {
783                 name=get_id()+"_CLONE";
784
785                 throw runtime_error("Cloning of non-inline canvases is not yet supported");
786         }
787
788         Handle canvas(new Canvas(name));
789
790         if(is_inline())
791         {
792                 canvas->is_inline_=true;
793                 // \todo this was setting parent_=0 - is there a reason for that?
794                 // this was causing bug 1838132, where cloning an inline canvas that contains an imported image fails
795                 // it was failing to ascertain the absolute pathname of the imported image, since it needs the pathname
796                 // of the canvas to get that, which is stored in the parent canvas
797                 canvas->parent_=parent();
798                 //canvas->set_inline(parent());
799         }
800
801         canvas->set_guid(get_guid()^deriv_guid);
802
803         const_iterator iter;
804         for(iter=begin();iter!=end();++iter)
805         {
806                 Layer::Handle layer((*iter)->clone(deriv_guid));
807                 if(layer)
808                 {
809                         assert(layer.count()==1);
810                         int presize(size());
811                         canvas->push_back(layer);
812                         if(!(layer.count()>1))
813                         {
814                                 synfig::error("Canvas::clone(): Cloned layer insertion failure!");
815                                 synfig::error("Canvas::clone(): \tlayer.count()=%d",layer.count());
816                                 synfig::error("Canvas::clone(): \tlayer->get_name()=%s",layer->get_name().c_str());
817                                 synfig::error("Canvas::clone(): \tbefore size()=%d",presize);
818                                 synfig::error("Canvas::clone(): \tafter size()=%d",size());
819                         }
820                         assert(layer.count()>1);
821                 }
822                 else
823                 {
824                         synfig::error("Unable to clone layer");
825                 }
826         }
827
828         canvas->signal_group_pair_removed().clear();
829         canvas->signal_group_pair_added().clear();
830
831         return canvas;
832 }
833
834 void
835 Canvas::set_inline(LooseHandle parent)
836 {
837         if(is_inline_ && parent_)
838         {
839
840         }
841
842         id_="inline";
843         is_inline_=true;
844         parent_=parent;
845
846         // Have the parent inherit all of the group stuff
847
848         std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
849
850         for(iter=group_db_.begin();iter!=group_db_.end();++iter)
851         {
852                 parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
853         }
854
855         rend_desc()=parent->rend_desc();
856 }
857
858 Canvas::Handle
859 Canvas::create_inline(Handle parent)
860 {
861         assert(parent);
862         //if(parent->is_inline())
863         //      return create_inline(parent->parent());
864
865         Handle canvas(new Canvas("inline"));
866         canvas->set_inline(parent);
867         return canvas;
868 }
869
870 Canvas::Handle
871 Canvas::new_child_canvas()
872 {
873         if(is_inline() && parent_)
874                 return parent_->new_child_canvas();
875 //              runtime_error("You cannot create a child Canvas in an inline Canvas");
876
877         // Create a new canvas
878         children().push_back(create());
879         Canvas::Handle canvas(children().back());
880
881         canvas->parent_=this;
882
883         canvas->rend_desc()=rend_desc();
884
885         return canvas;
886 }
887
888 Canvas::Handle
889 Canvas::new_child_canvas(const String &id)
890 {
891         if(is_inline() && parent_)
892                 return parent_->new_child_canvas(id);
893 //              runtime_error("You cannot create a child Canvas in an inline Canvas");
894
895         // Create a new canvas
896         children().push_back(create());
897         Canvas::Handle canvas(children().back());
898
899         canvas->set_id(id);
900         canvas->parent_=this;
901         canvas->rend_desc()=rend_desc();
902
903         return canvas;
904 }
905
906 Canvas::Handle
907 Canvas::add_child_canvas(Canvas::Handle child_canvas, const synfig::String& id)
908 {
909         if(is_inline() && parent_)
910                 return parent_->add_child_canvas(child_canvas,id);
911
912         if(child_canvas->parent() && !child_canvas->is_inline())
913                 throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
914
915         if(!valid_id(id))
916                 throw runtime_error("Invalid ID");
917
918         try
919         {
920                 find_canvas(id);
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 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
990 String
991 Canvas::get_meta_data(const String& key)const
992 {
993         if(!meta_data_.count(key))
994                 return String();
995         return meta_data_.find(key)->second;
996 }
997
998 void
999 Canvas::set_meta_data(const String& key, const String& data)
1000 {
1001         if(meta_data_[key]!=data)
1002         {
1003                 meta_data_[key]=data;
1004                 signal_meta_data_changed()(key);
1005                 signal_meta_data_changed(key)();
1006         }
1007 }
1008
1009 void
1010 Canvas::erase_meta_data(const String& key)
1011 {
1012         if(meta_data_.count(key))
1013         {
1014                 meta_data_.erase(key);
1015                 signal_meta_data_changed()(key);
1016                 signal_meta_data_changed(key)();
1017         }
1018 }
1019
1020 std::list<String>
1021 Canvas::get_meta_data_keys()const
1022 {
1023         std::list<String> ret;
1024
1025         std::map<String,String>::const_iterator iter;
1026
1027         for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
1028                 ret.push_back(iter->first);
1029
1030         return ret;
1031 }
1032
1033 /* note - the "Motion Blur" and "Duplicate" layers need the dynamic
1034                   parameters of any PasteCanvas layers they loop over to be
1035                   maintained.  When the variables in the following function
1036                   refer to "motion blur", they mean either of these two
1037                   layers. */
1038 void
1039 synfig::optimize_layers(Time time, Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
1040 {
1041         Context iter;
1042
1043         std::vector< std::pair<float,Layer::Handle> > sort_list;
1044         int i, motion_blur_i=0; // motion_blur_i is for resolving which layer comes first in the event of a z_depth tie
1045         float motion_blur_z_depth=0; // the z_depth of the least deep motion blur layer in this context
1046         bool seen_motion_blur_locally = false;
1047         bool motion_blurred; // the final result - is this layer blurred or not?
1048
1049         // If the parent didn't cause us to already be motion blurred,
1050         // check whether there's a motion blur in this context,
1051         // and if so, calculate its z_depth.
1052         if (!seen_motion_blur_in_parent)
1053                 for(iter=context,i=0;*iter;iter++,i++)
1054                 {
1055                         Layer::Handle layer=*iter;
1056
1057                         // If the layer isn't active, don't worry about it
1058                         if(!layer->active())
1059                                 continue;
1060
1061                         // Any layer with an amount of zero is implicitly disabled.
1062                         ValueBase value(layer->get_param("amount"));
1063                         if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1064                                 continue;
1065
1066                         if(layer->get_name()=="MotionBlur" || layer->get_name()=="duplicate")
1067                         {
1068                                 float z_depth(layer->get_z_depth()*1.0001+i);
1069
1070                                 // If we've seen a motion blur before in this context...
1071                                 if (seen_motion_blur_locally)
1072                                 {
1073                                         // ... then we're only interested in this one if it's less deep...
1074                                         if (z_depth < motion_blur_z_depth)
1075                                         {
1076                                                 motion_blur_z_depth = z_depth;
1077                                                 motion_blur_i = i;
1078                                         }
1079                                 }
1080                                 // ... otherwise we're always interested in it.
1081                                 else
1082                                 {
1083                                         motion_blur_z_depth = z_depth;
1084                                         motion_blur_i = i;
1085                                         seen_motion_blur_locally = true;
1086                                 }
1087                         }
1088                 }
1089
1090         // Go ahead and start romping through the canvas to paste
1091         for(iter=context,i=0;*iter;iter++,i++)
1092         {
1093                 Layer::Handle layer=*iter;
1094                 float z_depth(layer->get_z_depth()*1.0001+i);
1095
1096                 // If the layer isn't active, don't worry about it
1097                 if(!layer->active())
1098                         continue;
1099
1100                 // Any layer with an amount of zero is implicitly disabled.
1101                 ValueBase value(layer->get_param("amount"));
1102                 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1103                         continue;
1104
1105                 // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
1106                 //               time-shifted layers weren't being sorted by z-depth (bug #1806852)
1107                 if(layer->get_name()=="PasteCanvas")
1108                 {
1109                         Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1110
1111                         // we need to blur the sub canvas if:
1112                         // our parent is blurred,
1113                         // or the child is lower than a local blur,
1114                         // or the child is at the same z_depth as a local blur, but later in the context
1115
1116 #if 0 // DEBUG
1117                         if (seen_motion_blur_in_parent)                                 synfig::info("seen BLUR in parent\n");
1118                         else if (seen_motion_blur_locally)
1119                                 if (z_depth > motion_blur_z_depth)                      synfig::info("paste is deeper than BLUR\n");
1120                                 else if (z_depth == motion_blur_z_depth) {      synfig::info("paste is same depth as BLUR\n");
1121                                         if (i > motion_blur_i)                                  synfig::info("paste is physically deeper than BLUR\n");
1122                                         else                                                                    synfig::info("paste is less physically deep than BLUR\n");
1123                                 } else                                                                          synfig::info("paste is less deep than BLUR\n");
1124                         else                                                                                    synfig::info("no BLUR at all\n");
1125 #endif  // DEBUG
1126
1127                         motion_blurred = (seen_motion_blur_in_parent ||
1128                                                           (seen_motion_blur_locally &&
1129                                                            (z_depth > motion_blur_z_depth ||
1130                                                                 (z_depth == motion_blur_z_depth && i > motion_blur_i))));
1131
1132                         Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1133                         Canvas::Handle paste_sub_canvas = paste_canvas->get_sub_canvas();
1134                         if(paste_sub_canvas)
1135                                 optimize_layers(time, paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
1136
1137 // \todo: uncommenting the following breaks the rendering of at least examples/backdrop.sifz quite severely
1138 // #define SYNFIG_OPTIMIZE_PASTE_CANVAS
1139 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
1140                         Canvas::iterator sub_iter;
1141
1142                         // Determine if we can just remove the paste canvas altogether
1143                         if (paste_canvas->get_blend_method()    == Color::BLEND_COMPOSITE       &&
1144                                 paste_canvas->get_amount()                      == 1.0f                                         &&
1145                                 paste_canvas->get_zoom()                        == 0                                            &&
1146                                 paste_canvas->get_time_offset()         == 0                                            &&
1147                                 paste_canvas->get_origin()                      == Point(0,0)                           )
1148                                 try {
1149                                         for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1150                                         {
1151                                                 Layer* layer=sub_iter->get();
1152
1153                                                 // any layers that deform end up breaking things
1154                                                 // so do things the old way if we run into anything like this
1155                                                 if(!dynamic_cast<Layer_NoDeform*>(layer))
1156                                                         throw int();
1157
1158                                                 ValueBase value(layer->get_param("blend_method"));
1159                                                 if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1160                                                         throw int();
1161                                         }
1162
1163                                         // It has turned out that we don't need a paste canvas
1164                                         // layer, so just go ahead and add all the layers onto
1165                                         // the current stack and be done with it
1166                                         while(sub_canvas->size())
1167                                         {
1168                                                 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,sub_canvas->front()));
1169                                                 //op_canvas->push_back_simple(sub_canvas->front());
1170                                                 sub_canvas->pop_front();
1171                                         }
1172                                         continue;
1173                                 }
1174                                 catch(int)
1175                                 { }
1176 #endif  // SYNFIG_OPTIMIZE_PASTE_CANVAS
1177
1178                         Layer::Handle new_layer(Layer::create("PasteCanvas"));
1179                         dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(false);
1180                         if (motion_blurred)
1181                         {
1182                                 Layer::DynamicParamList dynamic_param_list(paste_canvas->dynamic_param_list());
1183                                 for(Layer::DynamicParamList::const_iterator iter(dynamic_param_list.begin()); iter != dynamic_param_list.end(); ++iter)
1184                                         new_layer->connect_dynamic_param(iter->first, iter->second);
1185                         }
1186                         Layer::ParamList param_list(paste_canvas->get_param_list());
1187                         //param_list.erase("canvas");
1188                         new_layer->set_param_list(param_list);
1189                         dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_sub_canvas(sub_canvas);
1190                         dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
1191                         layer=new_layer;
1192                 }
1193                 else                                    // not a PasteCanvas - does it use blend method 'Straight'?
1194                 {
1195                         /* when we use the 'straight' blend method, every pixel on the layer affects the layers underneath,
1196                          * not just the non-transparent pixels; the following workarea wraps non-pastecanvas layers in a
1197                          * new pastecanvas to ensure that the straight blend affects the full plane, not just the area
1198                          * within the layer's bounding box
1199                          */
1200
1201                         // \todo: this code probably needs modification to work properly with motionblur and duplicate
1202                         etl::handle<Layer_Composite> composite = etl::handle<Layer_Composite>::cast_dynamic(layer);
1203
1204                         /* some layers (such as circle) don't touch pixels that aren't
1205                          * part of the circle, so they don't get blended correctly when
1206                          * using a straight blend.  so we encapsulate the circle, and the
1207                          * encapsulation layer takes care of the transparent pixels
1208                          * for us.  if we do that for all layers, however, then the
1209                          * distortion layers no longer work, since they have no
1210                          * context to work on.  the Layer::reads_context() method
1211                          * returns true for layers which need to be able to see
1212                          * their context.  we can't encapsulate those.
1213                          */
1214                         if (composite &&
1215                                 Color::is_straight(composite->get_blend_method()) &&
1216                                 !composite->reads_context())
1217                         {
1218                                 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1219                                 sub_canvas->push_back(composite = composite->clone());
1220                                 layer = Layer::create("PasteCanvas");
1221                                 composite->set_description(strprintf("Wrapped clone of '%s'", composite->get_non_empty_description().c_str()));
1222                                 layer->set_description(strprintf("PasteCanvas wrapper for '%s'", composite->get_non_empty_description().c_str()));
1223                                 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1224                                 paste_canvas->set_blend_method(composite->get_blend_method());
1225                                 paste_canvas->set_amount(composite->get_amount());
1226                                 sub_canvas->set_time(time); // region and outline don't calculate their bounding rects until their time is set
1227                                 composite->set_blend_method(Color::BLEND_STRAIGHT); // do this before calling set_sub_canvas(), but after set_time()
1228                                 composite->set_amount(1.0f); // after set_time()
1229                                 paste_canvas->set_sub_canvas(sub_canvas);
1230                         }
1231                 }
1232
1233                 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1234                 //op_canvas->push_back_simple(layer);
1235         }
1236
1237         //sort_list.sort();
1238         stable_sort(sort_list.begin(),sort_list.end());
1239         std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
1240         for(iter2=sort_list.begin();iter2!=sort_list.end();++iter2)
1241                 op_canvas->push_back_simple(iter2->second);
1242         op_canvas->op_flag_=true;
1243 }
1244
1245 void
1246 Canvas::get_times_vfunc(Node::time_set &set) const
1247 {
1248         const_iterator  i = begin(),
1249                                 iend = end();
1250
1251         for(; i != iend; ++i)
1252         {
1253                 const Node::time_set &tset = (*i)->get_times();
1254                 set.insert(tset.begin(),tset.end());
1255         }
1256 }
1257
1258 std::set<etl::handle<Layer> >
1259 Canvas::get_layers_in_group(const String&group)
1260 {
1261         if(is_inline() && parent_)
1262                 return parent_->get_layers_in_group(group);
1263
1264         if(group_db_.count(group)==0)
1265                 return std::set<etl::handle<Layer> >();
1266         return group_db_.find(group)->second;
1267 }
1268
1269 std::set<String>
1270 Canvas::get_groups()const
1271 {
1272         if(is_inline() && parent_)
1273                 return parent_->get_groups();
1274
1275         std::set<String> ret;
1276         std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
1277         for(iter=group_db_.begin();iter!=group_db_.end();++iter)
1278                 ret.insert(iter->first);
1279         return ret;
1280 }
1281
1282 int
1283 Canvas::get_group_count()const
1284 {
1285         if(is_inline() && parent_)
1286                 return parent_->get_group_count();
1287
1288         return group_db_.size();
1289 }
1290
1291 void
1292 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1293 {
1294         group_db_[group].insert(layer);
1295         if(group_db_[group].size()==1)
1296                 signal_group_added()(group);
1297         else
1298                 signal_group_changed()(group);
1299
1300         signal_group_pair_added()(group,layer);
1301
1302         if(is_inline()  && parent_)
1303                 return parent_->add_group_pair(group,layer);
1304 }
1305
1306 void
1307 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1308 {
1309         group_db_[group].erase(layer);
1310
1311         signal_group_pair_removed()(group,layer);
1312
1313         if(group_db_[group].empty())
1314         {
1315                 group_db_.erase(group);
1316                 signal_group_removed()(group);
1317         }
1318         else
1319                 signal_group_changed()(group);
1320
1321         if(is_inline() && parent_)
1322                 return parent_->remove_group_pair(group,layer);
1323 }
1324
1325 void
1326 Canvas::add_connection(etl::loose_handle<Layer> layer, sigc::connection connection)
1327 {
1328         connections_[layer].push_back(connection);
1329 }
1330
1331 void
1332 Canvas::disconnect_connections(etl::loose_handle<Layer> layer)
1333 {
1334         std::vector<sigc::connection>::iterator iter;
1335         for(iter=connections_[layer].begin();iter!=connections_[layer].end();++iter)
1336                 iter->disconnect();
1337         connections_[layer].clear();
1338 }
1339
1340 void
1341 Canvas::rename_group(const String&old_name,const String&new_name)
1342 {
1343         if(is_inline() && parent_)
1344                 return parent_->rename_group(old_name,new_name);
1345
1346         {
1347                 std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
1348                 iter=group_db_.find(old_name);
1349                 if(iter!=group_db_.end())
1350                 for(++iter;iter!=group_db_.end() && iter->first.find(old_name)==0;iter=group_db_.find(old_name),++iter)
1351                 {
1352                         String name(iter->first,old_name.size(),String::npos);
1353                         name=new_name+name;
1354                         rename_group(iter->first,name);
1355                 }
1356         }
1357
1358         std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1359         std::set<etl::handle<Layer> >::iterator iter;
1360
1361         for(iter=layers.begin();iter!=layers.end();++iter)
1362         {
1363                 (*iter)->remove_from_group(old_name);
1364                 (*iter)->add_to_group(new_name);
1365         }
1366 }