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 "iconcontroler.h"
61 using namespace synfig;
62 using namespace studio;
65 /* === M A C R O S ========================================================= */
67 /* === G L O B A L S ======================================================= */
69 int studio::Instance::instance_count_=0;
71 /* === P R O C E D U R E S ================================================= */
73 /* === M E T H O D S ======================================================= */
75 Instance::Instance(Canvas::Handle canvas):
76 synfigapp::Instance (canvas),
77 // canvas_tree_store_ (Gtk::TreeStore::create(CanvasTreeModel())),
78 // canvas_tree_store_ (Gtk::TreeStore::create()),
79 history_tree_store_ (HistoryTreeStore::create(this)),
83 CanvasTreeModel model;
84 canvas_tree_store_=Gtk::TreeStore::create(model);
86 id_=instance_count_++;
88 // Connect up all the signals
89 signal_filename_changed().connect(sigc::mem_fun(*this,&studio::Instance::update_all_titles));
90 signal_unsaved_status_changed().connect(sigc::hide(sigc::mem_fun(*this,&studio::Instance::update_all_titles)));
91 signal_undo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_undo_status));
92 signal_redo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_redo_status));
94 signal_saved().connect(
97 studio::AutoRecover::auto_backup
102 canvas_tree_store_=Gtk::TreeStore::create(canvas_tree_model);
104 refresh_canvas_tree();
107 Instance::~Instance()
112 Instance::get_visible_canvases()const
115 CanvasViewList::const_iterator iter;
116 for(iter=canvas_view_list_.begin();iter!=canvas_view_list_.end();++iter)
117 if((*iter)->is_visible())
123 Instance::create(Canvas::Handle canvas)
125 // Construct a new instance
126 handle<Instance> instance(new Instance(canvas));
128 // Add the new instance to the application's instance list
129 App::instance_list.push_back(instance);
131 // Set up the instance with the default UI manager
132 instance->synfigapp::Instance::set_ui_interface(App::get_ui_interface());
134 // Signal the new instance
135 App::signal_instance_created()(instance);
137 // And then make sure that is has been selected
138 App::set_selected_instance(instance);
140 // Create the initial window for the root canvas
141 instance->focus(canvas);
147 Instance::find_canvas_view(Canvas::Handle canvas)
152 while(canvas->is_inline())
153 canvas=canvas->parent();
155 CanvasViewList::iterator iter;
157 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
158 if((*iter)->get_canvas()==canvas)
161 return CanvasView::create(this,canvas);
165 Instance::focus(Canvas::Handle canvas)
167 handle<CanvasView> canvas_view=find_canvas_view(canvas);
169 canvas_view->present();
173 Instance::set_undo_status(bool x)
176 App::toolbox->update_undo_redo();
177 signal_undo_redo_status_changed()();
181 Instance::set_redo_status(bool x)
184 App::toolbox->update_undo_redo();
185 signal_undo_redo_status_changed()();
189 studio::Instance::save_as(const synfig::String &file_name)
191 if(synfigapp::Instance::save_as(file_name))
193 // after changing the filename, update the render settings with the new filename
194 list<handle<CanvasView> >::iterator iter;
195 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
196 (*iter)->render_settings.set_entry_filename();
197 App::add_recent_file(file_name);
204 studio::Instance::save()
206 // the filename will be set to "Synfig Animation 1" or some such when first created
207 // and will be changed to an absolute path once it has been saved
208 // so if it still begins with "Synfig Animation " then we need to ask where to save it
209 if(get_file_name().find(DEFAULT_FILENAME_PREFIX)==0)
210 if (dialog_save_as())
213 return STATUS_CANCEL;
215 if (synfigapp::Instance::save())
218 App::dialog_error_blocking("Save - Error","Unable to save to '" + get_file_name() + "'");
223 studio::Instance::dialog_save_as()
225 string filename=basename(get_file_name());
226 Canvas::Handle canvas(get_canvas());
229 OneMoment one_moment;
230 std::set<Node*>::iterator iter;
231 for(iter=canvas->parent_set.begin();iter!=canvas->parent_set.end();++iter)
233 synfig::Node* node(*iter);
234 for(;!node->parent_set.empty();node=*node->parent_set.begin())
236 Layer::Handle parent_layer(dynamic_cast<Layer*>(node));
237 if(parent_layer && parent_layer->get_canvas()->get_root()!=get_canvas())
239 App::dialog_error_blocking("SaveAs - Error",
240 "There is currently a bug when using \"SaveAs\"\n"
241 "on a composition that is being referenced by other\n"
242 "files that are currently open. Close these\n"
243 "other files first before trying to use \"SaveAs\"."
254 // show the canvas' name if it has one, else its ID
255 while(App::dialog_save_file(_("Choose a Filename to Save As") +
257 (canvas->get_name().empty()
259 : canvas->get_name()) +
262 // If the filename still has wildcards, then we should
263 // continue looking for the file we want
264 if(find(filename.begin(),filename.end(),'*')!=filename.end())
267 std::string base = basename(filename);
268 if(find(base.begin(),base.end(),'.')==base.end())
273 String ext(String(filename.begin()+filename.find_last_of('.')+1,filename.end()));
274 if(ext!="sif" && ext!="sifz" && !App::dialog_yes_no(_("Unknown extension"),
275 _("You have given the file name an extension\nwhich I do not recognise. Are you sure this is what you want?")))
287 int stat_return = stat(filename.c_str(), &s);
289 // if stat() fails with something other than 'file doesn't exist', there's been a real
290 // error of some kind. let's give up now and ask for a new path.
291 if (stat_return == -1 && errno != ENOENT)
293 perror(filename.c_str());
294 App::dialog_error_blocking("SaveAs - Error","Unable to check whether '" + filename + "' exists.");
298 // if the file exists and the user doesn't want to overwrite it, keep prompting for a filename
299 if ((stat_return == 0) &&
300 !App::dialog_yes_no("File exists",
303 "' already exists.\n\n"
304 "Do you want to replace it with the file you are saving?"))
308 if(save_as(filename))
311 App::dialog_error_blocking("SaveAs - Error","Unable to save to '" + filename + "'");
318 Instance::update_all_titles()
320 list<handle<CanvasView> >::iterator iter;
321 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
322 (*iter)->update_title();
328 // This will increase the reference count so we don't get DELETED
329 // until we are ready
330 handle<Instance> me(this);
332 // Make sure we aren't selected as the current instance
333 if(studio::App::get_selected_instance()==this)
334 studio::App::set_selected_instance(0);
336 // Turn-off/clean-up auto recovery
337 studio::App::auto_recover->clear_backup(get_canvas());
339 // Remove us from the active instance list
340 std::list<etl::handle<studio::Instance> >::iterator iter;
341 for(iter=studio::App::instance_list.begin();iter!=studio::App::instance_list.end();iter++)
344 assert(iter!=studio::App::instance_list.end());
345 if(iter!=studio::App::instance_list.end())
346 studio::App::instance_list.erase(iter);
348 // Send out a signal that we are being deleted
349 studio::App::signal_instance_deleted()(this);
351 // Hide all of the canvas views
352 for(std::list<etl::handle<CanvasView> >::iterator iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
355 // Consume pending events before deleting the canvas views
356 while(studio::App::events_pending())studio::App::iteration(false);
358 // Delete all of the canvas views
359 canvas_view_list().clear();
361 // If there is another open instance to select,
362 // go ahead and do so. If not, never mind.
363 if(studio::App::instance_list.empty())
365 studio::App::set_selected_canvas_view(0);
366 studio::App::set_selected_instance(0);
369 studio::App::instance_list.front()->canvas_view_list().front()->present();
374 Instance::insert_canvas(Gtk::TreeRow row,Canvas::Handle canvas)
376 CanvasTreeModel canvas_tree_model;
379 row[canvas_tree_model.icon] = Gtk::Button().render_icon(Gtk::StockID("synfig-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
380 row[canvas_tree_model.id] = canvas->get_id();
381 row[canvas_tree_model.name] = canvas->get_name();
382 if(canvas->is_root())
383 row[canvas_tree_model.label] = basename(canvas->get_file_name());
385 if(!canvas->get_id().empty())
386 row[canvas_tree_model.label] = canvas->get_id();
388 if(!canvas->get_name().empty())
389 row[canvas_tree_model.label] = canvas->get_name();
391 row[canvas_tree_model.label] = _("[Unnamed]");
393 row[canvas_tree_model.canvas] = canvas;
394 row[canvas_tree_model.is_canvas] = true;
395 row[canvas_tree_model.is_value_node] = false;
398 synfig::Canvas::Children::iterator iter;
399 synfig::Canvas::Children &children(canvas->children());
401 for(iter=children.begin();iter!=children.end();iter++)
402 insert_canvas(*(canvas_tree_store()->append(row.children())),*iter);
406 if(!canvas->value_node_list().empty())
408 Gtk::TreeRow valuenode_row = *(canvas_tree_store()->append(row.children()));
410 valuenode_row[canvas_tree_model.label] = "<defs>";
411 valuenode_row[canvas_tree_model.canvas] = canvas;
412 valuenode_row[canvas_tree_model.is_canvas] = false;
413 valuenode_row[canvas_tree_model.is_value_node] = false;
415 synfig::ValueNodeList::iterator iter;
416 synfig::ValueNodeList &value_node_list(canvas->value_node_list());
418 for(iter=value_node_list.begin();iter!=value_node_list.end();iter++)
419 insert_value_node(*(canvas_tree_store()->append(valuenode_row.children())),canvas,*iter);
427 Instance::insert_value_node(Gtk::TreeRow row,Canvas::Handle canvas,etl::handle<synfig::ValueNode> value_node)
429 CanvasTreeModel canvas_tree_model;
433 row[canvas_tree_model.id] = value_node->get_id();
434 row[canvas_tree_model.name] = value_node->get_id();
435 row[canvas_tree_model.label] = value_node->get_id();
436 row[canvas_tree_model.canvas] = canvas;
437 row[canvas_tree_model.value_node] = value_node;
438 row[canvas_tree_model.is_canvas] = false;
439 row[canvas_tree_model.is_value_node] = true;
440 row[canvas_tree_model.icon] = Gtk::Button().render_icon(valuenode_icon(value_node),Gtk::ICON_SIZE_SMALL_TOOLBAR);
445 Instance::refresh_canvas_tree()
447 canvas_tree_store()->clear();
448 Gtk::TreeRow row = *(canvas_tree_store()->prepend());
449 insert_canvas(row,get_canvas());
453 Instance::dialog_cvs_commit()
455 calc_repository_info();
458 App::dialog_error_blocking(_("Error"),_("You must first add this composition to the repository"));
465 if(synfigapp::Instance::get_action_count())
467 if(!App::dialog_yes_no(_("CVS Commit"), _("This will save any changes you have made. Are you sure?")))
474 App::dialog_error_blocking(_("Error"),_("The local copy of the file hasn't been changed since the last update.\nNothing to commit!"));
478 if(!App::dialog_entry(_("CVS Commit"),_("Enter a log message describing the changes you have made"), message))
481 OneMoment one_moment;
486 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to COMMIT"));
492 Instance::dialog_cvs_add()
494 calc_repository_info();
497 App::dialog_error_blocking(_("Error"),_("This composition has already been added to the repository"));
504 //if(!App::dialog_entry(_("CVS Add"),_("Enter a log message describing the file"), message))
506 OneMoment one_moment;
511 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to ADD"));
517 Instance::dialog_cvs_update()
519 calc_repository_info();
522 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to update from!"));
527 App::dialog_error_blocking(_("Info"),_("This file is up-to-date"));
533 String filename(get_file_name());
534 if(synfigapp::Instance::get_action_count())
536 if(!App::dialog_yes_no(_("CVS Update"), _("This will save any changes you have made. Are you sure?")))
540 OneMoment one_moment;
541 time_t oldtime=get_original_timestamp();
543 calc_repository_info();
544 // If something has been updated...
545 if(oldtime!=get_original_timestamp())
552 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
554 //update_all_titles();
558 Instance::dialog_cvs_revert()
560 calc_repository_info();
563 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to revert to!"));
568 String filename(get_file_name());
569 if(!App::dialog_yes_no(_("CVS Revert"),
570 _("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?")
574 OneMoment one_moment;
576 // Remove the old file
577 if(remove(get_file_name().c_str())!=0)
579 App::dialog_error_blocking(_("Error"),_("Unable to remove previous version"));
588 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
590 //update_all_titles();
594 Instance::_revert(Instance *instance)
596 OneMoment one_moment;
598 String filename(instance->get_file_name());
600 Canvas::Handle canvas(instance->get_canvas());
604 if(canvas->count()!=1)
607 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."));
618 // Schedule a revert to occur in a few moments
619 Glib::signal_timeout().connect(
622 sigc::ptr_fun(&Instance::_revert),
632 Instance::safe_revert()
634 if(synfigapp::Instance::get_action_count())
635 if(!App::dialog_yes_no(_("Revert to saved"), _("You will lose any changes you have made since your last save.\nAre you sure?")))
642 Instance::safe_close()
644 handle<CanvasView> canvas_view = find_canvas_view(get_canvas());
645 handle<synfigapp::UIInterface> uim=canvas_view->get_ui_interface();
647 // if the animation is currently playing, closing the window will cause a crash,
649 if (canvas_view->is_playing())
651 canvas_view->present();
652 App::dialog_error_blocking("Close Error", "The animation is currently playing so the window cannot be closed.");
655 if(get_action_count())
658 string str=strprintf(_("Would you like to save your changes to %s?"),basename(get_file_name()).c_str() );
659 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
660 if(answer==synfigapp::UIInterface::RESPONSE_YES)
662 enum Status status = save();
663 if (status == STATUS_OK) break;
664 else if (status == STATUS_CANCEL) return false;
666 if(answer==synfigapp::UIInterface::RESPONSE_NO)
668 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
674 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());
675 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
677 if(answer==synfigapp::UIInterface::RESPONSE_YES)
679 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
690 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
692 synfigapp::Action::CandidateList candidate_list;
693 synfigapp::Action::CandidateList::iterator iter;
695 candidate_list=compile_candidate_list(param_list,category);
697 candidate_list.sort();
699 if(candidate_list.empty())
700 synfig::warning("%s:%d Action CandidateList is empty!", __FILE__, __LINE__);
702 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
704 Gtk::StockID stock_id(get_action_stock_id(*iter));
706 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
708 action_group->add(Gtk::Action::create(
709 "action-"+iter->name,
711 iter->local_name,iter->local_name
716 *const_cast<studio::Instance*>(this),
717 &studio::Instance::process_action
724 ui_info+=strprintf("<menuitem action='action-%s' />",iter->name.c_str());
730 Instance::add_actions_to_menu(Gtk::Menu *menu, const synfigapp::Action::ParamList ¶m_list,synfigapp::Action::Category category)const
732 synfigapp::Action::CandidateList candidate_list;
733 synfigapp::Action::CandidateList::iterator iter;
735 candidate_list=compile_candidate_list(param_list,category);
737 candidate_list.sort();
739 if(candidate_list.empty())
740 synfig::warning("%s:%d Action CandidateList is empty!", __FILE__, __LINE__);
742 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
744 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
746 Gtk::Image* image(manage(new Gtk::Image()));
747 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
750 if(iter->task=="raise")
751 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
752 else if(iter->task=="lower")
753 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
754 else if(iter->task=="move_top")
755 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
756 else if(iter->task=="move_bottom")
757 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
758 else if(iter->task=="remove")
759 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
760 else if(iter->task=="set_on")
761 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
762 else if(iter->task=="set_off")
763 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
764 else if(iter->task=="duplicate")
765 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
766 else if(iter->task=="remove")
767 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
770 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
771 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
772 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
775 menu->items().push_back(
776 Gtk::Menu_Helpers::ImageMenuElem(
782 *const_cast<studio::Instance*>(this),
783 &studio::Instance::process_action
796 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
798 synfigapp::Action::CandidateList candidate_list;
799 synfigapp::Action::CandidateList candidate_list2;
801 synfigapp::Action::CandidateList::iterator iter;
803 candidate_list=compile_candidate_list(param_list,category);
804 candidate_list2=compile_candidate_list(param_list2,category);
806 candidate_list.sort();
808 if(candidate_list.empty())
809 synfig::warning("%s:%d Action CandidateList is empty!", __FILE__, __LINE__);
810 if(candidate_list2.empty())
811 synfig::warning("%s:%d Action CandidateList2 is empty!", __FILE__, __LINE__);
813 // Seperate out the candidate lists so that there are no conflicts
814 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
816 synfigapp::Action::CandidateList::iterator iter2(candidate_list2.find(iter->name));
817 if(iter2!=candidate_list2.end())
818 candidate_list2.erase(iter2);
821 for(iter=candidate_list2.begin();iter!=candidate_list2.end();++iter)
823 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
825 Gtk::Image* image(manage(new Gtk::Image()));
826 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
828 /* if(iter->task=="raise")
829 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
830 else if(iter->task=="lower")
831 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
832 else if(iter->task=="move_top")
833 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
834 else if(iter->task=="move_bottom")
835 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
836 else if(iter->task=="remove")
837 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
838 else if(iter->task=="set_on")
839 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
840 else if(iter->task=="set_off")
841 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
842 else if(iter->task=="duplicate")
843 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
844 else if(iter->task=="remove")
845 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
848 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
849 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
850 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
853 menu->items().push_back(
854 Gtk::Menu_Helpers::ImageMenuElem(
860 *const_cast<studio::Instance*>(this),
861 &studio::Instance::process_action
872 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
874 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
876 Gtk::Image* image(manage(new Gtk::Image()));
877 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
878 /* if(iter->task=="raise")
879 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
880 else if(iter->task=="lower")
881 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
882 else if(iter->task=="move_top")
883 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
884 else if(iter->task=="move_bottom")
885 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
886 else if(iter->task=="remove")
887 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
888 else if(iter->task=="set_on")
889 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
890 else if(iter->task=="set_off")
891 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
892 else if(iter->task=="duplicate")
893 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
894 else if(iter->task=="remove")
895 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
898 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
899 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
900 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
903 menu->items().push_back(
904 Gtk::Menu_Helpers::ImageMenuElem(
910 *const_cast<studio::Instance*>(this),
911 &studio::Instance::process_action
924 Instance::process_action(String name, synfigapp::Action::ParamList param_list)
926 assert(synfigapp::Action::book().count(name));
928 synfigapp::Action::BookEntry entry(synfigapp::Action::book().find(name)->second);
930 synfigapp::Action::Handle action(entry.factory());
934 synfig::error("Bad Action");
938 action->set_param_list(param_list);
940 synfigapp::Action::ParamVocab param_vocab(entry.get_param_vocab());
941 synfigapp::Action::ParamVocab::const_iterator iter;
943 for(iter=param_vocab.begin();iter!=param_vocab.end();++iter)
945 if(!iter->get_mutual_exclusion().empty() && param_list.count(iter->get_mutual_exclusion()))
948 // If the parameter is optionally user-supplied,
949 // and has not been already provided in the param_list,
950 // then we should go ahead and see if we can
951 // provide that data.
952 if(iter->get_user_supplied() && param_list.count(iter->get_name())==0)
954 switch(iter->get_type())
956 case synfigapp::Action::Param::TYPE_STRING:
959 if(!studio::App::dialog_entry(entry.local_name, iter->get_local_name()+":"+iter->get_desc(),str))
961 action->set_param(iter->get_name(),str);
965 synfig::error("Unsupported user-supplied action parameter");
972 if(!action->is_ready())
974 synfig::error("Action not ready");
978 perform_action(action);
982 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas, synfigapp::ValueDesc value_desc, float location)
984 Gtk::Menu& parammenu(*menu);
986 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
988 if(!canvas_interface)
991 synfigapp::Action::ParamList param_list,param_list2;
992 param_list=canvas_interface->generate_param_list(value_desc);
993 param_list.add("origin",location);
995 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
997 param_list2=canvas_interface->generate_param_list(
998 synfigapp::ValueDesc(
999 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
1003 param_list2.add("origin",location);
1007 // Populate the convert menu by looping through
1008 // the ValueNode book and find the ones that are
1011 Gtk::Menu *convert_menu=manage(new Gtk::Menu());
1012 LinkableValueNode::Book::const_iterator iter;
1013 for(iter=LinkableValueNode::book().begin();iter!=LinkableValueNode::book().end();++iter)
1015 if(iter->second.check_type(value_desc.get_value_type()))
1017 convert_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->second.local_name,
1021 sigc::mem_fun(*canvas_interface.get(),&synfigapp::CanvasInterface::convert),
1031 parammenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::CONVERT,*convert_menu));
1034 if(param_list2.empty())
1035 add_actions_to_menu(¶mmenu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1037 add_actions_to_menu(¶mmenu, param_list2,param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1039 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
1041 value_desc=synfigapp::ValueDesc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),0);
1044 if(value_desc.is_value_node() && ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
1046 ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()));
1050 WaypointList::iterator iter(value_node->find(canvas->get_time()));
1051 parammenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoint"),
1055 sigc::mem_fun(*find_canvas_view(canvas),&studio::CanvasView::on_waypoint_clicked),
1071 edit_several_waypoints(etl::handle<CanvasView> canvas_view, std::list<synfigapp::ValueDesc> value_desc_list)
1073 etl::handle<synfigapp::CanvasInterface> canvas_interface(canvas_view->canvas_interface());
1076 "Edit Multiple Waypoints", // Title
1078 true // use_separator
1081 Widget_WaypointModel widget_waypoint_model;
1082 widget_waypoint_model.show();
1084 dialog.get_vbox()->pack_start(widget_waypoint_model);
1087 dialog.add_button(Gtk::StockID("gtk-apply"),1);
1088 dialog.add_button(Gtk::StockID("gtk-cancel"),0);
1092 if(dialog.run()==0 || widget_waypoint_model.get_waypoint_model().is_trivial())
1095 synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Set Waypoints"));
1097 std::list<synfigapp::ValueDesc>::iterator iter;
1098 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
1100 synfigapp::ValueDesc value_desc(*iter);
1102 if(!value_desc.is_valid())
1105 ValueNode_Animated::Handle value_node;
1107 // If this value isn't a ValueNode_Animated, but
1108 // it is somewhat constant, then go ahead and convert
1109 // it to a ValueNode_Animated.
1110 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
1113 if(value_desc.is_value_node())
1114 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
1116 value=value_desc.get_value();
1118 value_node=ValueNode_Animated::create(value,canvas_interface->get_time());
1120 synfigapp::Action::Handle action;
1122 if(!value_desc.is_value_node())
1124 action=synfigapp::Action::create("value_desc_connect");
1125 action->set_param("dest",value_desc);
1126 action->set_param("src",ValueNode::Handle(value_node));
1130 action=synfigapp::Action::create("value_node_replace");
1131 action->set_param("dest",value_desc.get_value_node());
1132 action->set_param("src",ValueNode::Handle(value_node));
1135 action->set_param("canvas",canvas_view->get_canvas());
1136 action->set_param("canvas_interface",canvas_interface);
1139 if(!canvas_interface->get_instance()->perform_action(action))
1141 canvas_view->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
1148 if(value_desc.is_value_node())
1149 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
1156 synfigapp::Action::Handle action(synfigapp::Action::create("waypoint_set_smart"));
1160 canvas_view->get_ui_interface()->error(_("Unable to find waypoint_set_smart action"));
1166 action->set_param("canvas",canvas_view->get_canvas());
1167 action->set_param("canvas_interface",canvas_interface);
1168 action->set_param("value_node",ValueNode::Handle(value_node));
1169 action->set_param("time",canvas_interface->get_time());
1170 action->set_param("model",widget_waypoint_model.get_waypoint_model());
1172 if(!canvas_interface->get_instance()->perform_action(action))
1174 canvas_view->get_ui_interface()->error(_("Unable to set a specific waypoint"));
1181 //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
1190 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas,const std::list<synfigapp::ValueDesc>& value_desc_list)
1192 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
1194 synfigapp::Action::ParamList param_list;
1195 param_list=canvas_interface->generate_param_list(value_desc_list);
1197 add_actions_to_menu(menu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1199 // Add the edit waypoints option if that might be useful
1200 if(canvas->rend_desc().get_time_end()-Time::epsilon()>canvas->rend_desc().get_time_start())
1202 menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
1206 &edit_several_waypoints
1210 find_canvas_view(canvas)