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 if(basename(get_file_name()).find("untitled")==0)
207 return synfigapp::Instance::save();
212 studio::Instance::dialog_save_as()
214 string filename="*.sif";
216 Canvas::Handle canvas(get_canvas());
219 OneMoment one_moment;
220 std::set<Node*>::iterator iter;
221 for(iter=canvas->parent_set.begin();iter!=canvas->parent_set.end();++iter)
223 synfig::Node* node(*iter);
224 for(;!node->parent_set.empty();node=*node->parent_set.begin())
226 Layer::Handle parent_layer(dynamic_cast<Layer*>(node));
227 if(parent_layer && parent_layer->get_canvas()->get_root()!=get_canvas())
229 App::dialog_error_blocking("SaveAs - Error",
230 "There is currently a bug when using \"SaveAs\"\n"
231 "on a composition that is being referenced by other\n"
232 "files that are currently open. Close these\n"
233 "other files first before trying to use \"SaveAs\"."
244 // show the canvas' name if it has one, else its ID
245 while(App::dialog_save_file(_("Choose a Filename to Save As") +
247 (canvas->get_name().empty()
249 : canvas->get_name()) +
252 // If the filename still has wildcards, then we should
253 // continue looking for the file we want
254 if(find(filename.begin(),filename.end(),'*')!=filename.end())
257 std::string base = basename(filename);
258 if(find(base.begin(),base.end(),'.')==base.end())
263 String ext(String(filename.begin()+filename.find_last_of('.')+1,filename.end()));
264 if(ext!="sif" && ext!="sifz" && !App::dialog_yes_no(_("Unknown extension"),
265 _("You have given the file name an extension\nwhich I do not recognise. Are you sure this is what you want?")))
277 // if stat() succeeds, or it fails with something other than 'file doesn't exist', the file exists
278 // if the file exists and the user doesn't want to overwrite it, keep prompting for a filename
279 if ((stat(filename.c_str(), &s) != -1 || errno != ENOENT) &&
280 !App::dialog_yes_no("File exists",
283 "' already exists.\n\n"
284 "Do you want to replace it with the file you are saving?"))
288 if(save_as(filename))
291 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())
630 string str=strprintf(_("Would you like to save your changes to %s?"),basename(get_file_name()).c_str() );
631 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)
640 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());
641 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
643 if(answer==synfigapp::UIInterface::RESPONSE_YES)
645 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
656 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
658 synfigapp::Action::CandidateList candidate_list;
659 synfigapp::Action::CandidateList::iterator iter;
661 candidate_list=compile_candidate_list(param_list,category);
663 candidate_list.sort();
665 if(candidate_list.empty())
666 synfig::warning("Action CandidateList is empty!");
668 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
670 Gtk::StockID stock_id(get_action_stock_id(*iter));
672 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
674 action_group->add(Gtk::Action::create(
675 "action-"+iter->name,
677 iter->local_name,iter->local_name
682 *const_cast<studio::Instance*>(this),
683 &studio::Instance::process_action
690 ui_info+=strprintf("<menuitem action='action-%s' />",iter->name.c_str());
696 Instance::add_actions_to_menu(Gtk::Menu *menu, const synfigapp::Action::ParamList ¶m_list,synfigapp::Action::Category category)const
698 synfigapp::Action::CandidateList candidate_list;
699 synfigapp::Action::CandidateList::iterator iter;
701 candidate_list=compile_candidate_list(param_list,category);
703 candidate_list.sort();
705 if(candidate_list.empty())
706 synfig::warning("Action CandidateList is empty!");
708 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
710 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
712 Gtk::Image* image(manage(new Gtk::Image()));
713 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
716 if(iter->task=="raise")
717 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
718 else if(iter->task=="lower")
719 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
720 else if(iter->task=="move_top")
721 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
722 else if(iter->task=="move_bottom")
723 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
724 else if(iter->task=="remove")
725 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
726 else if(iter->task=="set_on")
727 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
728 else if(iter->task=="set_off")
729 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
730 else if(iter->task=="duplicate")
731 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
732 else if(iter->task=="remove")
733 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
736 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
737 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
738 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
741 menu->items().push_back(
742 Gtk::Menu_Helpers::ImageMenuElem(
748 *const_cast<studio::Instance*>(this),
749 &studio::Instance::process_action
762 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
764 synfigapp::Action::CandidateList candidate_list;
765 synfigapp::Action::CandidateList candidate_list2;
767 synfigapp::Action::CandidateList::iterator iter;
769 candidate_list=compile_candidate_list(param_list,category);
770 candidate_list2=compile_candidate_list(param_list2,category);
772 candidate_list.sort();
774 if(candidate_list.empty())
775 synfig::warning("Action CandidateList is empty!");
776 if(candidate_list2.empty())
777 synfig::warning("Action CandidateList2 is empty!");
779 // Seperate out the candidate lists so that there are no conflicts
780 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
782 synfigapp::Action::CandidateList::iterator iter2(candidate_list2.find(iter->name));
783 if(iter2!=candidate_list2.end())
784 candidate_list2.erase(iter2);
787 for(iter=candidate_list2.begin();iter!=candidate_list2.end();++iter)
789 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
791 Gtk::Image* image(manage(new Gtk::Image()));
792 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
794 /* if(iter->task=="raise")
795 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
796 else if(iter->task=="lower")
797 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
798 else if(iter->task=="move_top")
799 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
800 else if(iter->task=="move_bottom")
801 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
802 else if(iter->task=="remove")
803 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
804 else if(iter->task=="set_on")
805 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
806 else if(iter->task=="set_off")
807 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
808 else if(iter->task=="duplicate")
809 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
810 else if(iter->task=="remove")
811 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
814 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
815 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
816 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
819 menu->items().push_back(
820 Gtk::Menu_Helpers::ImageMenuElem(
826 *const_cast<studio::Instance*>(this),
827 &studio::Instance::process_action
838 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
840 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
842 Gtk::Image* image(manage(new Gtk::Image()));
843 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
844 /* if(iter->task=="raise")
845 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
846 else if(iter->task=="lower")
847 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
848 else if(iter->task=="move_top")
849 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
850 else if(iter->task=="move_bottom")
851 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
852 else if(iter->task=="remove")
853 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
854 else if(iter->task=="set_on")
855 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
856 else if(iter->task=="set_off")
857 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
858 else if(iter->task=="duplicate")
859 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
860 else if(iter->task=="remove")
861 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
864 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
865 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
866 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
869 menu->items().push_back(
870 Gtk::Menu_Helpers::ImageMenuElem(
876 *const_cast<studio::Instance*>(this),
877 &studio::Instance::process_action
890 Instance::process_action(String name, synfigapp::Action::ParamList param_list)
892 assert(synfigapp::Action::book().count(name));
894 synfigapp::Action::BookEntry entry(synfigapp::Action::book().find(name)->second);
896 synfigapp::Action::Handle action(entry.factory());
900 synfig::error("Bad Action");
904 action->set_param_list(param_list);
906 synfigapp::Action::ParamVocab param_vocab(entry.get_param_vocab());
907 synfigapp::Action::ParamVocab::const_iterator iter;
909 for(iter=param_vocab.begin();iter!=param_vocab.end();++iter)
911 if(!iter->get_mutual_exclusion().empty() && param_list.count(iter->get_mutual_exclusion()))
914 // If the parameter is optionally user-supplied,
915 // and has not been already provided in the param_list,
916 // then we should go ahead and see if we can
917 // provide that data.
918 if(iter->get_user_supplied() && param_list.count(iter->get_name())==0)
920 switch(iter->get_type())
922 case synfigapp::Action::Param::TYPE_STRING:
925 if(!studio::App::dialog_entry(entry.local_name, iter->get_local_name()+":"+iter->get_desc(),str))
927 action->set_param(iter->get_name(),str);
931 synfig::error("Unsupported user-supplied action parameter");
938 if(!action->is_ready())
940 synfig::error("Action not ready");
944 perform_action(action);
948 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas, synfigapp::ValueDesc value_desc, float location)
950 Gtk::Menu& parammenu(*menu);
952 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
954 if(!canvas_interface)
957 synfigapp::Action::ParamList param_list,param_list2;
958 param_list=canvas_interface->generate_param_list(value_desc);
959 param_list.add("origin",location);
961 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
963 param_list2=canvas_interface->generate_param_list(
964 synfigapp::ValueDesc(
965 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
969 param_list2.add("origin",location);
973 // Populate the convert menu by looping through
974 // the ValueNode book and find the ones that are
977 Gtk::Menu *convert_menu=manage(new Gtk::Menu());
978 LinkableValueNode::Book::const_iterator iter;
979 for(iter=LinkableValueNode::book().begin();iter!=LinkableValueNode::book().end();++iter)
981 if(iter->second.check_type(value_desc.get_value_type()))
983 convert_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->second.local_name,
987 sigc::mem_fun(*canvas_interface.get(),&synfigapp::CanvasInterface::convert),
997 parammenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::CONVERT,*convert_menu));
1000 if(param_list2.empty())
1001 add_actions_to_menu(¶mmenu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1003 add_actions_to_menu(¶mmenu, param_list2,param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1005 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
1007 value_desc=synfigapp::ValueDesc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),0);
1010 if(value_desc.is_value_node() && ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
1012 ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()));
1016 WaypointList::iterator iter(value_node->find(canvas->get_time()));
1017 parammenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoint"),
1021 sigc::mem_fun(*find_canvas_view(canvas),&studio::CanvasView::on_waypoint_clicked),
1037 edit_several_waypoints(etl::handle<CanvasView> canvas_view, std::list<synfigapp::ValueDesc> value_desc_list)
1039 etl::handle<synfigapp::CanvasInterface> canvas_interface(canvas_view->canvas_interface());
1042 "Edit Multiple Waypoints", // Title
1044 true // use_separator
1047 Widget_WaypointModel widget_waypoint_model;
1048 widget_waypoint_model.show();
1050 dialog.get_vbox()->pack_start(widget_waypoint_model);
1053 dialog.add_button(Gtk::StockID("gtk-apply"),1);
1054 dialog.add_button(Gtk::StockID("gtk-cancel"),0);
1058 if(dialog.run()==0 || widget_waypoint_model.get_waypoint_model().is_trivial())
1061 synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Set Waypoints"));
1063 std::list<synfigapp::ValueDesc>::iterator iter;
1064 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
1066 synfigapp::ValueDesc value_desc(*iter);
1068 if(!value_desc.is_valid())
1071 ValueNode_Animated::Handle value_node;
1073 // If this value isn't a ValueNode_Animated, but
1074 // it is somewhat constant, then go ahead and convert
1075 // it to a ValueNode_Animated.
1076 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
1079 if(value_desc.is_value_node())
1080 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
1082 value=value_desc.get_value();
1084 value_node=ValueNode_Animated::create(value,canvas_interface->get_time());
1086 synfigapp::Action::Handle action;
1088 if(!value_desc.is_value_node())
1090 action=synfigapp::Action::create("value_desc_connect");
1091 action->set_param("dest",value_desc);
1092 action->set_param("src",ValueNode::Handle(value_node));
1096 action=synfigapp::Action::create("value_node_replace");
1097 action->set_param("dest",value_desc.get_value_node());
1098 action->set_param("src",ValueNode::Handle(value_node));
1101 action->set_param("canvas",canvas_view->get_canvas());
1102 action->set_param("canvas_interface",canvas_interface);
1105 if(!canvas_interface->get_instance()->perform_action(action))
1107 canvas_view->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
1114 if(value_desc.is_value_node())
1115 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
1122 synfigapp::Action::Handle action(synfigapp::Action::create("waypoint_set_smart"));
1126 canvas_view->get_ui_interface()->error(_("Unable to find waypoint_set_smart action"));
1132 action->set_param("canvas",canvas_view->get_canvas());
1133 action->set_param("canvas_interface",canvas_interface);
1134 action->set_param("value_node",ValueNode::Handle(value_node));
1135 action->set_param("time",canvas_interface->get_time());
1136 action->set_param("model",widget_waypoint_model.get_waypoint_model());
1138 if(!canvas_interface->get_instance()->perform_action(action))
1140 canvas_view->get_ui_interface()->error(_("Unable to set a specific waypoint"));
1147 //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
1156 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas,const std::list<synfigapp::ValueDesc>& value_desc_list)
1158 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
1160 synfigapp::Action::ParamList param_list;
1161 param_list=canvas_interface->generate_param_list(value_desc_list);
1163 add_actions_to_menu(menu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1165 // Add the edit waypoints option if that might be useful
1166 if(canvas->rend_desc().get_time_end()-Time::epsilon()>canvas->rend_desc().get_time_start())
1168 menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
1172 &edit_several_waypoints
1176 find_canvas_view(canvas)