1 /* === S Y N F I G ========================================================= */
5 ** $Id: instance.cpp,v 1.2 2005/01/13 18:37:30 darco Exp $
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
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.
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.
21 /* ========================================================================= */
23 /* === H E A D E R S ======================================================= */
34 #include <gtkmm/stock.h>
35 #include <gtkmm/image.h>
37 #include <gtkmm/button.h>
38 #include "canvasview.h"
40 #include <sigc++/signal.h>
41 #include <sigc++/adaptors/hide.h>
43 #include "onemoment.h"
45 #include "autorecover.h"
46 #include <sigc++/retype_return.h>
47 #include <sigc++/retype.h>
48 //#include <sigc++/hide.h>
49 #include <synfig/valuenode_composite.h>
50 #include "widget_waypointmodel.h"
51 #include <gtkmm/actiongroup.h>
52 #include "iconcontroler.h"
58 using namespace synfig;
59 using namespace studio;
62 /* === M A C R O S ========================================================= */
64 /* === G L O B A L S ======================================================= */
66 int studio::Instance::instance_count_=0;
68 /* === P R O C E D U R E S ================================================= */
70 /* === M E T H O D S ======================================================= */
72 Instance::Instance(Canvas::Handle canvas):
73 synfigapp::Instance (canvas),
74 // canvas_tree_store_ (Gtk::TreeStore::create(CanvasTreeModel())),
75 // canvas_tree_store_ (Gtk::TreeStore::create()),
76 history_tree_store_ (HistoryTreeStore::create(this)),
80 CanvasTreeModel model;
81 canvas_tree_store_=Gtk::TreeStore::create(model);
83 id_=instance_count_++;
85 // Connect up all the signals
86 signal_filename_changed().connect(sigc::mem_fun(*this,&studio::Instance::update_all_titles));
87 signal_unsaved_status_changed().connect(sigc::hide(sigc::mem_fun(*this,&studio::Instance::update_all_titles)));
88 signal_undo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_undo_status));
89 signal_redo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_redo_status));
91 signal_saved().connect(
94 studio::AutoRecover::auto_backup
99 canvas_tree_store_=Gtk::TreeStore::create(canvas_tree_model);
101 refresh_canvas_tree();
104 Instance::~Instance()
109 Instance::get_visible_canvases()const
112 CanvasViewList::const_iterator iter;
113 for(iter=canvas_view_list_.begin();iter!=canvas_view_list_.end();++iter)
114 if((*iter)->is_visible())
120 Instance::create(Canvas::Handle canvas)
122 // Construct a new instance
123 handle<Instance> instance(new Instance(canvas));
125 // Add the new instance to the application's instance list
126 App::instance_list.push_back(instance);
128 // Set up the instance with the default UI manager
129 instance->synfigapp::Instance::set_ui_interface(App::get_ui_interface());
131 // Signal the new instance
132 App::signal_instance_created()(instance);
134 // And then make sure that is has been selected
135 App::set_selected_instance(instance);
137 // Create the initial window for the root canvas
138 instance->focus(canvas);
144 Instance::find_canvas_view(Canvas::Handle canvas)
149 while(canvas->is_inline())
150 canvas=canvas->parent();
152 CanvasViewList::iterator iter;
154 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
155 if((*iter)->get_canvas()==canvas)
158 return CanvasView::create(this,canvas);
162 Instance::focus(Canvas::Handle canvas)
164 handle<CanvasView> canvas_view=find_canvas_view(canvas);
166 canvas_view->present();
170 Instance::set_undo_status(bool x)
173 App::toolbox->update_undo_redo();
174 signal_undo_redo_status_changed()();
178 Instance::set_redo_status(bool x)
181 App::toolbox->update_undo_redo();
182 signal_undo_redo_status_changed()();
186 studio::Instance::save_as(const synfig::String &file_name)const
188 if(synfigapp::Instance::save_as(file_name))
190 App::add_recent_file(file_name);
197 studio::Instance::save_as(const synfig::String &file_name)
199 if(synfigapp::Instance::save_as(file_name))
201 App::add_recent_file(file_name);
208 studio::Instance::save()
210 if(basename(get_file_name()).find("untitled")==0)
216 return synfigapp::Instance::save();
221 studio::Instance::dialog_save_as()
223 string filename="*.sif";
225 Canvas::Handle canvas(get_canvas());
228 OneMoment one_moment;
229 std::set<Node*>::iterator iter;
230 for(iter=canvas->parent_set.begin();iter!=canvas->parent_set.end();++iter)
232 synfig::Node* node(*iter);
233 for(;!node->parent_set.empty();node=*node->parent_set.begin())
235 Layer::Handle parent_layer(dynamic_cast<Layer*>(node));
236 if(parent_layer && parent_layer->get_canvas()->get_root()!=get_canvas())
238 App::dialog_error_blocking("SaveAs - Error",
239 "There is currently a bug when using \"SaveAs\"\n"
240 "on a composition that is being referenced by other\n"
241 "files that are currently open. Close these\n"
242 "other files first before trying to use \"SaveAs\"."
253 while(App::dialog_saveas_file("SaveAs", filename))
255 // If the filename still has wildcards, then we should
256 // continue looking for the file we want
257 if(find(filename.begin(),filename.end(),'*')!=filename.end())
260 if(find(filename.begin(),filename.end(),'.')==filename.end())
265 String ext(String(filename.begin()+filename.find_last_of('.')+1,filename.end()));
266 if(ext!="sif" && ext!="sifz" && !App::dialog_yes_no(_("Unknown extension"),
267 _("You have given the file name an extension\nwhich I do not recognise. Are you sure this is what you want?")))
277 if(save_as(filename))
280 App::dialog_error_blocking("SaveAs - Error","Unable to save file");
285 Instance::update_all_titles()
287 list<handle<CanvasView> >::iterator iter;
288 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
289 (*iter)->update_title();
295 // This will increase the reference count so we don't get DELETED
296 // until we are ready
297 handle<Instance> me(this);
299 // Make sure we aren't selected as the current instance
300 if(studio::App::get_selected_instance()==this)
301 studio::App::set_selected_instance(0);
303 // Turn-off/clean-up auto recovery
304 studio::App::auto_recover->clear_backup(get_canvas());
306 // Remove us from the active instance list
307 std::list<etl::handle<studio::Instance> >::iterator iter;
308 for(iter=studio::App::instance_list.begin();iter!=studio::App::instance_list.end();iter++)
311 assert(iter!=studio::App::instance_list.end());
312 if(iter!=studio::App::instance_list.end())
313 studio::App::instance_list.erase(iter);
315 // Send out a signal that we are being deleted
316 studio::App::signal_instance_deleted()(this);
318 // Hide all of the canvas views
319 for(std::list<etl::handle<CanvasView> >::iterator iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
322 // Delete all of the canvas views
323 canvas_view_list().clear();
325 while(studio::App::events_pending())studio::App::iteration(false);
327 // If there is another open instance to select,
328 // go ahead and do so. If not, never mind.
329 if(studio::App::instance_list.empty())
331 studio::App::set_selected_canvas_view(0);
332 studio::App::set_selected_instance(0);
336 studio::App::set_selected_canvas_view(studio::App::instance_list.front()->canvas_view_list().front());
337 //studio::App::set_selected_instance(studio::App::instance_list.front());
343 Instance::insert_canvas(Gtk::TreeRow row,Canvas::Handle canvas)
345 CanvasTreeModel canvas_tree_model;
348 row[canvas_tree_model.icon] = Gtk::Button().render_icon(Gtk::StockID("synfig-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
349 row[canvas_tree_model.id] = canvas->get_id();
350 row[canvas_tree_model.name] = canvas->get_name();
351 if(canvas->is_root())
352 row[canvas_tree_model.label] = basename(canvas->get_file_name());
354 if(!canvas->get_id().empty())
355 row[canvas_tree_model.label] = canvas->get_id();
357 if(!canvas->get_name().empty())
358 row[canvas_tree_model.label] = canvas->get_name();
360 row[canvas_tree_model.label] = _("[Unnamed]");
362 row[canvas_tree_model.canvas] = canvas;
363 row[canvas_tree_model.is_canvas] = true;
364 row[canvas_tree_model.is_value_node] = false;
367 synfig::Canvas::Children::iterator iter;
368 synfig::Canvas::Children &children(canvas->children());
370 for(iter=children.begin();iter!=children.end();iter++)
371 insert_canvas(*(canvas_tree_store()->append(row.children())),*iter);
375 if(!canvas->value_node_list().empty())
377 Gtk::TreeRow valuenode_row = *(canvas_tree_store()->append(row.children()));
379 valuenode_row[canvas_tree_model.label] = "<defs>";
380 valuenode_row[canvas_tree_model.canvas] = canvas;
381 valuenode_row[canvas_tree_model.is_canvas] = false;
382 valuenode_row[canvas_tree_model.is_value_node] = false;
384 synfig::ValueNodeList::iterator iter;
385 synfig::ValueNodeList &value_node_list(canvas->value_node_list());
387 for(iter=value_node_list.begin();iter!=value_node_list.end();iter++)
388 insert_value_node(*(canvas_tree_store()->append(valuenode_row.children())),canvas,*iter);
396 Instance::insert_value_node(Gtk::TreeRow row,Canvas::Handle canvas,etl::handle<synfig::ValueNode> value_node)
398 CanvasTreeModel canvas_tree_model;
402 row[canvas_tree_model.id] = value_node->get_id();
403 row[canvas_tree_model.name] = value_node->get_id();
404 row[canvas_tree_model.label] = value_node->get_id();
405 row[canvas_tree_model.canvas] = canvas;
406 row[canvas_tree_model.value_node] = value_node;
407 row[canvas_tree_model.is_canvas] = false;
408 row[canvas_tree_model.is_value_node] = true;
409 row[canvas_tree_model.icon] = Gtk::Button().render_icon(valuenode_icon(value_node),Gtk::ICON_SIZE_SMALL_TOOLBAR);
414 Instance::refresh_canvas_tree()
416 canvas_tree_store()->clear();
417 Gtk::TreeRow row = *(canvas_tree_store()->prepend());
418 insert_canvas(row,get_canvas());
422 Instance::dialog_cvs_commit()
424 calc_repository_info();
427 App::dialog_error_blocking(_("Error"),_("You must first add this composition to the repository"));
434 if(synfigapp::Instance::get_action_count())
436 if(!App::dialog_yes_no(_("CVS Commit"), _("This will save any changes you have made. Are you sure?")))
443 App::dialog_error_blocking(_("Error"),_("The local copy of the file hasn't been changed since the last update.\nNothing to commit!"));
447 if(!App::dialog_entry(_("CVS Commit"),_("Enter a log message describing the changes you have made"), message))
450 OneMoment one_moment;
455 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to COMMIT"));
461 Instance::dialog_cvs_add()
463 calc_repository_info();
466 App::dialog_error_blocking(_("Error"),_("This composition has already been added to the repository"));
473 //if(!App::dialog_entry(_("CVS Add"),_("Enter a log message describing the file"), message))
475 OneMoment one_moment;
480 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to ADD"));
486 Instance::dialog_cvs_update()
488 calc_repository_info();
491 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to update from!"));
496 App::dialog_error_blocking(_("Info"),_("This file is up-to-date"));
502 String filename(get_file_name());
503 if(synfigapp::Instance::get_action_count())
505 if(!App::dialog_yes_no(_("CVS Update"), _("This will save any changes you have made. Are you sure?")))
509 OneMoment one_moment;
510 time_t oldtime=get_original_timestamp();
512 calc_repository_info();
513 // If something has been updated...
514 if(oldtime!=get_original_timestamp())
521 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
523 //update_all_titles();
527 Instance::dialog_cvs_revert()
529 calc_repository_info();
532 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to revert to!"));
537 String filename(get_file_name());
538 if(!App::dialog_yes_no(_("CVS Revert"),
539 _("This will abandon all changes you have made\nsince the last time you performed a commit\noperation. This cannot be undone! Are you sure\nyou want to do this?")
543 OneMoment one_moment;
545 // Remove the old file
546 if(remove(get_file_name().c_str())!=0)
548 App::dialog_error_blocking(_("Error"),_("Unable to remove previous version"));
557 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
559 //update_all_titles();
563 Instance::_revert(Instance *instance)
565 OneMoment one_moment;
567 String filename(instance->get_file_name());
569 Canvas::Handle canvas(instance->get_canvas());
573 if(canvas->count()!=1)
576 App::dialog_error_blocking(_("Error: Revert Failed"),_("The revert operation has failed. This can be due to it being\nreferenced by another composition that is already open, or\nbecause of an internal error in SYNFIG Studio. Try closing any\ncompositions that might reference this composition and try\nagain, or restart SYNFIG studio."));
587 // Schedule a revert to occur in a few moments
588 Glib::signal_timeout().connect(
591 sigc::ptr_fun(&Instance::_revert),
601 Instance::safe_revert()
603 if(synfigapp::Instance::get_action_count())
604 if(!App::dialog_yes_no(_("Revert to saved"), _("You will loose any changes you have made since your last save.\nAre you sure?")))
611 Instance::safe_close()
613 handle<synfigapp::UIInterface> uim;
614 uim=find_canvas_view(get_canvas())->get_ui_interface();
616 if(get_action_count())
618 string str=strprintf(_("Would you like to save your changes to %s?"),basename(get_file_name()).c_str() );
619 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
620 if(answer==synfigapp::UIInterface::RESPONSE_YES)
622 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
628 string str=strprintf(_("%s has changes not yet on the CVS repository.\nWould you like to commit these changes?"),basename(get_file_name()).c_str());
629 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
631 if(answer==synfigapp::UIInterface::RESPONSE_YES)
633 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
644 Instance::add_actions_to_group(const Glib::RefPtr<Gtk::ActionGroup>& action_group, synfig::String& ui_info, const synfigapp::Action::ParamList ¶m_list, synfigapp::Action::Category category)const
646 synfigapp::Action::CanidateList canidate_list;
647 synfigapp::Action::CanidateList::iterator iter;
649 canidate_list=compile_canidate_list(param_list,category);
651 canidate_list.sort();
653 if(canidate_list.empty())
654 synfig::warning("Action CanidateList is empty!");
656 for(iter=canidate_list.begin();iter!=canidate_list.end();++iter)
658 Gtk::StockID stock_id(get_action_stock_id(*iter));
660 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
662 action_group->add(Gtk::Action::create(
663 "action-"+iter->name,
665 iter->local_name,iter->local_name
670 *const_cast<studio::Instance*>(this),
671 &studio::Instance::process_action
678 ui_info+=strprintf("<menuitem action='action-%s' />",iter->name.c_str());
684 Instance::add_actions_to_menu(Gtk::Menu *menu, const synfigapp::Action::ParamList ¶m_list,synfigapp::Action::Category category)const
686 synfigapp::Action::CanidateList canidate_list;
687 synfigapp::Action::CanidateList::iterator iter;
689 canidate_list=compile_canidate_list(param_list,category);
691 canidate_list.sort();
693 if(canidate_list.empty())
694 synfig::warning("Action CanidateList is empty!");
696 for(iter=canidate_list.begin();iter!=canidate_list.end();++iter)
698 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
700 Gtk::Image* image(manage(new Gtk::Image()));
701 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
704 if(iter->task=="raise")
705 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
706 else if(iter->task=="lower")
707 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
708 else if(iter->task=="move_top")
709 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
710 else if(iter->task=="move_bottom")
711 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
712 else if(iter->task=="remove")
713 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
714 else if(iter->task=="set_on")
715 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
716 else if(iter->task=="set_off")
717 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
718 else if(iter->task=="duplicate")
719 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
720 else if(iter->task=="remove")
721 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
724 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
725 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
726 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
729 menu->items().push_back(
730 Gtk::Menu_Helpers::ImageMenuElem(
736 *const_cast<studio::Instance*>(this),
737 &studio::Instance::process_action
750 Instance::add_actions_to_menu(Gtk::Menu *menu, const synfigapp::Action::ParamList ¶m_list,const synfigapp::Action::ParamList ¶m_list2,synfigapp::Action::Category category)const
752 synfigapp::Action::CanidateList canidate_list;
753 synfigapp::Action::CanidateList canidate_list2;
755 synfigapp::Action::CanidateList::iterator iter;
757 canidate_list=compile_canidate_list(param_list,category);
758 canidate_list2=compile_canidate_list(param_list2,category);
760 canidate_list.sort();
762 if(canidate_list.empty())
763 synfig::warning("Action CanidateList is empty!");
764 if(canidate_list2.empty())
765 synfig::warning("Action CanidateList2 is empty!");
767 // Seperate out the canidate lists so that there are no conflicts
768 for(iter=canidate_list.begin();iter!=canidate_list.end();++iter)
770 synfigapp::Action::CanidateList::iterator iter2(canidate_list2.find(iter->name));
771 if(iter2!=canidate_list2.end())
772 canidate_list2.erase(iter2);
775 for(iter=canidate_list2.begin();iter!=canidate_list2.end();++iter)
777 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
779 Gtk::Image* image(manage(new Gtk::Image()));
780 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
782 /* if(iter->task=="raise")
783 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
784 else if(iter->task=="lower")
785 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
786 else if(iter->task=="move_top")
787 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
788 else if(iter->task=="move_bottom")
789 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
790 else if(iter->task=="remove")
791 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
792 else if(iter->task=="set_on")
793 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
794 else if(iter->task=="set_off")
795 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
796 else if(iter->task=="duplicate")
797 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
798 else if(iter->task=="remove")
799 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
802 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
803 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
804 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
807 menu->items().push_back(
808 Gtk::Menu_Helpers::ImageMenuElem(
814 *const_cast<studio::Instance*>(this),
815 &studio::Instance::process_action
826 for(iter=canidate_list.begin();iter!=canidate_list.end();++iter)
828 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
830 Gtk::Image* image(manage(new Gtk::Image()));
831 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
832 /* if(iter->task=="raise")
833 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
834 else if(iter->task=="lower")
835 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
836 else if(iter->task=="move_top")
837 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
838 else if(iter->task=="move_bottom")
839 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
840 else if(iter->task=="remove")
841 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
842 else if(iter->task=="set_on")
843 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
844 else if(iter->task=="set_off")
845 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
846 else if(iter->task=="duplicate")
847 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
848 else if(iter->task=="remove")
849 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
852 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
853 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
854 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
857 menu->items().push_back(
858 Gtk::Menu_Helpers::ImageMenuElem(
864 *const_cast<studio::Instance*>(this),
865 &studio::Instance::process_action
878 Instance::process_action(String name, synfigapp::Action::ParamList param_list)
880 assert(synfigapp::Action::book().count(name));
882 synfigapp::Action::BookEntry entry(synfigapp::Action::book().find(name)->second);
884 synfigapp::Action::Handle action(entry.factory());
888 synfig::error("Bad Action");
892 action->set_param_list(param_list);
894 synfigapp::Action::ParamVocab param_vocab(entry.get_param_vocab());
895 synfigapp::Action::ParamVocab::const_iterator iter;
897 for(iter=param_vocab.begin();iter!=param_vocab.end();++iter)
899 if(!iter->get_mutual_exclusion().empty() && param_list.count(iter->get_mutual_exclusion()))
902 // If the parameter is optionally user-supplied,
903 // and has not been already provided in the param_list,
904 // then we should go ahead and see if we can
905 // provide that data.
906 if(iter->get_user_supplied() && param_list.count(iter->get_name())==0)
908 switch(iter->get_type())
910 case synfigapp::Action::Param::TYPE_STRING:
913 if(!studio::App::dialog_entry(entry.local_name, iter->get_local_name()+":"+iter->get_desc(),str))
915 action->set_param(iter->get_name(),str);
919 synfig::error("Unsupported user-supplied action parameter");
926 if(!action->is_ready())
928 synfig::error("Action not ready");
932 perform_action(action);
936 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas, synfigapp::ValueDesc value_desc, float location)
938 Gtk::Menu& parammenu(*menu);
940 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
942 if(!canvas_interface)
945 synfigapp::Action::ParamList param_list,param_list2;
946 param_list=canvas_interface->generate_param_list(value_desc);
947 param_list.add("origin",location);
949 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
951 param_list2=canvas_interface->generate_param_list(
952 synfigapp::ValueDesc(
953 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
957 param_list2.add("origin",location);
961 // Populate the convert menu by looping through
962 // the ValueNode book and find the ones that are
965 Gtk::Menu *convert_menu=manage(new Gtk::Menu());
966 LinkableValueNode::Book::const_iterator iter;
967 for(iter=LinkableValueNode::book().begin();iter!=LinkableValueNode::book().end();++iter)
969 if(iter->second.check_type(value_desc.get_value_type()))
971 convert_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->second.local_name,
975 sigc::mem_fun(*canvas_interface.get(),&synfigapp::CanvasInterface::convert),
985 parammenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::CONVERT,*convert_menu));
988 if(param_list2.empty())
989 add_actions_to_menu(¶mmenu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
991 add_actions_to_menu(¶mmenu, param_list2,param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
993 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
995 value_desc=synfigapp::ValueDesc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),0);
998 if(value_desc.is_value_node() && ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
1000 ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()));
1004 WaypointList::iterator iter(value_node->find(canvas->get_time()));
1005 parammenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoint"),
1009 sigc::mem_fun(*find_canvas_view(canvas),&studio::CanvasView::on_waypoint_clicked),
1025 edit_several_waypoints(etl::handle<CanvasView> canvas_view, std::list<synfigapp::ValueDesc> value_desc_list)
1027 etl::handle<synfigapp::CanvasInterface> canvas_interface(canvas_view->canvas_interface());
1030 "Edit Multiple Waypoints", // Title
1032 true // use_separator
1035 Widget_WaypointModel widget_waypoint_model;
1036 widget_waypoint_model.show();
1038 dialog.get_vbox()->pack_start(widget_waypoint_model);
1041 dialog.add_button(Gtk::StockID("gtk-apply"),1);
1042 dialog.add_button(Gtk::StockID("gtk-cancel"),0);
1046 if(dialog.run()==0 || widget_waypoint_model.get_waypoint_model().is_trivial())
1049 synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Set Waypoints"));
1051 std::list<synfigapp::ValueDesc>::iterator iter;
1052 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
1054 synfigapp::ValueDesc value_desc(*iter);
1056 if(!value_desc.is_valid())
1059 ValueNode_Animated::Handle value_node;
1061 // If this value isn't a ValueNode_Animated, but
1062 // it is somewhat constant, then go ahead and convert
1063 // it to a ValueNode_Animated.
1064 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
1067 if(value_desc.is_value_node())
1068 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
1070 value=value_desc.get_value();
1072 value_node=ValueNode_Animated::create(value,canvas_interface->get_time());
1074 synfigapp::Action::Handle action;
1076 if(!value_desc.is_value_node())
1078 action=synfigapp::Action::create("value_desc_connect");
1079 action->set_param("dest",value_desc);
1080 action->set_param("src",ValueNode::Handle(value_node));
1084 action=synfigapp::Action::create("value_node_replace");
1085 action->set_param("dest",value_desc.get_value_node());
1086 action->set_param("src",ValueNode::Handle(value_node));
1089 action->set_param("canvas",canvas_view->get_canvas());
1090 action->set_param("canvas_interface",canvas_interface);
1093 if(!canvas_interface->get_instance()->perform_action(action))
1095 canvas_view->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
1102 if(value_desc.is_value_node())
1103 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
1110 synfigapp::Action::Handle action(synfigapp::Action::create("waypoint_set_smart"));
1114 canvas_view->get_ui_interface()->error(_("Unable to find waypoint_set_smart action"));
1120 action->set_param("canvas",canvas_view->get_canvas());
1121 action->set_param("canvas_interface",canvas_interface);
1122 action->set_param("value_node",ValueNode::Handle(value_node));
1123 action->set_param("time",canvas_interface->get_time());
1124 action->set_param("model",widget_waypoint_model.get_waypoint_model());
1126 if(!canvas_interface->get_instance()->perform_action(action))
1128 canvas_view->get_ui_interface()->error(_("Unable to set a specific waypoint"));
1135 //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
1144 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas,const std::list<synfigapp::ValueDesc>& value_desc_list)
1146 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
1148 synfigapp::Action::ParamList param_list;
1149 param_list=canvas_interface->generate_param_list(value_desc_list);
1151 add_actions_to_menu(menu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1153 // Add the edit waypoints option if that might be useful
1154 if(canvas->rend_desc().get_time_end()-Time::epsilon()>canvas->rend_desc().get_time_start())
1156 menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
1160 &edit_several_waypoints
1164 find_canvas_view(canvas)