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