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