1 /* === S Y N F I G ========================================================= */
2 /*! \file gtkmm/instance.cpp
8 ** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 ** Copyright (c) 2007 Chris Moore
11 ** This package is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU General Public License as
13 ** published by the Free Software Foundation; either version 2 of
14 ** the License, or (at your option) any later version.
16 ** This package is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** General Public License for more details.
22 /* ========================================================================= */
24 /* === H E A D E R S ======================================================= */
35 #include <gtkmm/stock.h>
36 #include <gtkmm/image.h>
38 #include <gtkmm/button.h>
39 #include "canvasview.h"
41 #include <sigc++/signal.h>
42 #include <sigc++/adaptors/hide.h>
44 #include "onemoment.h"
46 #include "autorecover.h"
47 #include <sigc++/retype_return.h>
48 #include <sigc++/retype.h>
49 //#include <sigc++/hide.h>
50 #include <synfig/valuenode_composite.h>
51 #include "widget_waypointmodel.h"
52 #include <gtkmm/actiongroup.h>
53 #include "iconcontroller.h"
61 using namespace synfig;
62 using namespace studio;
65 /* === M A C R O S ========================================================= */
67 /* === G L O B A L S ======================================================= */
69 int studio::Instance::instance_count_=0;
71 /* === P R O C E D U R E S ================================================= */
73 /* === M E T H O D S ======================================================= */
75 Instance::Instance(Canvas::Handle canvas):
76 synfigapp::Instance (canvas),
77 // canvas_tree_store_ (Gtk::TreeStore::create(CanvasTreeModel())),
78 // canvas_tree_store_ (Gtk::TreeStore::create()),
79 history_tree_store_ (HistoryTreeStore::create(this)),
83 CanvasTreeModel model;
84 canvas_tree_store_=Gtk::TreeStore::create(model);
86 id_=instance_count_++;
88 // Connect up all the signals
89 signal_filename_changed().connect(sigc::mem_fun(*this,&studio::Instance::update_all_titles));
90 signal_unsaved_status_changed().connect(sigc::hide(sigc::mem_fun(*this,&studio::Instance::update_all_titles)));
91 signal_undo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_undo_status));
92 signal_redo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_redo_status));
94 signal_saved().connect(
97 studio::AutoRecover::auto_backup
102 canvas_tree_store_=Gtk::TreeStore::create(canvas_tree_model);
104 refresh_canvas_tree();
107 Instance::~Instance()
112 Instance::get_visible_canvases()const
115 CanvasViewList::const_iterator iter;
116 for(iter=canvas_view_list_.begin();iter!=canvas_view_list_.end();++iter)
117 if((*iter)->is_visible())
123 Instance::create(Canvas::Handle canvas)
125 // Construct a new instance
126 handle<Instance> instance(new Instance(canvas));
128 // Add the new instance to the application's instance list
129 App::instance_list.push_back(instance);
131 // Set up the instance with the default UI manager
132 instance->synfigapp::Instance::set_ui_interface(App::get_ui_interface());
134 // Signal the new instance
135 App::signal_instance_created()(instance);
137 // And then make sure that is has been selected
138 App::set_selected_instance(instance);
140 // Create the initial window for the root canvas
141 instance->focus(canvas);
147 Instance::find_canvas_view(Canvas::Handle canvas)
152 while(canvas->is_inline())
153 canvas=canvas->parent();
155 CanvasViewList::iterator iter;
157 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
158 if((*iter)->get_canvas()==canvas)
161 return CanvasView::create(this,canvas);
165 Instance::focus(Canvas::Handle canvas)
167 handle<CanvasView> canvas_view=find_canvas_view(canvas);
169 canvas_view->present();
173 Instance::set_undo_status(bool x)
176 App::toolbox->update_undo_redo();
177 signal_undo_redo_status_changed()();
181 Instance::set_redo_status(bool x)
184 App::toolbox->update_undo_redo();
185 signal_undo_redo_status_changed()();
189 studio::Instance::save_as(const synfig::String &file_name)
191 if(synfigapp::Instance::save_as(file_name))
193 // after changing the filename, update the render settings with the new filename
194 list<handle<CanvasView> >::iterator iter;
195 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
196 (*iter)->render_settings.set_entry_filename();
197 App::add_recent_file(file_name);
204 studio::Instance::save()
206 // the filename will be set to "Synfig Animation 1" or some such when first created
207 // and will be changed to an absolute path once it has been saved
208 // so if it still begins with "Synfig Animation " then we need to ask where to save it
209 if(get_file_name().find(DEFAULT_FILENAME_PREFIX)==0)
210 if (dialog_save_as())
213 return STATUS_CANCEL;
215 if (synfigapp::Instance::save())
218 App::dialog_error_blocking("Save - Error","Unable to save to '" + get_file_name() + "'");
223 studio::Instance::dialog_save_as()
225 string filename=basename(get_file_name());
226 Canvas::Handle canvas(get_canvas());
229 OneMoment one_moment;
230 std::set<Node*>::iterator iter;
231 for(iter=canvas->parent_set.begin();iter!=canvas->parent_set.end();++iter)
233 synfig::Node* node(*iter);
234 for(;!node->parent_set.empty();node=*node->parent_set.begin())
236 Layer::Handle parent_layer(dynamic_cast<Layer*>(node));
237 if(parent_layer && parent_layer->get_canvas()->get_root()!=get_canvas())
239 App::dialog_error_blocking("SaveAs - Error",
240 "There is currently a bug when using \"SaveAs\"\n"
241 "on a composition that is being referenced by other\n"
242 "files that are currently open. Close these\n"
243 "other files first before trying to use \"SaveAs\"."
254 // show the canvas' name if it has one, else its ID
255 while(App::dialog_save_file(_("Choose a Filename to Save As") +
257 (canvas->get_name().empty()
259 : canvas->get_name()) +
262 // If the filename still has wildcards, then we should
263 // continue looking for the file we want
264 if(find(filename.begin(),filename.end(),'*')!=filename.end())
267 if (filename_extension(filename) == "")
272 String ext(filename_extension(filename));
273 if(ext!=".sif" && ext!=".sifz" && !App::dialog_yes_no(_("Unknown extension"),
274 _("You have given the file name an extension\nwhich I do not recognize. Are you sure this is what you want?")))
284 int stat_return = stat(filename.c_str(), &s);
286 // if stat() fails with something other than 'file doesn't exist', there's been a real
287 // error of some kind. let's give up now and ask for a new path.
288 if (stat_return == -1 && errno != ENOENT)
290 perror(filename.c_str());
291 App::dialog_error_blocking("SaveAs - Error","Unable to check whether '" + filename + "' exists.");
295 // if the file exists and the user doesn't want to overwrite it, keep prompting for a filename
296 if ((stat_return == 0) &&
297 !App::dialog_yes_no("File exists",
300 "' already exists.\n\n"
301 "Do you want to replace it with the file you are saving?"))
305 if(save_as(filename))
308 App::dialog_error_blocking("SaveAs - Error","Unable to save to '" + filename + "'");
315 Instance::update_all_titles()
317 list<handle<CanvasView> >::iterator iter;
318 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
319 (*iter)->update_title();
325 // This will increase the reference count so we don't get DELETED
326 // until we are ready
327 handle<Instance> me(this);
329 // Make sure we aren't selected as the current instance
330 if(studio::App::get_selected_instance()==this)
331 studio::App::set_selected_instance(0);
333 // Turn-off/clean-up auto recovery
334 studio::App::auto_recover->clear_backup(get_canvas());
336 // Remove us from the active instance list
337 std::list<etl::handle<studio::Instance> >::iterator iter;
338 for(iter=studio::App::instance_list.begin();iter!=studio::App::instance_list.end();iter++)
341 assert(iter!=studio::App::instance_list.end());
342 if(iter!=studio::App::instance_list.end())
343 studio::App::instance_list.erase(iter);
345 // Send out a signal that we are being deleted
346 studio::App::signal_instance_deleted()(this);
348 // Hide all of the canvas views
349 for(std::list<etl::handle<CanvasView> >::iterator iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
352 // Consume pending events before deleting the canvas views
353 while(studio::App::events_pending())studio::App::iteration(false);
355 // Delete all of the canvas views
356 canvas_view_list().clear();
358 // If there is another open instance to select,
359 // go ahead and do so. If not, never mind.
360 if(studio::App::instance_list.empty())
362 studio::App::set_selected_canvas_view(0);
363 studio::App::set_selected_instance(0);
366 studio::App::instance_list.front()->canvas_view_list().front()->present();
371 Instance::insert_canvas(Gtk::TreeRow row,Canvas::Handle canvas)
373 CanvasTreeModel canvas_tree_model;
376 row[canvas_tree_model.icon] = Gtk::Button().render_icon(Gtk::StockID("synfig-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
377 row[canvas_tree_model.id] = canvas->get_id();
378 row[canvas_tree_model.name] = canvas->get_name();
379 if(canvas->is_root())
380 row[canvas_tree_model.label] = basename(canvas->get_file_name());
382 if(!canvas->get_id().empty())
383 row[canvas_tree_model.label] = canvas->get_id();
385 if(!canvas->get_name().empty())
386 row[canvas_tree_model.label] = canvas->get_name();
388 row[canvas_tree_model.label] = _("[Unnamed]");
390 row[canvas_tree_model.canvas] = canvas;
391 row[canvas_tree_model.is_canvas] = true;
392 row[canvas_tree_model.is_value_node] = false;
395 synfig::Canvas::Children::iterator iter;
396 synfig::Canvas::Children &children(canvas->children());
398 for(iter=children.begin();iter!=children.end();iter++)
399 insert_canvas(*(canvas_tree_store()->append(row.children())),*iter);
403 if(!canvas->value_node_list().empty())
405 Gtk::TreeRow valuenode_row = *(canvas_tree_store()->append(row.children()));
407 valuenode_row[canvas_tree_model.label] = "<defs>";
408 valuenode_row[canvas_tree_model.canvas] = canvas;
409 valuenode_row[canvas_tree_model.is_canvas] = false;
410 valuenode_row[canvas_tree_model.is_value_node] = false;
412 synfig::ValueNodeList::iterator iter;
413 synfig::ValueNodeList &value_node_list(canvas->value_node_list());
415 for(iter=value_node_list.begin();iter!=value_node_list.end();iter++)
416 insert_value_node(*(canvas_tree_store()->append(valuenode_row.children())),canvas,*iter);
424 Instance::insert_value_node(Gtk::TreeRow row,Canvas::Handle canvas,etl::handle<synfig::ValueNode> value_node)
426 CanvasTreeModel canvas_tree_model;
430 row[canvas_tree_model.id] = value_node->get_id();
431 row[canvas_tree_model.name] = value_node->get_id();
432 row[canvas_tree_model.label] = value_node->get_id();
433 row[canvas_tree_model.canvas] = canvas;
434 row[canvas_tree_model.value_node] = value_node;
435 row[canvas_tree_model.is_canvas] = false;
436 row[canvas_tree_model.is_value_node] = true;
437 row[canvas_tree_model.icon] = Gtk::Button().render_icon(valuenode_icon(value_node),Gtk::ICON_SIZE_SMALL_TOOLBAR);
442 Instance::refresh_canvas_tree()
444 canvas_tree_store()->clear();
445 Gtk::TreeRow row = *(canvas_tree_store()->prepend());
446 insert_canvas(row,get_canvas());
450 Instance::dialog_cvs_commit()
452 calc_repository_info();
455 App::dialog_error_blocking(_("Error"),_("You must first add this composition to the repository"));
462 if(synfigapp::Instance::get_action_count())
464 if(!App::dialog_yes_no(_("CVS Commit"), _("This will save any changes you have made. Are you sure?")))
471 App::dialog_error_blocking(_("Error"),_("The local copy of the file hasn't been changed since the last update.\nNothing to commit!"));
475 if(!App::dialog_entry(_("CVS Commit"),_("Enter a log message describing the changes you have made"), message))
478 OneMoment one_moment;
483 App::dialog_error_blocking(_("Error"),_("An error has occurred when trying to COMMIT"));
489 Instance::dialog_cvs_add()
491 calc_repository_info();
494 App::dialog_error_blocking(_("Error"),_("This composition has already been added to the repository"));
501 //if(!App::dialog_entry(_("CVS Add"),_("Enter a log message describing the file"), message))
503 OneMoment one_moment;
508 App::dialog_error_blocking(_("Error"),_("An error has occurred when trying to ADD"));
514 Instance::dialog_cvs_update()
516 calc_repository_info();
519 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to update from!"));
524 App::dialog_error_blocking(_("Info"),_("This file is up-to-date"));
530 String filename(get_file_name());
531 if(synfigapp::Instance::get_action_count())
533 if(!App::dialog_yes_no(_("CVS Update"), _("This will save any changes you have made. Are you sure?")))
537 OneMoment one_moment;
538 time_t oldtime=get_original_timestamp();
540 calc_repository_info();
541 // If something has been updated...
542 if(oldtime!=get_original_timestamp())
549 App::dialog_error_blocking(_("Error"),_("An error has occurred when trying to UPDATE"));
551 //update_all_titles();
555 Instance::dialog_cvs_revert()
557 calc_repository_info();
560 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to revert to!"));
565 String filename(get_file_name());
566 if(!App::dialog_yes_no(_("CVS Revert"),
567 _("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?")
571 OneMoment one_moment;
573 // Remove the old file
574 if(remove(get_file_name().c_str())!=0)
576 App::dialog_error_blocking(_("Error"),_("Unable to remove previous version"));
585 App::dialog_error_blocking(_("Error"),_("An error has occurred when trying to UPDATE"));
587 //update_all_titles();
591 Instance::_revert(Instance *instance)
593 OneMoment one_moment;
595 String filename(instance->get_file_name());
597 Canvas::Handle canvas(instance->get_canvas());
601 if(canvas->count()!=1)
604 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."));
615 // Schedule a revert to occur in a few moments
616 Glib::signal_timeout().connect(
619 sigc::ptr_fun(&Instance::_revert),
629 Instance::safe_revert()
631 if(synfigapp::Instance::get_action_count())
632 if(!App::dialog_yes_no(_("Revert to saved"), _("You will lose any changes you have made since your last save.\nAre you sure?")))
639 Instance::safe_close()
641 handle<CanvasView> canvas_view = find_canvas_view(get_canvas());
642 handle<synfigapp::UIInterface> uim=canvas_view->get_ui_interface();
644 // if the animation is currently playing, closing the window will cause a crash,
646 if (canvas_view->is_playing())
648 canvas_view->present();
649 App::dialog_error_blocking("Close Error", "The animation is currently playing so the window cannot be closed.");
652 if(get_action_count())
655 string str=strprintf(_("Would you like to save your changes to %s?"),basename(get_file_name()).c_str() );
656 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
657 if(answer==synfigapp::UIInterface::RESPONSE_YES)
659 enum Status status = save();
660 if (status == STATUS_OK) break;
661 else if (status == STATUS_CANCEL) return false;
663 if(answer==synfigapp::UIInterface::RESPONSE_NO)
665 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
671 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());
672 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,synfigapp::UIInterface::RESPONSE_YES);
674 if(answer==synfigapp::UIInterface::RESPONSE_YES)
676 if(answer==synfigapp::UIInterface::RESPONSE_CANCEL)
687 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
689 synfigapp::Action::CandidateList candidate_list;
690 synfigapp::Action::CandidateList::iterator iter;
692 candidate_list=compile_candidate_list(param_list,category);
694 candidate_list.sort();
696 if(candidate_list.empty())
697 synfig::warning("%s:%d Action CandidateList is empty!", __FILE__, __LINE__);
699 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
701 Gtk::StockID stock_id(get_action_stock_id(*iter));
703 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
705 action_group->add(Gtk::Action::create(
706 "action-"+iter->name,
708 iter->local_name,iter->local_name
713 *const_cast<studio::Instance*>(this),
714 &studio::Instance::process_action
721 ui_info+=strprintf("<menuitem action='action-%s' />",iter->name.c_str());
727 Instance::add_actions_to_menu(Gtk::Menu *menu, const synfigapp::Action::ParamList ¶m_list,synfigapp::Action::Category category)const
729 synfigapp::Action::CandidateList candidate_list;
730 synfigapp::Action::CandidateList::iterator iter;
732 candidate_list=compile_candidate_list(param_list,category);
734 candidate_list.sort();
736 if(candidate_list.empty())
737 synfig::warning("%s:%d Action CandidateList is empty!", __FILE__, __LINE__);
739 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
741 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
743 Gtk::Image* image(manage(new Gtk::Image()));
744 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
747 if(iter->task=="raise")
748 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
749 else if(iter->task=="lower")
750 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
751 else if(iter->task=="move_top")
752 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
753 else if(iter->task=="move_bottom")
754 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
755 else if(iter->task=="remove")
756 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
757 else if(iter->task=="set_on")
758 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
759 else if(iter->task=="set_off")
760 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
761 else if(iter->task=="duplicate")
762 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
763 else if(iter->task=="remove")
764 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
767 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
768 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
769 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
772 menu->items().push_back(
773 Gtk::Menu_Helpers::ImageMenuElem(
779 *const_cast<studio::Instance*>(this),
780 &studio::Instance::process_action
793 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
795 synfigapp::Action::CandidateList candidate_list;
796 synfigapp::Action::CandidateList candidate_list2;
798 synfigapp::Action::CandidateList::iterator iter;
800 candidate_list=compile_candidate_list(param_list,category);
801 candidate_list2=compile_candidate_list(param_list2,category);
803 candidate_list.sort();
805 if(candidate_list.empty())
806 synfig::warning("%s:%d Action CandidateList is empty!", __FILE__, __LINE__);
807 if(candidate_list2.empty())
808 synfig::warning("%s:%d Action CandidateList2 is empty!", __FILE__, __LINE__);
810 // Separate out the candidate lists so that there are no conflicts
811 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
813 synfigapp::Action::CandidateList::iterator iter2(candidate_list2.find(iter->name));
814 if(iter2!=candidate_list2.end())
815 candidate_list2.erase(iter2);
818 for(iter=candidate_list2.begin();iter!=candidate_list2.end();++iter)
820 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
822 Gtk::Image* image(manage(new Gtk::Image()));
823 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
825 /* if(iter->task=="raise")
826 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
827 else if(iter->task=="lower")
828 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
829 else if(iter->task=="move_top")
830 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
831 else if(iter->task=="move_bottom")
832 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
833 else if(iter->task=="remove")
834 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
835 else if(iter->task=="set_on")
836 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
837 else if(iter->task=="set_off")
838 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
839 else if(iter->task=="duplicate")
840 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
841 else if(iter->task=="remove")
842 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
845 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
846 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
847 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
850 menu->items().push_back(
851 Gtk::Menu_Helpers::ImageMenuElem(
857 *const_cast<studio::Instance*>(this),
858 &studio::Instance::process_action
869 for(iter=candidate_list.begin();iter!=candidate_list.end();++iter)
871 if(!(iter->category&synfigapp::Action::CATEGORY_HIDDEN))
873 Gtk::Image* image(manage(new Gtk::Image()));
874 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
875 /* if(iter->task=="raise")
876 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
877 else if(iter->task=="lower")
878 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
879 else if(iter->task=="move_top")
880 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
881 else if(iter->task=="move_bottom")
882 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
883 else if(iter->task=="remove")
884 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
885 else if(iter->task=="set_on")
886 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
887 else if(iter->task=="set_off")
888 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
889 else if(iter->task=="duplicate")
890 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
891 else if(iter->task=="remove")
892 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
895 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
896 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
897 Gtk::Stock::lookup(Gtk::StockID("synfig-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
900 menu->items().push_back(
901 Gtk::Menu_Helpers::ImageMenuElem(
907 *const_cast<studio::Instance*>(this),
908 &studio::Instance::process_action
921 Instance::process_action(String name, synfigapp::Action::ParamList param_list)
923 assert(synfigapp::Action::book().count(name));
925 synfigapp::Action::BookEntry entry(synfigapp::Action::book().find(name)->second);
927 synfigapp::Action::Handle action(entry.factory());
931 synfig::error("Bad Action");
935 action->set_param_list(param_list);
937 synfigapp::Action::ParamVocab param_vocab(entry.get_param_vocab());
938 synfigapp::Action::ParamVocab::const_iterator iter;
940 for(iter=param_vocab.begin();iter!=param_vocab.end();++iter)
942 if(!iter->get_mutual_exclusion().empty() && param_list.count(iter->get_mutual_exclusion()))
945 // If the parameter is optionally user-supplied,
946 // and has not been already provided in the param_list,
947 // then we should go ahead and see if we can
948 // provide that data.
949 if(iter->get_user_supplied() && param_list.count(iter->get_name())==0)
951 switch(iter->get_type())
953 case synfigapp::Action::Param::TYPE_STRING:
956 if(!studio::App::dialog_entry(entry.local_name, iter->get_local_name()+":"+iter->get_desc(),str))
958 action->set_param(iter->get_name(),str);
962 synfig::error("Unsupported user-supplied action parameter");
969 if(!action->is_ready())
971 synfig::error("Action not ready");
975 perform_action(action);
979 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas, synfigapp::ValueDesc value_desc, float location)
981 Gtk::Menu& parammenu(*menu);
983 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
985 if(!canvas_interface)
988 synfigapp::Action::ParamList param_list,param_list2;
989 param_list=canvas_interface->generate_param_list(value_desc);
990 param_list.add("origin",location);
992 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
994 param_list2=canvas_interface->generate_param_list(
995 synfigapp::ValueDesc(
996 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
1000 param_list2.add("origin",location);
1004 // Populate the convert menu by looping through
1005 // the ValueNode book and find the ones that are
1008 Gtk::Menu *convert_menu=manage(new Gtk::Menu());
1009 LinkableValueNode::Book::const_iterator iter;
1010 for(iter=LinkableValueNode::book().begin();iter!=LinkableValueNode::book().end();++iter)
1012 if(iter->second.check_type(value_desc.get_value_type()))
1014 convert_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->second.local_name,
1018 sigc::mem_fun(*canvas_interface.get(),&synfigapp::CanvasInterface::convert),
1028 parammenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::CONVERT,*convert_menu));
1031 if(param_list2.empty())
1032 add_actions_to_menu(¶mmenu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1034 add_actions_to_menu(¶mmenu, param_list2,param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1036 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
1038 value_desc=synfigapp::ValueDesc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),0);
1041 if(value_desc.is_value_node() && ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
1043 ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()));
1047 WaypointList::iterator iter(value_node->find(canvas->get_time()));
1048 parammenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoint"),
1052 sigc::mem_fun(*find_canvas_view(canvas),&studio::CanvasView::on_waypoint_clicked),
1068 edit_several_waypoints(etl::handle<CanvasView> canvas_view, std::list<synfigapp::ValueDesc> value_desc_list)
1070 etl::handle<synfigapp::CanvasInterface> canvas_interface(canvas_view->canvas_interface());
1073 "Edit Multiple Waypoints", // Title
1075 true // use_separator
1078 Widget_WaypointModel widget_waypoint_model;
1079 widget_waypoint_model.show();
1081 dialog.get_vbox()->pack_start(widget_waypoint_model);
1084 dialog.add_button(Gtk::StockID("gtk-apply"),1);
1085 dialog.add_button(Gtk::StockID("gtk-cancel"),0);
1089 if(dialog.run()==0 || widget_waypoint_model.get_waypoint_model().is_trivial())
1092 synfigapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Set Waypoints"));
1094 std::list<synfigapp::ValueDesc>::iterator iter;
1095 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
1097 synfigapp::ValueDesc value_desc(*iter);
1099 if(!value_desc.is_valid())
1102 ValueNode_Animated::Handle value_node;
1104 // If this value isn't a ValueNode_Animated, but
1105 // it is somewhat constant, then go ahead and convert
1106 // it to a ValueNode_Animated.
1107 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
1110 if(value_desc.is_value_node())
1111 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
1113 value=value_desc.get_value();
1115 value_node=ValueNode_Animated::create(value,canvas_interface->get_time());
1117 synfigapp::Action::Handle action;
1119 if(!value_desc.is_value_node())
1121 action=synfigapp::Action::create("value_desc_connect");
1122 action->set_param("dest",value_desc);
1123 action->set_param("src",ValueNode::Handle(value_node));
1127 action=synfigapp::Action::create("value_node_replace");
1128 action->set_param("dest",value_desc.get_value_node());
1129 action->set_param("src",ValueNode::Handle(value_node));
1132 action->set_param("canvas",canvas_view->get_canvas());
1133 action->set_param("canvas_interface",canvas_interface);
1136 if(!canvas_interface->get_instance()->perform_action(action))
1138 canvas_view->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
1145 if(value_desc.is_value_node())
1146 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
1153 synfigapp::Action::Handle action(synfigapp::Action::create("waypoint_set_smart"));
1157 canvas_view->get_ui_interface()->error(_("Unable to find waypoint_set_smart action"));
1163 action->set_param("canvas",canvas_view->get_canvas());
1164 action->set_param("canvas_interface",canvas_interface);
1165 action->set_param("value_node",ValueNode::Handle(value_node));
1166 action->set_param("time",canvas_interface->get_time());
1167 action->set_param("model",widget_waypoint_model.get_waypoint_model());
1169 if(!canvas_interface->get_instance()->perform_action(action))
1171 canvas_view->get_ui_interface()->error(_("Unable to set a specific waypoint"));
1178 //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
1187 Instance::make_param_menu(Gtk::Menu *menu,synfig::Canvas::Handle canvas,const std::list<synfigapp::ValueDesc>& value_desc_list)
1189 etl::handle<synfigapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
1191 synfigapp::Action::ParamList param_list;
1192 param_list=canvas_interface->generate_param_list(value_desc_list);
1194 add_actions_to_menu(menu, param_list,synfigapp::Action::CATEGORY_VALUEDESC|synfigapp::Action::CATEGORY_VALUENODE);
1196 // Add the edit waypoints option if that might be useful
1197 if(canvas->rend_desc().get_time_end()-Time::epsilon()>canvas->rend_desc().get_time_start())
1199 menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
1203 &edit_several_waypoints
1207 find_canvas_view(canvas)