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