Merge branch 'tidying' into chris
[synfig.git] / synfig-studio / trunk / src / synfigapp / canvasinterface.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file canvasinterface.cpp
3 **      \brief Template File
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 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 //#include <iostream>
33
34 #include <ETL/clock>
35 #include <synfig/valuenode_scale.h>
36 #include <synfig/valuenode_timedswap.h>
37 #include <synfig/valuenode_composite.h>
38 #include <synfig/valuenode_subtract.h>
39 #include <synfig/valuenode_linear.h>
40 #include <synfig/valuenode_reference.h>
41 #include <synfig/valuenode_twotone.h>
42 #include <synfig/valuenode_stripes.h>
43
44 #include <synfig/waypoint.h>
45 #include <synfig/loadcanvas.h>
46 #include <synfig/importer.h>
47 #include <synfig/guidset.h>
48
49 #include "canvasinterface.h"
50 #include "instance.h"
51
52 #include "actions/layeradd.h"
53 #include "actions/valuedescconvert.h"
54 #include "actions/valuenodeadd.h"
55 #include "actions/editmodeset.h"
56 #include "action_system.h"
57
58 #include "main.h"
59
60 #include <synfig/gradient.h>
61
62 #endif
63
64 /* === U S I N G =========================================================== */
65
66 using namespace std;
67 using namespace etl;
68 using namespace synfig;
69 using namespace synfigapp;
70
71 /* === M A C R O S ========================================================= */
72
73 /* === G L O B A L S ======================================================= */
74
75 /* === P R O C E D U R E S ================================================= */
76
77 /* === M E T H O D S ======================================================= */
78
79 CanvasInterface::CanvasInterface(loose_handle<Instance> instance,handle<Canvas> canvas):
80         instance_(instance),
81         canvas_(canvas),
82         cur_time_(canvas->rend_desc().get_frame_start()),
83         mode_(MODE_NORMAL|MODE_ANIMATE_PAST|MODE_ANIMATE_FUTURE)
84 {
85         set_selection_manager(get_instance()->get_selection_manager());
86         set_ui_interface(get_instance()->get_ui_interface());
87 }
88
89 CanvasInterface::~CanvasInterface()
90 {
91         synfig::info("synfigapp::CanvasInterface::~CanvasInterface(): Deleted");
92 }
93
94 void
95 CanvasInterface::set_time(synfig::Time x)
96 {
97         if(get_canvas()->rend_desc().get_frame_rate())
98         {
99                 float fps(get_canvas()->rend_desc().get_frame_rate());
100                 Time r(x.round(fps));
101                 //synfig::info("CanvasInterface::set_time(): %s rounded to %s\n",x.get_string(fps).c_str(),r.get_string(fps).c_str());
102                 x=r;
103         }
104         if(cur_time_.is_equal(x))
105                 return;
106         cur_time_=x;
107
108         signal_time_changed()();
109         signal_dirty_preview()();
110 }
111
112 synfig::Time
113 CanvasInterface::get_time()const
114 {
115         return cur_time_;
116 }
117
118 void
119 CanvasInterface::refresh_current_values()
120 {
121         get_canvas()->set_time(cur_time_);
122         signal_time_changed()();
123         signal_dirty_preview()();
124 }
125
126 etl::handle<CanvasInterface>
127 CanvasInterface::create(loose_handle<Instance> instance,handle<Canvas> canvas)
128 {
129         etl::handle<CanvasInterface> intrfc;
130         intrfc=new CanvasInterface(instance,canvas);
131         instance->canvas_interface_list().push_front(intrfc);
132         return intrfc;
133 }
134
135 void
136 CanvasInterface::set_mode(Mode x)
137 {
138         Action::Handle  action(Action::EditModeSet::create());
139
140         assert(action);
141
142         action->set_param("canvas",get_canvas());
143         action->set_param("canvas_interface",etl::loose_handle<CanvasInterface>(this));
144         action->set_param("edit_mode",x);
145
146         if(!action->is_ready())
147         {
148                 get_ui_interface()->error(_("Action Not Ready, unable to change mode"));
149                 assert(0);
150                 return;
151         }
152
153         if(!get_instance()->perform_action(action))
154                 get_ui_interface()->error(_("Unable to change mode"));
155
156 //      mode_=x;
157 //      signal_mode_changed_(x);
158 }
159
160 CanvasInterface::Mode
161 CanvasInterface::get_mode()const
162 {
163         return mode_;
164 }
165
166
167
168 Layer::Handle
169 CanvasInterface::add_layer_to(String name, Canvas::Handle canvas, int depth)
170 {
171         synfigapp::Action::PassiveGrouper group(get_instance().get(),_("Add Layer To"));
172
173         Layer::Handle   layer(Layer::create(name));
174
175         assert(layer);
176
177         if(!layer)
178                 return 0;
179
180         if(canvas!=get_canvas() && !canvas->is_inline())
181         {
182                 synfig::error("Bad canvas passed to \"add_layer_to\"");
183                 return 0;
184         }
185
186         layer->set_canvas(canvas);
187
188         // Apply some defaults
189         if(layer->set_param("fg",synfigapp::Main::get_foreground_color()))
190                 layer->set_param("bg",synfigapp::Main::get_background_color());
191         else
192                 layer->set_param("color",synfigapp::Main::get_foreground_color());
193
194         layer->set_param("width",synfigapp::Main::get_bline_width().units(get_canvas()->rend_desc()));
195         layer->set_param("gradient",synfigapp::Main::get_gradient());
196         if(name!="zoom")
197                 layer->set_param("amount",synfigapp::Main::get_opacity());
198         layer->set_param("blend_method",synfigapp::Main::get_blend_method());
199
200         {
201                 // Grab the layer's list pf parameters
202                 Layer::ParamList paramlist=layer->get_param_list();
203                 Layer::ParamList::iterator iter;
204                 for(iter=paramlist.begin();iter!=paramlist.end();++iter)
205                 {
206                         ValueNode::Handle value_node;
207
208                         if(iter->second.get_type()==ValueBase::TYPE_LIST)
209                                 value_node=LinkableValueNode::create("dynamic_list",iter->second);
210                         else if(LinkableValueNode::check_type("composite",iter->second.get_type()) &&
211                                 (iter->second.get_type()!=ValueBase::TYPE_COLOR && iter->second.get_type()!=ValueBase::TYPE_VECTOR)
212                         )
213                                 value_node=LinkableValueNode::create("composite",iter->second);
214
215                         if(value_node)
216                                 layer->connect_dynamic_param(iter->first,value_node);
217                 }
218         }
219
220         // Action to add the layer
221         Action::Handle  action(Action::LayerAdd::create());
222
223         assert(action);
224         if(!action)
225                 return 0;
226
227         action->set_param("canvas",canvas);
228         action->set_param("canvas_interface",etl::loose_handle<CanvasInterface>(this));
229         action->set_param("new",layer);
230
231         if(!action->is_ready())
232         {
233                 get_ui_interface()->error(_("Action Not Ready"));
234                 return 0;
235         }
236
237         if(!get_instance()->perform_action(action))
238         {
239                 get_ui_interface()->error(_("Action Failed."));
240                 return 0;
241         }
242
243         synfig::info("DEPTH=%d",depth);
244         // Action to move the layer (if necessary)
245         if(depth>0)
246         {
247                 Action::Handle  action(Action::create("layer_move"));
248
249                 assert(action);
250                 if(!action)
251                         return 0;
252
253                 action->set_param("canvas",canvas);
254                 action->set_param("canvas_interface",etl::loose_handle<CanvasInterface>(this));
255                 action->set_param("layer",layer);
256                 action->set_param("new_index",depth);
257
258                 if(!action->is_ready())
259                 {
260                         get_ui_interface()->error(_("Move Action Not Ready"));
261                         return 0;
262                 }
263
264                 if(!get_instance()->perform_action(action))
265                 {
266                         get_ui_interface()->error(_("Move Action Failed."));
267                         return 0;
268                 }
269         }
270
271
272         return layer;
273 }
274
275
276 bool
277 CanvasInterface::convert(ValueDesc value_desc, String type)
278 {
279         Action::Handle  action(Action::ValueDescConvert::create());
280
281         assert(action);
282         if(!action)
283                 return 0;
284
285         action->set_param("canvas",get_canvas());
286         action->set_param("canvas_interface",etl::loose_handle<CanvasInterface>(this));
287         action->set_param("value_desc",value_desc);
288         action->set_param("type",type);
289
290         if(!action->is_ready())
291         {
292                 get_ui_interface()->error(_("Action Not Ready"));
293                 return 0;
294         }
295
296         if(get_instance()->perform_action(action))
297                 return true;
298
299         get_ui_interface()->error(_("Action Failed."));
300         return false;
301 }
302
303 bool
304 CanvasInterface::add_value_node(synfig::ValueNode::Handle value_node, synfig::String name)
305 {
306         if(name.empty())
307         {
308                 get_ui_interface()->error(_("Empty name!"));
309                 return false;
310         }
311
312         Action::Handle  action(Action::ValueNodeAdd::create());
313
314         assert(action);
315         if(!action)
316                 return 0;
317
318         action->set_param("canvas",get_canvas());
319         action->set_param("canvas_interface",etl::loose_handle<CanvasInterface>(this));
320         action->set_param("new",value_node);
321         action->set_param("name",name);
322
323         if(!action->is_ready())
324         {
325                 get_ui_interface()->error(_("Action Not Ready"));
326                 return 0;
327         }
328
329         if(get_instance()->perform_action(action))
330                 return true;
331
332         get_ui_interface()->error(_("Action Failed."));
333         return false;
334 }
335
336 Action::ParamList
337 CanvasInterface::generate_param_list(const ValueDesc &value_desc)
338 {
339         synfigapp::Action::ParamList param_list;
340         param_list.add("time",get_time());
341         param_list.add("canvas_interface",etl::handle<CanvasInterface>(this));
342         param_list.add("canvas",get_canvas());
343
344         param_list.add("value_desc",value_desc);
345
346         if(value_desc.parent_is_value_node())
347                 param_list.add("parent_value_node",value_desc.get_parent_value_node());
348
349         if(value_desc.is_value_node())
350                 param_list.add("value_node",value_desc.get_value_node());
351
352         if(value_desc.is_const())
353                 param_list.add("value",value_desc.get_value());
354
355         if(value_desc.parent_is_layer_param())
356         {
357                 param_list.add("parent_layer",value_desc.get_layer());
358                 param_list.add("parent_layer_param",value_desc.get_param_name());
359         }
360
361         {
362                 synfigapp::SelectionManager::ChildrenList children_list;
363                 children_list=get_selection_manager()->get_selected_children();
364                 if(!value_desc.parent_is_canvas() && children_list.size()==1)
365                 {
366                         param_list.add("dest",value_desc);
367                         param_list.add("src",children_list.front().get_value_node());
368                 }
369         }
370         return param_list;
371 }
372
373 Action::ParamList
374 CanvasInterface::generate_param_list(const std::list<synfigapp::ValueDesc> &value_desc_list)
375 {
376         synfigapp::Action::ParamList param_list;
377         param_list.add("time",get_time());
378         param_list.add("canvas_interface",etl::handle<CanvasInterface>(this));
379         param_list.add("canvas",get_canvas());
380
381         std::list<synfigapp::ValueDesc>::const_iterator iter;
382         for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
383         {
384                 param_list.add("value_desc",*iter);
385                 if(iter->is_value_node())
386                 {
387                         param_list.add("value_node",iter->get_value_node());
388                 }
389         }
390
391
392         return param_list;
393 }
394
395 void
396 CanvasInterface::set_rend_desc(const synfig::RendDesc &rend_desc)
397 {
398         Action::Handle  action(Action::create("canvas_rend_desc_set"));
399
400         assert(action);
401         if(!action)
402                 return;
403
404         action->set_param("canvas",get_canvas());
405         action->set_param("canvas_interface",etl::loose_handle<CanvasInterface>(this));
406         action->set_param("rend_desc",rend_desc);
407
408         if(!get_instance()->perform_action(action))
409                 get_ui_interface()->error(_("Action Failed."));
410 }
411
412 bool
413 CanvasInterface::set_name(const String &x)
414 {
415         //! \todo This needs to be converted into an action
416         get_canvas()->set_name(x);
417         signal_id_changed_();
418         return true;
419 }
420
421 bool
422 CanvasInterface::set_description(const String &x)
423 {
424         //! \todo This needs to be converted into an action
425         get_canvas()->set_description(x);
426         return true;
427 }
428
429 bool
430 CanvasInterface::set_id(const String &x)
431 {
432         //! \todo This needs to be converted into an action
433         get_canvas()->set_id(x);
434         signal_id_changed_();
435         return true;
436 }
437
438
439 void
440 CanvasInterface::jump_to_next_keyframe()
441 {
442         synfig::info("Current time: %s",get_time().get_string().c_str());
443         try
444         {
445                 synfig::Keyframe keyframe(*get_canvas()->keyframe_list().find_next(get_time()));
446                 synfig::info("Jumping to keyframe \"%s\" at %s",keyframe.get_description().c_str(),keyframe.get_time().get_string().c_str());
447                 set_time(keyframe.get_time());
448         }
449         catch(...) { synfig::warning("Unable to find next keyframe"); }
450 }
451
452 void
453 CanvasInterface::jump_to_prev_keyframe()
454 {
455         synfig::info("Current time: %s",get_time().get_string().c_str());
456         try
457         {
458                 synfig::Keyframe keyframe(*get_canvas()->keyframe_list().find_prev(get_time()));
459                 synfig::info("Jumping to keyframe \"%s\" at %s",keyframe.get_description().c_str(),keyframe.get_time().get_string().c_str());
460                 set_time(keyframe.get_time());
461         }
462         catch(...) { synfig::warning("Unable to find prev keyframe"); }
463 }
464
465 bool
466 CanvasInterface::import(const synfig::String &filename, bool /*copy*/)
467 {
468         Action::PassiveGrouper group(get_instance().get(),_("Import Image"));
469
470         synfig::info("Attempting to import "+filename);
471
472
473         if(find(filename.begin(),filename.end(),'.')==filename.end())
474         {
475                 get_ui_interface()->error("Filename must have an extension!");
476                 return false;
477         }
478
479         String ext(String(filename.begin()+filename.find_last_of('.')+1,filename.end()));
480         std::transform(ext.begin(),ext.end(),ext.begin(),&::tolower);
481
482         // If this is a SIF file, then we need to do things slightly differently
483         if(ext=="sif" || ext=="sifz")try
484         {
485
486                 Canvas::Handle outside_canvas(synfig::open_canvas(filename));
487                 if(!outside_canvas)
488                         throw String(_("Unable to open this composition"));
489
490                 Layer::Handle layer(add_layer_to("PasteCanvas",get_canvas()));
491                 if(!layer)
492                         throw String(_("Unable to create \"Paste Canvas\" layer"));
493                 if(!layer->set_param("canvas",ValueBase(outside_canvas)))
494                         throw int();
495
496                 //layer->set_description(basename(filename));
497                 signal_layer_new_description()(layer,filename);
498                 return true;
499         }
500         catch(String x)
501         {
502                 get_ui_interface()->error(x+" -- "+filename);
503                 return false;
504         }
505         catch(...)
506         {
507                 get_ui_interface()->error(_("Uncaught exception when attempting\nto open this composition -- ")+filename);
508                 return false;
509         }
510
511         if(!Importer::book().count(ext))
512         {
513                 get_ui_interface()->error(_("I don't know how to open images of this type -- ")+ext);
514                 return false;
515         }
516
517         try
518         {
519                 Layer::Handle layer(add_layer_to("Import",get_canvas()));
520                 int w,h;
521                 if(!layer)
522                         throw int();
523                 if(!layer->set_param("filename",ValueBase(filename)))
524                         throw int();
525                 w=layer->get_param("_width").get(int());
526                 h=layer->get_param("_height").get(int());
527                 if(w&&h)
528                 {
529                         Vector size=ValueBase(get_canvas()->rend_desc().get_br()-get_canvas()->rend_desc().get_tl());
530                         Vector x;
531                         if(size[0]<size[1])
532                         {
533                                 x[0]=size[0];
534                                 x[1]=size[0]/w*h;
535                                 if(size[0]<0 ^ size[1]<0)
536                                         x[1]=-x[1];
537                         }
538                         else
539                         {
540                                 x[1]=size[1];
541                                 x[0]=size[1]/h*w;
542                                 if(size[0]<0 ^ size[1]<0)
543                                         x[0]=-x[0];
544                         }
545                         if(!layer->set_param("tl",ValueBase(-x/2)))
546                                 throw int();
547                         if(!layer->set_param("br",ValueBase(x/2)))
548                                 throw int();
549                 }
550                 else
551                 {
552                         if(!layer->set_param("tl",ValueBase(get_canvas()->rend_desc().get_tl())))
553                                 throw int();
554                         if(!layer->set_param("br",ValueBase(get_canvas()->rend_desc().get_br())))
555                                 throw int();
556                 }
557
558                 layer->set_description(basename(filename));
559                 signal_layer_new_description()(layer,filename);
560
561                 return true;
562         }
563         catch(...)
564         {
565                 get_ui_interface()->error("Unable to import "+filename);
566                 group.cancel();
567                 return false;
568         }
569 }
570
571
572 void
573 CanvasInterface::waypoint_duplicate(synfigapp::ValueDesc value_desc,synfig::Waypoint waypoint)
574 {
575         Action::Handle  action(Action::create("waypoint_set_smart"));
576
577         assert(action);
578         if(!action)
579                 return;
580
581         waypoint.make_unique();
582         waypoint.set_time(get_time());
583
584         ValueNode::Handle value_node(value_desc.get_value_node());
585
586         action->set_param("canvas",get_canvas());
587         action->set_param("canvas_interface",etl::loose_handle<CanvasInterface>(this));
588         action->set_param("waypoint",waypoint);
589         action->set_param("time",get_time());
590         action->set_param("value_node",value_node);
591
592         if(!get_instance()->perform_action(action))
593                 get_ui_interface()->error(_("Action Failed."));
594 }
595
596 void
597 CanvasInterface::waypoint_remove(synfigapp::ValueDesc value_desc,synfig::Waypoint waypoint)
598 {
599         Action::Handle  action(Action::create("waypoint_remove"));
600
601         assert(action);
602         if(!action)
603                 return;
604
605         ValueNode::Handle value_node(value_desc.get_value_node());
606
607         action->set_param("canvas",get_canvas());
608         action->set_param("canvas_interface",etl::loose_handle<CanvasInterface>(this));
609         action->set_param("waypoint",waypoint);
610         action->set_param("value_node",value_node);
611
612         if(!get_instance()->perform_action(action))
613                 get_ui_interface()->error(_("Action Failed."));
614 }
615
616
617 void
618 CanvasInterface::auto_export(ValueNode::Handle /*value_node*/)
619 {
620 /*
621         // Check to see if we are already exported.
622         if(value_node->is_exported())
623                 return;
624
625         Action::Handle  action(Action::create("value_node_add"));
626
627         assert(action);
628         if(!action)
629                 return;
630
631         String name(strprintf(_("Unnamed%08d"),synfig::UniqueID().get_uid()));
632
633         action->set_param("canvas",get_canvas());
634         action->set_param("canvas_interface",etl::loose_handle<CanvasInterface>(this));
635         action->set_param("new",value_node);
636         action->set_param("name",name);
637
638         if(!get_instance()->perform_action(action))
639                 get_ui_interface()->error(_("Action Failed."));
640 */
641 }
642
643 void
644 CanvasInterface::auto_export(const ValueDesc& /*value_desc*/)
645 {
646         // THIS FUNCTION IS DEPRECATED, AND IS NOW A STUB.
647 #if 0
648         // Check to see if we are already exported.
649         if(value_desc.is_exported())
650                 return;
651
652         Action::Handle  action(Action::create("value_desc_export"));
653
654         assert(action);
655         if(!action)
656                 return;
657
658         String name(strprintf(_("Unnamed%08d"),synfig::UniqueID().get_uid()));
659
660         action->set_param("canvas",get_canvas());
661         action->set_param("canvas_interface",etl::loose_handle<CanvasInterface>(this));
662         action->set_param("value_desc",value_desc);
663         action->set_param("name",name);
664
665         if(!get_instance()->perform_action(action))
666                 get_ui_interface()->error(_("Action Failed."));
667 #endif
668 }
669
670 bool
671 CanvasInterface::change_value(synfigapp::ValueDesc value_desc,synfig::ValueBase new_value)
672 {
673         // If this isn't really a change, then don't bother
674         if(new_value==value_desc.get_value(get_time()))
675                 return true;
676
677         // If this change needs to take place elsewhere, then so be it.
678         if(value_desc.get_canvas() && value_desc.get_canvas()->get_root()!=get_canvas()->get_root())do
679         {
680                 etl::handle<Instance> instance;
681                 instance=find_instance(value_desc.get_canvas()->get_root());
682
683                 if(instance)
684                         return instance->find_canvas_interface(value_desc.get_canvas())->change_value(value_desc,new_value);
685                 else
686                 {
687                         get_ui_interface()->error(_("The value you are trying to edit is in a composition\nwhich doesn't seem to be open. Open that composition and you\nshould be able to edit this value as normal."));
688                         return false;
689                 }
690         }while(0);
691 #ifdef _DEBUG
692         else
693         { synfig::warning("Can't get canvas from value desc...?"); }
694 #endif
695
696         synfigapp::Action::Handle action(synfigapp::Action::create("value_desc_set"));
697         if(!action)
698         {
699                 return false;
700         }
701
702         action->set_param("canvas",get_canvas());
703         action->set_param("canvas_interface",etl::loose_handle<CanvasInterface>(this));
704         action->set_param("time",get_time());
705         action->set_param("value_desc",value_desc);
706         action->set_param("new_value",new_value);
707
708         return get_instance()->perform_action(action);
709 }
710
711 void
712 CanvasInterface::set_meta_data(const synfig::String& key,const synfig::String& data)
713 {
714         get_canvas()->set_meta_data(key,data);
715 }
716
717
718 // this function goes with find_important_value_descs()
719 static int
720 _process_value_desc(const synfigapp::ValueDesc& value_desc,std::vector<synfigapp::ValueDesc>& out, synfig::GUIDSet& guid_set)
721 {
722         int ret(0);
723
724         if(value_desc.get_value_type()==ValueBase::TYPE_CANVAS)
725         {
726                 Canvas::Handle canvas;
727                 canvas=value_desc.get_value().get(canvas);
728                 if(!canvas || !canvas->is_inline())
729                         return ret;
730                 ret+=CanvasInterface::find_important_value_descs(canvas,out,guid_set);
731         }
732
733         if(value_desc.is_value_node())
734         {
735                 ValueNode::Handle value_node(value_desc.get_value_node());
736
737                 if(guid_set.count(value_node->get_guid()))
738                         return ret;
739                 guid_set.insert(value_node->get_guid());
740
741                 if(LinkableValueNode::Handle::cast_dynamic(value_node))
742                 {
743                         if(ValueNode_DynamicList::Handle::cast_dynamic(value_node))
744                         {
745                                 out.push_back(value_desc);
746                                 ret++;
747                         }
748                         // Process the linkable ValueNode's children
749                         LinkableValueNode::Handle value_node_copy(LinkableValueNode::Handle::cast_dynamic(value_node));
750                         int i;
751                         for(i=0;i<value_node_copy->link_count();i++)
752                         {
753                                 ValueNode::Handle link(value_node_copy->get_link(i));
754                                 if(!link->is_exported())
755                                         ret+=_process_value_desc(ValueDesc(value_node_copy,i),out,guid_set);
756                         }
757                 }
758                 else if(ValueNode_Animated::Handle::cast_dynamic(value_node))
759                 {
760                         out.push_back(value_desc);
761                         ret++;
762                 }
763         }
764
765         return ret;
766 }
767
768 int
769 CanvasInterface::find_important_value_descs(synfig::Canvas::Handle canvas,std::vector<synfigapp::ValueDesc>& out,synfig::GUIDSet& guid_set)
770 {
771         int ret(0);
772         if(!canvas->is_inline())
773         {
774                 ValueNodeList::const_iterator iter;
775
776                 for(
777                         iter=canvas->value_node_list().begin();
778                         iter!=canvas->value_node_list().end();
779                         ++iter)
780                         ret+=_process_value_desc(ValueDesc(canvas,(*iter)->get_id()),out,guid_set);
781         }
782
783         Canvas::const_iterator iter;
784
785         for(iter=canvas->begin();iter!=canvas->end();++iter)
786         {
787                 Layer::Handle layer(*iter);
788
789                 Layer::DynamicParamList::const_iterator iter;
790                 for(
791                         iter=layer->dynamic_param_list().begin();
792                         iter!=layer->dynamic_param_list().end();
793                         ++iter)
794                 {
795                         if(!iter->second->is_exported())
796                                 ret+=_process_value_desc(ValueDesc(layer,iter->first),out,guid_set);
797                 }
798                 ValueBase value(layer->get_param("canvas"));
799                 if(value.is_valid())
800                         ret+=_process_value_desc(ValueDesc(layer,"canvas"),out,guid_set);
801         }
802
803         return ret;
804 }
805
806 int
807 CanvasInterface::find_important_value_descs(std::vector<synfigapp::ValueDesc>& out)
808 {
809         synfig::GUIDSet tmp;
810         return find_important_value_descs(get_canvas(),out,tmp);
811 }
812
813 void
814 CanvasInterface::seek_frame(int frames)
815 {
816         if(!frames)
817                 return;
818         float fps(get_canvas()->rend_desc().get_frame_rate());
819         Time newtime(get_time()+(float)frames/fps);
820         newtime=newtime.round(fps);
821
822         if(newtime<=get_canvas()->rend_desc().get_time_start())
823                 newtime=get_canvas()->rend_desc().get_time_start();
824         if(newtime>=get_canvas()->rend_desc().get_time_end())
825                 newtime=get_canvas()->rend_desc().get_time_end();
826         set_time(newtime);
827 }
828
829 void
830 CanvasInterface::seek_time(synfig::Time time)
831 {
832         if(!time)
833                 return;
834
835         float fps(get_canvas()->rend_desc().get_frame_rate());
836
837         if(time>=synfig::Time::end())
838         {
839                 set_time(get_canvas()->rend_desc().get_time_end());
840                 return;
841         }
842         if(time<=synfig::Time::begin())
843         {
844                 set_time(get_canvas()->rend_desc().get_time_start());
845                 return;
846         }
847
848         Time newtime(get_time()+time);
849         newtime=newtime.round(fps);
850
851         if(newtime<=get_canvas()->rend_desc().get_time_start())
852                 newtime=get_canvas()->rend_desc().get_time_start();
853         if(newtime>=get_canvas()->rend_desc().get_time_end())
854                 newtime=get_canvas()->rend_desc().get_time_end();
855         set_time(newtime);
856 }