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