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