1 /* === S Y N F I G ========================================================= */
2 /*! \file gtkmm/instance.cpp
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007 Chris Moore
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.
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.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
35 #include <gtkmm/stock.h>
36 #include <gtkmm/image.h>
38 #include <gtkmm/button.h>
39 #include "canvasview.h"
41 #include <sigc++/signal.h>
42 #include <sigc++/adaptors/hide.h>
44 #include "onemoment.h"
46 #include "autorecover.h"
47 #include <sigc++/retype_return.h>
48 #include <sigc++/retype.h>
49 //#include <sigc++/hide.h>
50 #include <synfig/valuenode_composite.h>
51 #include "widget_waypointmodel.h"
52 #include <gtkmm/actiongroup.h>
53 #include "iconcontroller.h"
63 using namespace synfig;
64 using namespace studio;
67 /* === M A C R O S ========================================================= */
69 /* === G L O B A L S ======================================================= */
71 int studio::Instance::instance_count_=0;
73 /* === P R O C E D U R E S ================================================= */
75 /* === M E T H O D S ======================================================= */
77 Instance::Instance(synfig::Canvas::Handle canvas):
78 synfigapp::Instance (canvas),
79 // canvas_tree_store_ (Gtk::TreeStore::create(CanvasTreeModel())),
80 // canvas_tree_store_ (Gtk::TreeStore::create()),
81 history_tree_store_ (HistoryTreeStore::create(this)),
85 CanvasTreeModel model;
86 canvas_tree_store_=Gtk::TreeStore::create(model);
88 id_=instance_count_++;
90 // Connect up all the signals
91 signal_filename_changed().connect(sigc::mem_fun(*this,&studio::Instance::update_all_titles));
92 signal_unsaved_status_changed().connect(sigc::hide(sigc::mem_fun(*this,&studio::Instance::update_all_titles)));
93 signal_undo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_undo_status));
94 signal_redo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_redo_status));
96 signal_saved().connect(
99 studio::AutoRecover::auto_backup
104 canvas_tree_store_=Gtk::TreeStore::create(canvas_tree_model);
106 refresh_canvas_tree();
109 Instance::~Instance()
114 Instance::get_visible_canvases()const
117 CanvasViewList::const_iterator iter;
118 for(iter=canvas_view_list_.begin();iter!=canvas_view_list_.end();++iter)
119 if((*iter)->is_visible())
125 Instance::create(synfig::Canvas::Handle canvas)
127 // Construct a new instance
128 handle<Instance> instance(new Instance(canvas));
130 // Add the new instance to the application's instance list
131 App::instance_list.push_back(instance);
133 // Set up the instance with the default UI manager
134 instance->synfigapp::Instance::set_ui_interface(App::get_ui_interface());
136 // Signal the new instance
137 App::signal_instance_created()(instance);
139 // And then make sure that is has been selected
140 App::set_selected_instance(instance);
142 // Create the initial window for the root canvas
143 instance->focus(canvas);
149 Instance::find_canvas_view(etl::handle<synfig::Canvas> canvas)
154 while(canvas->is_inline())
155 canvas=canvas->parent();
157 CanvasViewList::iterator iter;
159 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
160 if((*iter)->get_canvas()==canvas)
163 return CanvasView::create(this,canvas);
167 Instance::focus(etl::handle<synfig::Canvas> canvas)
169 handle<CanvasView> canvas_view=find_canvas_view(canvas);
171 canvas_view->present();
175 Instance::set_undo_status(bool x)
178 App::toolbox->update_undo_redo();
179 signal_undo_redo_status_changed()();
183 Instance::set_redo_status(bool x)
186 App::toolbox->update_undo_redo();
187 signal_undo_redo_status_changed()();
191 studio::Instance::save_as(const synfig::String &file_name)
193 if(synfigapp::Instance::save_as(file_name))
195 // after changing the filename, update the render settings with the new filename
196 list<handle<CanvasView> >::iterator iter;
197 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
198 (*iter)->render_settings.set_entry_filename();
199 App::add_recent_file(file_name);
206 studio::Instance::save()
208 // the filename will be set to "Synfig Animation 1" or some such when first created
209 // and will be changed to an absolute path once it has been saved
210 // so if it still begins with "Synfig Animation " then we need to ask where to save it
211 if(get_file_name().find(DEFAULT_FILENAME_PREFIX)==0)
212 if (dialog_save_as())
215 return STATUS_CANCEL;
217 if (synfigapp::Instance::save())
220 App::dialog_error_blocking("Save - Error","Unable to save to '" + get_file_name() + "'");
225 studio::Instance::dialog_save_as()
227 string filename=basename(get_file_name());
228 Canvas::Handle canvas(get_canvas());
231 OneMoment one_moment;
232 std::set<Node*>::iterator iter;
233 for(iter=canvas->parent_set.begin();iter!=canvas->parent_set.end();++iter)
235 synfig::Node* node(*iter);
236 for(;!node->parent_set.empty();node=*node->parent_set.begin())
238 Layer::Handle parent_layer(dynamic_cast<Layer*>(node));
239 if(parent_layer && parent_layer->get_canvas()->get_root()!=get_canvas())
241 App::dialog_error_blocking("SaveAs - Error",
242 "There is currently a bug when using \"SaveAs\"\n"
243 "on a composition that is being referenced by other\n"
244 "files that are currently open. Close these\n"
245 "other files first before trying to use \"SaveAs\"."
256 // show the canvas' name if it has one, else its ID
257 while(App::dialog_save_file(_("Choose a Filename to Save As") +
259 (canvas->get_name().empty()
261 : canvas->get_name()) +
264 // If the filename still has wildcards, then we should
265 // continue looking for the file we want
266 if(find(filename.begin(),filename.end(),'*')!=filename.end())
269 if (filename_extension(filename) == "")
274 String ext(filename_extension(filename));
275 if(ext!=".sif" && ext!=".sifz" && !App::dialog_yes_no(_("Unknown extension"),
276 _("You have given the file name an extension\nwhich I do not recognize. Are you sure this is what you want?")))
286 int stat_return = stat(filename.c_str(), &s);
288 // if stat() fails with something other than 'file doesn't exist', there's been a real
289 // error of some kind. let's give up now and ask for a new path.
290 if (stat_return == -1 && errno != ENOENT)
292 perror(filename.c_str());
293 App::dialog_error_blocking("SaveAs - Error","Unable to check whether '" + filename + "' exists.");
297 // if the file exists and the user doesn't want to overwrite it, keep prompting for a filename
298 if ((stat_return == 0) &&
299 !App::dialog_yes_no("File exists",
302 "' already exists.\n\n"
303 "Do you want to replace it with the file you are saving?"))
307 if(save_as(filename))
310 App::dialog_error_blocking("SaveAs - Error","Unable to save to '" + filename + "'");
317 Instance::update_all_titles()
319 list<handle<CanvasView> >::iterator iter;
320 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
321 (*iter)->update_title();
327 // This will increase the reference count so we don't get DELETED
328 // until we are ready
329 handle<Instance> me(this);
331 // Make sure we aren't selected as the current instance
332 if(studio::App::get_selected_instance()==this)
333 studio::App::set_selected_instance(0);
335 // Turn-off/clean-up auto recovery
336 studio::App::auto_recover->clear_backup(get_canvas());
338 // Remove us from the active instance list
339 std::list<etl::handle<studio::Instance> >::iterator iter;
340 for(iter=studio::App::instance_list.begin();iter!=studio::App::instance_list.end();iter++)
343 assert(iter!=studio::App::instance_list.end());
344 if(iter!=studio::App::instance_list.end())
345 studio::App::instance_list.erase(iter);
347 // Send out a signal that we are being deleted
348 studio::App::signal_instance_deleted()(this);
350 // Hide all of the canvas views
351 for(std::list<etl::handle<CanvasView> >::iterator iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
354 // Consume pending events before deleting the canvas views
355 while(studio::App::events_pending())studio::App::iteration(false);
357 // Delete all of the canvas views
358 canvas_view_list().clear();
360 // If there is another open instance to select,
361 // go ahead and do so. If not, never mind.
362 if(studio::App::instance_list.empty())
364 studio::App::set_selected_canvas_view(0);
365 studio::App::set_selected_instance(0);
368 studio::App::instance_list.front()->canvas_view_list().front()->present();
373 Instance::insert_canvas(Gtk::TreeRow row, synfig::Canvas::Handle canvas)
375 CanvasTreeModel canvas_tree_model;
378 row[canvas_tree_model.icon] = Gtk::Button().render_icon(Gtk::StockID("synfig-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
379 row[canvas_tree_model.id] = canvas->get_id();
380 row[canvas_tree_model.name] = canvas->get_name();
381 if(canvas->is_root())
382 row[canvas_tree_model.label] = basename(canvas->get_file_name());
384 if(!canvas->get_id().empty())
385 row[canvas_tree_model.label] = canvas->get_id();
387 if(!canvas->get_name().empty())
388 row[canvas_tree_model.label] = canvas->get_name();
390 row[canvas_tree_model.label] = _("[Unnamed]");
392 row[canvas_tree_model.canvas] = canvas;
393 row[canvas_tree_model.is_canvas] = true;
394 row[canvas_tree_model.is_value_node] = false;
397 synfig::Canvas::Children::iterator iter;
398 synfig::Canvas::Children &children(canvas->children());
400 for(iter=children.begin();iter!=children.end();iter++)
401 insert_canvas(*(canvas_tree_store()->append(row.children())),*iter);
405 if(!canvas->value_node_list().empty())
407 Gtk::TreeRow valuenode_row = *(canvas_tree_store()->append(row.children()));
409 valuenode_row[canvas_tree_model.label] = "<defs>";
410 valuenode_row[canvas_tree_model.canvas] = canvas;
411 valuenode_row[canvas_tree_model.is_canvas] = false;
412 valuenode_row[canvas_tree_model.is_value_node] = false;
414 synfig::ValueNodeList::iterator iter;
415 synfig::ValueNodeList &value_node_list(canvas->value_node_list());
417 for(iter=value_node_list.begin();iter!=value_node_list.end();iter++)
418 insert_value_node(*(canvas_tree_store()->append(valuenode_row.children())),canvas,*iter);
426 Instance::insert_value_node(Gtk::TreeRow row,Canvas::Handle canvas,etl::handle<synfig::ValueNode> value_node)
428 CanvasTreeModel canvas_tree_model;
432 row[canvas_tree_model.id] = value_node->get_id();
433 row[canvas_tree_model.name] = value_node->get_id();
434 row[canvas_tree_model.label] = value_node->get_id();
435 row[canvas_tree_model.canvas] = canvas;
436 row[canvas_tree_model.value_node] = value_node;
437 row[canvas_tree_model.is_canvas] = false;
438 row[canvas_tree_model.is_value_node] = true;
439 row[canvas_tree_model.icon] = Gtk::Button().render_icon(valuenode_icon(value_node),Gtk::ICON_SIZE_SMALL_TOOLBAR);
444 Instance::refresh_canvas_tree()
446 canvas_tree_store()->clear();
447 Gtk::TreeRow row = *(canvas_tree_store()->prepend());
448 insert_canvas(row,get_canvas());
452 Instance::dialog_cvs_commit()
454 calc_repository_info();
457 App::dialog_error_blocking(_("Error"),_("You must first add this composition to the repository"));
464 if(synfigapp::Instance::get_action_count())
466 if(!App::dialog_yes_no(_("CVS Commit"), _("This will save any changes you have made. Are you sure?")))
473 App::dialog_error_blocking(_("Error"),_("The local copy of the file hasn't been changed since the last update.\nNothing to commit!"));
477 if(!App::dialog_entry(_("CVS Commit"),_("Enter a log message describing the changes you have made"), message))
480 OneMoment one_moment;
485 App::dialog_error_blocking(_("Error"),_("An error has occurred when trying to COMMIT"));
491 Instance::dialog_cvs_add()
493 calc_repository_info();
496 App::dialog_error_blocking(_("Error"),_("This composition has already been added to the repository"));
503 //if(!App::dialog_entry(_("CVS Add"),_("Enter a log message describing the file"), message))
505 OneMoment one_moment;
510 App::dialog_error_blocking(_("Error"),_("An error has occurred when trying to ADD"));
516 Instance::dialog_cvs_update()
518 calc_repository_info();
521 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to update from!"));
526 App::dialog_error_blocking(_("Info"),_("This file is up-to-date"));
532 String filename(get_file_name());
533 if(synfigapp::Instance::get_action_count())
535 if(!App::dialog_yes_no(_("CVS Update"), _("This will save any changes you have made. Are you sure?")))
539 OneMoment one_moment;
540 time_t oldtime=get_original_timestamp();
542 calc_repository_info();
543 // If something has been updated...
544 if(oldtime!=get_original_timestamp())
551 App::dialog_error_blocking(_("Error"),_("An error has occurred when trying to UPDATE"));
553 //update_all_titles();
557 Instance::dialog_cvs_revert()
559 calc_repository_info();
562 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to revert to!"));
567 String filename(get_file_name());
568 if(!App::dialog_yes_no(_("CVS Revert"),
569 _("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?")
573 OneMoment one_moment;
575 // Remove the old file
576 if(remove(get_file_name().c_str())!=0)
578 App::dialog_error_blocking(_("Error"),_("Unable to remove previous version"));
587 App::dialog_error_blocking(_("Error"),_("An error has occurred when trying to UPDATE"));
589 //update_all_titles();
593 Instance::_revert(Instance *instance)
595 OneMoment one_moment;
597 String filename(instance->get_file_name());
599 Canvas::Handle canvas(instance->get_canvas());
603 if(canvas->count()!=1)
606 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."));
617 // Schedule a revert to occur in a few moments
618 Glib::signal_timeout().connect(
621 sigc::ptr_fun(&Instance::_revert),
631 Instance::safe_revert()
633 if(synfigapp::Instance::get_action_count())
634 if(!App::dialog_yes_no(_("Revert to saved"), _("You will lose any changes you have made since your last save.\nAre you sure?")))
641 Instance::safe_close()
643 handle<CanvasView> canvas_view = find_canvas_view(get_canvas());
644 handle<synfigapp::UIInterface> uim=canvas_view->get_ui_interface();
646 // if the animation is currently playing, closing the window will cause a crash,
648 if (canvas_view->is_playing())
650 canvas_view->present();
651 App::dialog_error_blocking("Close Error", "The animation is currently playing so the window cannot be closed.");
654 if(get_action_count())
657 string str=strprintf(_("Would you like to save your changes to %s?"),basename(get_file_name()).c_str() );
658 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
659 if(answer==synfigapp::UIInterface::RESPONSE_YES)
661 enum Status status = save();
662 if (status == STATUS_OK) break;
663 else if (status == STATUS_CANCEL) return false;
665 if(answer==synfigapp::UIInterface::RESPONSE_NO)
667 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
673 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());
674 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
676 if(answer==synfigapp::UIInterface::RESPONSE_YES)
678 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
689 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
691 synfigapp::Action::CandidateList candidate_list;
692 synfigapp::Action::CandidateList::iterator iter;
694 candidate_list=compile_candidate_list(param_list,category);
696 candidate_list.sort();
698 if(candidate_list.empty())
699 synfig::warning("%s:%d Action CandidateList is empty!", __FILE__, __LINE__);
701 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
703 Gtk::StockID stock_id(get_action_stock_id(*iter));
705 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
707 action_group->add(Gtk::Action::create(
708 "action-"+iter->name,
710 iter->local_name,iter->local_name
715 *const_cast<studio::Instance*>(this),
716 &studio::Instance::process_action
723 ui_info+=strprintf("<menuitem action='action-%s' />",iter->name.c_str());
729 Instance::add_actions_to_menu(Gtk::Menu *menu, const synfigapp::Action::ParamList ¶m_list,synfigapp::Action::Category category)const
731 synfigapp::Action::CandidateList candidate_list;
732 synfigapp::Action::CandidateList::iterator iter;
734 candidate_list=compile_candidate_list(param_list,category);
736 candidate_list.sort();
738 if(candidate_list.empty())
739 synfig::warning("%s:%d Action CandidateList is empty!", __FILE__, __LINE__);
741 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
743 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
745 Gtk::Image* image(manage(new Gtk::Image()));
746 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
749 if(iter->task=="raise")
750 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
751 else if(iter->task=="lower")
752 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
753 else if(iter->task=="move_top")
754 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
755 else if(iter->task=="move_bottom")
756 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
757 else if(iter->task=="remove")
758 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
759 else if(iter->task=="set_on")
760 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
761 else if(iter->task=="set_off")
762 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
763 else if(iter->task=="duplicate")
764 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
765 else if(iter->task=="remove")
766 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
769 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
770 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
771 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
774 menu->items().push_back(
775 Gtk::Menu_Helpers::ImageMenuElem(
781 *const_cast<studio::Instance*>(this),
782 &studio::Instance::process_action
795 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
797 synfigapp::Action::CandidateList candidate_list;
798 synfigapp::Action::CandidateList candidate_list2;
800 synfigapp::Action::CandidateList::iterator iter;
802 candidate_list=compile_candidate_list(param_list,category);
803 candidate_list2=compile_candidate_list(param_list2,category);
805 candidate_list.sort();
807 if(candidate_list.empty())
808 synfig::warning("%s:%d Action CandidateList is empty!", __FILE__, __LINE__);
809 if(candidate_list2.empty())
810 synfig::warning("%s:%d Action CandidateList2 is empty!", __FILE__, __LINE__);
812 // Separate out the candidate lists so that there are no conflicts
813 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
815 synfigapp::Action::CandidateList::iterator iter2(candidate_list2.find(iter->name));
816 if(iter2!=candidate_list2.end())
817 candidate_list2.erase(iter2);
820 for(iter=candidate_list2.begin();iter!=candidate_list2.end();++iter)
822 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
824 Gtk::Image* image(manage(new Gtk::Image()));
825 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
827 /* if(iter->task=="raise")
828 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
829 else if(iter->task=="lower")
830 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
831 else if(iter->task=="move_top")
832 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
833 else if(iter->task=="move_bottom")
834 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
835 else if(iter->task=="remove")
836 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
837 else if(iter->task=="set_on")
838 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
839 else if(iter->task=="set_off")
840 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
841 else if(iter->task=="duplicate")
842 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
843 else if(iter->task=="remove")
844 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
847 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
848 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
849 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
852 menu->items().push_back(
853 Gtk::Menu_Helpers::ImageMenuElem(
859 *const_cast<studio::Instance*>(this),
860 &studio::Instance::process_action
871 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
873 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
875 Gtk::Image* image(manage(new Gtk::Image()));
876 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
877 /* if(iter->task=="raise")
878 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
879 else if(iter->task=="lower")
880 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
881 else if(iter->task=="move_top")
882 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
883 else if(iter->task=="move_bottom")
884 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
885 else if(iter->task=="remove")
886 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
887 else if(iter->task=="set_on")
888 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
889 else if(iter->task=="set_off")
890 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
891 else if(iter->task=="duplicate")
892 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
893 else if(iter->task=="remove")
894 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
897 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
898 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
899 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
902 menu->items().push_back(
903 Gtk::Menu_Helpers::ImageMenuElem(
909 *const_cast<studio::Instance*>(this),
910 &studio::Instance::process_action
923 Instance::process_action(synfig::String name, synfigapp::Action::ParamList param_list)
925 assert(synfigapp::Action::book().count(name));
927 synfigapp::Action::BookEntry entry(synfigapp::Action::book().find(name)->second);
929 synfigapp::Action::Handle action(entry.factory());
933 synfig::error("Bad Action");
937 action->set_param_list(param_list);
939 synfigapp::Action::ParamVocab param_vocab(entry.get_param_vocab());
940 synfigapp::Action::ParamVocab::const_iterator iter;
942 for(iter=param_vocab.begin();iter!=param_vocab.end();++iter)
944 if(!iter->get_mutual_exclusion().empty() && param_list.count(iter->get_mutual_exclusion()))
947 // If the parameter is optionally user-supplied,
948 // and has not been already provided in the param_list,
949 // then we should go ahead and see if we can
950 // provide that data.
951 if(iter->get_user_supplied() && param_list.count(iter->get_name())==0)
953 switch(iter->get_type())
955 case synfigapp::Action::Param::TYPE_STRING:
958 if(!studio::App::dialog_entry(entry.local_name, iter->get_local_name()+":"+iter->get_desc(),str))
960 action->set_param(iter->get_name(),str);
964 synfig::error("Unsupported user-supplied action parameter");
971 if(!action->is_ready())
973 synfig::error("Action not ready");
977 perform_action(action);
981 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas, synfigapp::ValueDesc value_desc, float location)
983 Gtk::Menu& parammenu(*menu);
985 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
987 if(!canvas_interface)
990 synfigapp::Action::ParamList param_list,param_list2;
991 param_list=canvas_interface->generate_param_list(value_desc);
992 param_list.add("origin",location);
994 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
996 param_list2=canvas_interface->generate_param_list(
997 synfigapp::ValueDesc(
998 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
1002 param_list2.add("origin",location);
1006 // Populate the convert menu by looping through
1007 // the ValueNode book and find the ones that are
1009 // don't allow the Index parameter of the Duplicate layer to be converted
1010 if (!value_desc.parent_is_layer_param() || value_desc.get_layer()->get_name() != "duplicate" || value_desc.get_param_name() != "index")
1012 Gtk::Menu *convert_menu=manage(new Gtk::Menu());
1013 LinkableValueNode::Book::const_iterator iter;
1014 for(iter=LinkableValueNode::book().begin();iter!=LinkableValueNode::book().end();++iter)
1016 if(iter->second.check_type(value_desc.get_value_type()))
1018 convert_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->second.local_name,
1022 sigc::mem_fun(*canvas_interface.get(),&synfigapp::CanvasInterface::convert),
1032 parammenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::CONVERT,*convert_menu));
1035 if(param_list2.empty())
1036 add_actions_to_menu(¶mmenu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1038 add_actions_to_menu(¶mmenu, param_list2,param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1040 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
1042 value_desc=synfigapp::ValueDesc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),0);
1045 if(value_desc.is_value_node() && ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
1047 ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()));
1051 WaypointList::iterator iter(value_node->find(canvas->get_time()));
1052 parammenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoint"),
1056 sigc::mem_fun(*find_canvas_view(canvas),&studio::CanvasView::on_waypoint_clicked),
1072 edit_several_waypoints(etl::handle<CanvasView> canvas_view, std::list<synfigapp::ValueDesc> value_desc_list)
1074 etl::handle<synfigapp::CanvasInterface> canvas_interface(canvas_view->canvas_interface());
1077 "Edit Multiple Waypoints", // Title
1079 true // use_separator
1082 Widget_WaypointModel widget_waypoint_model;
1083 widget_waypoint_model.show();
1085 dialog.get_vbox()->pack_start(widget_waypoint_model);
1088 dialog.add_button(Gtk::StockID("gtk-apply"),1);
1089 dialog.add_button(Gtk::StockID("gtk-cancel"),0);
1093 if(dialog.run()==0 || widget_waypoint_model.get_waypoint_model().is_trivial())
1096 synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Set Waypoints"));
1098 std::list<synfigapp::ValueDesc>::iterator iter;
1099 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
1101 synfigapp::ValueDesc value_desc(*iter);
1103 if(!value_desc.is_valid())
1106 ValueNode_Animated::Handle value_node;
1108 // If this value isn't a ValueNode_Animated, but
1109 // it is somewhat constant, then go ahead and convert
1110 // it to a ValueNode_Animated.
1111 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
1114 if(value_desc.is_value_node())
1115 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
1117 value=value_desc.get_value();
1119 value_node=ValueNode_Animated::create(value,canvas_interface->get_time());
1121 synfigapp::Action::Handle action;
1123 if(!value_desc.is_value_node())
1125 action=synfigapp::Action::create("value_desc_connect");
1126 action->set_param("dest",value_desc);
1127 action->set_param("src",ValueNode::Handle(value_node));
1131 action=synfigapp::Action::create("value_node_replace");
1132 action->set_param("dest",value_desc.get_value_node());
1133 action->set_param("src",ValueNode::Handle(value_node));
1136 action->set_param("canvas",canvas_view->get_canvas());
1137 action->set_param("canvas_interface",canvas_interface);
1140 if(!canvas_interface->get_instance()->perform_action(action))
1142 canvas_view->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
1149 if(value_desc.is_value_node())
1150 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
1157 synfigapp::Action::Handle action(synfigapp::Action::create("waypoint_set_smart"));
1161 canvas_view->get_ui_interface()->error(_("Unable to find waypoint_set_smart action"));
1167 action->set_param("canvas",canvas_view->get_canvas());
1168 action->set_param("canvas_interface",canvas_interface);
1169 action->set_param("value_node",ValueNode::Handle(value_node));
1170 action->set_param("time",canvas_interface->get_time());
1171 action->set_param("model",widget_waypoint_model.get_waypoint_model());
1173 if(!canvas_interface->get_instance()->perform_action(action))
1175 canvas_view->get_ui_interface()->error(_("Unable to set a specific waypoint"));
1182 //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
1191 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas,const std::list<synfigapp::ValueDesc>& value_desc_list)
1193 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
1195 synfigapp::Action::ParamList param_list;
1196 param_list=canvas_interface->generate_param_list(value_desc_list);
1198 add_actions_to_menu(menu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1200 // Add the edit waypoints option if that might be useful
1201 if(canvas->rend_desc().get_time_end()-Time::epsilon()>canvas->rend_desc().get_time_start())
1203 menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
1207 &edit_several_waypoints
1211 find_canvas_view(canvas)