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)const
190 if(synfigapp::Instance::save_as(file_name))
192 App::add_recent_file(file_name);
199 studio::Instance::save_as(const synfig::String &file_name)
201 if(synfigapp::Instance::save_as(file_name))
203 App::add_recent_file(file_name);
210 studio::Instance::save()
212 if(basename(get_file_name()).find("untitled")==0)
218 return synfigapp::Instance::save();
223 studio::Instance::dialog_save_as()
225 string filename="*.sif";
227 Canvas::Handle canvas(get_canvas());
230 OneMoment one_moment;
231 std::set<Node*>::iterator iter;
232 for(iter=canvas->parent_set.begin();iter!=canvas->parent_set.end();++iter)
234 synfig::Node* node(*iter);
235 for(;!node->parent_set.empty();node=*node->parent_set.begin())
237 Layer::Handle parent_layer(dynamic_cast<Layer*>(node));
238 if(parent_layer && parent_layer->get_canvas()->get_root()!=get_canvas())
240 App::dialog_error_blocking("SaveAs - Error",
241 "There is currently a bug when using \"SaveAs\"\n"
242 "on a composition that is being referenced by other\n"
243 "files that are currently open. Close these\n"
244 "other files first before trying to use \"SaveAs\"."
255 // show the canvas' name if it has one, else its ID
256 while(App::dialog_save_file(_("Choose a Filename to Save As") +
258 (canvas->get_name().empty()
260 : canvas->get_name()) +
263 // If the filename still has wildcards, then we should
264 // continue looking for the file we want
265 if(find(filename.begin(),filename.end(),'*')!=filename.end())
268 std::string base = basename(filename);
269 if(find(base.begin(),base.end(),'.')==base.end())
274 String ext(String(filename.begin()+filename.find_last_of('.')+1,filename.end()));
275 if(ext!="sif" && ext!="sifz" && !App::dialog_yes_no(_("Unknown extension"),
276 _("You have given the file name an extension\nwhich I do not recognise. Are you sure this is what you want?")))
288 // if stat() succeeds, or it fails with something other than 'file doesn't exist', the file exists
289 // if the file exists and the user doesn't want to overwrite it, keep prompting for a filename
290 if ((stat(filename.c_str(), &s) != -1 || errno != ENOENT) &&
291 !App::dialog_yes_no("File exists",
294 "' already exists.\n\n"
295 "Do you want to replace it with the file you are saving?"))
299 if(save_as(filename))
302 App::dialog_error_blocking("SaveAs - Error","Unable to save file");
307 Instance::update_all_titles()
309 list<handle<CanvasView> >::iterator iter;
310 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
311 (*iter)->update_title();
317 // This will increase the reference count so we don't get DELETED
318 // until we are ready
319 handle<Instance> me(this);
321 // Make sure we aren't selected as the current instance
322 if(studio::App::get_selected_instance()==this)
323 studio::App::set_selected_instance(0);
325 // Turn-off/clean-up auto recovery
326 studio::App::auto_recover->clear_backup(get_canvas());
328 // Remove us from the active instance list
329 std::list<etl::handle<studio::Instance> >::iterator iter;
330 for(iter=studio::App::instance_list.begin();iter!=studio::App::instance_list.end();iter++)
333 assert(iter!=studio::App::instance_list.end());
334 if(iter!=studio::App::instance_list.end())
335 studio::App::instance_list.erase(iter);
337 // Send out a signal that we are being deleted
338 studio::App::signal_instance_deleted()(this);
340 // Hide all of the canvas views
341 for(std::list<etl::handle<CanvasView> >::iterator iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
344 // Consume pending events before deleting the canvas views
345 while(studio::App::events_pending())studio::App::iteration(false);
347 // Delete all of the canvas views
348 canvas_view_list().clear();
350 // If there is another open instance to select,
351 // go ahead and do so. If not, never mind.
352 if(studio::App::instance_list.empty())
354 studio::App::set_selected_canvas_view(0);
355 studio::App::set_selected_instance(0);
359 studio::App::set_selected_canvas_view(studio::App::instance_list.front()->canvas_view_list().front());
360 //studio::App::set_selected_instance(studio::App::instance_list.front());
366 Instance::insert_canvas(Gtk::TreeRow row,Canvas::Handle canvas)
368 CanvasTreeModel canvas_tree_model;
371 row[canvas_tree_model.icon] = Gtk::Button().render_icon(Gtk::StockID("synfig-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
372 row[canvas_tree_model.id] = canvas->get_id();
373 row[canvas_tree_model.name] = canvas->get_name();
374 if(canvas->is_root())
375 row[canvas_tree_model.label] = basename(canvas->get_file_name());
377 if(!canvas->get_id().empty())
378 row[canvas_tree_model.label] = canvas->get_id();
380 if(!canvas->get_name().empty())
381 row[canvas_tree_model.label] = canvas->get_name();
383 row[canvas_tree_model.label] = _("[Unnamed]");
385 row[canvas_tree_model.canvas] = canvas;
386 row[canvas_tree_model.is_canvas] = true;
387 row[canvas_tree_model.is_value_node] = false;
390 synfig::Canvas::Children::iterator iter;
391 synfig::Canvas::Children &children(canvas->children());
393 for(iter=children.begin();iter!=children.end();iter++)
394 insert_canvas(*(canvas_tree_store()->append(row.children())),*iter);
398 if(!canvas->value_node_list().empty())
400 Gtk::TreeRow valuenode_row = *(canvas_tree_store()->append(row.children()));
402 valuenode_row[canvas_tree_model.label] = "<defs>";
403 valuenode_row[canvas_tree_model.canvas] = canvas;
404 valuenode_row[canvas_tree_model.is_canvas] = false;
405 valuenode_row[canvas_tree_model.is_value_node] = false;
407 synfig::ValueNodeList::iterator iter;
408 synfig::ValueNodeList &value_node_list(canvas->value_node_list());
410 for(iter=value_node_list.begin();iter!=value_node_list.end();iter++)
411 insert_value_node(*(canvas_tree_store()->append(valuenode_row.children())),canvas,*iter);
419 Instance::insert_value_node(Gtk::TreeRow row,Canvas::Handle canvas,etl::handle<synfig::ValueNode> value_node)
421 CanvasTreeModel canvas_tree_model;
425 row[canvas_tree_model.id] = value_node->get_id();
426 row[canvas_tree_model.name] = value_node->get_id();
427 row[canvas_tree_model.label] = value_node->get_id();
428 row[canvas_tree_model.canvas] = canvas;
429 row[canvas_tree_model.value_node] = value_node;
430 row[canvas_tree_model.is_canvas] = false;
431 row[canvas_tree_model.is_value_node] = true;
432 row[canvas_tree_model.icon] = Gtk::Button().render_icon(valuenode_icon(value_node),Gtk::ICON_SIZE_SMALL_TOOLBAR);
437 Instance::refresh_canvas_tree()
439 canvas_tree_store()->clear();
440 Gtk::TreeRow row = *(canvas_tree_store()->prepend());
441 insert_canvas(row,get_canvas());
445 Instance::dialog_cvs_commit()
447 calc_repository_info();
450 App::dialog_error_blocking(_("Error"),_("You must first add this composition to the repository"));
457 if(synfigapp::Instance::get_action_count())
459 if(!App::dialog_yes_no(_("CVS Commit"), _("This will save any changes you have made. Are you sure?")))
466 App::dialog_error_blocking(_("Error"),_("The local copy of the file hasn't been changed since the last update.\nNothing to commit!"));
470 if(!App::dialog_entry(_("CVS Commit"),_("Enter a log message describing the changes you have made"), message))
473 OneMoment one_moment;
478 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to COMMIT"));
484 Instance::dialog_cvs_add()
486 calc_repository_info();
489 App::dialog_error_blocking(_("Error"),_("This composition has already been added to the repository"));
496 //if(!App::dialog_entry(_("CVS Add"),_("Enter a log message describing the file"), message))
498 OneMoment one_moment;
503 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to ADD"));
509 Instance::dialog_cvs_update()
511 calc_repository_info();
514 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to update from!"));
519 App::dialog_error_blocking(_("Info"),_("This file is up-to-date"));
525 String filename(get_file_name());
526 if(synfigapp::Instance::get_action_count())
528 if(!App::dialog_yes_no(_("CVS Update"), _("This will save any changes you have made. Are you sure?")))
532 OneMoment one_moment;
533 time_t oldtime=get_original_timestamp();
535 calc_repository_info();
536 // If something has been updated...
537 if(oldtime!=get_original_timestamp())
544 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
546 //update_all_titles();
550 Instance::dialog_cvs_revert()
552 calc_repository_info();
555 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to revert to!"));
560 String filename(get_file_name());
561 if(!App::dialog_yes_no(_("CVS Revert"),
562 _("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?")
566 OneMoment one_moment;
568 // Remove the old file
569 if(remove(get_file_name().c_str())!=0)
571 App::dialog_error_blocking(_("Error"),_("Unable to remove previous version"));
580 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
582 //update_all_titles();
586 Instance::_revert(Instance *instance)
588 OneMoment one_moment;
590 String filename(instance->get_file_name());
592 Canvas::Handle canvas(instance->get_canvas());
596 if(canvas->count()!=1)
599 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."));
610 // Schedule a revert to occur in a few moments
611 Glib::signal_timeout().connect(
614 sigc::ptr_fun(&Instance::_revert),
624 Instance::safe_revert()
626 if(synfigapp::Instance::get_action_count())
627 if(!App::dialog_yes_no(_("Revert to saved"), _("You will lose any changes you have made since your last save.\nAre you sure?")))
634 Instance::safe_close()
636 handle<synfigapp::UIInterface> uim;
637 uim=find_canvas_view(get_canvas())->get_ui_interface();
639 if(get_action_count())
641 string str=strprintf(_("Would you like to save your changes to %s?"),basename(get_file_name()).c_str() );
642 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)
651 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());
652 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
654 if(answer==synfigapp::UIInterface::RESPONSE_YES)
656 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
667 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
669 synfigapp::Action::CandidateList candidate_list;
670 synfigapp::Action::CandidateList::iterator iter;
672 candidate_list=compile_candidate_list(param_list,category);
674 candidate_list.sort();
676 if(candidate_list.empty())
677 synfig::warning("Action CandidateList is empty!");
679 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
681 Gtk::StockID stock_id(get_action_stock_id(*iter));
683 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
685 action_group->add(Gtk::Action::create(
686 "action-"+iter->name,
688 iter->local_name,iter->local_name
693 *const_cast<studio::Instance*>(this),
694 &studio::Instance::process_action
701 ui_info+=strprintf("<menuitem action='action-%s' />",iter->name.c_str());
707 Instance::add_actions_to_menu(Gtk::Menu *menu, const synfigapp::Action::ParamList ¶m_list,synfigapp::Action::Category category)const
709 synfigapp::Action::CandidateList candidate_list;
710 synfigapp::Action::CandidateList::iterator iter;
712 candidate_list=compile_candidate_list(param_list,category);
714 candidate_list.sort();
716 if(candidate_list.empty())
717 synfig::warning("Action CandidateList is empty!");
719 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
721 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
723 Gtk::Image* image(manage(new Gtk::Image()));
724 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
727 if(iter->task=="raise")
728 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
729 else if(iter->task=="lower")
730 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
731 else if(iter->task=="move_top")
732 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
733 else if(iter->task=="move_bottom")
734 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
735 else if(iter->task=="remove")
736 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
737 else if(iter->task=="set_on")
738 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
739 else if(iter->task=="set_off")
740 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
741 else if(iter->task=="duplicate")
742 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
743 else if(iter->task=="remove")
744 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
747 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
748 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
749 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
752 menu->items().push_back(
753 Gtk::Menu_Helpers::ImageMenuElem(
759 *const_cast<studio::Instance*>(this),
760 &studio::Instance::process_action
773 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
775 synfigapp::Action::CandidateList candidate_list;
776 synfigapp::Action::CandidateList candidate_list2;
778 synfigapp::Action::CandidateList::iterator iter;
780 candidate_list=compile_candidate_list(param_list,category);
781 candidate_list2=compile_candidate_list(param_list2,category);
783 candidate_list.sort();
785 if(candidate_list.empty())
786 synfig::warning("Action CandidateList is empty!");
787 if(candidate_list2.empty())
788 synfig::warning("Action CandidateList2 is empty!");
790 // Seperate out the candidate lists so that there are no conflicts
791 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
793 synfigapp::Action::CandidateList::iterator iter2(candidate_list2.find(iter->name));
794 if(iter2!=candidate_list2.end())
795 candidate_list2.erase(iter2);
798 for(iter=candidate_list2.begin();iter!=candidate_list2.end();++iter)
800 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
802 Gtk::Image* image(manage(new Gtk::Image()));
803 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
805 /* if(iter->task=="raise")
806 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
807 else if(iter->task=="lower")
808 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
809 else if(iter->task=="move_top")
810 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
811 else if(iter->task=="move_bottom")
812 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
813 else if(iter->task=="remove")
814 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
815 else if(iter->task=="set_on")
816 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
817 else if(iter->task=="set_off")
818 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
819 else if(iter->task=="duplicate")
820 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
821 else if(iter->task=="remove")
822 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
825 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
826 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
827 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
830 menu->items().push_back(
831 Gtk::Menu_Helpers::ImageMenuElem(
837 *const_cast<studio::Instance*>(this),
838 &studio::Instance::process_action
849 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
851 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
853 Gtk::Image* image(manage(new Gtk::Image()));
854 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
855 /* if(iter->task=="raise")
856 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
857 else if(iter->task=="lower")
858 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
859 else if(iter->task=="move_top")
860 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
861 else if(iter->task=="move_bottom")
862 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
863 else if(iter->task=="remove")
864 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
865 else if(iter->task=="set_on")
866 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
867 else if(iter->task=="set_off")
868 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
869 else if(iter->task=="duplicate")
870 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
871 else if(iter->task=="remove")
872 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
875 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
876 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
877 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
880 menu->items().push_back(
881 Gtk::Menu_Helpers::ImageMenuElem(
887 *const_cast<studio::Instance*>(this),
888 &studio::Instance::process_action
901 Instance::process_action(String name, synfigapp::Action::ParamList param_list)
903 assert(synfigapp::Action::book().count(name));
905 synfigapp::Action::BookEntry entry(synfigapp::Action::book().find(name)->second);
907 synfigapp::Action::Handle action(entry.factory());
911 synfig::error("Bad Action");
915 action->set_param_list(param_list);
917 synfigapp::Action::ParamVocab param_vocab(entry.get_param_vocab());
918 synfigapp::Action::ParamVocab::const_iterator iter;
920 for(iter=param_vocab.begin();iter!=param_vocab.end();++iter)
922 if(!iter->get_mutual_exclusion().empty() && param_list.count(iter->get_mutual_exclusion()))
925 // If the parameter is optionally user-supplied,
926 // and has not been already provided in the param_list,
927 // then we should go ahead and see if we can
928 // provide that data.
929 if(iter->get_user_supplied() && param_list.count(iter->get_name())==0)
931 switch(iter->get_type())
933 case synfigapp::Action::Param::TYPE_STRING:
936 if(!studio::App::dialog_entry(entry.local_name, iter->get_local_name()+":"+iter->get_desc(),str))
938 action->set_param(iter->get_name(),str);
942 synfig::error("Unsupported user-supplied action parameter");
949 if(!action->is_ready())
951 synfig::error("Action not ready");
955 perform_action(action);
959 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas, synfigapp::ValueDesc value_desc, float location)
961 Gtk::Menu& parammenu(*menu);
963 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
965 if(!canvas_interface)
968 synfigapp::Action::ParamList param_list,param_list2;
969 param_list=canvas_interface->generate_param_list(value_desc);
970 param_list.add("origin",location);
972 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
974 param_list2=canvas_interface->generate_param_list(
975 synfigapp::ValueDesc(
976 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
980 param_list2.add("origin",location);
984 // Populate the convert menu by looping through
985 // the ValueNode book and find the ones that are
988 Gtk::Menu *convert_menu=manage(new Gtk::Menu());
989 LinkableValueNode::Book::const_iterator iter;
990 for(iter=LinkableValueNode::book().begin();iter!=LinkableValueNode::book().end();++iter)
992 if(iter->second.check_type(value_desc.get_value_type()))
994 convert_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->second.local_name,
998 sigc::mem_fun(*canvas_interface.get(),&synfigapp::CanvasInterface::convert),
1008 parammenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::CONVERT,*convert_menu));
1011 if(param_list2.empty())
1012 add_actions_to_menu(¶mmenu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1014 add_actions_to_menu(¶mmenu, param_list2,param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1016 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
1018 value_desc=synfigapp::ValueDesc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),0);
1021 if(value_desc.is_value_node() && ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
1023 ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()));
1027 WaypointList::iterator iter(value_node->find(canvas->get_time()));
1028 parammenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoint"),
1032 sigc::mem_fun(*find_canvas_view(canvas),&studio::CanvasView::on_waypoint_clicked),
1048 edit_several_waypoints(etl::handle<CanvasView> canvas_view, std::list<synfigapp::ValueDesc> value_desc_list)
1050 etl::handle<synfigapp::CanvasInterface> canvas_interface(canvas_view->canvas_interface());
1053 "Edit Multiple Waypoints", // Title
1055 true // use_separator
1058 Widget_WaypointModel widget_waypoint_model;
1059 widget_waypoint_model.show();
1061 dialog.get_vbox()->pack_start(widget_waypoint_model);
1064 dialog.add_button(Gtk::StockID("gtk-apply"),1);
1065 dialog.add_button(Gtk::StockID("gtk-cancel"),0);
1069 if(dialog.run()==0 || widget_waypoint_model.get_waypoint_model().is_trivial())
1072 synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Set Waypoints"));
1074 std::list<synfigapp::ValueDesc>::iterator iter;
1075 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
1077 synfigapp::ValueDesc value_desc(*iter);
1079 if(!value_desc.is_valid())
1082 ValueNode_Animated::Handle value_node;
1084 // If this value isn't a ValueNode_Animated, but
1085 // it is somewhat constant, then go ahead and convert
1086 // it to a ValueNode_Animated.
1087 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
1090 if(value_desc.is_value_node())
1091 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
1093 value=value_desc.get_value();
1095 value_node=ValueNode_Animated::create(value,canvas_interface->get_time());
1097 synfigapp::Action::Handle action;
1099 if(!value_desc.is_value_node())
1101 action=synfigapp::Action::create("value_desc_connect");
1102 action->set_param("dest",value_desc);
1103 action->set_param("src",ValueNode::Handle(value_node));
1107 action=synfigapp::Action::create("value_node_replace");
1108 action->set_param("dest",value_desc.get_value_node());
1109 action->set_param("src",ValueNode::Handle(value_node));
1112 action->set_param("canvas",canvas_view->get_canvas());
1113 action->set_param("canvas_interface",canvas_interface);
1116 if(!canvas_interface->get_instance()->perform_action(action))
1118 canvas_view->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
1125 if(value_desc.is_value_node())
1126 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
1133 synfigapp::Action::Handle action(synfigapp::Action::create("waypoint_set_smart"));
1137 canvas_view->get_ui_interface()->error(_("Unable to find waypoint_set_smart action"));
1143 action->set_param("canvas",canvas_view->get_canvas());
1144 action->set_param("canvas_interface",canvas_interface);
1145 action->set_param("value_node",ValueNode::Handle(value_node));
1146 action->set_param("time",canvas_interface->get_time());
1147 action->set_param("model",widget_waypoint_model.get_waypoint_model());
1149 if(!canvas_interface->get_instance()->perform_action(action))
1151 canvas_view->get_ui_interface()->error(_("Unable to set a specific waypoint"));
1158 //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
1167 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas,const std::list<synfigapp::ValueDesc>& value_desc_list)
1169 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
1171 synfigapp::Action::ParamList param_list;
1172 param_list=canvas_interface->generate_param_list(value_desc_list);
1174 add_actions_to_menu(menu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1176 // Add the edit waypoints option if that might be useful
1177 if(canvas->rend_desc().get_time_end()-Time::epsilon()>canvas->rend_desc().get_time_start())
1179 menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
1183 &edit_several_waypoints
1187 find_canvas_view(canvas)