1 /* === S Y N F I G ========================================================= */
5 ** $Id: instance.cpp,v 1.2 2005/01/13 18:37:30 darco Exp $
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 // Delete all of the canvas views
323 canvas_view_list().clear();
325 // If there is another open instance to select,
326 // go ahead and do so. If not, never mind.
327 if(studio::App::instance_list.empty())
329 studio::App::set_selected_canvas_view(0);
330 studio::App::set_selected_instance(0);
334 studio::App::set_selected_canvas_view(studio::App::instance_list.front()->canvas_view_list().front());
335 //studio::App::set_selected_instance(studio::App::instance_list.front());
341 Instance::insert_canvas(Gtk::TreeRow row,Canvas::Handle canvas)
343 CanvasTreeModel canvas_tree_model;
346 row[canvas_tree_model.icon] = Gtk::Button().render_icon(Gtk::StockID("synfig-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
347 row[canvas_tree_model.id] = canvas->get_id();
348 row[canvas_tree_model.name] = canvas->get_name();
349 if(canvas->is_root())
350 row[canvas_tree_model.label] = basename(canvas->get_file_name());
352 if(!canvas->get_id().empty())
353 row[canvas_tree_model.label] = canvas->get_id();
355 if(!canvas->get_name().empty())
356 row[canvas_tree_model.label] = canvas->get_name();
358 row[canvas_tree_model.label] = _("[Unnamed]");
360 row[canvas_tree_model.canvas] = canvas;
361 row[canvas_tree_model.is_canvas] = true;
362 row[canvas_tree_model.is_value_node] = false;
365 synfig::Canvas::Children::iterator iter;
366 synfig::Canvas::Children &children(canvas->children());
368 for(iter=children.begin();iter!=children.end();iter++)
369 insert_canvas(*(canvas_tree_store()->append(row.children())),*iter);
373 if(!canvas->value_node_list().empty())
375 Gtk::TreeRow valuenode_row = *(canvas_tree_store()->append(row.children()));
377 valuenode_row[canvas_tree_model.label] = "<defs>";
378 valuenode_row[canvas_tree_model.canvas] = canvas;
379 valuenode_row[canvas_tree_model.is_canvas] = false;
380 valuenode_row[canvas_tree_model.is_value_node] = false;
382 synfig::ValueNodeList::iterator iter;
383 synfig::ValueNodeList &value_node_list(canvas->value_node_list());
385 for(iter=value_node_list.begin();iter!=value_node_list.end();iter++)
386 insert_value_node(*(canvas_tree_store()->append(valuenode_row.children())),canvas,*iter);
394 Instance::insert_value_node(Gtk::TreeRow row,Canvas::Handle canvas,etl::handle<synfig::ValueNode> value_node)
396 CanvasTreeModel canvas_tree_model;
400 row[canvas_tree_model.id] = value_node->get_id();
401 row[canvas_tree_model.name] = value_node->get_id();
402 row[canvas_tree_model.label] = value_node->get_id();
403 row[canvas_tree_model.canvas] = canvas;
404 row[canvas_tree_model.value_node] = value_node;
405 row[canvas_tree_model.is_canvas] = false;
406 row[canvas_tree_model.is_value_node] = true;
407 row[canvas_tree_model.icon] = Gtk::Button().render_icon(valuenode_icon(value_node),Gtk::ICON_SIZE_SMALL_TOOLBAR);
412 Instance::refresh_canvas_tree()
414 canvas_tree_store()->clear();
415 Gtk::TreeRow row = *(canvas_tree_store()->prepend());
416 insert_canvas(row,get_canvas());
420 Instance::dialog_cvs_commit()
422 calc_repository_info();
425 App::dialog_error_blocking(_("Error"),_("You must first add this composition to the repository"));
432 if(synfigapp::Instance::get_action_count())
434 if(!App::dialog_yes_no(_("CVS Commit"), _("This will save any changes you have made. Are you sure?")))
441 App::dialog_error_blocking(_("Error"),_("The local copy of the file hasn't been changed since the last update.\nNothing to commit!"));
445 if(!App::dialog_entry(_("CVS Commit"),_("Enter a log message describing the changes you have made"), message))
448 OneMoment one_moment;
453 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to COMMIT"));
459 Instance::dialog_cvs_add()
461 calc_repository_info();
464 App::dialog_error_blocking(_("Error"),_("This composition has already been added to the repository"));
471 //if(!App::dialog_entry(_("CVS Add"),_("Enter a log message describing the file"), message))
473 OneMoment one_moment;
478 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to ADD"));
484 Instance::dialog_cvs_update()
486 calc_repository_info();
489 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to update from!"));
494 App::dialog_error_blocking(_("Info"),_("This file is up-to-date"));
500 String filename(get_file_name());
501 if(synfigapp::Instance::get_action_count())
503 if(!App::dialog_yes_no(_("CVS Update"), _("This will save any changes you have made. Are you sure?")))
507 OneMoment one_moment;
508 time_t oldtime=get_original_timestamp();
510 calc_repository_info();
511 // If something has been updated...
512 if(oldtime!=get_original_timestamp())
519 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
521 //update_all_titles();
525 Instance::dialog_cvs_revert()
527 calc_repository_info();
530 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to revert to!"));
535 String filename(get_file_name());
536 if(!App::dialog_yes_no(_("CVS Revert"),
537 _("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?")
541 OneMoment one_moment;
543 // Remove the old file
544 if(remove(get_file_name().c_str())!=0)
546 App::dialog_error_blocking(_("Error"),_("Unable to remove previous version"));
555 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
557 //update_all_titles();
561 Instance::_revert(Instance *instance)
563 OneMoment one_moment;
565 String filename(instance->get_file_name());
567 Canvas::Handle canvas(instance->get_canvas());
571 if(canvas->count()!=1)
574 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."));
585 // Schedule a revert to occur in a few moments
586 Glib::signal_timeout().connect(
589 sigc::ptr_fun(&Instance::_revert),
599 Instance::safe_revert()
601 if(synfigapp::Instance::get_action_count())
602 if(!App::dialog_yes_no(_("Revert to saved"), _("You will loose any changes you have made since your last save.\nAre you sure?")))
609 Instance::safe_close()
611 handle<synfigapp::UIInterface> uim;
612 uim=find_canvas_view(get_canvas())->get_ui_interface();
614 if(get_action_count())
616 string str=strprintf(_("Would you like to save your changes to %s?"),basename(get_file_name()).c_str() );
617 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
618 if(answer==synfigapp::UIInterface::RESPONSE_YES)
620 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
626 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());
627 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
629 if(answer==synfigapp::UIInterface::RESPONSE_YES)
631 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
637 while(studio::App::events_pending())studio::App::iteration(false);
644 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
646 synfigapp::Action::CanidateList canidate_list;
647 synfigapp::Action::CanidateList::iterator iter;
649 canidate_list=compile_canidate_list(param_list,category);
651 canidate_list.sort();
653 if(canidate_list.empty())
654 synfig::warning("Action CanidateList is empty!");
656 for(iter=canidate_list.begin();iter!=canidate_list.end();++iter)
658 Gtk::StockID stock_id(get_action_stock_id(*iter));
660 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
662 action_group->add(Gtk::Action::create(
663 "action-"+iter->name,
665 iter->local_name,iter->local_name
670 *const_cast<studio::Instance*>(this),
671 &studio::Instance::process_action
678 ui_info+=strprintf("<menuitem action='action-%s' />",iter->name.c_str());
684 Instance::add_actions_to_menu(Gtk::Menu *menu, const synfigapp::Action::ParamList ¶m_list,synfigapp::Action::Category category)const
686 synfigapp::Action::CanidateList canidate_list;
687 synfigapp::Action::CanidateList::iterator iter;
689 canidate_list=compile_canidate_list(param_list,category);
691 canidate_list.sort();
693 if(canidate_list.empty())
694 synfig::warning("Action CanidateList is empty!");
696 for(iter=canidate_list.begin();iter!=canidate_list.end();++iter)
698 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
700 Gtk::Image* image(manage(new Gtk::Image()));
701 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
704 if(iter->task=="raise")
705 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
706 else if(iter->task=="lower")
707 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
708 else if(iter->task=="move_top")
709 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
710 else if(iter->task=="move_bottom")
711 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
712 else if(iter->task=="remove")
713 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
714 else if(iter->task=="set_on")
715 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
716 else if(iter->task=="set_off")
717 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
718 else if(iter->task=="duplicate")
719 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
720 else if(iter->task=="remove")
721 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
724 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
725 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
726 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
729 menu->items().push_back(
730 Gtk::Menu_Helpers::ImageMenuElem(
736 *const_cast<studio::Instance*>(this),
737 &studio::Instance::process_action
750 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
752 synfigapp::Action::CanidateList canidate_list;
753 synfigapp::Action::CanidateList canidate_list2;
755 synfigapp::Action::CanidateList::iterator iter;
757 canidate_list=compile_canidate_list(param_list,category);
758 canidate_list2=compile_canidate_list(param_list2,category);
760 canidate_list.sort();
762 if(canidate_list.empty())
763 synfig::warning("Action CanidateList is empty!");
764 if(canidate_list2.empty())
765 synfig::warning("Action CanidateList2 is empty!");
767 // Seperate out the canidate lists so that there are no conflicts
768 for(iter=canidate_list.begin();iter!=canidate_list.end();++iter)
770 synfigapp::Action::CanidateList::iterator iter2(canidate_list2.find(iter->name));
771 if(iter2!=canidate_list2.end())
772 canidate_list2.erase(iter2);
775 for(iter=canidate_list2.begin();iter!=canidate_list2.end();++iter)
777 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
779 Gtk::Image* image(manage(new Gtk::Image()));
780 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
782 /* if(iter->task=="raise")
783 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
784 else if(iter->task=="lower")
785 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
786 else if(iter->task=="move_top")
787 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
788 else if(iter->task=="move_bottom")
789 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
790 else if(iter->task=="remove")
791 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
792 else if(iter->task=="set_on")
793 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
794 else if(iter->task=="set_off")
795 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
796 else if(iter->task=="duplicate")
797 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
798 else if(iter->task=="remove")
799 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
802 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
803 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
804 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
807 menu->items().push_back(
808 Gtk::Menu_Helpers::ImageMenuElem(
814 *const_cast<studio::Instance*>(this),
815 &studio::Instance::process_action
826 for(iter=canidate_list.begin();iter!=canidate_list.end();++iter)
828 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
830 Gtk::Image* image(manage(new Gtk::Image()));
831 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
832 /* if(iter->task=="raise")
833 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
834 else if(iter->task=="lower")
835 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
836 else if(iter->task=="move_top")
837 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
838 else if(iter->task=="move_bottom")
839 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
840 else if(iter->task=="remove")
841 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
842 else if(iter->task=="set_on")
843 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
844 else if(iter->task=="set_off")
845 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
846 else if(iter->task=="duplicate")
847 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
848 else if(iter->task=="remove")
849 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
852 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
853 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
854 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
857 menu->items().push_back(
858 Gtk::Menu_Helpers::ImageMenuElem(
864 *const_cast<studio::Instance*>(this),
865 &studio::Instance::process_action
878 Instance::process_action(String name, synfigapp::Action::ParamList param_list)
880 assert(synfigapp::Action::book().count(name));
882 synfigapp::Action::BookEntry entry(synfigapp::Action::book().find(name)->second);
884 synfigapp::Action::Handle action(entry.factory());
888 synfig::error("Bad Action");
892 action->set_param_list(param_list);
894 synfigapp::Action::ParamVocab param_vocab(entry.get_param_vocab());
895 synfigapp::Action::ParamVocab::const_iterator iter;
897 for(iter=param_vocab.begin();iter!=param_vocab.end();++iter)
899 if(!iter->get_mutual_exclusion().empty() && param_list.count(iter->get_mutual_exclusion()))
902 // If the parameter is optionally user-supplied,
903 // and has not been already provided in the param_list,
904 // then we should go ahead and see if we can
905 // provide that data.
906 if(iter->get_user_supplied() && param_list.count(iter->get_name())==0)
908 switch(iter->get_type())
910 case synfigapp::Action::Param::TYPE_STRING:
913 if(!studio::App::dialog_entry(entry.local_name, iter->get_local_name()+":"+iter->get_desc(),str))
915 action->set_param(iter->get_name(),str);
919 synfig::error("Unsupported user-supplied action parameter");
926 if(!action->is_ready())
928 synfig::error("Action not ready");
932 perform_action(action);
936 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas, synfigapp::ValueDesc value_desc, float location)
938 Gtk::Menu& parammenu(*menu);
940 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
942 if(!canvas_interface)
945 synfigapp::Action::ParamList param_list,param_list2;
946 param_list=canvas_interface->generate_param_list(value_desc);
947 param_list.add("origin",location);
949 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
951 param_list2=canvas_interface->generate_param_list(
952 synfigapp::ValueDesc(
953 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
957 param_list2.add("origin",location);
961 // Populate the convert menu by looping through
962 // the ValueNode book and find the ones that are
965 Gtk::Menu *convert_menu=manage(new Gtk::Menu());
966 LinkableValueNode::Book::const_iterator iter;
967 for(iter=LinkableValueNode::book().begin();iter!=LinkableValueNode::book().end();++iter)
969 if(iter->second.check_type(value_desc.get_value_type()))
971 convert_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->second.local_name,
975 sigc::mem_fun(*canvas_interface.get(),&synfigapp::CanvasInterface::convert),
985 parammenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::CONVERT,*convert_menu));
988 if(param_list2.empty())
989 add_actions_to_menu(¶mmenu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
991 add_actions_to_menu(¶mmenu, param_list2,param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
993 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
995 value_desc=synfigapp::ValueDesc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),0);
998 if(value_desc.is_value_node() && ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
1000 ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()));
1004 WaypointList::iterator iter(value_node->find(canvas->get_time()));
1005 parammenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoint"),
1009 sigc::mem_fun(*find_canvas_view(canvas),&studio::CanvasView::on_waypoint_clicked),
1025 edit_several_waypoints(etl::handle<CanvasView> canvas_view, std::list<synfigapp::ValueDesc> value_desc_list)
1027 etl::handle<synfigapp::CanvasInterface> canvas_interface(canvas_view->canvas_interface());
1030 "Edit Multiple Waypoints", // Title
1032 true // use_separator
1035 Widget_WaypointModel widget_waypoint_model;
1036 widget_waypoint_model.show();
1038 dialog.get_vbox()->pack_start(widget_waypoint_model);
1041 dialog.add_button(Gtk::StockID("gtk-apply"),1);
1042 dialog.add_button(Gtk::StockID("gtk-cancel"),0);
1046 if(dialog.run()==0 || widget_waypoint_model.get_waypoint_model().is_trivial())
1049 synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Set Waypoints"));
1051 std::list<synfigapp::ValueDesc>::iterator iter;
1052 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
1054 synfigapp::ValueDesc value_desc(*iter);
1056 if(!value_desc.is_valid())
1059 ValueNode_Animated::Handle value_node;
1061 // If this value isn't a ValueNode_Animated, but
1062 // it is somewhat constant, then go ahead and convert
1063 // it to a ValueNode_Animated.
1064 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
1067 if(value_desc.is_value_node())
1068 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
1070 value=value_desc.get_value();
1072 value_node=ValueNode_Animated::create(value,canvas_interface->get_time());
1074 synfigapp::Action::Handle action;
1076 if(!value_desc.is_value_node())
1078 action=synfigapp::Action::create("value_desc_connect");
1079 action->set_param("dest",value_desc);
1080 action->set_param("src",ValueNode::Handle(value_node));
1084 action=synfigapp::Action::create("value_node_replace");
1085 action->set_param("dest",value_desc.get_value_node());
1086 action->set_param("src",ValueNode::Handle(value_node));
1089 action->set_param("canvas",canvas_view->get_canvas());
1090 action->set_param("canvas_interface",canvas_interface);
1093 if(!canvas_interface->get_instance()->perform_action(action))
1095 canvas_view->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
1102 if(value_desc.is_value_node())
1103 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
1110 synfigapp::Action::Handle action(synfigapp::Action::create("waypoint_set_smart"));
1114 canvas_view->get_ui_interface()->error(_("Unable to find waypoint_set_smart action"));
1120 action->set_param("canvas",canvas_view->get_canvas());
1121 action->set_param("canvas_interface",canvas_interface);
1122 action->set_param("value_node",ValueNode::Handle(value_node));
1123 action->set_param("time",canvas_interface->get_time());
1124 action->set_param("model",widget_waypoint_model.get_waypoint_model());
1126 if(!canvas_interface->get_instance()->perform_action(action))
1128 canvas_view->get_ui_interface()->error(_("Unable to set a specific waypoint"));
1135 //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
1144 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas,const std::list<synfigapp::ValueDesc>& value_desc_list)
1146 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
1148 synfigapp::Action::ParamList param_list;
1149 param_list=canvas_interface->generate_param_list(value_desc_list);
1151 add_actions_to_menu(menu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1153 // Add the edit waypoints option if that might be useful
1154 if(canvas->rend_desc().get_time_end()-Time::epsilon()>canvas->rend_desc().get_time_start())
1156 menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
1160 &edit_several_waypoints
1164 find_canvas_view(canvas)