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