1 /* === S Y N F I G ========================================================= */
2 /*! \file gtkmm/instance.cpp
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"
60 using namespace synfig;
61 using namespace studio;
64 /* === M A C R O S ========================================================= */
66 /* === G L O B A L S ======================================================= */
68 int studio::Instance::instance_count_=0;
70 /* === P R O C E D U R E S ================================================= */
72 /* === M E T H O D S ======================================================= */
74 Instance::Instance(Canvas::Handle canvas):
75 synfigapp::Instance (canvas),
76 // canvas_tree_store_ (Gtk::TreeStore::create(CanvasTreeModel())),
77 // canvas_tree_store_ (Gtk::TreeStore::create()),
78 history_tree_store_ (HistoryTreeStore::create(this)),
82 CanvasTreeModel model;
83 canvas_tree_store_=Gtk::TreeStore::create(model);
85 id_=instance_count_++;
87 // Connect up all the signals
88 signal_filename_changed().connect(sigc::mem_fun(*this,&studio::Instance::update_all_titles));
89 signal_unsaved_status_changed().connect(sigc::hide(sigc::mem_fun(*this,&studio::Instance::update_all_titles)));
90 signal_undo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_undo_status));
91 signal_redo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_redo_status));
93 signal_saved().connect(
96 studio::AutoRecover::auto_backup
101 canvas_tree_store_=Gtk::TreeStore::create(canvas_tree_model);
103 refresh_canvas_tree();
106 Instance::~Instance()
111 Instance::get_visible_canvases()const
114 CanvasViewList::const_iterator iter;
115 for(iter=canvas_view_list_.begin();iter!=canvas_view_list_.end();++iter)
116 if((*iter)->is_visible())
122 Instance::create(Canvas::Handle canvas)
124 // Construct a new instance
125 handle<Instance> instance(new Instance(canvas));
127 // Add the new instance to the application's instance list
128 App::instance_list.push_back(instance);
130 // Set up the instance with the default UI manager
131 instance->synfigapp::Instance::set_ui_interface(App::get_ui_interface());
133 // Signal the new instance
134 App::signal_instance_created()(instance);
136 // And then make sure that is has been selected
137 App::set_selected_instance(instance);
139 // Create the initial window for the root canvas
140 instance->focus(canvas);
146 Instance::find_canvas_view(Canvas::Handle canvas)
151 while(canvas->is_inline())
152 canvas=canvas->parent();
154 CanvasViewList::iterator iter;
156 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
157 if((*iter)->get_canvas()==canvas)
160 return CanvasView::create(this,canvas);
164 Instance::focus(Canvas::Handle canvas)
166 handle<CanvasView> canvas_view=find_canvas_view(canvas);
168 canvas_view->present();
172 Instance::set_undo_status(bool x)
175 App::toolbox->update_undo_redo();
176 signal_undo_redo_status_changed()();
180 Instance::set_redo_status(bool x)
183 App::toolbox->update_undo_redo();
184 signal_undo_redo_status_changed()();
188 studio::Instance::save_as(const synfig::String &file_name)const
190 if(synfigapp::Instance::save_as(file_name))
192 App::add_recent_file(file_name);
199 studio::Instance::save_as(const synfig::String &file_name)
201 if(synfigapp::Instance::save_as(file_name))
203 App::add_recent_file(file_name);
210 studio::Instance::save()
212 if(basename(get_file_name()).find("untitled")==0)
218 return synfigapp::Instance::save();
223 studio::Instance::dialog_save_as()
225 string filename="*.sif";
227 Canvas::Handle canvas(get_canvas());
230 OneMoment one_moment;
231 std::set<Node*>::iterator iter;
232 for(iter=canvas->parent_set.begin();iter!=canvas->parent_set.end();++iter)
234 synfig::Node* node(*iter);
235 for(;!node->parent_set.empty();node=*node->parent_set.begin())
237 Layer::Handle parent_layer(dynamic_cast<Layer*>(node));
238 if(parent_layer && parent_layer->get_canvas()->get_root()!=get_canvas())
240 App::dialog_error_blocking("SaveAs - Error",
241 "There is currently a bug when using \"SaveAs\"\n"
242 "on a composition that is being referenced by other\n"
243 "files that are currently open. Close these\n"
244 "other files first before trying to use \"SaveAs\"."
255 while(App::dialog_saveas_file("SaveAs", filename))
257 // If the filename still has wildcards, then we should
258 // continue looking for the file we want
259 if(find(filename.begin(),filename.end(),'*')!=filename.end())
262 if(find(filename.begin(),filename.end(),'.')==filename.end())
267 String ext(String(filename.begin()+filename.find_last_of('.')+1,filename.end()));
268 if(ext!="sif" && ext!="sifz" && !App::dialog_yes_no(_("Unknown extension"),
269 _("You have given the file name an extension\nwhich I do not recognise. Are you sure this is what you want?")))
281 // if stat() succeeds, or it fails with something other than 'file doesn't exist', the file exists
282 // if the file exists and the user doesn't want to overwrite it, keep prompting for a filename
283 if ((stat(filename.c_str(), &s) != -1 || errno != ENOENT) &&
284 !App::dialog_yes_no("File exists",
287 "' already exists.\n\n"
288 "Do you want to replace it with the file you are saving?"))
292 if(save_as(filename))
295 App::dialog_error_blocking("SaveAs - Error","Unable to save file");
300 Instance::update_all_titles()
302 list<handle<CanvasView> >::iterator iter;
303 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
304 (*iter)->update_title();
310 // This will increase the reference count so we don't get DELETED
311 // until we are ready
312 handle<Instance> me(this);
314 // Make sure we aren't selected as the current instance
315 if(studio::App::get_selected_instance()==this)
316 studio::App::set_selected_instance(0);
318 // Turn-off/clean-up auto recovery
319 studio::App::auto_recover->clear_backup(get_canvas());
321 // Remove us from the active instance list
322 std::list<etl::handle<studio::Instance> >::iterator iter;
323 for(iter=studio::App::instance_list.begin();iter!=studio::App::instance_list.end();iter++)
326 assert(iter!=studio::App::instance_list.end());
327 if(iter!=studio::App::instance_list.end())
328 studio::App::instance_list.erase(iter);
330 // Send out a signal that we are being deleted
331 studio::App::signal_instance_deleted()(this);
333 // Hide all of the canvas views
334 for(std::list<etl::handle<CanvasView> >::iterator iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
337 // Consume pending events before deleting the canvas views
338 while(studio::App::events_pending())studio::App::iteration(false);
340 // Delete all of the canvas views
341 canvas_view_list().clear();
343 // If there is another open instance to select,
344 // go ahead and do so. If not, never mind.
345 if(studio::App::instance_list.empty())
347 studio::App::set_selected_canvas_view(0);
348 studio::App::set_selected_instance(0);
352 studio::App::set_selected_canvas_view(studio::App::instance_list.front()->canvas_view_list().front());
353 //studio::App::set_selected_instance(studio::App::instance_list.front());
359 Instance::insert_canvas(Gtk::TreeRow row,Canvas::Handle canvas)
361 CanvasTreeModel canvas_tree_model;
364 row[canvas_tree_model.icon] = Gtk::Button().render_icon(Gtk::StockID("synfig-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
365 row[canvas_tree_model.id] = canvas->get_id();
366 row[canvas_tree_model.name] = canvas->get_name();
367 if(canvas->is_root())
368 row[canvas_tree_model.label] = basename(canvas->get_file_name());
370 if(!canvas->get_id().empty())
371 row[canvas_tree_model.label] = canvas->get_id();
373 if(!canvas->get_name().empty())
374 row[canvas_tree_model.label] = canvas->get_name();
376 row[canvas_tree_model.label] = _("[Unnamed]");
378 row[canvas_tree_model.canvas] = canvas;
379 row[canvas_tree_model.is_canvas] = true;
380 row[canvas_tree_model.is_value_node] = false;
383 synfig::Canvas::Children::iterator iter;
384 synfig::Canvas::Children &children(canvas->children());
386 for(iter=children.begin();iter!=children.end();iter++)
387 insert_canvas(*(canvas_tree_store()->append(row.children())),*iter);
391 if(!canvas->value_node_list().empty())
393 Gtk::TreeRow valuenode_row = *(canvas_tree_store()->append(row.children()));
395 valuenode_row[canvas_tree_model.label] = "<defs>";
396 valuenode_row[canvas_tree_model.canvas] = canvas;
397 valuenode_row[canvas_tree_model.is_canvas] = false;
398 valuenode_row[canvas_tree_model.is_value_node] = false;
400 synfig::ValueNodeList::iterator iter;
401 synfig::ValueNodeList &value_node_list(canvas->value_node_list());
403 for(iter=value_node_list.begin();iter!=value_node_list.end();iter++)
404 insert_value_node(*(canvas_tree_store()->append(valuenode_row.children())),canvas,*iter);
412 Instance::insert_value_node(Gtk::TreeRow row,Canvas::Handle canvas,etl::handle<synfig::ValueNode> value_node)
414 CanvasTreeModel canvas_tree_model;
418 row[canvas_tree_model.id] = value_node->get_id();
419 row[canvas_tree_model.name] = value_node->get_id();
420 row[canvas_tree_model.label] = value_node->get_id();
421 row[canvas_tree_model.canvas] = canvas;
422 row[canvas_tree_model.value_node] = value_node;
423 row[canvas_tree_model.is_canvas] = false;
424 row[canvas_tree_model.is_value_node] = true;
425 row[canvas_tree_model.icon] = Gtk::Button().render_icon(valuenode_icon(value_node),Gtk::ICON_SIZE_SMALL_TOOLBAR);
430 Instance::refresh_canvas_tree()
432 canvas_tree_store()->clear();
433 Gtk::TreeRow row = *(canvas_tree_store()->prepend());
434 insert_canvas(row,get_canvas());
438 Instance::dialog_cvs_commit()
440 calc_repository_info();
443 App::dialog_error_blocking(_("Error"),_("You must first add this composition to the repository"));
450 if(synfigapp::Instance::get_action_count())
452 if(!App::dialog_yes_no(_("CVS Commit"), _("This will save any changes you have made. Are you sure?")))
459 App::dialog_error_blocking(_("Error"),_("The local copy of the file hasn't been changed since the last update.\nNothing to commit!"));
463 if(!App::dialog_entry(_("CVS Commit"),_("Enter a log message describing the changes you have made"), message))
466 OneMoment one_moment;
471 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to COMMIT"));
477 Instance::dialog_cvs_add()
479 calc_repository_info();
482 App::dialog_error_blocking(_("Error"),_("This composition has already been added to the repository"));
489 //if(!App::dialog_entry(_("CVS Add"),_("Enter a log message describing the file"), message))
491 OneMoment one_moment;
496 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to ADD"));
502 Instance::dialog_cvs_update()
504 calc_repository_info();
507 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to update from!"));
512 App::dialog_error_blocking(_("Info"),_("This file is up-to-date"));
518 String filename(get_file_name());
519 if(synfigapp::Instance::get_action_count())
521 if(!App::dialog_yes_no(_("CVS Update"), _("This will save any changes you have made. Are you sure?")))
525 OneMoment one_moment;
526 time_t oldtime=get_original_timestamp();
528 calc_repository_info();
529 // If something has been updated...
530 if(oldtime!=get_original_timestamp())
537 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
539 //update_all_titles();
543 Instance::dialog_cvs_revert()
545 calc_repository_info();
548 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to revert to!"));
553 String filename(get_file_name());
554 if(!App::dialog_yes_no(_("CVS Revert"),
555 _("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?")
559 OneMoment one_moment;
561 // Remove the old file
562 if(remove(get_file_name().c_str())!=0)
564 App::dialog_error_blocking(_("Error"),_("Unable to remove previous version"));
573 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
575 //update_all_titles();
579 Instance::_revert(Instance *instance)
581 OneMoment one_moment;
583 String filename(instance->get_file_name());
585 Canvas::Handle canvas(instance->get_canvas());
589 if(canvas->count()!=1)
592 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."));
603 // Schedule a revert to occur in a few moments
604 Glib::signal_timeout().connect(
607 sigc::ptr_fun(&Instance::_revert),
617 Instance::safe_revert()
619 if(synfigapp::Instance::get_action_count())
620 if(!App::dialog_yes_no(_("Revert to saved"), _("You will loose any changes you have made since your last save.\nAre you sure?")))
627 Instance::safe_close()
629 handle<synfigapp::UIInterface> uim;
630 uim=find_canvas_view(get_canvas())->get_ui_interface();
632 if(get_action_count())
634 string str=strprintf(_("Would you like to save your changes to %s?"),basename(get_file_name()).c_str() );
635 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
636 if(answer==synfigapp::UIInterface::RESPONSE_YES)
638 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
644 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());
645 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
647 if(answer==synfigapp::UIInterface::RESPONSE_YES)
649 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
660 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
662 synfigapp::Action::CandidateList candidate_list;
663 synfigapp::Action::CandidateList::iterator iter;
665 candidate_list=compile_candidate_list(param_list,category);
667 candidate_list.sort();
669 if(candidate_list.empty())
670 synfig::warning("Action CandidateList is empty!");
672 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
674 Gtk::StockID stock_id(get_action_stock_id(*iter));
676 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
678 action_group->add(Gtk::Action::create(
679 "action-"+iter->name,
681 iter->local_name,iter->local_name
686 *const_cast<studio::Instance*>(this),
687 &studio::Instance::process_action
694 ui_info+=strprintf("<menuitem action='action-%s' />",iter->name.c_str());
700 Instance::add_actions_to_menu(Gtk::Menu *menu, const synfigapp::Action::ParamList ¶m_list,synfigapp::Action::Category category)const
702 synfigapp::Action::CandidateList candidate_list;
703 synfigapp::Action::CandidateList::iterator iter;
705 candidate_list=compile_candidate_list(param_list,category);
707 candidate_list.sort();
709 if(candidate_list.empty())
710 synfig::warning("Action CandidateList is empty!");
712 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
714 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
716 Gtk::Image* image(manage(new Gtk::Image()));
717 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
720 if(iter->task=="raise")
721 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
722 else if(iter->task=="lower")
723 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
724 else if(iter->task=="move_top")
725 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
726 else if(iter->task=="move_bottom")
727 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
728 else if(iter->task=="remove")
729 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
730 else if(iter->task=="set_on")
731 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
732 else if(iter->task=="set_off")
733 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
734 else if(iter->task=="duplicate")
735 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
736 else if(iter->task=="remove")
737 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
740 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
741 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
742 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
745 menu->items().push_back(
746 Gtk::Menu_Helpers::ImageMenuElem(
752 *const_cast<studio::Instance*>(this),
753 &studio::Instance::process_action
766 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
768 synfigapp::Action::CandidateList candidate_list;
769 synfigapp::Action::CandidateList candidate_list2;
771 synfigapp::Action::CandidateList::iterator iter;
773 candidate_list=compile_candidate_list(param_list,category);
774 candidate_list2=compile_candidate_list(param_list2,category);
776 candidate_list.sort();
778 if(candidate_list.empty())
779 synfig::warning("Action CandidateList is empty!");
780 if(candidate_list2.empty())
781 synfig::warning("Action CandidateList2 is empty!");
783 // Seperate out the candidate lists so that there are no conflicts
784 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
786 synfigapp::Action::CandidateList::iterator iter2(candidate_list2.find(iter->name));
787 if(iter2!=candidate_list2.end())
788 candidate_list2.erase(iter2);
791 for(iter=candidate_list2.begin();iter!=candidate_list2.end();++iter)
793 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
795 Gtk::Image* image(manage(new Gtk::Image()));
796 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
798 /* if(iter->task=="raise")
799 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
800 else if(iter->task=="lower")
801 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
802 else if(iter->task=="move_top")
803 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
804 else if(iter->task=="move_bottom")
805 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
806 else if(iter->task=="remove")
807 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
808 else if(iter->task=="set_on")
809 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
810 else if(iter->task=="set_off")
811 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
812 else if(iter->task=="duplicate")
813 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
814 else if(iter->task=="remove")
815 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
818 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
819 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
820 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
823 menu->items().push_back(
824 Gtk::Menu_Helpers::ImageMenuElem(
830 *const_cast<studio::Instance*>(this),
831 &studio::Instance::process_action
842 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
844 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
846 Gtk::Image* image(manage(new Gtk::Image()));
847 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
848 /* if(iter->task=="raise")
849 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
850 else if(iter->task=="lower")
851 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
852 else if(iter->task=="move_top")
853 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
854 else if(iter->task=="move_bottom")
855 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
856 else if(iter->task=="remove")
857 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
858 else if(iter->task=="set_on")
859 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
860 else if(iter->task=="set_off")
861 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
862 else if(iter->task=="duplicate")
863 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
864 else if(iter->task=="remove")
865 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
868 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
869 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
870 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
873 menu->items().push_back(
874 Gtk::Menu_Helpers::ImageMenuElem(
880 *const_cast<studio::Instance*>(this),
881 &studio::Instance::process_action
894 Instance::process_action(String name, synfigapp::Action::ParamList param_list)
896 assert(synfigapp::Action::book().count(name));
898 synfigapp::Action::BookEntry entry(synfigapp::Action::book().find(name)->second);
900 synfigapp::Action::Handle action(entry.factory());
904 synfig::error("Bad Action");
908 action->set_param_list(param_list);
910 synfigapp::Action::ParamVocab param_vocab(entry.get_param_vocab());
911 synfigapp::Action::ParamVocab::const_iterator iter;
913 for(iter=param_vocab.begin();iter!=param_vocab.end();++iter)
915 if(!iter->get_mutual_exclusion().empty() && param_list.count(iter->get_mutual_exclusion()))
918 // If the parameter is optionally user-supplied,
919 // and has not been already provided in the param_list,
920 // then we should go ahead and see if we can
921 // provide that data.
922 if(iter->get_user_supplied() && param_list.count(iter->get_name())==0)
924 switch(iter->get_type())
926 case synfigapp::Action::Param::TYPE_STRING:
929 if(!studio::App::dialog_entry(entry.local_name, iter->get_local_name()+":"+iter->get_desc(),str))
931 action->set_param(iter->get_name(),str);
935 synfig::error("Unsupported user-supplied action parameter");
942 if(!action->is_ready())
944 synfig::error("Action not ready");
948 perform_action(action);
952 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas, synfigapp::ValueDesc value_desc, float location)
954 Gtk::Menu& parammenu(*menu);
956 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
958 if(!canvas_interface)
961 synfigapp::Action::ParamList param_list,param_list2;
962 param_list=canvas_interface->generate_param_list(value_desc);
963 param_list.add("origin",location);
965 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
967 param_list2=canvas_interface->generate_param_list(
968 synfigapp::ValueDesc(
969 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
973 param_list2.add("origin",location);
977 // Populate the convert menu by looping through
978 // the ValueNode book and find the ones that are
981 Gtk::Menu *convert_menu=manage(new Gtk::Menu());
982 LinkableValueNode::Book::const_iterator iter;
983 for(iter=LinkableValueNode::book().begin();iter!=LinkableValueNode::book().end();++iter)
985 if(iter->second.check_type(value_desc.get_value_type()))
987 convert_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->second.local_name,
991 sigc::mem_fun(*canvas_interface.get(),&synfigapp::CanvasInterface::convert),
1001 parammenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::CONVERT,*convert_menu));
1004 if(param_list2.empty())
1005 add_actions_to_menu(¶mmenu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1007 add_actions_to_menu(¶mmenu, param_list2,param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1009 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
1011 value_desc=synfigapp::ValueDesc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),0);
1014 if(value_desc.is_value_node() && ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
1016 ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()));
1020 WaypointList::iterator iter(value_node->find(canvas->get_time()));
1021 parammenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoint"),
1025 sigc::mem_fun(*find_canvas_view(canvas),&studio::CanvasView::on_waypoint_clicked),
1041 edit_several_waypoints(etl::handle<CanvasView> canvas_view, std::list<synfigapp::ValueDesc> value_desc_list)
1043 etl::handle<synfigapp::CanvasInterface> canvas_interface(canvas_view->canvas_interface());
1046 "Edit Multiple Waypoints", // Title
1048 true // use_separator
1051 Widget_WaypointModel widget_waypoint_model;
1052 widget_waypoint_model.show();
1054 dialog.get_vbox()->pack_start(widget_waypoint_model);
1057 dialog.add_button(Gtk::StockID("gtk-apply"),1);
1058 dialog.add_button(Gtk::StockID("gtk-cancel"),0);
1062 if(dialog.run()==0 || widget_waypoint_model.get_waypoint_model().is_trivial())
1065 synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Set Waypoints"));
1067 std::list<synfigapp::ValueDesc>::iterator iter;
1068 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
1070 synfigapp::ValueDesc value_desc(*iter);
1072 if(!value_desc.is_valid())
1075 ValueNode_Animated::Handle value_node;
1077 // If this value isn't a ValueNode_Animated, but
1078 // it is somewhat constant, then go ahead and convert
1079 // it to a ValueNode_Animated.
1080 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
1083 if(value_desc.is_value_node())
1084 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
1086 value=value_desc.get_value();
1088 value_node=ValueNode_Animated::create(value,canvas_interface->get_time());
1090 synfigapp::Action::Handle action;
1092 if(!value_desc.is_value_node())
1094 action=synfigapp::Action::create("value_desc_connect");
1095 action->set_param("dest",value_desc);
1096 action->set_param("src",ValueNode::Handle(value_node));
1100 action=synfigapp::Action::create("value_node_replace");
1101 action->set_param("dest",value_desc.get_value_node());
1102 action->set_param("src",ValueNode::Handle(value_node));
1105 action->set_param("canvas",canvas_view->get_canvas());
1106 action->set_param("canvas_interface",canvas_interface);
1109 if(!canvas_interface->get_instance()->perform_action(action))
1111 canvas_view->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
1118 if(value_desc.is_value_node())
1119 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
1126 synfigapp::Action::Handle action(synfigapp::Action::create("waypoint_set_smart"));
1130 canvas_view->get_ui_interface()->error(_("Unable to find waypoint_set_smart action"));
1136 action->set_param("canvas",canvas_view->get_canvas());
1137 action->set_param("canvas_interface",canvas_interface);
1138 action->set_param("value_node",ValueNode::Handle(value_node));
1139 action->set_param("time",canvas_interface->get_time());
1140 action->set_param("model",widget_waypoint_model.get_waypoint_model());
1142 if(!canvas_interface->get_instance()->perform_action(action))
1144 canvas_view->get_ui_interface()->error(_("Unable to set a specific waypoint"));
1151 //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
1160 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas,const std::list<synfigapp::ValueDesc>& value_desc_list)
1162 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
1164 synfigapp::Action::ParamList param_list;
1165 param_list=canvas_interface->generate_param_list(value_desc_list);
1167 add_actions_to_menu(menu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1169 // Add the edit waypoints option if that might be useful
1170 if(canvas->rend_desc().get_time_end()-Time::epsilon()>canvas->rend_desc().get_time_start())
1172 menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
1176 &edit_several_waypoints
1180 find_canvas_view(canvas)