1 /* === S I N F G =========================================================== */
5 ** $Id: instance.cpp,v 1.2 2005/01/13 18:37:30 darco Exp $
8 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
10 ** This software and associated documentation
11 ** are CONFIDENTIAL and PROPRIETARY property of
12 ** the above-mentioned copyright holder.
14 ** You may not copy, print, publish, or in any
15 ** other way distribute this software without
16 ** a prior written agreement with
17 ** the copyright holder.
20 /* ========================================================================= */
22 /* === H E A D E R S ======================================================= */
33 #include <gtkmm/stock.h>
34 #include <gtkmm/image.h>
36 #include <gtkmm/button.h>
37 #include "canvasview.h"
39 #include <sigc++/signal.h>
40 #include <sigc++/adaptors/hide.h>
42 #include "onemoment.h"
44 #include "autorecover.h"
45 #include <sigc++/retype_return.h>
46 #include <sigc++/retype.h>
47 //#include <sigc++/hide.h>
48 #include <sinfg/valuenode_composite.h>
49 #include "widget_waypointmodel.h"
50 #include <gtkmm/actiongroup.h>
51 #include "iconcontroler.h"
57 using namespace sinfg;
58 using namespace studio;
61 /* === M A C R O S ========================================================= */
63 /* === G L O B A L S ======================================================= */
65 int studio::Instance::instance_count_=0;
67 /* === P R O C E D U R E S ================================================= */
69 /* === M E T H O D S ======================================================= */
71 Instance::Instance(Canvas::Handle canvas):
72 sinfgapp::Instance (canvas),
73 // canvas_tree_store_ (Gtk::TreeStore::create(CanvasTreeModel())),
74 // canvas_tree_store_ (Gtk::TreeStore::create()),
75 history_tree_store_ (HistoryTreeStore::create(this)),
79 CanvasTreeModel model;
80 canvas_tree_store_=Gtk::TreeStore::create(model);
82 id_=instance_count_++;
84 // Connect up all the signals
85 signal_filename_changed().connect(sigc::mem_fun(*this,&studio::Instance::update_all_titles));
86 signal_unsaved_status_changed().connect(sigc::hide(sigc::mem_fun(*this,&studio::Instance::update_all_titles)));
87 signal_undo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_undo_status));
88 signal_redo_status().connect(sigc::mem_fun(*this,&studio::Instance::set_redo_status));
90 signal_saved().connect(
93 studio::AutoRecover::auto_backup
98 canvas_tree_store_=Gtk::TreeStore::create(canvas_tree_model);
100 refresh_canvas_tree();
103 Instance::~Instance()
108 Instance::get_visible_canvases()const
111 CanvasViewList::const_iterator iter;
112 for(iter=canvas_view_list_.begin();iter!=canvas_view_list_.end();++iter)
113 if((*iter)->is_visible())
119 Instance::create(Canvas::Handle canvas)
121 // Construct a new instance
122 handle<Instance> instance(new Instance(canvas));
124 // Add the new instance to the application's instance list
125 App::instance_list.push_back(instance);
127 // Set up the instance with the default UI manager
128 instance->sinfgapp::Instance::set_ui_interface(App::get_ui_interface());
130 // Signal the new instance
131 App::signal_instance_created()(instance);
133 // And then make sure that is has been selected
134 App::set_selected_instance(instance);
136 // Create the initial window for the root canvas
137 instance->focus(canvas);
143 Instance::find_canvas_view(Canvas::Handle canvas)
148 while(canvas->is_inline())
149 canvas=canvas->parent();
151 CanvasViewList::iterator iter;
153 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
154 if((*iter)->get_canvas()==canvas)
157 return CanvasView::create(this,canvas);
161 Instance::focus(Canvas::Handle canvas)
163 handle<CanvasView> canvas_view=find_canvas_view(canvas);
165 canvas_view->present();
169 Instance::set_undo_status(bool x)
172 App::toolbox->update_undo_redo();
173 signal_undo_redo_status_changed()();
177 Instance::set_redo_status(bool x)
180 App::toolbox->update_undo_redo();
181 signal_undo_redo_status_changed()();
185 studio::Instance::save_as(const sinfg::String &file_name)const
187 if(sinfgapp::Instance::save_as(file_name))
189 App::add_recent_file(file_name);
196 studio::Instance::save_as(const sinfg::String &file_name)
198 if(sinfgapp::Instance::save_as(file_name))
200 App::add_recent_file(file_name);
207 studio::Instance::save()
209 if(basename(get_file_name()).find("untitled")==0)
215 return sinfgapp::Instance::save();
220 studio::Instance::dialog_save_as()
222 string filename="*.sif";
224 Canvas::Handle canvas(get_canvas());
227 OneMoment one_moment;
228 std::set<Node*>::iterator iter;
229 for(iter=canvas->parent_set.begin();iter!=canvas->parent_set.end();++iter)
231 sinfg::Node* node(*iter);
232 for(;!node->parent_set.empty();node=*node->parent_set.begin())
234 Layer::Handle parent_layer(dynamic_cast<Layer*>(node));
235 if(parent_layer && parent_layer->get_canvas()->get_root()!=get_canvas())
237 App::dialog_error_blocking("SaveAs - Error",
238 "There is currently a bug when using \"SaveAs\"\n"
239 "on a composition that is being referenced by other\n"
240 "files that are currently open. Close these\n"
241 "other files first before trying to use \"SaveAs\"."
252 while(App::dialog_saveas_file("SaveAs", filename))
254 // If the filename still has wildcards, then we should
255 // continue looking for the file we want
256 if(find(filename.begin(),filename.end(),'*')!=filename.end())
259 if(find(filename.begin(),filename.end(),'.')==filename.end())
264 String ext(String(filename.begin()+filename.find_last_of('.')+1,filename.end()));
265 if(ext!="sif" && ext!="sifz" && !App::dialog_yes_no(_("Unknown extension"),
266 _("You have given the file name an extension\nwhich I do not recognise. Are you sure this is what you want?")))
276 if(save_as(filename))
279 App::dialog_error_blocking("SaveAs - Error","Unable to save file");
284 Instance::update_all_titles()
286 list<handle<CanvasView> >::iterator iter;
287 for(iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
288 (*iter)->update_title();
294 // This will increase the reference count so we don't get DELETED
295 // until we are ready
296 handle<Instance> me(this);
298 // Make sure we aren't selected as the current instance
299 if(studio::App::get_selected_instance()==this)
300 studio::App::set_selected_instance(0);
302 // Turn-off/clean-up auto recovery
303 studio::App::auto_recover->clear_backup(get_canvas());
305 // Remove us from the active instance list
306 std::list<etl::handle<studio::Instance> >::iterator iter;
307 for(iter=studio::App::instance_list.begin();iter!=studio::App::instance_list.end();iter++)
310 assert(iter!=studio::App::instance_list.end());
311 if(iter!=studio::App::instance_list.end())
312 studio::App::instance_list.erase(iter);
314 // Send out a signal that we are being deleted
315 studio::App::signal_instance_deleted()(this);
317 // Hide all of the canvas views
318 for(std::list<etl::handle<CanvasView> >::iterator iter=canvas_view_list().begin();iter!=canvas_view_list().end();iter++)
321 // Delete all of the canvas views
322 canvas_view_list().clear();
324 // If there is another open instance to select,
325 // go ahead and do so. If not, never mind.
326 if(studio::App::instance_list.empty())
328 studio::App::set_selected_canvas_view(0);
329 studio::App::set_selected_instance(0);
333 studio::App::set_selected_canvas_view(studio::App::instance_list.front()->canvas_view_list().front());
334 //studio::App::set_selected_instance(studio::App::instance_list.front());
340 Instance::insert_canvas(Gtk::TreeRow row,Canvas::Handle canvas)
342 CanvasTreeModel canvas_tree_model;
345 row[canvas_tree_model.icon] = Gtk::Button().render_icon(Gtk::StockID("sinfg-canvas"),Gtk::ICON_SIZE_SMALL_TOOLBAR);
346 row[canvas_tree_model.id] = canvas->get_id();
347 row[canvas_tree_model.name] = canvas->get_name();
348 if(canvas->is_root())
349 row[canvas_tree_model.label] = basename(canvas->get_file_name());
351 if(!canvas->get_id().empty())
352 row[canvas_tree_model.label] = canvas->get_id();
354 if(!canvas->get_name().empty())
355 row[canvas_tree_model.label] = canvas->get_name();
357 row[canvas_tree_model.label] = _("[Unnamed]");
359 row[canvas_tree_model.canvas] = canvas;
360 row[canvas_tree_model.is_canvas] = true;
361 row[canvas_tree_model.is_value_node] = false;
364 sinfg::Canvas::Children::iterator iter;
365 sinfg::Canvas::Children &children(canvas->children());
367 for(iter=children.begin();iter!=children.end();iter++)
368 insert_canvas(*(canvas_tree_store()->append(row.children())),*iter);
372 if(!canvas->value_node_list().empty())
374 Gtk::TreeRow valuenode_row = *(canvas_tree_store()->append(row.children()));
376 valuenode_row[canvas_tree_model.label] = "<defs>";
377 valuenode_row[canvas_tree_model.canvas] = canvas;
378 valuenode_row[canvas_tree_model.is_canvas] = false;
379 valuenode_row[canvas_tree_model.is_value_node] = false;
381 sinfg::ValueNodeList::iterator iter;
382 sinfg::ValueNodeList &value_node_list(canvas->value_node_list());
384 for(iter=value_node_list.begin();iter!=value_node_list.end();iter++)
385 insert_value_node(*(canvas_tree_store()->append(valuenode_row.children())),canvas,*iter);
393 Instance::insert_value_node(Gtk::TreeRow row,Canvas::Handle canvas,etl::handle<sinfg::ValueNode> value_node)
395 CanvasTreeModel canvas_tree_model;
399 row[canvas_tree_model.id] = value_node->get_id();
400 row[canvas_tree_model.name] = value_node->get_id();
401 row[canvas_tree_model.label] = value_node->get_id();
402 row[canvas_tree_model.canvas] = canvas;
403 row[canvas_tree_model.value_node] = value_node;
404 row[canvas_tree_model.is_canvas] = false;
405 row[canvas_tree_model.is_value_node] = true;
406 row[canvas_tree_model.icon] = Gtk::Button().render_icon(valuenode_icon(value_node),Gtk::ICON_SIZE_SMALL_TOOLBAR);
411 Instance::refresh_canvas_tree()
413 canvas_tree_store()->clear();
414 Gtk::TreeRow row = *(canvas_tree_store()->prepend());
415 insert_canvas(row,get_canvas());
419 Instance::dialog_cvs_commit()
421 calc_repository_info();
424 App::dialog_error_blocking(_("Error"),_("You must first add this composition to the repository"));
431 if(sinfgapp::Instance::get_action_count())
433 if(!App::dialog_yes_no(_("CVS Commit"), _("This will save any changes you have made. Are you sure?")))
440 App::dialog_error_blocking(_("Error"),_("The local copy of the file hasn't been changed since the last update.\nNothing to commit!"));
444 if(!App::dialog_entry(_("CVS Commit"),_("Enter a log message describing the changes you have made"), message))
447 OneMoment one_moment;
452 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to COMMIT"));
458 Instance::dialog_cvs_add()
460 calc_repository_info();
463 App::dialog_error_blocking(_("Error"),_("This composition has already been added to the repository"));
470 //if(!App::dialog_entry(_("CVS Add"),_("Enter a log message describing the file"), message))
472 OneMoment one_moment;
477 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to ADD"));
483 Instance::dialog_cvs_update()
485 calc_repository_info();
488 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to update from!"));
493 App::dialog_error_blocking(_("Info"),_("This file is up-to-date"));
499 String filename(get_file_name());
500 if(sinfgapp::Instance::get_action_count())
502 if(!App::dialog_yes_no(_("CVS Update"), _("This will save any changes you have made. Are you sure?")))
506 OneMoment one_moment;
507 time_t oldtime=get_original_timestamp();
509 calc_repository_info();
510 // If something has been updated...
511 if(oldtime!=get_original_timestamp())
518 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
520 //update_all_titles();
524 Instance::dialog_cvs_revert()
526 calc_repository_info();
529 App::dialog_error_blocking(_("Error"),_("This file is not under version control, so there is nothing to revert to!"));
534 String filename(get_file_name());
535 if(!App::dialog_yes_no(_("CVS Revert"),
536 _("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?")
540 OneMoment one_moment;
542 // Remove the old file
543 if(remove(get_file_name().c_str())!=0)
545 App::dialog_error_blocking(_("Error"),_("Unable to remove previous version"));
554 App::dialog_error_blocking(_("Error"),_("An error has occured when trying to UPDATE"));
556 //update_all_titles();
560 Instance::_revert(Instance *instance)
562 OneMoment one_moment;
564 String filename(instance->get_file_name());
566 Canvas::Handle canvas(instance->get_canvas());
570 if(canvas->count()!=1)
573 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 SINFG Studio. Try closing any\ncompositions that might reference this composition and try\nagain, or restart SINFG studio."));
584 // Schedule a revert to occur in a few moments
585 Glib::signal_timeout().connect(
588 sigc::ptr_fun(&Instance::_revert),
598 Instance::safe_revert()
600 if(sinfgapp::Instance::get_action_count())
601 if(!App::dialog_yes_no(_("Revert to saved"), _("You will loose any changes you have made since your last save.\nAre you sure?")))
608 Instance::safe_close()
610 handle<sinfgapp::UIInterface> uim;
611 uim=find_canvas_view(get_canvas())->get_ui_interface();
613 if(get_action_count())
615 string str=strprintf(_("Would you like to save your changes to %s?"),basename(get_file_name()).c_str() );
616 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,sinfgapp::UIInterface::RESPONSE_YES);
617 if(answer==sinfgapp::UIInterface::RESPONSE_YES)
619 if(answer==sinfgapp::UIInterface::RESPONSE_CANCEL)
625 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());
626 int answer=uim->yes_no_cancel(get_canvas()->get_name(),str,sinfgapp::UIInterface::RESPONSE_YES);
628 if(answer==sinfgapp::UIInterface::RESPONSE_YES)
630 if(answer==sinfgapp::UIInterface::RESPONSE_CANCEL)
636 while(studio::App::events_pending())studio::App::iteration(false);
643 Instance::add_actions_to_group(const Glib::RefPtr<Gtk::ActionGroup>& action_group, sinfg::String& ui_info, const sinfgapp::Action::ParamList ¶m_list, sinfgapp::Action::Category category)const
645 sinfgapp::Action::CanidateList canidate_list;
646 sinfgapp::Action::CanidateList::iterator iter;
648 canidate_list=compile_canidate_list(param_list,category);
650 canidate_list.sort();
652 if(canidate_list.empty())
653 sinfg::warning("Action CanidateList is empty!");
655 for(iter=canidate_list.begin();iter!=canidate_list.end();++iter)
657 Gtk::StockID stock_id(get_action_stock_id(*iter));
659 if(!(iter->category&sinfgapp::Action::CATEGORY_HIDDEN))
661 action_group->add(Gtk::Action::create(
662 "action-"+iter->name,
664 iter->local_name,iter->local_name
669 *const_cast<studio::Instance*>(this),
670 &studio::Instance::process_action
677 ui_info+=strprintf("<menuitem action='action-%s' />",iter->name.c_str());
683 Instance::add_actions_to_menu(Gtk::Menu *menu, const sinfgapp::Action::ParamList ¶m_list,sinfgapp::Action::Category category)const
685 sinfgapp::Action::CanidateList canidate_list;
686 sinfgapp::Action::CanidateList::iterator iter;
688 canidate_list=compile_canidate_list(param_list,category);
690 canidate_list.sort();
692 if(canidate_list.empty())
693 sinfg::warning("Action CanidateList is empty!");
695 for(iter=canidate_list.begin();iter!=canidate_list.end();++iter)
697 if(!(iter->category&sinfgapp::Action::CATEGORY_HIDDEN))
699 Gtk::Image* image(manage(new Gtk::Image()));
700 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
703 if(iter->task=="raise")
704 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
705 else if(iter->task=="lower")
706 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
707 else if(iter->task=="move_top")
708 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
709 else if(iter->task=="move_bottom")
710 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
711 else if(iter->task=="remove")
712 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
713 else if(iter->task=="set_on")
714 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
715 else if(iter->task=="set_off")
716 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
717 else if(iter->task=="duplicate")
718 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
719 else if(iter->task=="remove")
720 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
723 Gtk::Stock::lookup(Gtk::StockID("sinfg-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
724 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
725 Gtk::Stock::lookup(Gtk::StockID("sinfg-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
728 menu->items().push_back(
729 Gtk::Menu_Helpers::ImageMenuElem(
735 *const_cast<studio::Instance*>(this),
736 &studio::Instance::process_action
749 Instance::add_actions_to_menu(Gtk::Menu *menu, const sinfgapp::Action::ParamList ¶m_list,const sinfgapp::Action::ParamList ¶m_list2,sinfgapp::Action::Category category)const
751 sinfgapp::Action::CanidateList canidate_list;
752 sinfgapp::Action::CanidateList canidate_list2;
754 sinfgapp::Action::CanidateList::iterator iter;
756 canidate_list=compile_canidate_list(param_list,category);
757 canidate_list2=compile_canidate_list(param_list2,category);
759 canidate_list.sort();
761 if(canidate_list.empty())
762 sinfg::warning("Action CanidateList is empty!");
763 if(canidate_list2.empty())
764 sinfg::warning("Action CanidateList2 is empty!");
766 // Seperate out the canidate lists so that there are no conflicts
767 for(iter=canidate_list.begin();iter!=canidate_list.end();++iter)
769 sinfgapp::Action::CanidateList::iterator iter2(canidate_list2.find(iter->name));
770 if(iter2!=canidate_list2.end())
771 canidate_list2.erase(iter2);
774 for(iter=canidate_list2.begin();iter!=canidate_list2.end();++iter)
776 if(!(iter->category&sinfgapp::Action::CATEGORY_HIDDEN))
778 Gtk::Image* image(manage(new Gtk::Image()));
779 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
781 /* if(iter->task=="raise")
782 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
783 else if(iter->task=="lower")
784 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
785 else if(iter->task=="move_top")
786 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
787 else if(iter->task=="move_bottom")
788 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
789 else if(iter->task=="remove")
790 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
791 else if(iter->task=="set_on")
792 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
793 else if(iter->task=="set_off")
794 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
795 else if(iter->task=="duplicate")
796 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
797 else if(iter->task=="remove")
798 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
801 Gtk::Stock::lookup(Gtk::StockID("sinfg-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
802 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
803 Gtk::Stock::lookup(Gtk::StockID("sinfg-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
806 menu->items().push_back(
807 Gtk::Menu_Helpers::ImageMenuElem(
813 *const_cast<studio::Instance*>(this),
814 &studio::Instance::process_action
825 for(iter=canidate_list.begin();iter!=canidate_list.end();++iter)
827 if(!(iter->category&sinfgapp::Action::CATEGORY_HIDDEN))
829 Gtk::Image* image(manage(new Gtk::Image()));
830 Gtk::Stock::lookup(get_action_stock_id(*iter),Gtk::ICON_SIZE_MENU,*image);
831 /* if(iter->task=="raise")
832 Gtk::Stock::lookup(Gtk::Stock::GO_UP,Gtk::ICON_SIZE_MENU,*image);
833 else if(iter->task=="lower")
834 Gtk::Stock::lookup(Gtk::Stock::GO_DOWN,Gtk::ICON_SIZE_MENU,*image);
835 else if(iter->task=="move_top")
836 Gtk::Stock::lookup(Gtk::Stock::GOTO_TOP,Gtk::ICON_SIZE_MENU,*image);
837 else if(iter->task=="move_bottom")
838 Gtk::Stock::lookup(Gtk::Stock::GOTO_BOTTOM,Gtk::ICON_SIZE_MENU,*image);
839 else if(iter->task=="remove")
840 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
841 else if(iter->task=="set_on")
842 Gtk::Stock::lookup(Gtk::Stock::YES,Gtk::ICON_SIZE_MENU,*image);
843 else if(iter->task=="set_off")
844 Gtk::Stock::lookup(Gtk::Stock::NO,Gtk::ICON_SIZE_MENU,*image);
845 else if(iter->task=="duplicate")
846 Gtk::Stock::lookup(Gtk::Stock::COPY,Gtk::ICON_SIZE_MENU,*image);
847 else if(iter->task=="remove")
848 Gtk::Stock::lookup(Gtk::Stock::DELETE,Gtk::ICON_SIZE_MENU,*image);
851 Gtk::Stock::lookup(Gtk::StockID("sinfg-"+iter->name),Gtk::ICON_SIZE_MENU,*image) ||
852 Gtk::Stock::lookup(Gtk::StockID("gtk-"+iter->task),Gtk::ICON_SIZE_MENU,*image) ||
853 Gtk::Stock::lookup(Gtk::StockID("sinfg-"+iter->task),Gtk::ICON_SIZE_MENU,*image);
856 menu->items().push_back(
857 Gtk::Menu_Helpers::ImageMenuElem(
863 *const_cast<studio::Instance*>(this),
864 &studio::Instance::process_action
877 Instance::process_action(String name, sinfgapp::Action::ParamList param_list)
879 assert(sinfgapp::Action::book().count(name));
881 sinfgapp::Action::BookEntry entry(sinfgapp::Action::book().find(name)->second);
883 sinfgapp::Action::Handle action(entry.factory());
887 sinfg::error("Bad Action");
891 action->set_param_list(param_list);
893 sinfgapp::Action::ParamVocab param_vocab(entry.get_param_vocab());
894 sinfgapp::Action::ParamVocab::const_iterator iter;
896 for(iter=param_vocab.begin();iter!=param_vocab.end();++iter)
898 if(!iter->get_mutual_exclusion().empty() && param_list.count(iter->get_mutual_exclusion()))
901 // If the parameter is optionally user-supplied,
902 // and has not been already provided in the param_list,
903 // then we should go ahead and see if we can
904 // provide that data.
905 if(iter->get_user_supplied() && param_list.count(iter->get_name())==0)
907 switch(iter->get_type())
909 case sinfgapp::Action::Param::TYPE_STRING:
912 if(!studio::App::dialog_entry(entry.local_name, iter->get_local_name()+":"+iter->get_desc(),str))
914 action->set_param(iter->get_name(),str);
918 sinfg::error("Unsupported user-supplied action parameter");
925 if(!action->is_ready())
927 sinfg::error("Action not ready");
931 perform_action(action);
935 Instance::make_param_menu(Gtk::Menu *menu,sinfg::Canvas::Handle canvas, sinfgapp::ValueDesc value_desc, float location)
937 Gtk::Menu& parammenu(*menu);
939 etl::handle<sinfgapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
941 if(!canvas_interface)
944 sinfgapp::Action::ParamList param_list,param_list2;
945 param_list=canvas_interface->generate_param_list(value_desc);
946 param_list.add("origin",location);
948 if(value_desc.get_value_type()==ValueBase::TYPE_BLINEPOINT && value_desc.is_value_node() && ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()))
950 param_list2=canvas_interface->generate_param_list(
952 ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node())
956 param_list2.add("origin",location);
960 // Populate the convert menu by looping through
961 // the ValueNode book and find the ones that are
964 Gtk::Menu *convert_menu=manage(new Gtk::Menu());
965 LinkableValueNode::Book::const_iterator iter;
966 for(iter=LinkableValueNode::book().begin();iter!=LinkableValueNode::book().end();++iter)
968 if(iter->second.check_type(value_desc.get_value_type()))
970 convert_menu->items().push_back(Gtk::Menu_Helpers::MenuElem(iter->second.local_name,
974 sigc::mem_fun(*canvas_interface.get(),&sinfgapp::CanvasInterface::convert),
984 parammenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::CONVERT,*convert_menu));
987 if(param_list2.empty())
988 add_actions_to_menu(¶mmenu, param_list,sinfgapp::Action::CATEGORY_VALUEDESC|sinfgapp::Action::CATEGORY_VALUENODE);
990 add_actions_to_menu(¶mmenu, param_list2,param_list,sinfgapp::Action::CATEGORY_VALUEDESC|sinfgapp::Action::CATEGORY_VALUENODE);
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 value_desc=sinfgapp::ValueDesc(ValueNode_Composite::Handle::cast_dynamic(value_desc.get_value_node()),0);
997 if(value_desc.is_value_node() && ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()))
999 ValueNode_Animated::Handle value_node(ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node()));
1003 WaypointList::iterator iter(value_node->find(canvas->get_time()));
1004 parammenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoint"),
1008 sigc::mem_fun(*find_canvas_view(canvas),&studio::CanvasView::on_waypoint_clicked),
1024 edit_several_waypoints(etl::handle<CanvasView> canvas_view, std::list<sinfgapp::ValueDesc> value_desc_list)
1026 etl::handle<sinfgapp::CanvasInterface> canvas_interface(canvas_view->canvas_interface());
1029 "Edit Multiple Waypoints", // Title
1031 true // use_separator
1034 Widget_WaypointModel widget_waypoint_model;
1035 widget_waypoint_model.show();
1037 dialog.get_vbox()->pack_start(widget_waypoint_model);
1040 dialog.add_button(Gtk::StockID("gtk-apply"),1);
1041 dialog.add_button(Gtk::StockID("gtk-cancel"),0);
1045 if(dialog.run()==0 || widget_waypoint_model.get_waypoint_model().is_trivial())
1048 sinfgapp::Action::PassiveGrouper group(canvas_interface->get_instance().get(),_("Set Waypoints"));
1050 std::list<sinfgapp::ValueDesc>::iterator iter;
1051 for(iter=value_desc_list.begin();iter!=value_desc_list.end();++iter)
1053 sinfgapp::ValueDesc value_desc(*iter);
1055 if(!value_desc.is_valid())
1058 ValueNode_Animated::Handle value_node;
1060 // If this value isn't a ValueNode_Animated, but
1061 // it is somewhat constant, then go ahead and convert
1062 // it to a ValueNode_Animated.
1063 if(!value_desc.is_value_node() || ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node()))
1066 if(value_desc.is_value_node())
1067 value=ValueNode_Const::Handle::cast_dynamic(value_desc.get_value_node())->get_value();
1069 value=value_desc.get_value();
1071 value_node=ValueNode_Animated::create(value,canvas_interface->get_time());
1073 sinfgapp::Action::Handle action;
1075 if(!value_desc.is_value_node())
1077 action=sinfgapp::Action::create("value_desc_connect");
1078 action->set_param("dest",value_desc);
1079 action->set_param("src",ValueNode::Handle(value_node));
1083 action=sinfgapp::Action::create("value_node_replace");
1084 action->set_param("dest",value_desc.get_value_node());
1085 action->set_param("src",ValueNode::Handle(value_node));
1088 action->set_param("canvas",canvas_view->get_canvas());
1089 action->set_param("canvas_interface",canvas_interface);
1092 if(!canvas_interface->get_instance()->perform_action(action))
1094 canvas_view->get_ui_interface()->error(_("Unable to convert to animated waypoint"));
1101 if(value_desc.is_value_node())
1102 value_node=ValueNode_Animated::Handle::cast_dynamic(value_desc.get_value_node());
1109 sinfgapp::Action::Handle action(sinfgapp::Action::create("waypoint_set_smart"));
1113 canvas_view->get_ui_interface()->error(_("Unable to find waypoint_set_smart action"));
1119 action->set_param("canvas",canvas_view->get_canvas());
1120 action->set_param("canvas_interface",canvas_interface);
1121 action->set_param("value_node",ValueNode::Handle(value_node));
1122 action->set_param("time",canvas_interface->get_time());
1123 action->set_param("model",widget_waypoint_model.get_waypoint_model());
1125 if(!canvas_interface->get_instance()->perform_action(action))
1127 canvas_view->get_ui_interface()->error(_("Unable to set a specific waypoint"));
1134 //get_canvas_view()->get_ui_interface()->error(_("Unable to animate a specific valuedesc"));
1143 Instance::make_param_menu(Gtk::Menu *menu,sinfg::Canvas::Handle canvas,const std::list<sinfgapp::ValueDesc>& value_desc_list)
1145 etl::handle<sinfgapp::CanvasInterface> canvas_interface(find_canvas_interface(canvas));
1147 sinfgapp::Action::ParamList param_list;
1148 param_list=canvas_interface->generate_param_list(value_desc_list);
1150 add_actions_to_menu(menu, param_list,sinfgapp::Action::CATEGORY_VALUEDESC|sinfgapp::Action::CATEGORY_VALUENODE);
1152 // Add the edit waypoints option if that might be useful
1153 if(canvas->rend_desc().get_time_end()-Time::epsilon()>canvas->rend_desc().get_time_start())
1155 menu->items().push_back(Gtk::Menu_Helpers::MenuElem(_("Edit Waypoints"),
1159 &edit_several_waypoints
1163 find_canvas_view(canvas)