Pass the current 'time' value when optimizing layers. We're going to need it in...
[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(Time time, 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                 // note: this used to include "&& paste_canvas->get_time_offset()==0", but then
1086                 //               time-shifted layers weren't being sorted by z-depth (bug #1806852)
1087                 if(layer->get_name()=="PasteCanvas")
1088                 {
1089                         Layer_PasteCanvas* paste_canvas(static_cast<Layer_PasteCanvas*>(layer.get()));
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(time, paste_sub_canvas->get_context(),sub_canvas,motion_blurred);
1116
1117 // \todo: uncommenting the following breaks the rendering of at least examples/backdrop.sifz quite severely
1118 // #define SYNFIG_OPTIMIZE_PASTE_CANVAS
1119 #ifdef SYNFIG_OPTIMIZE_PASTE_CANVAS
1120                         Canvas::iterator sub_iter;
1121
1122                         // Determine if we can just remove the paste canvas altogether
1123                         if (paste_canvas->get_blend_method()    == Color::BLEND_COMPOSITE       &&
1124                                 paste_canvas->get_amount()                      == 1.0f                                         &&
1125                                 paste_canvas->get_zoom()                        == 0                                            &&
1126                                 paste_canvas->get_time_offset()         == 0                                            &&
1127                                 paste_canvas->get_origin()                      == Point(0,0)                           )
1128                                 try {
1129                                         for(sub_iter=sub_canvas->begin();sub_iter!=sub_canvas->end();++sub_iter)
1130                                         {
1131                                                 Layer* layer=sub_iter->get();
1132
1133                                                 // any layers that deform end up breaking things
1134                                                 // so do things the old way if we run into anything like this
1135                                                 if(!dynamic_cast<Layer_NoDeform*>(layer))
1136                                                         throw int();
1137
1138                                                 ValueBase value(layer->get_param("blend_method"));
1139                                                 if(value.get_type()!=ValueBase::TYPE_INTEGER || value.get(int())!=(int)Color::BLEND_COMPOSITE)
1140                                                         throw int();
1141                                         }
1142
1143                                         // It has turned out that we don't need a paste canvas
1144                                         // layer, so just go ahead and add all the layers onto
1145                                         // the current stack and be done with it
1146                                         while(sub_canvas->size())
1147                                         {
1148                                                 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,sub_canvas->front()));
1149                                                 //op_canvas->push_back_simple(sub_canvas->front());
1150                                                 sub_canvas->pop_front();
1151                                         }
1152                                         continue;
1153                                 }
1154                                 catch(int)
1155                                 { }
1156 #endif  // SYNFIG_OPTIMIZE_PASTE_CANVAS
1157
1158                         Layer::Handle new_layer(Layer::create("PasteCanvas"));
1159                         dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(false);
1160                         if (motion_blurred)
1161                         {
1162                                 Layer::DynamicParamList dynamic_param_list(paste_canvas->dynamic_param_list());
1163                                 for(Layer::DynamicParamList::const_iterator iter(dynamic_param_list.begin()); iter != dynamic_param_list.end(); ++iter)
1164                                         new_layer->connect_dynamic_param(iter->first, iter->second);
1165                         }
1166                         Layer::ParamList param_list(paste_canvas->get_param_list());
1167                         //param_list.erase("canvas");
1168                         new_layer->set_param_list(param_list);
1169                         dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_sub_canvas(sub_canvas);
1170                         dynamic_cast<Layer_PasteCanvas*>(new_layer.get())->set_muck_with_time(true);
1171                         layer=new_layer;
1172                 }
1173
1174                 sort_list.push_back(std::pair<float,Layer::Handle>(z_depth,layer));
1175                 //op_canvas->push_back_simple(layer);
1176         }
1177
1178         //sort_list.sort();
1179         stable_sort(sort_list.begin(),sort_list.end());
1180         std::vector< std::pair<float,Layer::Handle> >::iterator iter2;
1181         for(iter2=sort_list.begin();iter2!=sort_list.end();++iter2)
1182                 op_canvas->push_back_simple(iter2->second);
1183         op_canvas->op_flag_=true;
1184 }
1185
1186 void
1187 Canvas::get_times_vfunc(Node::time_set &set) const
1188 {
1189         const_iterator  i = begin(),
1190                                 iend = end();
1191
1192         for(; i != iend; ++i)
1193         {
1194                 const Node::time_set &tset = (*i)->get_times();
1195                 set.insert(tset.begin(),tset.end());
1196         }
1197 }
1198
1199 std::set<etl::handle<Layer> >
1200 Canvas::get_layers_in_group(const String&group)
1201 {
1202         if(is_inline() && parent_)
1203                 return parent_->get_layers_in_group(group);
1204
1205         if(group_db_.count(group)==0)
1206                 return std::set<etl::handle<Layer> >();
1207         return group_db_.find(group)->second;
1208 }
1209
1210 std::set<String>
1211 Canvas::get_groups()const
1212 {
1213         if(is_inline() && parent_)
1214                 return parent_->get_groups();
1215
1216         std::set<String> ret;
1217         std::map<String,std::set<etl::handle<Layer> > >::const_iterator iter;
1218         for(iter=group_db_.begin();iter!=group_db_.end();++iter)
1219                 ret.insert(iter->first);
1220         return ret;
1221 }
1222
1223 int
1224 Canvas::get_group_count()const
1225 {
1226         if(is_inline() && parent_)
1227                 return parent_->get_group_count();
1228
1229         return group_db_.size();
1230 }
1231
1232 void
1233 Canvas::add_group_pair(String group, etl::handle<Layer> layer)
1234 {
1235         group_db_[group].insert(layer);
1236         if(group_db_[group].size()==1)
1237                 signal_group_added()(group);
1238         else
1239                 signal_group_changed()(group);
1240
1241         signal_group_pair_added()(group,layer);
1242
1243         if(is_inline()  && parent_)
1244                 return parent_->add_group_pair(group,layer);
1245 }
1246
1247 void
1248 Canvas::remove_group_pair(String group, etl::handle<Layer> layer)
1249 {
1250         group_db_[group].erase(layer);
1251
1252         signal_group_pair_removed()(group,layer);
1253
1254         if(group_db_[group].empty())
1255         {
1256                 group_db_.erase(group);
1257                 signal_group_removed()(group);
1258         }
1259         else
1260                 signal_group_changed()(group);
1261
1262         if(is_inline() && parent_)
1263                 return parent_->remove_group_pair(group,layer);
1264 }
1265
1266 void
1267 Canvas::add_connection(etl::loose_handle<Layer> layer, sigc::connection connection)
1268 {
1269         connections_[layer].push_back(connection);
1270 }
1271
1272 void
1273 Canvas::disconnect_connections(etl::loose_handle<Layer> layer)
1274 {
1275         std::vector<sigc::connection>::iterator iter;
1276         for(iter=connections_[layer].begin();iter!=connections_[layer].end();++iter)
1277                 iter->disconnect();
1278         connections_[layer].clear();
1279 }
1280
1281 void
1282 Canvas::rename_group(const String&old_name,const String&new_name)
1283 {
1284         if(is_inline() && parent_)
1285                 return parent_->rename_group(old_name,new_name);
1286
1287         {
1288                 std::map<String,std::set<etl::handle<Layer> > >::iterator iter;
1289                 iter=group_db_.find(old_name);
1290                 if(iter!=group_db_.end())
1291                 for(++iter;iter!=group_db_.end() && iter->first.find(old_name)==0;iter=group_db_.find(old_name),++iter)
1292                 {
1293                         String name(iter->first,old_name.size(),String::npos);
1294                         name=new_name+name;
1295                         rename_group(iter->first,name);
1296                 }
1297         }
1298
1299         std::set<etl::handle<Layer> > layers(get_layers_in_group(old_name));
1300         std::set<etl::handle<Layer> >::iterator iter;
1301
1302         for(iter=layers.begin();iter!=layers.end();++iter)
1303         {
1304                 (*iter)->remove_from_group(old_name);
1305                 (*iter)->add_to_group(new_name);
1306         }
1307 }