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