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