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)
190 if(synfigapp::Instance::save_as(file_name))
192 App::add_recent_file(file_name);
199 studio::Instance::save()
201 // the filename will be set to "Synfig Animation 1" or some such when first created
202 // and will be changed to an absolute path once it has been saved
203 // so if it still begins with "Synfig Animation " then we need to ask where to save it
204 if(get_file_name().find(DEFAULT_FILENAME_PREFIX)==0)
205 return dialog_save_as();
207 return synfigapp::Instance::save();
211 studio::Instance::dialog_save_as()
213 string filename=basename(get_file_name());
214 Canvas::Handle canvas(get_canvas());
217 OneMoment one_moment;
218 std::set<Node*>::iterator iter;
219 for(iter=canvas->parent_set.begin();iter!=canvas->parent_set.end();++iter)
221 synfig::Node* node(*iter);
222 for(;!node->parent_set.empty();node=*node->parent_set.begin())
224 Layer::Handle parent_layer(dynamic_cast<Layer*>(node));
225 if(parent_layer && parent_layer->get_canvas()->get_root()!=get_canvas())
227 App::dialog_error_blocking("SaveAs - Error",
228 "There is currently a bug when using \"SaveAs\"\n"
229 "on a composition that is being referenced by other\n"
230 "files that are currently open. Close these\n"
231 "other files first before trying to use \"SaveAs\"."
242 // show the canvas' name if it has one, else its ID
243 while(App::dialog_save_file(_("Choose a Filename to Save As") +
245 (canvas->get_name().empty()
247 : canvas->get_name()) +
250 // If the filename still has wildcards, then we should
251 // continue looking for the file we want
252 if(find(filename.begin(),filename.end(),'*')!=filename.end())
255 std::string base = basename(filename);
256 if(find(base.begin(),base.end(),'.')==base.end())
261 String ext(String(filename.begin()+filename.find_last_of('.')+1,filename.end()));
262 if(ext!="sif" && ext!="sifz" && !App::dialog_yes_no(_("Unknown extension"),
263 _("You have given the file name an extension\nwhich I do not recognise. Are you sure this is what you want?")))
275 // if stat() succeeds, or it fails with something other than 'file doesn't exist', the file exists
276 // if the file exists and the user doesn't want to overwrite it, keep prompting for a filename
277 if ((stat(filename.c_str(), &s) != -1 || errno != ENOENT) &&
278 !App::dialog_yes_no("File exists",
281 "' already exists.\n\n"
282 "Do you want to replace it with the file you are saving?"))
286 if(save_as(filename))
289 App::dialog_error_blocking("SaveAs - Error","Unable to save file");
296 Instance::update_all_titles()
298 list<handle<CanvasView> >::iterator iter;
299 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
300 (*iter)->update_title();
306 // This will increase the reference count so we don't get DELETED
307 // until we are ready
308 handle<Instance> me(this);
310 // Make sure we aren't selected as the current instance
311 if(studio::App::get_selected_instance()==this)
312 studio::App::set_selected_instance(0);
314 // Turn-off/clean-up auto recovery
315 studio::App::auto_recover->clear_backup(get_canvas());
317 // Remove us from the active instance list
318 std::list<etl::handle<studio::Instance> >::iterator iter;
319 for(iter=studio::App::instance_list.begin();iter!=studio::App::instance_list.end();iter++)
322 assert(iter!=studio::App::instance_list.end());
323 if(iter!=studio::App::instance_list.end())
324 studio::App::instance_list.erase(iter);
326 // Send out a signal that we are being deleted
327 studio::App::signal_instance_deleted()(this);
329 // Hide all of the canvas views
330 for(std::list<etl::handle<CanvasView> >::iterator iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
333 // Consume pending events before deleting the canvas views
334 while(studio::App::events_pending())studio::App::iteration(false);
336 // Delete all of the canvas views
337 canvas_view_list().clear();
339 // If there is another open instance to select,
340 // go ahead and do so. If not, never mind.
341 if(studio::App::instance_list.empty())
343 studio::App::set_selected_canvas_view(0);
344 studio::App::set_selected_instance(0);
348 studio::App::set_selected_canvas_view(studio::App::instance_list.front()->canvas_view_list().front());
349 //studio::App::set_selected_instance(studio::App::instance_list.front());
355 Instance::insert_canvas(Gtk::TreeRow row,Canvas::Handle canvas)
357 CanvasTreeModel canvas_tree_model;
360 row[canvas_tree_model.icon] = Gtk::Button().render_icon(Gtk::StockID("synfig-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
361 row[canvas_tree_model.id] = canvas->get_id();
362 row[canvas_tree_model.name] = canvas->get_name();
363 if(canvas->is_root())
364 row[canvas_tree_model.label] = basename(canvas->get_file_name());
366 if(!canvas->get_id().empty())
367 row[canvas_tree_model.label] = canvas->get_id();
369 if(!canvas->get_name().empty())
370 row[canvas_tree_model.label] = canvas->get_name();
372 row[canvas_tree_model.label] = _("[Unnamed]");
374 row[canvas_tree_model.canvas] = canvas;
375 row[canvas_tree_model.is_canvas] = true;
376 row[canvas_tree_model.is_value_node] = false;
379 synfig::Canvas::Children::iterator iter;
380 synfig::Canvas::Children &children(canvas->children());
382 for(iter=children.begin();iter!=children.end();iter++)
383 insert_canvas(*(canvas_tree_store()->append(row.children())),*iter);
387 if(!canvas->value_node_list().empty())
389 Gtk::TreeRow valuenode_row = *(canvas_tree_store()->append(row.children()));
391 valuenode_row[canvas_tree_model.label] = "<defs>";
392 valuenode_row[canvas_tree_model.canvas] = canvas;
393 valuenode_row[canvas_tree_model.is_canvas] = false;
394 valuenode_row[canvas_tree_model.is_value_node] = false;
396 synfig::ValueNodeList::iterator iter;
397 synfig::ValueNodeList &value_node_list(canvas->value_node_list());
399 for(iter=value_node_list.begin();iter!=value_node_list.end();iter++)
400 insert_value_node(*(canvas_tree_store()->append(valuenode_row.children())),canvas,*iter);
408 Instance::insert_value_node(Gtk::TreeRow row,Canvas::Handle canvas,etl::handle<synfig::ValueNode> value_node)
410 CanvasTreeModel canvas_tree_model;
414 row[canvas_tree_model.id] = value_node->get_id();
415 row[canvas_tree_model.name] = value_node->get_id();
416 row[canvas_tree_model.label] = value_node->get_id();
417 row[canvas_tree_model.canvas] = canvas;
418 row[canvas_tree_model.value_node] = value_node;
419 row[canvas_tree_model.is_canvas] = false;
420 row[canvas_tree_model.is_value_node] = true;
421 row[canvas_tree_model.icon] = Gtk::Button().render_icon(valuenode_icon(value_node),Gtk::ICON_SIZE_SMALL_TOOLBAR);
426 Instance::refresh_canvas_tree()
428 canvas_tree_store()->clear();
429 Gtk::TreeRow row = *(canvas_tree_store()->prepend());
430 insert_canvas(row,get_canvas());
434 Instance::dialog_cvs_commit()
436 calc_repository_info();
439 App::dialog_error_blocking(_("Error"),_("You must first add this composition to the repository"));
446 if(synfigapp::Instance::get_action_count())
448 if(!App::dialog_yes_no(_("CVS Commit"), _("This will save any changes you have made. Are you sure?")))
455 App::dialog_error_blocking(_("Error"),_("The local copy of the file hasn't been changed since the last update.\nNothing to commit!"));
459 if(!App::dialog_entry(_("CVS Commit"),_("Enter a log message describing the changes you have made"), message))
462 OneMoment one_moment;
467 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to COMMIT"));
473 Instance::dialog_cvs_add()
475 calc_repository_info();
478 App::dialog_error_blocking(_("Error"),_("This composition has already been added to the repository"));
485 //if(!App::dialog_entry(_("CVS Add"),_("Enter a log message describing the file"), message))
487 OneMoment one_moment;
492 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to ADD"));
498 Instance::dialog_cvs_update()
500 calc_repository_info();
503 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to update from!"));
508 App::dialog_error_blocking(_("Info"),_("This file is up-to-date"));
514 String filename(get_file_name());
515 if(synfigapp::Instance::get_action_count())
517 if(!App::dialog_yes_no(_("CVS Update"), _("This will save any changes you have made. Are you sure?")))
521 OneMoment one_moment;
522 time_t oldtime=get_original_timestamp();
524 calc_repository_info();
525 // If something has been updated...
526 if(oldtime!=get_original_timestamp())
533 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
535 //update_all_titles();
539 Instance::dialog_cvs_revert()
541 calc_repository_info();
544 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to revert to!"));
549 String filename(get_file_name());
550 if(!App::dialog_yes_no(_("CVS Revert"),
551 _("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?")
555 OneMoment one_moment;
557 // Remove the old file
558 if(remove(get_file_name().c_str())!=0)
560 App::dialog_error_blocking(_("Error"),_("Unable to remove previous version"));
569 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
571 //update_all_titles();
575 Instance::_revert(Instance *instance)
577 OneMoment one_moment;
579 String filename(instance->get_file_name());
581 Canvas::Handle canvas(instance->get_canvas());
585 if(canvas->count()!=1)
588 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."));
599 // Schedule a revert to occur in a few moments
600 Glib::signal_timeout().connect(
603 sigc::ptr_fun(&Instance::_revert),
613 Instance::safe_revert()
615 if(synfigapp::Instance::get_action_count())
616 if(!App::dialog_yes_no(_("Revert to saved"), _("You will lose any changes you have made since your last save.\nAre you sure?")))
623 Instance::safe_close()
625 handle<synfigapp::UIInterface> uim;
626 uim=find_canvas_view(get_canvas())->get_ui_interface();
628 if(get_action_count())
631 string str=strprintf(_("Would you like to save your changes to %s?"),basename(get_file_name()).c_str() );
632 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
633 if(answer==synfigapp::UIInterface::RESPONSE_YES)
635 if(answer==synfigapp::UIInterface::RESPONSE_NO)
637 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
643 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());
644 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
646 if(answer==synfigapp::UIInterface::RESPONSE_YES)
648 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
659 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
661 synfigapp::Action::CandidateList candidate_list;
662 synfigapp::Action::CandidateList::iterator iter;
664 candidate_list=compile_candidate_list(param_list,category);
666 candidate_list.sort();
668 if(candidate_list.empty())
669 synfig::warning("Action CandidateList is empty!");
671 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
673 Gtk::StockID stock_id(get_action_stock_id(*iter));
675 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
677 action_group->add(Gtk::Action::create(
678 "action-"+iter->name,
680 iter->local_name,iter->local_name
685 *const_cast<studio::Instance*>(this),
686 &studio::Instance::process_action
693 ui_info+=strprintf("<menuitem action='action-%s' />",iter->name.c_str());
699 Instance::add_actions_to_menu(Gtk::Menu *menu, const synfigapp::Action::ParamList ¶m_list,synfigapp::Action::Category category)const
701 synfigapp::Action::CandidateList candidate_list;
702 synfigapp::Action::CandidateList::iterator iter;
704 candidate_list=compile_candidate_list(param_list,category);
706 candidate_list.sort();
708 if(candidate_list.empty())
709 synfig::warning("Action CandidateList is empty!");
711 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
713 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
715 Gtk::Image* image(manage(new Gtk::Image()));
716 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
719 if(iter->task=="raise")
720 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
721 else if(iter->task=="lower")
722 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
723 else if(iter->task=="move_top")
724 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
725 else if(iter->task=="move_bottom")
726 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
727 else if(iter->task=="remove")
728 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
729 else if(iter->task=="set_on")
730 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
731 else if(iter->task=="set_off")
732 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
733 else if(iter->task=="duplicate")
734 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
735 else if(iter->task=="remove")
736 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
739 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
740 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
741 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
744 menu->items().push_back(
745 Gtk::Menu_Helpers::ImageMenuElem(
751 *const_cast<studio::Instance*>(this),
752 &studio::Instance::process_action
765 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
767 synfigapp::Action::CandidateList candidate_list;
768 synfigapp::Action::CandidateList candidate_list2;
770 synfigapp::Action::CandidateList::iterator iter;
772 candidate_list=compile_candidate_list(param_list,category);
773 candidate_list2=compile_candidate_list(param_list2,category);
775 candidate_list.sort();
777 if(candidate_list.empty())
778 synfig::warning("Action CandidateList is empty!");
779 if(candidate_list2.empty())
780 synfig::warning("Action CandidateList2 is empty!");
782 // Seperate out the candidate lists so that there are no conflicts
783 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
785 synfigapp::Action::CandidateList::iterator iter2(candidate_list2.find(iter->name));
786 if(iter2!=candidate_list2.end())
787 candidate_list2.erase(iter2);
790 for(iter=candidate_list2.begin();iter!=candidate_list2.end();++iter)
792 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
794 Gtk::Image* image(manage(new Gtk::Image()));
795 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
797 /* if(iter->task=="raise")
798 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
799 else if(iter->task=="lower")
800 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
801 else if(iter->task=="move_top")
802 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
803 else if(iter->task=="move_bottom")
804 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
805 else if(iter->task=="remove")
806 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
807 else if(iter->task=="set_on")
808 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
809 else if(iter->task=="set_off")
810 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
811 else if(iter->task=="duplicate")
812 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
813 else if(iter->task=="remove")
814 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
817 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
818 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
819 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
822 menu->items().push_back(
823 Gtk::Menu_Helpers::ImageMenuElem(
829 *const_cast<studio::Instance*>(this),
830 &studio::Instance::process_action
841 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
843 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
845 Gtk::Image* image(manage(new Gtk::Image()));
846 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
847 /* if(iter->task=="raise")
848 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
849 else if(iter->task=="lower")
850 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
851 else if(iter->task=="move_top")
852 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
853 else if(iter->task=="move_bottom")
854 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
855 else if(iter->task=="remove")
856 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
857 else if(iter->task=="set_on")
858 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
859 else if(iter->task=="set_off")
860 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
861 else if(iter->task=="duplicate")
862 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
863 else if(iter->task=="remove")
864 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
867 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
868 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
869 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
872 menu->items().push_back(
873 Gtk::Menu_Helpers::ImageMenuElem(
879 *const_cast<studio::Instance*>(this),
880 &studio::Instance::process_action
893 Instance::process_action(String name, synfigapp::Action::ParamList param_list)
895 assert(synfigapp::Action::book().count(name));
897 synfigapp::Action::BookEntry entry(synfigapp::Action::book().find(name)->second);
899 synfigapp::Action::Handle action(entry.factory());
903 synfig::error("Bad Action");
907 action->set_param_list(param_list);
909 synfigapp::Action::ParamVocab param_vocab(entry.get_param_vocab());
910 synfigapp::Action::ParamVocab::const_iterator iter;
912 for(iter=param_vocab.begin();iter!=param_vocab.end();++iter)
914 if(!iter->get_mutual_exclusion().empty() && param_list.count(iter->get_mutual_exclusion()))
917 // If the parameter is optionally user-supplied,
918 // and has not been already provided in the param_list,
919 // then we should go ahead and see if we can
920 // provide that data.
921 if(iter->get_user_supplied() && param_list.count(iter->get_name())==0)
923 switch(iter->get_type())
925 case synfigapp::Action::Param::TYPE_STRING:
928 if(!studio::App::dialog_entry(entry.local_name, iter->get_local_name()+":"+iter->get_desc(),str))
930 action->set_param(iter->get_name(),str);
934 synfig::error("Unsupported user-supplied action parameter");
941 if(!action->is_ready())
943 synfig::error("Action not ready");
947 perform_action(action);
951 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas, synfigapp::ValueDesc value_desc, float location)
953 Gtk::Menu& parammenu(*menu);
955 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
957 if(!canvas_interface)
960 synfigapp::Action::ParamList param_list,param_list2;
961 param_list=canvas_interface->generate_param_list(value_desc);
962 param_list.add("origin",location);
964 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
966 param_list2=canvas_interface->generate_param_list(
967 synfigapp::ValueDesc(
968 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
972 param_list2.add("origin",location);
976 // Populate the convert menu by looping through
977 // the ValueNode book and find the ones that are
980 Gtk::Menu *convert_menu=manage(new Gtk::Menu());
981 LinkableValueNode::Book::const_iterator iter;
982 for(iter=LinkableValueNode::book().begin();iter!=LinkableValueNode::book().end();++iter)
984 if(iter->second.check_type(value_desc.get_value_type()))
986 convert_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->second.local_name,
990 sigc::mem_fun(*canvas_interface.get(),&synfigapp::CanvasInterface::convert),
1000 parammenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::CONVERT,*convert_menu));
1003 if(param_list2.empty())
1004 add_actions_to_menu(¶mmenu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1006 add_actions_to_menu(¶mmenu, param_list2,param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1008 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
1010 value_desc=synfigapp::ValueDesc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),0);
1013 if(value_desc.is_value_node() && ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
1015 ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()));
1019 WaypointList::iterator iter(value_node->find(canvas->get_time()));
1020 parammenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoint"),
1024 sigc::mem_fun(*find_canvas_view(canvas),&studio::CanvasView::on_waypoint_clicked),
1040 edit_several_waypoints(etl::handle<CanvasView> canvas_view, std::list<synfigapp::ValueDesc> value_desc_list)
1042 etl::handle<synfigapp::CanvasInterface> canvas_interface(canvas_view->canvas_interface());
1045 "Edit Multiple Waypoints", // Title
1047 true // use_separator
1050 Widget_WaypointModel widget_waypoint_model;
1051 widget_waypoint_model.show();
1053 dialog.get_vbox()->pack_start(widget_waypoint_model);
1056 dialog.add_button(Gtk::StockID("gtk-apply"),1);
1057 dialog.add_button(Gtk::StockID("gtk-cancel"),0);
1061 if(dialog.run()==0 || widget_waypoint_model.get_waypoint_model().is_trivial())
1064 synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Set Waypoints"));
1066 std::list<synfigapp::ValueDesc>::iterator iter;
1067 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
1069 synfigapp::ValueDesc value_desc(*iter);
1071 if(!value_desc.is_valid())
1074 ValueNode_Animated::Handle value_node;
1076 // If this value isn't a ValueNode_Animated, but
1077 // it is somewhat constant, then go ahead and convert
1078 // it to a ValueNode_Animated.
1079 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
1082 if(value_desc.is_value_node())
1083 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
1085 value=value_desc.get_value();
1087 value_node=ValueNode_Animated::create(value,canvas_interface->get_time());
1089 synfigapp::Action::Handle action;
1091 if(!value_desc.is_value_node())
1093 action=synfigapp::Action::create("value_desc_connect");
1094 action->set_param("dest",value_desc);
1095 action->set_param("src",ValueNode::Handle(value_node));
1099 action=synfigapp::Action::create("value_node_replace");
1100 action->set_param("dest",value_desc.get_value_node());
1101 action->set_param("src",ValueNode::Handle(value_node));
1104 action->set_param("canvas",canvas_view->get_canvas());
1105 action->set_param("canvas_interface",canvas_interface);
1108 if(!canvas_interface->get_instance()->perform_action(action))
1110 canvas_view->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
1117 if(value_desc.is_value_node())
1118 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
1125 synfigapp::Action::Handle action(synfigapp::Action::create("waypoint_set_smart"));
1129 canvas_view->get_ui_interface()->error(_("Unable to find waypoint_set_smart action"));
1135 action->set_param("canvas",canvas_view->get_canvas());
1136 action->set_param("canvas_interface",canvas_interface);
1137 action->set_param("value_node",ValueNode::Handle(value_node));
1138 action->set_param("time",canvas_interface->get_time());
1139 action->set_param("model",widget_waypoint_model.get_waypoint_model());
1141 if(!canvas_interface->get_instance()->perform_action(action))
1143 canvas_view->get_ui_interface()->error(_("Unable to set a specific waypoint"));
1150 //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
1159 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas,const std::list<synfigapp::ValueDesc>& value_desc_list)
1161 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
1163 synfigapp::Action::ParamList param_list;
1164 param_list=canvas_interface->generate_param_list(value_desc_list);
1166 add_actions_to_menu(menu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1168 // Add the edit waypoints option if that might be useful
1169 if(canvas->rend_desc().get_time_end()-Time::epsilon()>canvas->rend_desc().get_time_start())
1171 menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
1175 &edit_several_waypoints
1179 find_canvas_view(canvas)