Make Canvas::find_canvas() and Canvas::surefind_canvas() look more alike. No functio...
[synfig.git] / synfig-core / trunk / src / synfig / canvas.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file canvas.cpp
3 **      \brief Canvas Class Member Definitions
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007, 2008 Chris Moore
10 **
11 **      This package is free software; you can redistribute it and/or
12 **      modify it under the terms of the GNU General Public License as
13 **      published by the Free Software Foundation; either version 2 of
14 **      the License, or (at your option) any later version.
15 **
16 **      This package is distributed in the hope that it will be useful,
17 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **      General Public License for more details.
20 **      \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #define SYNFIG_NO_ANGLE
27
28 #ifdef USING_PCH
29 #       include "pch.h"
30 #else
31 #ifdef HAVE_CONFIG_H
32 #       include <config.h>
33 #endif
34
35 #include "layer.h"
36 #include "canvas.h"
37 #include <cassert>
38 #include "exception.h"
39 #include "time.h"
40 #include "context.h"
41 #include "layer_pastecanvas.h"
42 #include <sigc++/bind.h>
43
44 #endif
45
46 using namespace synfig;
47 using namespace etl;
48 using namespace std;
49
50 namespace synfig { extern Canvas::Handle open_canvas(const String &filename, String &errors); };
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                         String errors;
541                         if(is_absolute_path(file_name))
542                                 external_canvas=open_canvas(file_name, errors);
543                         else
544                                 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name, errors);
545
546                         if(!external_canvas)
547                                 throw Exception::FileNotFound(file_name);
548                         externals_[file_name]=external_canvas;
549                 }
550
551                 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
552         }
553
554         // If we do not have any resolution, then we assume that the
555         // request is for this immediate canvas
556         if(id.find_first_of(':')==string::npos)
557         {
558                 Children::iterator iter;
559
560                 // Search for the image in the image list,
561                 // and return it if it is found
562                 for(iter=children().begin();iter!=children().end();iter++)
563                         if(id==(*iter)->get_id())
564                                 return *iter;
565
566                 // Create a new canvas and return it
567                 //synfig::warning("Implicitly creating canvas named "+id);
568                 return new_child_canvas(id);
569         }
570
571         // If the first character is the separator, then
572         // this references the root canvas.
573         if(id[0]==':')
574                 return get_root()->surefind_canvas(string(id,1));
575
576         // Now we know that the requested Canvas is in a child
577         // of this canvas. We have to find that canvas and
578         // call "find_canvas" on it, and return the result.
579
580         String canvas_name=string(id,0,id.find_first_of(':'));
581
582         Canvas::Handle child_canvas=surefind_canvas(canvas_name);
583
584         return child_canvas->surefind_canvas(string(id,id.find_first_of(':')+1));
585 }
586
587 Canvas::Handle
588 Canvas::find_canvas(const String &id)
589 {
590         return
591                 Canvas::Handle::cast_const(
592                         const_cast<const Canvas*>(this)->find_canvas(id)
593                 );
594 }
595
596 Canvas::ConstHandle
597 Canvas::find_canvas(const String &id)const
598 {
599         if(is_inline() && parent_)
600                 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                         String errors;
628                         if(is_absolute_path(file_name))
629                                 external_canvas=open_canvas(file_name, errors);
630                         else
631                                 external_canvas=open_canvas(get_file_path()+ETL_DIRECTORY_SEPARATOR+file_name, errors);
632
633                         if(!external_canvas)
634                                 throw Exception::FileNotFound(file_name);
635                         externals_[file_name]=external_canvas;
636                 }
637
638                 return Handle::cast_const(external_canvas.constant()->find_canvas(external_id));
639         }
640
641         // If we do not have any resolution, then we assume that the
642         // request is for this immediate canvas
643         if(id.find_first_of(':')==string::npos)
644         {
645                 Children::const_iterator iter;
646
647                 // Search for the image in the image list,
648                 // and return it if it is found
649                 for(iter=children().begin();iter!=children().end();iter++)
650                         if(id==(*iter)->get_id())
651                                 return *iter;
652
653                 throw Exception::IDNotFound("Child Canvas in Parent Canvas: (child)"+id);
654         }
655
656         // If the first character is the separator, then
657         // this references the root canvas.
658         if(id[0]==':')
659                 return get_root()->find_canvas(string(id,1));
660
661         // Now we know that the requested Canvas is in a child
662         // of this canvas. We have to find that canvas and
663         // call "find_canvas" on it, and return the result.
664
665         String canvas_name=string(id,0,id.find_first_of(':'));
666
667         Canvas::ConstHandle child_canvas=find_canvas(canvas_name);
668
669         return child_canvas->find_canvas(string(id,id.find_first_of(':')+1));
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         add_child(x.get());
710
711         LooseHandle correct_canvas(this);
712         //while(correct_canvas->is_inline())correct_canvas=correct_canvas->parent();
713         Layer::LooseHandle loose_layer(x);
714
715         add_connection(loose_layer,
716                                    sigc::connection::connection(
717                                            x->signal_added_to_group().connect(
718                                                    sigc::bind(
719                                                            sigc::mem_fun(
720                                                                    *correct_canvas,
721                                                                    &Canvas::add_group_pair),
722                                                            loose_layer))));
723         add_connection(loose_layer,
724                                    sigc::connection::connection(
725                                            x->signal_removed_from_group().connect(
726                                                    sigc::bind(
727                                                            sigc::mem_fun(
728                                                                    *correct_canvas,
729                                                                    &Canvas::remove_group_pair),
730                                                            loose_layer))));
731
732         if(!x->get_group().empty())
733                 add_group_pair(x->get_group(),x);
734
735         changed();
736 }
737
738 void
739 Canvas::push_back_simple(etl::handle<Layer> x)
740 {
741         CanvasBase::insert(end(),x);
742         changed();
743 }
744
745 void
746 Canvas::erase(iterator iter)
747 {
748         if(!(*iter)->get_group().empty())
749                 remove_group_pair((*iter)->get_group(),(*iter));
750
751         // HACK: We really shouldn't be wiping
752         // out these signals entirely. We should
753         // only be removing the specific connections
754         // that we made. At the moment, I'm too
755         // lazy to add the code to keep track
756         // of those connections, and no one else
757         // is using these signals, so I'll just
758         // leave these next two lines like they
759         // are for now - darco 07-30-2004
760
761         // so don't wipe them out entirely
762         // - dooglus 09-21-2007
763         disconnect_connections(*iter);
764
765         if(!op_flag_)remove_child(iter->get());
766
767         CanvasBase::erase(iter);
768         if(!op_flag_)changed();
769 }
770
771 Canvas::Handle
772 Canvas::clone(const GUID& deriv_guid)const
773 {
774         synfig::String name;
775         if(is_inline())
776                 name="inline";
777         else
778         {
779                 name=get_id()+"_CLONE";
780
781                 throw runtime_error("Cloning of non-inline canvases is not yet supported");
782         }
783
784         Handle canvas(new Canvas(name));
785
786         if(is_inline())
787         {
788                 canvas->is_inline_=true;
789                 // \todo this was setting parent_=0 - is there a reason for that?
790                 // this was causing bug 1838132, where cloning an inline canvas that contains an imported image fails
791                 // it was failing to ascertain the absolute pathname of the imported image, since it needs the pathname
792                 // of the canvas to get that, which is stored in the parent canvas
793                 canvas->parent_=parent();
794                 canvas->rend_desc() = rend_desc();
795                 //canvas->set_inline(parent());
796         }
797
798         canvas->set_guid(get_guid()^deriv_guid);
799
800         const_iterator iter;
801         for(iter=begin();iter!=end();++iter)
802         {
803                 Layer::Handle layer((*iter)->clone(deriv_guid));
804                 if(layer)
805                 {
806                         assert(layer.count()==1);
807                         int presize(size());
808                         canvas->push_back(layer);
809                         if(!(layer.count()>1))
810                         {
811                                 synfig::error("Canvas::clone(): Cloned layer insertion failure!");
812                                 synfig::error("Canvas::clone(): \tlayer.count()=%d",layer.count());
813                                 synfig::error("Canvas::clone(): \tlayer->get_name()=%s",layer->get_name().c_str());
814                                 synfig::error("Canvas::clone(): \tbefore size()=%d",presize);
815                                 synfig::error("Canvas::clone(): \tafter size()=%d",size());
816                         }
817                         assert(layer.count()>1);
818                 }
819                 else
820                 {
821                         synfig::error("Unable to clone layer");
822                 }
823         }
824
825         canvas->signal_group_pair_removed().clear();
826         canvas->signal_group_pair_added().clear();
827
828         return canvas;
829 }
830
831 void
832 Canvas::set_inline(LooseHandle parent)
833 {
834         if(is_inline_ && parent_)
835         {
836
837         }
838
839         id_="inline";
840         is_inline_=true;
841         parent_=parent;
842
843         // Have the parent inherit all of the group stuff
844
845         std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
846
847         for(iter=group_db_.begin();iter!=group_db_.end();++iter)
848         {
849                 parent->group_db_[iter->first].insert(iter->second.begin(),iter->second.end());
850         }
851
852         rend_desc()=parent->rend_desc();
853 }
854
855 Canvas::Handle
856 Canvas::create_inline(Handle parent)
857 {
858         assert(parent);
859         //if(parent->is_inline())
860         //      return create_inline(parent->parent());
861
862         Handle canvas(new Canvas("inline"));
863         canvas->set_inline(parent);
864         return canvas;
865 }
866
867 Canvas::Handle
868 Canvas::new_child_canvas()
869 {
870         if(is_inline() && parent_)
871                 return parent_->new_child_canvas();
872 //              runtime_error("You cannot create a child Canvas in an inline Canvas");
873
874         // Create a new canvas
875         children().push_back(create());
876         Canvas::Handle canvas(children().back());
877
878         canvas->parent_=this;
879
880         canvas->rend_desc()=rend_desc();
881
882         return canvas;
883 }
884
885 Canvas::Handle
886 Canvas::new_child_canvas(const String &id)
887 {
888         if(is_inline() && parent_)
889                 return parent_->new_child_canvas(id);
890 //              runtime_error("You cannot create a child Canvas in an inline Canvas");
891
892         // Create a new canvas
893         children().push_back(create());
894         Canvas::Handle canvas(children().back());
895
896         canvas->set_id(id);
897         canvas->parent_=this;
898         canvas->rend_desc()=rend_desc();
899
900         return canvas;
901 }
902
903 Canvas::Handle
904 Canvas::add_child_canvas(Canvas::Handle child_canvas, const synfig::String& id)
905 {
906         if(is_inline() && parent_)
907                 return parent_->add_child_canvas(child_canvas,id);
908
909         if(child_canvas->parent() && !child_canvas->is_inline())
910                 throw std::runtime_error("Cannot add child canvas because it belongs to someone else!");
911
912         if(!valid_id(id))
913                 throw runtime_error("Invalid ID");
914
915         try
916         {
917                 find_canvas(id);
918                 throw Exception::IDAlreadyExists(id);
919         }
920         catch(Exception::IDNotFound)
921         {
922                 if(child_canvas->is_inline())
923                         child_canvas->is_inline_=false;
924                 child_canvas->id_=id;
925                 children().push_back(child_canvas);
926                 child_canvas->parent_=this;
927         }
928
929         return child_canvas;
930 }
931
932 void
933 Canvas::remove_child_canvas(Canvas::Handle child_canvas)
934 {
935         if(is_inline() && parent_)
936                 return parent_->remove_child_canvas(child_canvas);
937
938         if(child_canvas->parent_!=this)
939                 throw runtime_error("Given child does not belong to me");
940
941         if(find(children().begin(),children().end(),child_canvas)==children().end())
942                 throw Exception::IDNotFound(child_canvas->get_id());
943
944         children().remove(child_canvas);
945
946         child_canvas->parent_=0;
947 }
948
949 void
950 Canvas::set_file_name(const String &file_name)
951 {
952         if(parent())
953                 parent()->set_file_name(file_name);
954         else
955         {
956                 file_name_=file_name;
957                 signal_file_name_changed_();
958         }
959 }
960
961 sigc::signal<void>&
962 Canvas::signal_file_name_changed()
963 {
964         if(parent())
965                 return signal_file_name_changed();
966         else
967                 return signal_file_name_changed_;
968 }
969
970 String
971 Canvas::get_file_name()const
972 {
973         if(parent())
974                 return parent()->get_file_name();
975         return file_name_;
976 }
977
978 String
979 Canvas::get_file_path()const
980 {
981         if(parent())
982                 return parent()->get_file_path();
983         return dirname(file_name_);
984 }
985
986 String
987 Canvas::get_meta_data(const String& key)const
988 {
989         if(!meta_data_.count(key))
990                 return String();
991         return meta_data_.find(key)->second;
992 }
993
994 void
995 Canvas::set_meta_data(const String& key, const String& data)
996 {
997         if(meta_data_[key]!=data)
998         {
999                 meta_data_[key]=data;
1000                 signal_meta_data_changed()(key);
1001                 signal_meta_data_changed(key)();
1002         }
1003 }
1004
1005 void
1006 Canvas::erase_meta_data(const String& key)
1007 {
1008         if(meta_data_.count(key))
1009         {
1010                 meta_data_.erase(key);
1011                 signal_meta_data_changed()(key);
1012                 signal_meta_data_changed(key)();
1013         }
1014 }
1015
1016 std::list<String>
1017 Canvas::get_meta_data_keys()const
1018 {
1019         std::list<String> ret;
1020
1021         std::map<String,String>::const_iterator iter;
1022
1023         for(iter=meta_data_.begin();!(iter==meta_data_.end());++iter)
1024                 ret.push_back(iter->first);
1025
1026         return ret;
1027 }
1028
1029 /* note - the "Motion Blur" and "Duplicate" layers need the dynamic
1030                   parameters of any PasteCanvas layers they loop over to be
1031                   maintained.  When the variables in the following function
1032                   refer to "motion blur", they mean either of these two
1033                   layers. */
1034 void
1035 synfig::optimize_layers(Time time, Context context, Canvas::Handle op_canvas, bool seen_motion_blur_in_parent)
1036 {
1037         Context iter;
1038
1039         std::vector< std::pair<float,Layer::Handle> > sort_list;
1040         int i, motion_blur_i=0; // motion_blur_i is for resolving which layer comes first in the event of a z_depth tie
1041         float motion_blur_z_depth=0; // the z_depth of the least deep motion blur layer in this context
1042         bool seen_motion_blur_locally = false;
1043         bool motion_blurred; // the final result - is this layer blurred or not?
1044
1045         // If the parent didn't cause us to already be motion blurred,
1046         // check whether there's a motion blur in this context,
1047         // and if so, calculate its z_depth.
1048         if (!seen_motion_blur_in_parent)
1049                 for(iter=context,i=0;*iter;iter++,i++)
1050                 {
1051                         Layer::Handle layer=*iter;
1052
1053                         // If the layer isn't active, don't worry about it
1054                         if(!layer->active())
1055                                 continue;
1056
1057                         // Any layer with an amount of zero is implicitly disabled.
1058                         ValueBase value(layer->get_param("amount"));
1059                         if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1060                                 continue;
1061
1062                         if(layer->get_name()=="MotionBlur" || layer->get_name()=="duplicate")
1063                         {
1064                                 float z_depth(layer->get_z_depth()*1.0001+i);
1065
1066                                 // If we've seen a motion blur before in this context...
1067                                 if (seen_motion_blur_locally)
1068                                 {
1069                                         // ... then we're only interested in this one if it's less deep...
1070                                         if (z_depth < motion_blur_z_depth)
1071                                         {
1072                                                 motion_blur_z_depth = z_depth;
1073                                                 motion_blur_i = i;
1074                                         }
1075                                 }
1076                                 // ... otherwise we're always interested in it.
1077                                 else
1078                                 {
1079                                         motion_blur_z_depth = z_depth;
1080                                         motion_blur_i = i;
1081                                         seen_motion_blur_locally = true;
1082                                 }
1083                         }
1084                 }
1085
1086         // Go ahead and start romping through the canvas to paste
1087         for(iter=context,i=0;*iter;iter++,i++)
1088         {
1089                 Layer::Handle layer=*iter;
1090                 float z_depth(layer->get_z_depth()*1.0001+i);
1091
1092                 // If the layer isn't active, don't worry about it
1093                 if(!layer->active())
1094                         continue;
1095
1096                 // Any layer with an amount of zero is implicitly disabled.
1097                 ValueBase value(layer->get_param("amount"));
1098                 if(value.get_type()==ValueBase::TYPE_REAL && value.get(Real())==0)
1099                         continue;
1100
1101                 // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
1102                 //               time-shifted layers weren't being sorted by z-depth (bug #1806852)
1103                 if(layer->get_name()=="PasteCanvas")
1104                 {
1105                         Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1106
1107                         // we need to blur the sub canvas if:
1108                         // our parent is blurred,
1109                         // or the child is lower than a local blur,
1110                         // or the child is at the same z_depth as a local blur, but later in the context
1111
1112 #if 0 // DEBUG
1113                         if (seen_motion_blur_in_parent)                                 synfig::info("seen BLUR in parent\n");
1114                         else if (seen_motion_blur_locally)
1115                                 if (z_depth > motion_blur_z_depth)                      synfig::info("paste is deeper than BLUR\n");
1116                                 else if (z_depth == motion_blur_z_depth) {      synfig::info("paste is same depth as BLUR\n");
1117                                         if (i > motion_blur_i)                                  synfig::info("paste is physically deeper than BLUR\n");
1118                                         else                                                                    synfig::info("paste is less physically deep than BLUR\n");
1119                                 } else                                                                          synfig::info("paste is less deep than BLUR\n");
1120                         else                                                                                    synfig::info("no BLUR at all\n");
1121 #endif  // DEBUG
1122
1123                         motion_blurred = (seen_motion_blur_in_parent ||
1124                                                           (seen_motion_blur_locally &&
1125                                                            (z_depth > motion_blur_z_depth ||
1126                                                                 (z_depth == motion_blur_z_depth && i > motion_blur_i))));
1127
1128                         Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1129                         Canvas::Handle paste_sub_canvas = paste_canvas->get_sub_canvas();
1130                         if(paste_sub_canvas)
1131                                 optimize_layers(time, paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
1132
1133 // \todo: uncommenting the following breaks the rendering of at least examples/backdrop.sifz quite severely
1134 // #define SYNFIG_OPTIMIZE_PASTE_CANVAS
1135 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
1136                         Canvas::iterator sub_iter;
1137
1138                         // Determine if we can just remove the paste canvas altogether
1139                         if (paste_canvas->get_blend_method()    == Color::BLEND_COMPOSITE       &&
1140                                 paste_canvas->get_amount()                      == 1.0f                                         &&
1141                                 paste_canvas->get_zoom()                        == 0                                            &&
1142                                 paste_canvas->get_time_offset()         == 0                                            &&
1143                                 paste_canvas->get_origin()                      == Point(0,0)                           )
1144                                 try {
1145                                         for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1146                                         {
1147                                                 Layer* layer=sub_iter->get();
1148
1149                                                 // any layers that deform end up breaking things
1150                                                 // so do things the old way if we run into anything like this
1151                                                 if(!dynamic_cast<Layer_NoDeform*>(layer))
1152                                                         throw int();
1153
1154                                                 ValueBase value(layer->get_param("blend_method"));
1155                                                 if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1156                                                         throw int();
1157                                         }
1158
1159                                         // It has turned out that we don't need a paste canvas
1160                                         // layer, so just go ahead and add all the layers onto
1161                                         // the current stack and be done with it
1162                                         while(sub_canvas->size())
1163                                         {
1164                                                 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,sub_canvas->front()));
1165                                                 //op_canvas->push_back_simple(sub_canvas->front());
1166                                                 sub_canvas->pop_front();
1167                                         }
1168                                         continue;
1169                                 }
1170                                 catch(int)
1171                                 { }
1172 #endif  // SYNFIG_OPTIMIZE_PASTE_CANVAS
1173
1174                         Layer::Handle new_layer(Layer::create("PasteCanvas"));
1175                         dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(false);
1176                         if (motion_blurred)
1177                         {
1178                                 Layer::DynamicParamList dynamic_param_list(paste_canvas->dynamic_param_list());
1179                                 for(Layer::DynamicParamList::const_iterator iter(dynamic_param_list.begin()); iter != dynamic_param_list.end(); ++iter)
1180                                         new_layer->connect_dynamic_param(iter->first, iter->second);
1181                         }
1182                         Layer::ParamList param_list(paste_canvas->get_param_list());
1183                         //param_list.erase("canvas");
1184                         new_layer->set_param_list(param_list);
1185                         dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_sub_canvas(sub_canvas);
1186                         dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
1187                         layer=new_layer;
1188                 }
1189                 else                                    // not a PasteCanvas - does it use blend method 'Straight'?
1190                 {
1191                         /* when we use the 'straight' blend method, every pixel on the layer affects the layers underneath,
1192                          * not just the non-transparent pixels; the following workarea wraps non-pastecanvas layers in a
1193                          * new pastecanvas to ensure that the straight blend affects the full plane, not just the area
1194                          * within the layer's bounding box
1195                          */
1196
1197                         // \todo: this code probably needs modification to work properly with motionblur and duplicate
1198                         etl::handle<Layer_Composite> composite = etl::handle<Layer_Composite>::cast_dynamic(layer);
1199
1200                         /* some layers (such as circle) don't touch pixels that aren't
1201                          * part of the circle, so they don't get blended correctly when
1202                          * using a straight blend.  so we encapsulate the circle, and the
1203                          * encapsulation layer takes care of the transparent pixels
1204                          * for us.  if we do that for all layers, however, then the
1205                          * distortion layers no longer work, since they have no
1206                          * context to work on.  the Layer::reads_context() method
1207                          * returns true for layers which need to be able to see
1208                          * their context.  we can't encapsulate those.
1209                          */
1210                         if (composite &&
1211                                 Color::is_straight(composite->get_blend_method()) &&
1212                                 !composite->reads_context())
1213                         {
1214                                 Canvas::Handle sub_canvas(Canvas::create_inline(op_canvas));
1215                                 sub_canvas->push_back(composite = composite->clone());
1216                                 layer = Layer::create("PasteCanvas");
1217                                 composite->set_description(strprintf("Wrapped clone of '%s'", composite->get_non_empty_description().c_str()));
1218                                 layer->set_description(strprintf("PasteCanvas wrapper for '%s'", composite->get_non_empty_description().c_str()));
1219                                 Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
1220                                 paste_canvas->set_blend_method(composite->get_blend_method());
1221                                 paste_canvas->set_amount(composite->get_amount());
1222                                 sub_canvas->set_time(time); // region and outline don't calculate their bounding rects until their time is set
1223                                 composite->set_blend_method(Color::BLEND_STRAIGHT); // do this before calling set_sub_canvas(), but after set_time()
1224                                 composite->set_amount(1.0f); // after set_time()
1225                                 paste_canvas->set_sub_canvas(sub_canvas);
1226                         }
1227                 }
1228
1229                 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1230                 //op_canvas->push_back_simple(layer);
1231         }
1232
1233         //sort_list.sort();
1234         stable_sort(sort_list.begin(),sort_list.end());
1235         std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
1236         for(iter2=sort_list.begin();iter2!=sort_list.end();++iter2)
1237                 op_canvas->push_back_simple(iter2->second);
1238         op_canvas->op_flag_=true;
1239 }
1240
1241 void
1242 Canvas::get_times_vfunc(Node::time_set &set) const
1243 {
1244         const_iterator  i = begin(),
1245                                 iend = end();
1246
1247         for(; i != iend; ++i)
1248         {
1249                 const Node::time_set &tset = (*i)->get_times();
1250                 set.insert(tset.begin(),tset.end());
1251         }
1252 }
1253
1254 std::set<etl::handle<Layer> >
1255 Canvas::get_layers_in_group(const String&group)
1256 {
1257         if(is_inline() && parent_)
1258                 return parent_->get_layers_in_group(group);
1259
1260         if(group_db_.count(group)==0)
1261                 return std::set<etl::handle<Layer> >();
1262         return group_db_.find(group)->second;
1263 }
1264
1265 std::set<String>
1266 Canvas::get_groups()const
1267 {
1268         if(is_inline() && parent_)
1269                 return parent_->get_groups();
1270
1271         std::set<String> ret;
1272         std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
1273         for(iter=group_db_.begin();iter!=group_db_.end();++iter)
1274                 ret.insert(iter->first);
1275         return ret;
1276 }
1277
1278 int
1279 Canvas::get_group_count()const
1280 {
1281         if(is_inline() && parent_)
1282                 return parent_->get_group_count();
1283
1284         return group_db_.size();
1285 }
1286
1287 void
1288 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1289 {
1290         group_db_[group].insert(layer);
1291         if(group_db_[group].size()==1)
1292                 signal_group_added()(group);
1293         else
1294                 signal_group_changed()(group);
1295
1296         signal_group_pair_added()(group,layer);
1297
1298         if(is_inline()  && parent_)
1299                 return parent_->add_group_pair(group,layer);
1300 }
1301
1302 void
1303 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1304 {
1305         group_db_[group].erase(layer);
1306
1307         signal_group_pair_removed()(group,layer);
1308
1309         if(group_db_[group].empty())
1310         {
1311                 group_db_.erase(group);
1312                 signal_group_removed()(group);
1313         }
1314         else
1315                 signal_group_changed()(group);
1316
1317         if(is_inline() && parent_)
1318                 return parent_->remove_group_pair(group,layer);
1319 }
1320
1321 void
1322 Canvas::add_connection(etl::loose_handle<Layer> layer, sigc::connection connection)
1323 {
1324         connections_[layer].push_back(connection);
1325 }
1326
1327 void
1328 Canvas::disconnect_connections(etl::loose_handle<Layer> layer)
1329 {
1330         std::vector<sigc::connection>::iterator iter;
1331         for(iter=connections_[layer].begin();iter!=connections_[layer].end();++iter)
1332                 iter->disconnect();
1333         connections_[layer].clear();
1334 }
1335
1336 void
1337 Canvas::rename_group(const String&old_name,const String&new_name)
1338 {
1339         if(is_inline() && parent_)
1340                 return parent_->rename_group(old_name,new_name);
1341
1342         {
1343                 std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
1344                 iter=group_db_.find(old_name);
1345                 if(iter!=group_db_.end())
1346                 for(++iter;iter!=group_db_.end() && iter->first.find(old_name)==0;iter=group_db_.find(old_name),++iter)
1347                 {
1348                         String name(iter->first,old_name.size(),String::npos);
1349                         name=new_name+name;
1350                         rename_group(iter->first,name);
1351                 }
1352         }
1353
1354         std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1355         std::set<etl::handle<Layer> >::iterator iter;
1356
1357         for(iter=layers.begin();iter!=layers.end();++iter)
1358         {
1359                 (*iter)->remove_from_group(old_name);
1360                 (*iter)->add_to_group(new_name);
1361         }
1362 }