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"
58 using namespace synfig;
59 using namespace studio;
62 /* === M A C R O S ========================================================= */
64 /* === G L O B A L S ======================================================= */
66 int studio::Instance::instance_count_=0;
68 /* === P R O C E D U R E S ================================================= */
70 /* === M E T H O D S ======================================================= */
72 Instance::Instance(Canvas::Handle canvas):
73 synfigapp::Instance (canvas),
74 // canvas_tree_store_ (Gtk::TreeStore::create(CanvasTreeModel())),
75 // canvas_tree_store_ (Gtk::TreeStore::create()),
76 history_tree_store_ (HistoryTreeStore::create(this)),
80 CanvasTreeModel model;
81 canvas_tree_store_=Gtk::TreeStore::create(model);
83 id_=instance_count_++;
85 // Connect up all the signals
86 signal_filename_changed().connect(sigc::mem_fun(*this,&studio::Instance::update_all_titles));
87 signal_unsaved_status_changed().connect(sigc::hide(sigc::mem_fun(*this,&studio::Instance::update_all_titles)));
88 signal_undo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_undo_status));
89 signal_redo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_redo_status));
91 signal_saved().connect(
94 studio::AutoRecover::auto_backup
99 canvas_tree_store_=Gtk::TreeStore::create(canvas_tree_model);
101 refresh_canvas_tree();
104 Instance::~Instance()
109 Instance::get_visible_canvases()const
112 CanvasViewList::const_iterator iter;
113 for(iter=canvas_view_list_.begin();iter!=canvas_view_list_.end();++iter)
114 if((*iter)->is_visible())
120 Instance::create(Canvas::Handle canvas)
122 // Construct a new instance
123 handle<Instance> instance(new Instance(canvas));
125 // Add the new instance to the application's instance list
126 App::instance_list.push_back(instance);
128 // Set up the instance with the default UI manager
129 instance->synfigapp::Instance::set_ui_interface(App::get_ui_interface());
131 // Signal the new instance
132 App::signal_instance_created()(instance);
134 // And then make sure that is has been selected
135 App::set_selected_instance(instance);
137 // Create the initial window for the root canvas
138 instance->focus(canvas);
144 Instance::find_canvas_view(Canvas::Handle canvas)
149 while(canvas->is_inline())
150 canvas=canvas->parent();
152 CanvasViewList::iterator iter;
154 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
155 if((*iter)->get_canvas()==canvas)
158 return CanvasView::create(this,canvas);
162 Instance::focus(Canvas::Handle canvas)
164 handle<CanvasView> canvas_view=find_canvas_view(canvas);
166 canvas_view->present();
170 Instance::set_undo_status(bool x)
173 App::toolbox->update_undo_redo();
174 signal_undo_redo_status_changed()();
178 Instance::set_redo_status(bool x)
181 App::toolbox->update_undo_redo();
182 signal_undo_redo_status_changed()();
186 studio::Instance::save_as(const synfig::String &file_name)const
188 if(synfigapp::Instance::save_as(file_name))
190 App::add_recent_file(file_name);
197 studio::Instance::save_as(const synfig::String &file_name)
199 if(synfigapp::Instance::save_as(file_name))
201 App::add_recent_file(file_name);
208 studio::Instance::save()
210 if(basename(get_file_name()).find("untitled")==0)
216 return synfigapp::Instance::save();
221 studio::Instance::dialog_save_as()
223 string filename="*.sif";
225 Canvas::Handle canvas(get_canvas());
228 OneMoment one_moment;
229 std::set<Node*>::iterator iter;
230 for(iter=canvas->parent_set.begin();iter!=canvas->parent_set.end();++iter)
232 synfig::Node* node(*iter);
233 for(;!node->parent_set.empty();node=*node->parent_set.begin())
235 Layer::Handle parent_layer(dynamic_cast<Layer*>(node));
236 if(parent_layer && parent_layer->get_canvas()->get_root()!=get_canvas())
238 App::dialog_error_blocking("SaveAs - Error",
239 "There is currently a bug when using \"SaveAs\"\n"
240 "on a composition that is being referenced by other\n"
241 "files that are currently open. Close these\n"
242 "other files first before trying to use \"SaveAs\"."
253 while(App::dialog_saveas_file("SaveAs", filename))
255 // If the filename still has wildcards, then we should
256 // continue looking for the file we want
257 if(find(filename.begin(),filename.end(),'*')!=filename.end())
260 if(find(filename.begin(),filename.end(),'.')==filename.end())
265 String ext(String(filename.begin()+filename.find_last_of('.')+1,filename.end()));
266 if(ext!="sif" && ext!="sifz" && !App::dialog_yes_no(_("Unknown extension"),
267 _("You have given the file name an extension\nwhich I do not recognise. Are you sure this is what you want?")))
277 if(save_as(filename))
280 App::dialog_error_blocking("SaveAs - Error","Unable to save file");
285 Instance::update_all_titles()
287 list<handle<CanvasView> >::iterator iter;
288 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
289 (*iter)->update_title();
295 // This will increase the reference count so we don't get DELETED
296 // until we are ready
297 handle<Instance> me(this);
299 // Make sure we aren't selected as the current instance
300 if(studio::App::get_selected_instance()==this)
301 studio::App::set_selected_instance(0);
303 // Turn-off/clean-up auto recovery
304 studio::App::auto_recover->clear_backup(get_canvas());
306 // Remove us from the active instance list
307 std::list<etl::handle<studio::Instance> >::iterator iter;
308 for(iter=studio::App::instance_list.begin();iter!=studio::App::instance_list.end();iter++)
311 assert(iter!=studio::App::instance_list.end());
312 if(iter!=studio::App::instance_list.end())
313 studio::App::instance_list.erase(iter);
315 // Send out a signal that we are being deleted
316 studio::App::signal_instance_deleted()(this);
318 // Hide all of the canvas views
319 for(std::list<etl::handle<CanvasView> >::iterator iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
322 // Consume pending events before deleting the canvas views
323 while(studio::App::events_pending())studio::App::iteration(false);
325 // Delete all of the canvas views
326 canvas_view_list().clear();
328 // If there is another open instance to select,
329 // go ahead and do so. If not, never mind.
330 if(studio::App::instance_list.empty())
332 studio::App::set_selected_canvas_view(0);
333 studio::App::set_selected_instance(0);
337 studio::App::set_selected_canvas_view(studio::App::instance_list.front()->canvas_view_list().front());
338 //studio::App::set_selected_instance(studio::App::instance_list.front());
344 Instance::insert_canvas(Gtk::TreeRow row,Canvas::Handle canvas)
346 CanvasTreeModel canvas_tree_model;
349 row[canvas_tree_model.icon] = Gtk::Button().render_icon(Gtk::StockID("synfig-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
350 row[canvas_tree_model.id] = canvas->get_id();
351 row[canvas_tree_model.name] = canvas->get_name();
352 if(canvas->is_root())
353 row[canvas_tree_model.label] = basename(canvas->get_file_name());
355 if(!canvas->get_id().empty())
356 row[canvas_tree_model.label] = canvas->get_id();
358 if(!canvas->get_name().empty())
359 row[canvas_tree_model.label] = canvas->get_name();
361 row[canvas_tree_model.label] = _("[Unnamed]");
363 row[canvas_tree_model.canvas] = canvas;
364 row[canvas_tree_model.is_canvas] = true;
365 row[canvas_tree_model.is_value_node] = false;
368 synfig::Canvas::Children::iterator iter;
369 synfig::Canvas::Children &children(canvas->children());
371 for(iter=children.begin();iter!=children.end();iter++)
372 insert_canvas(*(canvas_tree_store()->append(row.children())),*iter);
376 if(!canvas->value_node_list().empty())
378 Gtk::TreeRow valuenode_row = *(canvas_tree_store()->append(row.children()));
380 valuenode_row[canvas_tree_model.label] = "<defs>";
381 valuenode_row[canvas_tree_model.canvas] = canvas;
382 valuenode_row[canvas_tree_model.is_canvas] = false;
383 valuenode_row[canvas_tree_model.is_value_node] = false;
385 synfig::ValueNodeList::iterator iter;
386 synfig::ValueNodeList &value_node_list(canvas->value_node_list());
388 for(iter=value_node_list.begin();iter!=value_node_list.end();iter++)
389 insert_value_node(*(canvas_tree_store()->append(valuenode_row.children())),canvas,*iter);
397 Instance::insert_value_node(Gtk::TreeRow row,Canvas::Handle canvas,etl::handle<synfig::ValueNode> value_node)
399 CanvasTreeModel canvas_tree_model;
403 row[canvas_tree_model.id] = value_node->get_id();
404 row[canvas_tree_model.name] = value_node->get_id();
405 row[canvas_tree_model.label] = value_node->get_id();
406 row[canvas_tree_model.canvas] = canvas;
407 row[canvas_tree_model.value_node] = value_node;
408 row[canvas_tree_model.is_canvas] = false;
409 row[canvas_tree_model.is_value_node] = true;
410 row[canvas_tree_model.icon] = Gtk::Button().render_icon(valuenode_icon(value_node),Gtk::ICON_SIZE_SMALL_TOOLBAR);
415 Instance::refresh_canvas_tree()
417 canvas_tree_store()->clear();
418 Gtk::TreeRow row = *(canvas_tree_store()->prepend());
419 insert_canvas(row,get_canvas());
423 Instance::dialog_cvs_commit()
425 calc_repository_info();
428 App::dialog_error_blocking(_("Error"),_("You must first add this composition to the repository"));
435 if(synfigapp::Instance::get_action_count())
437 if(!App::dialog_yes_no(_("CVS Commit"), _("This will save any changes you have made. Are you sure?")))
444 App::dialog_error_blocking(_("Error"),_("The local copy of the file hasn't been changed since the last update.\nNothing to commit!"));
448 if(!App::dialog_entry(_("CVS Commit"),_("Enter a log message describing the changes you have made"), message))
451 OneMoment one_moment;
456 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to COMMIT"));
462 Instance::dialog_cvs_add()
464 calc_repository_info();
467 App::dialog_error_blocking(_("Error"),_("This composition has already been added to the repository"));
474 //if(!App::dialog_entry(_("CVS Add"),_("Enter a log message describing the file"), message))
476 OneMoment one_moment;
481 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to ADD"));
487 Instance::dialog_cvs_update()
489 calc_repository_info();
492 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to update from!"));
497 App::dialog_error_blocking(_("Info"),_("This file is up-to-date"));
503 String filename(get_file_name());
504 if(synfigapp::Instance::get_action_count())
506 if(!App::dialog_yes_no(_("CVS Update"), _("This will save any changes you have made. Are you sure?")))
510 OneMoment one_moment;
511 time_t oldtime=get_original_timestamp();
513 calc_repository_info();
514 // If something has been updated...
515 if(oldtime!=get_original_timestamp())
522 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
524 //update_all_titles();
528 Instance::dialog_cvs_revert()
530 calc_repository_info();
533 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to revert to!"));
538 String filename(get_file_name());
539 if(!App::dialog_yes_no(_("CVS Revert"),
540 _("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?")
544 OneMoment one_moment;
546 // Remove the old file
547 if(remove(get_file_name().c_str())!=0)
549 App::dialog_error_blocking(_("Error"),_("Unable to remove previous version"));
558 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
560 //update_all_titles();
564 Instance::_revert(Instance *instance)
566 OneMoment one_moment;
568 String filename(instance->get_file_name());
570 Canvas::Handle canvas(instance->get_canvas());
574 if(canvas->count()!=1)
577 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."));
588 // Schedule a revert to occur in a few moments
589 Glib::signal_timeout().connect(
592 sigc::ptr_fun(&Instance::_revert),
602 Instance::safe_revert()
604 if(synfigapp::Instance::get_action_count())
605 if(!App::dialog_yes_no(_("Revert to saved"), _("You will loose any changes you have made since your last save.\nAre you sure?")))
612 Instance::safe_close()
614 handle<synfigapp::UIInterface> uim;
615 uim=find_canvas_view(get_canvas())->get_ui_interface();
617 if(get_action_count())
619 string str=strprintf(_("Would you like to save your changes to %s?"),basename(get_file_name()).c_str() );
620 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
621 if(answer==synfigapp::UIInterface::RESPONSE_YES)
623 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
629 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());
630 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
632 if(answer==synfigapp::UIInterface::RESPONSE_YES)
634 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
645 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
647 synfigapp::Action::CandidateList candidate_list;
648 synfigapp::Action::CandidateList::iterator iter;
650 candidate_list=compile_candidate_list(param_list,category);
652 candidate_list.sort();
654 if(candidate_list.empty())
655 synfig::warning("Action CandidateList is empty!");
657 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
659 Gtk::StockID stock_id(get_action_stock_id(*iter));
661 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
663 action_group->add(Gtk::Action::create(
664 "action-"+iter->name,
666 iter->local_name,iter->local_name
671 *const_cast<studio::Instance*>(this),
672 &studio::Instance::process_action
679 ui_info+=strprintf("<menuitem action='action-%s' />",iter->name.c_str());
685 Instance::add_actions_to_menu(Gtk::Menu *menu, const synfigapp::Action::ParamList ¶m_list,synfigapp::Action::Category category)const
687 synfigapp::Action::CandidateList candidate_list;
688 synfigapp::Action::CandidateList::iterator iter;
690 candidate_list=compile_candidate_list(param_list,category);
692 candidate_list.sort();
694 if(candidate_list.empty())
695 synfig::warning("Action CandidateList is empty!");
697 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
699 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
701 Gtk::Image* image(manage(new Gtk::Image()));
702 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
705 if(iter->task=="raise")
706 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
707 else if(iter->task=="lower")
708 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
709 else if(iter->task=="move_top")
710 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
711 else if(iter->task=="move_bottom")
712 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
713 else if(iter->task=="remove")
714 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
715 else if(iter->task=="set_on")
716 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
717 else if(iter->task=="set_off")
718 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
719 else if(iter->task=="duplicate")
720 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
721 else if(iter->task=="remove")
722 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
725 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
726 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
727 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
730 menu->items().push_back(
731 Gtk::Menu_Helpers::ImageMenuElem(
737 *const_cast<studio::Instance*>(this),
738 &studio::Instance::process_action
751 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
753 synfigapp::Action::CandidateList candidate_list;
754 synfigapp::Action::CandidateList candidate_list2;
756 synfigapp::Action::CandidateList::iterator iter;
758 candidate_list=compile_candidate_list(param_list,category);
759 candidate_list2=compile_candidate_list(param_list2,category);
761 candidate_list.sort();
763 if(candidate_list.empty())
764 synfig::warning("Action CandidateList is empty!");
765 if(candidate_list2.empty())
766 synfig::warning("Action CandidateList2 is empty!");
768 // Seperate out the candidate lists so that there are no conflicts
769 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
771 synfigapp::Action::CandidateList::iterator iter2(candidate_list2.find(iter->name));
772 if(iter2!=candidate_list2.end())
773 candidate_list2.erase(iter2);
776 for(iter=candidate_list2.begin();iter!=candidate_list2.end();++iter)
778 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
780 Gtk::Image* image(manage(new Gtk::Image()));
781 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
783 /* if(iter->task=="raise")
784 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
785 else if(iter->task=="lower")
786 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
787 else if(iter->task=="move_top")
788 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
789 else if(iter->task=="move_bottom")
790 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
791 else if(iter->task=="remove")
792 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
793 else if(iter->task=="set_on")
794 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
795 else if(iter->task=="set_off")
796 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
797 else if(iter->task=="duplicate")
798 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
799 else if(iter->task=="remove")
800 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
803 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
804 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
805 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
808 menu->items().push_back(
809 Gtk::Menu_Helpers::ImageMenuElem(
815 *const_cast<studio::Instance*>(this),
816 &studio::Instance::process_action
827 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
829 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
831 Gtk::Image* image(manage(new Gtk::Image()));
832 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
833 /* if(iter->task=="raise")
834 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
835 else if(iter->task=="lower")
836 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
837 else if(iter->task=="move_top")
838 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
839 else if(iter->task=="move_bottom")
840 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
841 else if(iter->task=="remove")
842 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
843 else if(iter->task=="set_on")
844 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
845 else if(iter->task=="set_off")
846 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
847 else if(iter->task=="duplicate")
848 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
849 else if(iter->task=="remove")
850 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
853 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
854 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
855 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
858 menu->items().push_back(
859 Gtk::Menu_Helpers::ImageMenuElem(
865 *const_cast<studio::Instance*>(this),
866 &studio::Instance::process_action
879 Instance::process_action(String name, synfigapp::Action::ParamList param_list)
881 assert(synfigapp::Action::book().count(name));
883 synfigapp::Action::BookEntry entry(synfigapp::Action::book().find(name)->second);
885 synfigapp::Action::Handle action(entry.factory());
889 synfig::error("Bad Action");
893 action->set_param_list(param_list);
895 synfigapp::Action::ParamVocab param_vocab(entry.get_param_vocab());
896 synfigapp::Action::ParamVocab::const_iterator iter;
898 for(iter=param_vocab.begin();iter!=param_vocab.end();++iter)
900 if(!iter->get_mutual_exclusion().empty() && param_list.count(iter->get_mutual_exclusion()))
903 // If the parameter is optionally user-supplied,
904 // and has not been already provided in the param_list,
905 // then we should go ahead and see if we can
906 // provide that data.
907 if(iter->get_user_supplied() && param_list.count(iter->get_name())==0)
909 switch(iter->get_type())
911 case synfigapp::Action::Param::TYPE_STRING:
914 if(!studio::App::dialog_entry(entry.local_name, iter->get_local_name()+":"+iter->get_desc(),str))
916 action->set_param(iter->get_name(),str);
920 synfig::error("Unsupported user-supplied action parameter");
927 if(!action->is_ready())
929 synfig::error("Action not ready");
933 perform_action(action);
937 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas, synfigapp::ValueDesc value_desc, float location)
939 Gtk::Menu& parammenu(*menu);
941 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
943 if(!canvas_interface)
946 synfigapp::Action::ParamList param_list,param_list2;
947 param_list=canvas_interface->generate_param_list(value_desc);
948 param_list.add("origin",location);
950 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
952 param_list2=canvas_interface->generate_param_list(
953 synfigapp::ValueDesc(
954 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
958 param_list2.add("origin",location);
962 // Populate the convert menu by looping through
963 // the ValueNode book and find the ones that are
966 Gtk::Menu *convert_menu=manage(new Gtk::Menu());
967 LinkableValueNode::Book::const_iterator iter;
968 for(iter=LinkableValueNode::book().begin();iter!=LinkableValueNode::book().end();++iter)
970 if(iter->second.check_type(value_desc.get_value_type()))
972 convert_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->second.local_name,
976 sigc::mem_fun(*canvas_interface.get(),&synfigapp::CanvasInterface::convert),
986 parammenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::CONVERT,*convert_menu));
989 if(param_list2.empty())
990 add_actions_to_menu(¶mmenu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
992 add_actions_to_menu(¶mmenu, param_list2,param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
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 value_desc=synfigapp::ValueDesc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),0);
999 if(value_desc.is_value_node() && ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
1001 ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()));
1005 WaypointList::iterator iter(value_node->find(canvas->get_time()));
1006 parammenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoint"),
1010 sigc::mem_fun(*find_canvas_view(canvas),&studio::CanvasView::on_waypoint_clicked),
1026 edit_several_waypoints(etl::handle<CanvasView> canvas_view, std::list<synfigapp::ValueDesc> value_desc_list)
1028 etl::handle<synfigapp::CanvasInterface> canvas_interface(canvas_view->canvas_interface());
1031 "Edit Multiple Waypoints", // Title
1033 true // use_separator
1036 Widget_WaypointModel widget_waypoint_model;
1037 widget_waypoint_model.show();
1039 dialog.get_vbox()->pack_start(widget_waypoint_model);
1042 dialog.add_button(Gtk::StockID("gtk-apply"),1);
1043 dialog.add_button(Gtk::StockID("gtk-cancel"),0);
1047 if(dialog.run()==0 || widget_waypoint_model.get_waypoint_model().is_trivial())
1050 synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Set Waypoints"));
1052 std::list<synfigapp::ValueDesc>::iterator iter;
1053 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
1055 synfigapp::ValueDesc value_desc(*iter);
1057 if(!value_desc.is_valid())
1060 ValueNode_Animated::Handle value_node;
1062 // If this value isn't a ValueNode_Animated, but
1063 // it is somewhat constant, then go ahead and convert
1064 // it to a ValueNode_Animated.
1065 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
1068 if(value_desc.is_value_node())
1069 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
1071 value=value_desc.get_value();
1073 value_node=ValueNode_Animated::create(value,canvas_interface->get_time());
1075 synfigapp::Action::Handle action;
1077 if(!value_desc.is_value_node())
1079 action=synfigapp::Action::create("value_desc_connect");
1080 action->set_param("dest",value_desc);
1081 action->set_param("src",ValueNode::Handle(value_node));
1085 action=synfigapp::Action::create("value_node_replace");
1086 action->set_param("dest",value_desc.get_value_node());
1087 action->set_param("src",ValueNode::Handle(value_node));
1090 action->set_param("canvas",canvas_view->get_canvas());
1091 action->set_param("canvas_interface",canvas_interface);
1094 if(!canvas_interface->get_instance()->perform_action(action))
1096 canvas_view->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
1103 if(value_desc.is_value_node())
1104 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
1111 synfigapp::Action::Handle action(synfigapp::Action::create("waypoint_set_smart"));
1115 canvas_view->get_ui_interface()->error(_("Unable to find waypoint_set_smart action"));
1121 action->set_param("canvas",canvas_view->get_canvas());
1122 action->set_param("canvas_interface",canvas_interface);
1123 action->set_param("value_node",ValueNode::Handle(value_node));
1124 action->set_param("time",canvas_interface->get_time());
1125 action->set_param("model",widget_waypoint_model.get_waypoint_model());
1127 if(!canvas_interface->get_instance()->perform_action(action))
1129 canvas_view->get_ui_interface()->error(_("Unable to set a specific waypoint"));
1136 //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
1145 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas,const std::list<synfigapp::ValueDesc>& value_desc_list)
1147 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
1149 synfigapp::Action::ParamList param_list;
1150 param_list=canvas_interface->generate_param_list(value_desc_list);
1152 add_actions_to_menu(menu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1154 // Add the edit waypoints option if that might be useful
1155 if(canvas->rend_desc().get_time_end()-Time::epsilon()>canvas->rend_desc().get_time_start())
1157 menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
1161 &edit_several_waypoints
1165 find_canvas_view(canvas)