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("Synfig Animation")==0)
207 return synfigapp::Instance::save();
212 studio::Instance::dialog_save_as()
214 string filename=basename(get_file_name());
215 Canvas::Handle canvas(get_canvas());
218 OneMoment one_moment;
219 std::set<Node*>::iterator iter;
220 for(iter=canvas->parent_set.begin();iter!=canvas->parent_set.end();++iter)
222 synfig::Node* node(*iter);
223 for(;!node->parent_set.empty();node=*node->parent_set.begin())
225 Layer::Handle parent_layer(dynamic_cast<Layer*>(node));
226 if(parent_layer && parent_layer->get_canvas()->get_root()!=get_canvas())
228 App::dialog_error_blocking("SaveAs - Error",
229 "There is currently a bug when using \"SaveAs\"\n"
230 "on a composition that is being referenced by other\n"
231 "files that are currently open. Close these\n"
232 "other files first before trying to use \"SaveAs\"."
243 // show the canvas' name if it has one, else its ID
244 while(App::dialog_save_file(_("Choose a Filename to Save As") +
246 (canvas->get_name().empty()
248 : canvas->get_name()) +
251 // If the filename still has wildcards, then we should
252 // continue looking for the file we want
253 if(find(filename.begin(),filename.end(),'*')!=filename.end())
256 std::string base = basename(filename);
257 if(find(base.begin(),base.end(),'.')==base.end())
262 String ext(String(filename.begin()+filename.find_last_of('.')+1,filename.end()));
263 if(ext!="sif" && ext!="sifz" && !App::dialog_yes_no(_("Unknown extension"),
264 _("You have given the file name an extension\nwhich I do not recognise. Are you sure this is what you want?")))
276 // if stat() succeeds, or it fails with something other than 'file doesn't exist', the file exists
277 // if the file exists and the user doesn't want to overwrite it, keep prompting for a filename
278 if ((stat(filename.c_str(), &s) != -1 || errno != ENOENT) &&
279 !App::dialog_yes_no("File exists",
282 "' already exists.\n\n"
283 "Do you want to replace it with the file you are saving?"))
287 if(save_as(filename))
290 App::dialog_error_blocking("SaveAs - Error","Unable to save file");
295 Instance::update_all_titles()
297 list<handle<CanvasView> >::iterator iter;
298 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
299 (*iter)->update_title();
305 // This will increase the reference count so we don't get DELETED
306 // until we are ready
307 handle<Instance> me(this);
309 // Make sure we aren't selected as the current instance
310 if(studio::App::get_selected_instance()==this)
311 studio::App::set_selected_instance(0);
313 // Turn-off/clean-up auto recovery
314 studio::App::auto_recover->clear_backup(get_canvas());
316 // Remove us from the active instance list
317 std::list<etl::handle<studio::Instance> >::iterator iter;
318 for(iter=studio::App::instance_list.begin();iter!=studio::App::instance_list.end();iter++)
321 assert(iter!=studio::App::instance_list.end());
322 if(iter!=studio::App::instance_list.end())
323 studio::App::instance_list.erase(iter);
325 // Send out a signal that we are being deleted
326 studio::App::signal_instance_deleted()(this);
328 // Hide all of the canvas views
329 for(std::list<etl::handle<CanvasView> >::iterator iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
332 // Consume pending events before deleting the canvas views
333 while(studio::App::events_pending())studio::App::iteration(false);
335 // Delete all of the canvas views
336 canvas_view_list().clear();
338 // If there is another open instance to select,
339 // go ahead and do so. If not, never mind.
340 if(studio::App::instance_list.empty())
342 studio::App::set_selected_canvas_view(0);
343 studio::App::set_selected_instance(0);
347 studio::App::set_selected_canvas_view(studio::App::instance_list.front()->canvas_view_list().front());
348 //studio::App::set_selected_instance(studio::App::instance_list.front());
354 Instance::insert_canvas(Gtk::TreeRow row,Canvas::Handle canvas)
356 CanvasTreeModel canvas_tree_model;
359 row[canvas_tree_model.icon] = Gtk::Button().render_icon(Gtk::StockID("synfig-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
360 row[canvas_tree_model.id] = canvas->get_id();
361 row[canvas_tree_model.name] = canvas->get_name();
362 if(canvas->is_root())
363 row[canvas_tree_model.label] = basename(canvas->get_file_name());
365 if(!canvas->get_id().empty())
366 row[canvas_tree_model.label] = canvas->get_id();
368 if(!canvas->get_name().empty())
369 row[canvas_tree_model.label] = canvas->get_name();
371 row[canvas_tree_model.label] = _("[Unnamed]");
373 row[canvas_tree_model.canvas] = canvas;
374 row[canvas_tree_model.is_canvas] = true;
375 row[canvas_tree_model.is_value_node] = false;
378 synfig::Canvas::Children::iterator iter;
379 synfig::Canvas::Children &children(canvas->children());
381 for(iter=children.begin();iter!=children.end();iter++)
382 insert_canvas(*(canvas_tree_store()->append(row.children())),*iter);
386 if(!canvas->value_node_list().empty())
388 Gtk::TreeRow valuenode_row = *(canvas_tree_store()->append(row.children()));
390 valuenode_row[canvas_tree_model.label] = "<defs>";
391 valuenode_row[canvas_tree_model.canvas] = canvas;
392 valuenode_row[canvas_tree_model.is_canvas] = false;
393 valuenode_row[canvas_tree_model.is_value_node] = false;
395 synfig::ValueNodeList::iterator iter;
396 synfig::ValueNodeList &value_node_list(canvas->value_node_list());
398 for(iter=value_node_list.begin();iter!=value_node_list.end();iter++)
399 insert_value_node(*(canvas_tree_store()->append(valuenode_row.children())),canvas,*iter);
407 Instance::insert_value_node(Gtk::TreeRow row,Canvas::Handle canvas,etl::handle<synfig::ValueNode> value_node)
409 CanvasTreeModel canvas_tree_model;
413 row[canvas_tree_model.id] = value_node->get_id();
414 row[canvas_tree_model.name] = value_node->get_id();
415 row[canvas_tree_model.label] = value_node->get_id();
416 row[canvas_tree_model.canvas] = canvas;
417 row[canvas_tree_model.value_node] = value_node;
418 row[canvas_tree_model.is_canvas] = false;
419 row[canvas_tree_model.is_value_node] = true;
420 row[canvas_tree_model.icon] = Gtk::Button().render_icon(valuenode_icon(value_node),Gtk::ICON_SIZE_SMALL_TOOLBAR);
425 Instance::refresh_canvas_tree()
427 canvas_tree_store()->clear();
428 Gtk::TreeRow row = *(canvas_tree_store()->prepend());
429 insert_canvas(row,get_canvas());
433 Instance::dialog_cvs_commit()
435 calc_repository_info();
438 App::dialog_error_blocking(_("Error"),_("You must first add this composition to the repository"));
445 if(synfigapp::Instance::get_action_count())
447 if(!App::dialog_yes_no(_("CVS Commit"), _("This will save any changes you have made. Are you sure?")))
454 App::dialog_error_blocking(_("Error"),_("The local copy of the file hasn't been changed since the last update.\nNothing to commit!"));
458 if(!App::dialog_entry(_("CVS Commit"),_("Enter a log message describing the changes you have made"), message))
461 OneMoment one_moment;
466 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to COMMIT"));
472 Instance::dialog_cvs_add()
474 calc_repository_info();
477 App::dialog_error_blocking(_("Error"),_("This composition has already been added to the repository"));
484 //if(!App::dialog_entry(_("CVS Add"),_("Enter a log message describing the file"), message))
486 OneMoment one_moment;
491 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to ADD"));
497 Instance::dialog_cvs_update()
499 calc_repository_info();
502 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to update from!"));
507 App::dialog_error_blocking(_("Info"),_("This file is up-to-date"));
513 String filename(get_file_name());
514 if(synfigapp::Instance::get_action_count())
516 if(!App::dialog_yes_no(_("CVS Update"), _("This will save any changes you have made. Are you sure?")))
520 OneMoment one_moment;
521 time_t oldtime=get_original_timestamp();
523 calc_repository_info();
524 // If something has been updated...
525 if(oldtime!=get_original_timestamp())
532 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
534 //update_all_titles();
538 Instance::dialog_cvs_revert()
540 calc_repository_info();
543 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to revert to!"));
548 String filename(get_file_name());
549 if(!App::dialog_yes_no(_("CVS Revert"),
550 _("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?")
554 OneMoment one_moment;
556 // Remove the old file
557 if(remove(get_file_name().c_str())!=0)
559 App::dialog_error_blocking(_("Error"),_("Unable to remove previous version"));
568 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
570 //update_all_titles();
574 Instance::_revert(Instance *instance)
576 OneMoment one_moment;
578 String filename(instance->get_file_name());
580 Canvas::Handle canvas(instance->get_canvas());
584 if(canvas->count()!=1)
587 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."));
598 // Schedule a revert to occur in a few moments
599 Glib::signal_timeout().connect(
602 sigc::ptr_fun(&Instance::_revert),
612 Instance::safe_revert()
614 if(synfigapp::Instance::get_action_count())
615 if(!App::dialog_yes_no(_("Revert to saved"), _("You will lose any changes you have made since your last save.\nAre you sure?")))
622 Instance::safe_close()
624 handle<synfigapp::UIInterface> uim;
625 uim=find_canvas_view(get_canvas())->get_ui_interface();
627 if(get_action_count())
629 string str=strprintf(_("Would you like to save your changes to %s?"),basename(get_file_name()).c_str() );
630 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
631 if(answer==synfigapp::UIInterface::RESPONSE_YES)
633 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
639 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());
640 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
642 if(answer==synfigapp::UIInterface::RESPONSE_YES)
644 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
655 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
657 synfigapp::Action::CandidateList candidate_list;
658 synfigapp::Action::CandidateList::iterator iter;
660 candidate_list=compile_candidate_list(param_list,category);
662 candidate_list.sort();
664 if(candidate_list.empty())
665 synfig::warning("Action CandidateList is empty!");
667 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
669 Gtk::StockID stock_id(get_action_stock_id(*iter));
671 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
673 action_group->add(Gtk::Action::create(
674 "action-"+iter->name,
676 iter->local_name,iter->local_name
681 *const_cast<studio::Instance*>(this),
682 &studio::Instance::process_action
689 ui_info+=strprintf("<menuitem action='action-%s' />",iter->name.c_str());
695 Instance::add_actions_to_menu(Gtk::Menu *menu, const synfigapp::Action::ParamList ¶m_list,synfigapp::Action::Category category)const
697 synfigapp::Action::CandidateList candidate_list;
698 synfigapp::Action::CandidateList::iterator iter;
700 candidate_list=compile_candidate_list(param_list,category);
702 candidate_list.sort();
704 if(candidate_list.empty())
705 synfig::warning("Action CandidateList is empty!");
707 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
709 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
711 Gtk::Image* image(manage(new Gtk::Image()));
712 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
715 if(iter->task=="raise")
716 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
717 else if(iter->task=="lower")
718 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
719 else if(iter->task=="move_top")
720 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
721 else if(iter->task=="move_bottom")
722 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
723 else if(iter->task=="remove")
724 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
725 else if(iter->task=="set_on")
726 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
727 else if(iter->task=="set_off")
728 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
729 else if(iter->task=="duplicate")
730 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
731 else if(iter->task=="remove")
732 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
735 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
736 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
737 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
740 menu->items().push_back(
741 Gtk::Menu_Helpers::ImageMenuElem(
747 *const_cast<studio::Instance*>(this),
748 &studio::Instance::process_action
761 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
763 synfigapp::Action::CandidateList candidate_list;
764 synfigapp::Action::CandidateList candidate_list2;
766 synfigapp::Action::CandidateList::iterator iter;
768 candidate_list=compile_candidate_list(param_list,category);
769 candidate_list2=compile_candidate_list(param_list2,category);
771 candidate_list.sort();
773 if(candidate_list.empty())
774 synfig::warning("Action CandidateList is empty!");
775 if(candidate_list2.empty())
776 synfig::warning("Action CandidateList2 is empty!");
778 // Seperate out the candidate lists so that there are no conflicts
779 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
781 synfigapp::Action::CandidateList::iterator iter2(candidate_list2.find(iter->name));
782 if(iter2!=candidate_list2.end())
783 candidate_list2.erase(iter2);
786 for(iter=candidate_list2.begin();iter!=candidate_list2.end();++iter)
788 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
790 Gtk::Image* image(manage(new Gtk::Image()));
791 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
793 /* if(iter->task=="raise")
794 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
795 else if(iter->task=="lower")
796 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
797 else if(iter->task=="move_top")
798 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
799 else if(iter->task=="move_bottom")
800 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
801 else if(iter->task=="remove")
802 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
803 else if(iter->task=="set_on")
804 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
805 else if(iter->task=="set_off")
806 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
807 else if(iter->task=="duplicate")
808 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
809 else if(iter->task=="remove")
810 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
813 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
814 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
815 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
818 menu->items().push_back(
819 Gtk::Menu_Helpers::ImageMenuElem(
825 *const_cast<studio::Instance*>(this),
826 &studio::Instance::process_action
837 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
839 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
841 Gtk::Image* image(manage(new Gtk::Image()));
842 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
843 /* if(iter->task=="raise")
844 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
845 else if(iter->task=="lower")
846 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
847 else if(iter->task=="move_top")
848 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
849 else if(iter->task=="move_bottom")
850 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
851 else if(iter->task=="remove")
852 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
853 else if(iter->task=="set_on")
854 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
855 else if(iter->task=="set_off")
856 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
857 else if(iter->task=="duplicate")
858 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
859 else if(iter->task=="remove")
860 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
863 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
864 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
865 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
868 menu->items().push_back(
869 Gtk::Menu_Helpers::ImageMenuElem(
875 *const_cast<studio::Instance*>(this),
876 &studio::Instance::process_action
889 Instance::process_action(String name, synfigapp::Action::ParamList param_list)
891 assert(synfigapp::Action::book().count(name));
893 synfigapp::Action::BookEntry entry(synfigapp::Action::book().find(name)->second);
895 synfigapp::Action::Handle action(entry.factory());
899 synfig::error("Bad Action");
903 action->set_param_list(param_list);
905 synfigapp::Action::ParamVocab param_vocab(entry.get_param_vocab());
906 synfigapp::Action::ParamVocab::const_iterator iter;
908 for(iter=param_vocab.begin();iter!=param_vocab.end();++iter)
910 if(!iter->get_mutual_exclusion().empty() && param_list.count(iter->get_mutual_exclusion()))
913 // If the parameter is optionally user-supplied,
914 // and has not been already provided in the param_list,
915 // then we should go ahead and see if we can
916 // provide that data.
917 if(iter->get_user_supplied() && param_list.count(iter->get_name())==0)
919 switch(iter->get_type())
921 case synfigapp::Action::Param::TYPE_STRING:
924 if(!studio::App::dialog_entry(entry.local_name, iter->get_local_name()+":"+iter->get_desc(),str))
926 action->set_param(iter->get_name(),str);
930 synfig::error("Unsupported user-supplied action parameter");
937 if(!action->is_ready())
939 synfig::error("Action not ready");
943 perform_action(action);
947 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas, synfigapp::ValueDesc value_desc, float location)
949 Gtk::Menu& parammenu(*menu);
951 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
953 if(!canvas_interface)
956 synfigapp::Action::ParamList param_list,param_list2;
957 param_list=canvas_interface->generate_param_list(value_desc);
958 param_list.add("origin",location);
960 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
962 param_list2=canvas_interface->generate_param_list(
963 synfigapp::ValueDesc(
964 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
968 param_list2.add("origin",location);
972 // Populate the convert menu by looping through
973 // the ValueNode book and find the ones that are
976 Gtk::Menu *convert_menu=manage(new Gtk::Menu());
977 LinkableValueNode::Book::const_iterator iter;
978 for(iter=LinkableValueNode::book().begin();iter!=LinkableValueNode::book().end();++iter)
980 if(iter->second.check_type(value_desc.get_value_type()))
982 convert_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->second.local_name,
986 sigc::mem_fun(*canvas_interface.get(),&synfigapp::CanvasInterface::convert),
996 parammenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::CONVERT,*convert_menu));
999 if(param_list2.empty())
1000 add_actions_to_menu(¶mmenu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1002 add_actions_to_menu(¶mmenu, param_list2,param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1004 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
1006 value_desc=synfigapp::ValueDesc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),0);
1009 if(value_desc.is_value_node() && ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
1011 ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()));
1015 WaypointList::iterator iter(value_node->find(canvas->get_time()));
1016 parammenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoint"),
1020 sigc::mem_fun(*find_canvas_view(canvas),&studio::CanvasView::on_waypoint_clicked),
1036 edit_several_waypoints(etl::handle<CanvasView> canvas_view, std::list<synfigapp::ValueDesc> value_desc_list)
1038 etl::handle<synfigapp::CanvasInterface> canvas_interface(canvas_view->canvas_interface());
1041 "Edit Multiple Waypoints", // Title
1043 true // use_separator
1046 Widget_WaypointModel widget_waypoint_model;
1047 widget_waypoint_model.show();
1049 dialog.get_vbox()->pack_start(widget_waypoint_model);
1052 dialog.add_button(Gtk::StockID("gtk-apply"),1);
1053 dialog.add_button(Gtk::StockID("gtk-cancel"),0);
1057 if(dialog.run()==0 || widget_waypoint_model.get_waypoint_model().is_trivial())
1060 synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Set Waypoints"));
1062 std::list<synfigapp::ValueDesc>::iterator iter;
1063 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
1065 synfigapp::ValueDesc value_desc(*iter);
1067 if(!value_desc.is_valid())
1070 ValueNode_Animated::Handle value_node;
1072 // If this value isn't a ValueNode_Animated, but
1073 // it is somewhat constant, then go ahead and convert
1074 // it to a ValueNode_Animated.
1075 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
1078 if(value_desc.is_value_node())
1079 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
1081 value=value_desc.get_value();
1083 value_node=ValueNode_Animated::create(value,canvas_interface->get_time());
1085 synfigapp::Action::Handle action;
1087 if(!value_desc.is_value_node())
1089 action=synfigapp::Action::create("value_desc_connect");
1090 action->set_param("dest",value_desc);
1091 action->set_param("src",ValueNode::Handle(value_node));
1095 action=synfigapp::Action::create("value_node_replace");
1096 action->set_param("dest",value_desc.get_value_node());
1097 action->set_param("src",ValueNode::Handle(value_node));
1100 action->set_param("canvas",canvas_view->get_canvas());
1101 action->set_param("canvas_interface",canvas_interface);
1104 if(!canvas_interface->get_instance()->perform_action(action))
1106 canvas_view->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
1113 if(value_desc.is_value_node())
1114 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
1121 synfigapp::Action::Handle action(synfigapp::Action::create("waypoint_set_smart"));
1125 canvas_view->get_ui_interface()->error(_("Unable to find waypoint_set_smart action"));
1131 action->set_param("canvas",canvas_view->get_canvas());
1132 action->set_param("canvas_interface",canvas_interface);
1133 action->set_param("value_node",ValueNode::Handle(value_node));
1134 action->set_param("time",canvas_interface->get_time());
1135 action->set_param("model",widget_waypoint_model.get_waypoint_model());
1137 if(!canvas_interface->get_instance()->perform_action(action))
1139 canvas_view->get_ui_interface()->error(_("Unable to set a specific waypoint"));
1146 //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
1155 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas,const std::list<synfigapp::ValueDesc>& value_desc_list)
1157 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
1159 synfigapp::Action::ParamList param_list;
1160 param_list=canvas_interface->generate_param_list(value_desc_list);
1162 add_actions_to_menu(menu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1164 // Add the edit waypoints option if that might be useful
1165 if(canvas->rend_desc().get_time_end()-Time::epsilon()>canvas->rend_desc().get_time_start())
1167 menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
1171 &edit_several_waypoints
1175 find_canvas_view(canvas)