From 800c329a0b77f9044923885abe0728028eca8350 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 19 Aug 2012 02:24:38 +0000 Subject: Patch => Graph git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@4721 a436a847-0d15-0410-975c-d299462d15a1 --- src/gui/App.cpp | 16 +- src/gui/App.hpp | 12 +- src/gui/BreadCrumbs.cpp | 16 +- src/gui/BreadCrumbs.hpp | 32 +- src/gui/Configuration.hpp | 8 +- src/gui/ConnectWindow.cpp | 10 +- src/gui/Edge.hpp | 2 +- src/gui/GraphBox.cpp | 706 +++++++++++++++++++++++++++++++++ src/gui/GraphBox.hpp | 182 +++++++++ src/gui/GraphCanvas.cpp | 900 ++++++++++++++++++++++++++++++++++++++++++ src/gui/GraphCanvas.hpp | 174 ++++++++ src/gui/GraphPortModule.cpp | 166 ++++++++ src/gui/GraphPortModule.hpp | 83 ++++ src/gui/GraphTreeWindow.cpp | 234 +++++++++++ src/gui/GraphTreeWindow.hpp | 123 ++++++ src/gui/GraphView.cpp | 206 ++++++++++ src/gui/GraphView.hpp | 112 ++++++ src/gui/GraphWindow.cpp | 77 ++++ src/gui/GraphWindow.hpp | 81 ++++ src/gui/LoadGraphWindow.cpp | 246 ++++++++++++ src/gui/LoadGraphWindow.hpp | 96 +++++ src/gui/LoadPatchWindow.cpp | 246 ------------ src/gui/LoadPatchWindow.hpp | 96 ----- src/gui/LoadPluginWindow.cpp | 38 +- src/gui/LoadPluginWindow.hpp | 10 +- src/gui/MessagesWindow.hpp | 2 +- src/gui/NewSubgraphWindow.cpp | 118 ++++++ src/gui/NewSubgraphWindow.hpp | 73 ++++ src/gui/NewSubpatchWindow.cpp | 119 ------ src/gui/NewSubpatchWindow.hpp | 73 ---- src/gui/NodeModule.cpp | 22 +- src/gui/NodeModule.hpp | 8 +- src/gui/ObjectMenu.hpp | 2 +- src/gui/PatchBox.cpp | 706 --------------------------------- src/gui/PatchBox.hpp | 182 --------- src/gui/PatchCanvas.cpp | 900 ------------------------------------------ src/gui/PatchCanvas.hpp | 174 -------- src/gui/PatchPortModule.cpp | 166 -------- src/gui/PatchPortModule.hpp | 83 ---- src/gui/PatchTreeWindow.cpp | 234 ----------- src/gui/PatchTreeWindow.hpp | 120 ------ src/gui/PatchView.cpp | 206 ---------- src/gui/PatchView.hpp | 112 ------ src/gui/PatchWindow.cpp | 77 ---- src/gui/PatchWindow.hpp | 81 ---- src/gui/Port.cpp | 26 +- src/gui/Port.hpp | 4 +- src/gui/PortMenu.cpp | 18 +- src/gui/PortMenu.hpp | 4 +- src/gui/SubgraphModule.cpp | 109 +++++ src/gui/SubgraphModule.hpp | 64 +++ src/gui/SubpatchModule.cpp | 109 ----- src/gui/SubpatchModule.hpp | 64 --- src/gui/ThreadedLoader.cpp | 12 +- src/gui/ThreadedLoader.hpp | 10 +- src/gui/WindowFactory.cpp | 174 ++++---- src/gui/WindowFactory.hpp | 54 +-- src/gui/ingen_gui.ui | 202 +++++----- src/gui/ingen_gui_lv2.cpp | 20 +- src/gui/wscript | 18 +- 60 files changed, 4110 insertions(+), 4108 deletions(-) create mode 100644 src/gui/GraphBox.cpp create mode 100644 src/gui/GraphBox.hpp create mode 100644 src/gui/GraphCanvas.cpp create mode 100644 src/gui/GraphCanvas.hpp create mode 100644 src/gui/GraphPortModule.cpp create mode 100644 src/gui/GraphPortModule.hpp create mode 100644 src/gui/GraphTreeWindow.cpp create mode 100644 src/gui/GraphTreeWindow.hpp create mode 100644 src/gui/GraphView.cpp create mode 100644 src/gui/GraphView.hpp create mode 100644 src/gui/GraphWindow.cpp create mode 100644 src/gui/GraphWindow.hpp create mode 100644 src/gui/LoadGraphWindow.cpp create mode 100644 src/gui/LoadGraphWindow.hpp delete mode 100644 src/gui/LoadPatchWindow.cpp delete mode 100644 src/gui/LoadPatchWindow.hpp create mode 100644 src/gui/NewSubgraphWindow.cpp create mode 100644 src/gui/NewSubgraphWindow.hpp delete mode 100644 src/gui/NewSubpatchWindow.cpp delete mode 100644 src/gui/NewSubpatchWindow.hpp delete mode 100644 src/gui/PatchBox.cpp delete mode 100644 src/gui/PatchBox.hpp delete mode 100644 src/gui/PatchCanvas.cpp delete mode 100644 src/gui/PatchCanvas.hpp delete mode 100644 src/gui/PatchPortModule.cpp delete mode 100644 src/gui/PatchPortModule.hpp delete mode 100644 src/gui/PatchTreeWindow.cpp delete mode 100644 src/gui/PatchTreeWindow.hpp delete mode 100644 src/gui/PatchView.cpp delete mode 100644 src/gui/PatchView.hpp delete mode 100644 src/gui/PatchWindow.cpp delete mode 100644 src/gui/PatchWindow.hpp create mode 100644 src/gui/SubgraphModule.cpp create mode 100644 src/gui/SubgraphModule.hpp delete mode 100644 src/gui/SubpatchModule.cpp delete mode 100644 src/gui/SubpatchModule.hpp (limited to 'src/gui') diff --git a/src/gui/App.cpp b/src/gui/App.cpp index de35de54..96bb1254 100644 --- a/src/gui/App.cpp +++ b/src/gui/App.cpp @@ -29,7 +29,7 @@ #include "ingen/World.hpp" #include "ingen/client/ClientStore.hpp" #include "ingen/client/ObjectModel.hpp" -#include "ingen/client/PatchModel.hpp" +#include "ingen/client/GraphModel.hpp" #include "ingen/client/SigClientInterface.hpp" #include "ingen/runtime_paths.hpp" #include "lilv/lilv.h" @@ -41,10 +41,10 @@ #include "LoadPluginWindow.hpp" #include "MessagesWindow.hpp" #include "NodeModule.hpp" -#include "PatchTreeWindow.hpp" -#include "PatchWindow.hpp" +#include "GraphTreeWindow.hpp" +#include "GraphWindow.hpp" #include "Port.hpp" -#include "SubpatchModule.hpp" +#include "SubgraphModule.hpp" #include "ThreadedLoader.hpp" #include "WidgetFactory.hpp" #include "WindowFactory.hpp" @@ -78,11 +78,11 @@ App::App(Ingen::World* world) WidgetFactory::get_widget_derived("connect_win", _connect_window); WidgetFactory::get_widget_derived("messages_win", _messages_window); - WidgetFactory::get_widget_derived("patch_tree_win", _patch_tree_window); + WidgetFactory::get_widget_derived("graph_tree_win", _graph_tree_window); WidgetFactory::get_widget("about_win", _about_dialog); _connect_window->init_dialog(*this); _messages_window->init_window(*this); - _patch_tree_window->init_window(*this); + _graph_tree_window->init_window(*this); _about_dialog->property_program_name() = "Ingen"; _about_dialog->property_logo_icon_name() = "ingen"; @@ -140,7 +140,7 @@ App::run() // Run main iterations here until we're attached to the engine. Otherwise // with 'ingen -egl' we'd get a bunch of notifications about load - // immediately before even knowing about the root patch or plugins) + // immediately before even knowing about the root graph or plugins) while (!_connect_window->attached()) if (_main->iteration()) break; @@ -163,7 +163,7 @@ App::attach(SharedPtr client) _store = SharedPtr(new ClientStore(_world->uris(), _world->log(), _world->interface(), client)); _loader = SharedPtr(new ThreadedLoader(*this, _world->interface())); - _patch_tree_window->init(*this, *_store); + _graph_tree_window->init(*this, *_store); _client->signal_response().connect( sigc::mem_fun(this, &App::response)); diff --git a/src/gui/App.hpp b/src/gui/App.hpp index 32c59300..ac909b2f 100644 --- a/src/gui/App.hpp +++ b/src/gui/App.hpp @@ -40,7 +40,7 @@ namespace Ingen { class World; namespace Client { class ClientStore; - class PatchModel; + class GraphModel; class PluginModel; class PortModel; class SigClientInterface; @@ -55,9 +55,9 @@ namespace Ingen { namespace GUI { class MessagesWindow; -class PatchCanvas; -class PatchTreeView; -class PatchTreeWindow; +class GraphCanvas; +class GraphTreeView; +class GraphTreeWindow; class ConnectWindow; class Configuration; class ThreadedLoader; @@ -100,7 +100,7 @@ public: ConnectWindow* connect_window() const { return _connect_window; } MessagesWindow* messages_dialog() const { return _messages_window; } - PatchTreeWindow* patch_tree() const { return _patch_tree_window; } + GraphTreeWindow* graph_tree() const { return _graph_tree_window; } Configuration* configuration() const { return _configuration; } WindowFactory* window_factory() const { return _window_factory; } @@ -158,7 +158,7 @@ protected: ConnectWindow* _connect_window; MessagesWindow* _messages_window; - PatchTreeWindow* _patch_tree_window; + GraphTreeWindow* _graph_tree_window; Gtk::AboutDialog* _about_dialog; WindowFactory* _window_factory; diff --git a/src/gui/BreadCrumbs.cpp b/src/gui/BreadCrumbs.cpp index 29b149a5..bc6fc756 100644 --- a/src/gui/BreadCrumbs.cpp +++ b/src/gui/BreadCrumbs.cpp @@ -39,14 +39,14 @@ BreadCrumbs::BreadCrumbs(App& app) set_can_focus(false); } -SharedPtr +SharedPtr BreadCrumbs::view(const Raul::Path& path) { for (std::list::const_iterator i = _breadcrumbs.begin(); i != _breadcrumbs.end(); ++i) if ((*i)->path() == path) return (*i)->view(); - return SharedPtr(); + return SharedPtr(); } /** Sets up the crumbs to display @a path. @@ -55,7 +55,7 @@ BreadCrumbs::view(const Raul::Path& path) * children preserved. */ void -BreadCrumbs::build(Raul::Path path, SharedPtr view) +BreadCrumbs::build(Raul::Path path, SharedPtr view) { bool old_enable_signal = _enable_signal; _enable_signal = false; @@ -68,7 +68,7 @@ BreadCrumbs::build(Raul::Path path, SharedPtr view) if (!(*i)->view()) (*i)->set_view(view); - // views are expensive, having two around for the same patch is a bug + // views are expensive, having two around for the same graph is a bug assert((*i)->view() == view); } else { @@ -103,7 +103,7 @@ BreadCrumbs::build(Raul::Path path, SharedPtr view) _breadcrumbs.back()->set_active(true); // Rebuild from scratch - // Getting here is bad unless absolutely necessary, since the PatchView cache is lost + // Getting here is bad unless absolutely necessary, since the GraphView cache is lost } else { _full_path = path; @@ -147,10 +147,10 @@ BreadCrumbs::build(Raul::Path path, SharedPtr view) */ BreadCrumbs::BreadCrumb* BreadCrumbs::create_crumb(const Raul::Path& path, - SharedPtr view) + SharedPtr view) { BreadCrumb* but = manage(new BreadCrumb(path, - (view && path == view->patch()->path()) ? view : SharedPtr())); + (view && path == view->graph()->path()) ? view : SharedPtr())); but->signal_toggled().connect(sigc::bind(sigc::mem_fun( this, &BreadCrumbs::breadcrumb_clicked), but)); @@ -168,7 +168,7 @@ BreadCrumbs::breadcrumb_clicked(BreadCrumb* crumb) // Tried to turn off the current active button, bad user, no cookie crumb->set_active(true); } else { - signal_patch_selected.emit(crumb->path(), crumb->view()); + signal_graph_selected.emit(crumb->path(), crumb->view()); if (crumb->path() != _active_path) crumb->set_active(false); } diff --git a/src/gui/BreadCrumbs.hpp b/src/gui/BreadCrumbs.hpp index 43c7f011..cdb11583 100644 --- a/src/gui/BreadCrumbs.hpp +++ b/src/gui/BreadCrumbs.hpp @@ -26,15 +26,15 @@ #include "raul/Path.hpp" #include "raul/SharedPtr.hpp" -#include "ingen/client/PatchModel.hpp" +#include "ingen/client/GraphModel.hpp" -#include "PatchView.hpp" +#include "GraphView.hpp" namespace Ingen { namespace GUI { /** Collection of breadcrumb buttons forming a path. - * This doubles as a cache for PatchViews. + * This doubles as a cache for GraphViews. * * \ingroup GUI */ @@ -43,17 +43,17 @@ class BreadCrumbs : public Gtk::HBox public: explicit BreadCrumbs(App& app); - SharedPtr view(const Raul::Path& path); + SharedPtr view(const Raul::Path& path); - void build(Raul::Path path, SharedPtr view); + void build(Raul::Path path, SharedPtr view); - sigc::signal > signal_patch_selected; + sigc::signal > signal_graph_selected; private: /** Breadcrumb button. * - * Each Breadcrumb stores a reference to a PatchView for quick switching. - * So, the amount of allocated PatchViews at a given time is equal to the + * Each Breadcrumb stores a reference to a GraphView for quick switching. + * So, the amount of allocated GraphViews at a given time is equal to the * number of visible breadcrumbs (which is the perfect cache for GUI * responsiveness balanced with mem consumption). * @@ -62,24 +62,24 @@ private: class BreadCrumb : public Gtk::ToggleButton { public: - BreadCrumb(const Raul::Path& path, SharedPtr view = SharedPtr()) + BreadCrumb(const Raul::Path& path, SharedPtr view = SharedPtr()) : _path(path) , _view(view) { - assert(!view || view->patch()->path() == path); + assert(!view || view->graph()->path() == path); set_border_width(0); set_path(path); set_can_focus(false); show_all(); } - void set_view(SharedPtr view) { - assert(!view || view->patch()->path() == _path); + void set_view(SharedPtr view) { + assert(!view || view->graph()->path() == _path); _view = view; } const Raul::Path& path() const { return _path; } - SharedPtr view() const { return _view; } + SharedPtr view() const { return _view; } void set_path(const Raul::Path& path) { remove(); @@ -89,17 +89,17 @@ private: lab->show(); add(*lab); - if (_view && _view->patch()->path() != path) + if (_view && _view->graph()->path() != path) _view.reset(); } private: Raul::Path _path; - SharedPtr _view; + SharedPtr _view; }; BreadCrumb* create_crumb(const Raul::Path& path, - SharedPtr view = SharedPtr()); + SharedPtr view = SharedPtr()); void breadcrumb_clicked(BreadCrumb* crumb); diff --git a/src/gui/Configuration.hpp b/src/gui/Configuration.hpp index c3aec5fc..75c352e9 100644 --- a/src/gui/Configuration.hpp +++ b/src/gui/Configuration.hpp @@ -49,8 +49,8 @@ public: void apply_settings(); - const std::string& patch_folder() { return _patch_folder; } - void set_patch_folder(const std::string& f) { _patch_folder = f; } + const std::string& graph_folder() { return _graph_folder; } + void set_graph_folder(const std::string& f) { _graph_folder = f; } uint32_t get_port_color(const Client::PortModel* p); @@ -62,8 +62,8 @@ public: private: App& _app; - /** Most recent patch folder shown in open dialog */ - std::string _patch_folder; + /** Most recent graph folder shown in open dialog */ + std::string _graph_folder; NameStyle _name_style; diff --git a/src/gui/ConnectWindow.cpp b/src/gui/ConnectWindow.cpp index ea196175..73874449 100644 --- a/src/gui/ConnectWindow.cpp +++ b/src/gui/ConnectWindow.cpp @@ -28,7 +28,7 @@ #include "ingen/Module.hpp" #include "ingen/World.hpp" #include "ingen/client/ClientStore.hpp" -#include "ingen/client/PatchModel.hpp" +#include "ingen/client/GraphModel.hpp" #include "ingen/client/ThreadedSigClientInterface.hpp" #include "ingen_config.h" @@ -324,7 +324,7 @@ void ConnectWindow::on_hide() { Gtk::Dialog::on_hide(); - if (_app->window_factory()->num_open_patch_windows() == 0) + if (_app->window_factory()->num_open_graph_windows() == 0) quit(); } @@ -414,15 +414,15 @@ ConnectWindow::gtk_callback() } else if (_connect_stage == 2) { _app->interface()->get(GraphObject::root_uri()); if (_widgets_loaded) - _progress_label->set_text(string("Requesting root patch...")); + _progress_label->set_text(string("Requesting root graph...")); ++_connect_stage; } else if (_connect_stage == 3) { if (_app->store()->size() > 0) { - SharedPtr root = PtrCast( + SharedPtr root = PtrCast( _app->store()->object(Raul::Path("/"))); if (root) { set_connected_to(_app->interface()); - _app->window_factory()->present_patch(root); + _app->window_factory()->present_graph(root); _app->interface()->get(Raul::URI("ingen:plugins")); if (_widgets_loaded) _progress_label->set_text(string("Loading plugins...")); diff --git a/src/gui/Edge.hpp b/src/gui/Edge.hpp index 0bc22a79..cf1dafe8 100644 --- a/src/gui/Edge.hpp +++ b/src/gui/Edge.hpp @@ -28,7 +28,7 @@ namespace Client { class EdgeModel; } namespace GUI { -/** An Edge in a Patch. +/** An Edge in a Graph. * * \ingroup GUI */ diff --git a/src/gui/GraphBox.cpp b/src/gui/GraphBox.cpp new file mode 100644 index 00000000..b0847f4a --- /dev/null +++ b/src/gui/GraphBox.cpp @@ -0,0 +1,706 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#include +#include +#include + +#include +#include +#include +#include + +#include "ingen/Interface.hpp" +#include "ingen/client/ClientStore.hpp" +#include "ingen/client/GraphModel.hpp" + +#include "App.hpp" +#include "BreadCrumbs.hpp" +#include "Configuration.hpp" +#include "ConnectWindow.hpp" +#include "LoadGraphWindow.hpp" +#include "LoadPluginWindow.hpp" +#include "MessagesWindow.hpp" +#include "NewSubgraphWindow.hpp" +#include "GraphCanvas.hpp" +#include "GraphTreeWindow.hpp" +#include "GraphView.hpp" +#include "GraphWindow.hpp" +#include "ThreadedLoader.hpp" +#include "WidgetFactory.hpp" +#include "WindowFactory.hpp" +#include "ingen_config.h" + +#ifdef HAVE_WEBKIT +#include +#endif + +namespace Ingen { + +using namespace Client; + +namespace GUI { + +static const int STATUS_CONTEXT_ENGINE = 0; +static const int STATUS_CONTEXT_GRAPH = 1; +static const int STATUS_CONTEXT_HOVER = 2; + +GraphBox::GraphBox(BaseObjectType* cobject, + const Glib::RefPtr& xml) + : Gtk::VBox(cobject) + , _app(NULL) + , _window(NULL) + , _breadcrumbs(NULL) + , _has_shown_documentation(false) + , _enable_signal(true) +{ + property_visible() = false; + + xml->get_widget("graph_win_alignment", _alignment); + xml->get_widget("graph_win_status_bar", _status_bar); + //xml->get_widget("graph_win_status_bar", _status_bar); + //xml->get_widget("graph_open_menuitem", _menu_open); + xml->get_widget("graph_import_menuitem", _menu_import); + //xml->get_widget("graph_open_into_menuitem", _menu_open_into); + xml->get_widget("graph_save_menuitem", _menu_save); + xml->get_widget("graph_save_as_menuitem", _menu_save_as); + xml->get_widget("graph_draw_menuitem", _menu_draw); + xml->get_widget("graph_cut_menuitem", _menu_cut); + xml->get_widget("graph_copy_menuitem", _menu_copy); + xml->get_widget("graph_paste_menuitem", _menu_paste); + xml->get_widget("graph_delete_menuitem", _menu_delete); + xml->get_widget("graph_select_all_menuitem", _menu_select_all); + xml->get_widget("graph_close_menuitem", _menu_close); + xml->get_widget("graph_quit_menuitem", _menu_quit); + xml->get_widget("graph_view_control_window_menuitem", _menu_view_control_window); + xml->get_widget("graph_view_engine_window_menuitem", _menu_view_engine_window); + xml->get_widget("graph_properties_menuitem", _menu_view_graph_properties); + xml->get_widget("graph_fullscreen_menuitem", _menu_fullscreen); + xml->get_widget("graph_human_names_menuitem", _menu_human_names); + xml->get_widget("graph_show_port_names_menuitem", _menu_show_port_names); + xml->get_widget("graph_zoom_in_menuitem", _menu_zoom_in); + xml->get_widget("graph_zoom_out_menuitem", _menu_zoom_out); + xml->get_widget("graph_zoom_normal_menuitem", _menu_zoom_normal); + xml->get_widget("graph_status_bar_menuitem", _menu_show_status_bar); + xml->get_widget("graph_arrange_menuitem", _menu_arrange); + xml->get_widget("graph_view_messages_window_menuitem", _menu_view_messages_window); + xml->get_widget("graph_view_graph_tree_window_menuitem", _menu_view_graph_tree_window); + xml->get_widget("graph_help_about_menuitem", _menu_help_about); + xml->get_widget("graph_documentation_paned", _doc_paned); + xml->get_widget("graph_documentation_scrolledwindow", _doc_scrolledwindow); + + _menu_view_control_window->property_sensitive() = false; + _menu_import->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_import)); + _menu_save->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_save)); + _menu_save_as->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_save_as)); + _menu_draw->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_draw)); + _menu_copy->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_copy)); + _menu_paste->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_paste)); + _menu_delete->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_delete)); + _menu_select_all->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_select_all)); + _menu_close->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_close)); + _menu_quit->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_quit)); + _menu_fullscreen->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_fullscreen_toggled)); + _menu_human_names->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_human_names_toggled)); + _menu_show_status_bar->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_status_bar_toggled)); + _menu_show_port_names->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_port_names_toggled)); + _menu_arrange->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_arrange)); + _menu_quit->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_quit)); + _menu_zoom_in->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_zoom_in)); + _menu_zoom_out->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_zoom_out)); + _menu_zoom_normal->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_zoom_normal)); + _menu_view_engine_window->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_show_engine)); + _menu_view_graph_properties->signal_activate().connect( + sigc::mem_fun(this, &GraphBox::event_show_properties)); + + Glib::RefPtr clipboard = Gtk::Clipboard::get(); + clipboard->signal_owner_change().connect( + sigc::mem_fun(this, &GraphBox::event_clipboard_changed)); +} + +GraphBox::~GraphBox() +{ + delete _breadcrumbs; +} + +SharedPtr +GraphBox::create(App& app, SharedPtr graph) +{ + GraphBox* result = NULL; + Glib::RefPtr xml = WidgetFactory::create("graph_win"); + xml->get_widget_derived("graph_win_vbox", result); + result->init_box(app); + result->set_graph(graph, SharedPtr()); + return SharedPtr(result); +} + +void +GraphBox::init_box(App& app) +{ + _app = &app; + + std::string engine_name = _app->interface()->uri(); + if (engine_name == "http://drobilla.net/ns/ingen#internal") { + engine_name = "internal engine"; + } + _status_bar->push(std::string("Connected to ") + engine_name, STATUS_CONTEXT_ENGINE); + + _menu_view_messages_window->signal_activate().connect( + sigc::mem_fun(_app->messages_dialog(), &MessagesWindow::present)); + _menu_view_graph_tree_window->signal_activate().connect( + sigc::mem_fun(_app->graph_tree(), &GraphTreeWindow::present)); + + _menu_help_about->signal_activate().connect(sigc::hide_return( + sigc::mem_fun(_app, &App::show_about))); + + _breadcrumbs = new BreadCrumbs(*_app); + _breadcrumbs->signal_graph_selected.connect( + sigc::mem_fun(this, &GraphBox::set_graph_from_path)); +} + +void +GraphBox::set_graph_from_path(const Raul::Path& path, SharedPtr view) +{ + if (view) { + assert(view->graph()->path() == path); + _app->window_factory()->present_graph(view->graph(), _window, view); + } else { + SharedPtr model = PtrCast( + _app->store()->object(path)); + if (model) { + _app->window_factory()->present_graph(model, _window); + } + } +} + +/** Sets the graph for this box and initializes everything. + * + * If @a view is NULL, a new view will be created. + */ +void +GraphBox::set_graph(SharedPtr graph, + SharedPtr view) +{ + if (!graph || graph == _graph) + return; + + _enable_signal = false; + + new_port_connection.disconnect(); + removed_port_connection.disconnect(); + edit_mode_connection.disconnect(); + _entered_connection.disconnect(); + _left_connection.disconnect(); + + _status_bar->pop(STATUS_CONTEXT_GRAPH); + + _graph = graph; + _view = view; + + if (!_view) + _view = _breadcrumbs->view(graph->path()); + + if (!_view) + _view = GraphView::create(*_app, graph); + + assert(_view); + + // Add view to our alignment + if (_view->get_parent()) + _view->get_parent()->remove(*_view.get()); + + _alignment->remove(); + _alignment->add(*_view.get()); + + if (_breadcrumbs->get_parent()) + _breadcrumbs->get_parent()->remove(*_breadcrumbs); + + _view->breadcrumb_container()->remove(); + _view->breadcrumb_container()->add(*_breadcrumbs); + _view->breadcrumb_container()->show(); + + _breadcrumbs->build(graph->path(), _view); + _breadcrumbs->show(); + + _menu_view_control_window->property_sensitive() = false; + + for (BlockModel::Ports::const_iterator p = graph->ports().begin(); + p != graph->ports().end(); ++p) { + if (_app->can_control(p->get())) { + _menu_view_control_window->property_sensitive() = true; + break; + } + } + + new_port_connection = graph->signal_new_port().connect( + sigc::mem_fun(this, &GraphBox::graph_port_added)); + removed_port_connection = graph->signal_removed_port().connect( + sigc::mem_fun(this, &GraphBox::graph_port_removed)); + + show(); + _alignment->show_all(); + hide_documentation(); + + _view->signal_object_entered.connect( + sigc::mem_fun(this, &GraphBox::object_entered)); + _view->signal_object_left.connect( + sigc::mem_fun(this, &GraphBox::object_left)); + + _enable_signal = true; +} + +void +GraphBox::graph_port_added(SharedPtr port) +{ + if (port->is_input() && _app->can_control(port.get())) { + _menu_view_control_window->property_sensitive() = true; + } +} + +void +GraphBox::graph_port_removed(SharedPtr port) +{ + if (!(port->is_input() && _app->can_control(port.get()))) + return; + + for (BlockModel::Ports::const_iterator i = _graph->ports().begin(); + i != _graph->ports().end(); ++i) { + if ((*i)->is_input() && _app->can_control(i->get())) { + _menu_view_control_window->property_sensitive() = true; + return; + } + } + + _menu_view_control_window->property_sensitive() = false; +} + +void +GraphBox::show_documentation(const std::string& doc, bool html) +{ +#ifdef HAVE_WEBKIT + WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new()); + webkit_web_view_load_html_string(view, doc.c_str(), ""); + _doc_scrolledwindow->add(*Gtk::manage(Glib::wrap(GTK_WIDGET(view)))); + _doc_scrolledwindow->show_all(); +#else + Gtk::TextView* view = Gtk::manage(new Gtk::TextView()); + view->get_buffer()->set_text(doc); + _doc_scrolledwindow->add(*view); + _doc_scrolledwindow->show_all(); +#endif + if (!_has_shown_documentation) { + const Gtk::Allocation allocation = get_allocation(); + _doc_paned->set_position(allocation.get_width() / 1.61803399); + } + _has_shown_documentation = true; +} + +void +GraphBox::hide_documentation() +{ + _doc_scrolledwindow->remove(); + _doc_scrolledwindow->hide(); + _doc_paned->set_position(INT_MAX); +} + +void +GraphBox::show_status(const ObjectModel* model) +{ + std::stringstream msg; + msg << model->path(); + + const PortModel* port = 0; + const BlockModel* block = 0; + + if ((port = dynamic_cast(model))) { + show_port_status(port, port->value()); + + } else if ((block = dynamic_cast(model))) { + const PluginModel* plugin = dynamic_cast(block->plugin()); + if (plugin) + msg << ((boost::format(" (%1%)") % plugin->human_name()).str()); + _status_bar->push(msg.str(), STATUS_CONTEXT_HOVER); + } +} + +void +GraphBox::show_port_status(const PortModel* port, const Raul::Atom& value) +{ + std::stringstream msg; + msg << port->path(); + + const BlockModel* parent = dynamic_cast(port->parent().get()); + if (parent) { + const PluginModel* plugin = dynamic_cast(parent->plugin()); + if (plugin) { + const std::string& human_name = plugin->port_human_name(port->index()); + if (!human_name.empty()) + msg << " (" << human_name << ")"; + } + } + + if (value.is_valid()) { + msg << " = " << _app->forge().str(value); + } + + _status_bar->pop(STATUS_CONTEXT_HOVER); + _status_bar->push(msg.str(), STATUS_CONTEXT_HOVER); +} + +void +GraphBox::object_entered(const ObjectModel* model) +{ + show_status(model); +} + +void +GraphBox::object_left(const ObjectModel* model) +{ + _status_bar->pop(STATUS_CONTEXT_GRAPH); + _status_bar->pop(STATUS_CONTEXT_HOVER); +} + +void +GraphBox::event_show_engine() +{ + if (_graph) + _app->connect_window()->show(); +} + +void +GraphBox::event_clipboard_changed(GdkEventOwnerChange* ev) +{ + Glib::RefPtr clipboard = Gtk::Clipboard::get(); + _menu_paste->set_sensitive(clipboard->wait_is_text_available()); +} + +void +GraphBox::event_show_properties() +{ + _app->window_factory()->present_properties(_graph); +} + +void +GraphBox::event_import() +{ + _app->window_factory()->present_load_graph(_graph); +} + +void +GraphBox::event_save() +{ + const Raul::Atom& document = _graph->get_property(_app->uris().ingen_document); + if (!document.is_valid() || document.type() != _app->uris().forge.URI) { + event_save_as(); + } else { + _app->loader()->save_graph(_graph, document.get_uri()); + _status_bar->push( + (boost::format("Saved %1% to %2%") % _graph->path().c_str() + % document.get_uri()).str(), + STATUS_CONTEXT_GRAPH); + } +} + +int +GraphBox::message_dialog(const Glib::ustring& message, + const Glib::ustring& secondary_text, + Gtk::MessageType type, + Gtk::ButtonsType buttons) +{ + Gtk::MessageDialog dialog(message, true, type, buttons, true); + dialog.set_secondary_text(secondary_text); + if (_window) { + dialog.set_transient_for(*_window); + } + return dialog.run(); +} + +void +GraphBox::event_save_as() +{ + const URIs& uris = _app->uris(); + while (true) { + Gtk::FileChooserDialog dialog("Save Graph", Gtk::FILE_CHOOSER_ACTION_SAVE); + if (_window) { + dialog.set_transient_for(*_window); + } + + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + Gtk::Button* save_button = dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); + save_button->property_has_default() = true; + + Gtk::FileFilter filt; + filt.add_pattern("*.ingen"); + filt.set_name("Ingen bundles"); + dialog.set_filter(filt); + + // Set current folder to most sensible default + const Raul::Atom& document = _graph->get_property(uris.ingen_document); + if (document.type() == uris.forge.URI) + dialog.set_uri(document.get_uri()); + else if (_app->configuration()->graph_folder().length() > 0) + dialog.set_current_folder(_app->configuration()->graph_folder()); + + if (dialog.run() != Gtk::RESPONSE_OK) + break; + + std::string filename = dialog.get_filename(); + std::string basename = Glib::path_get_basename(filename); + + if (basename.find('.') == std::string::npos) { + filename += ".ingen"; + basename += ".ingen"; + } else if (filename.substr(filename.length() - 10) != ".ingen") { + message_dialog( + "Ingen graphs must be saved to Ingen bundles (*.ingen).", + "", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); + continue; + } + + const std::string symbol(basename.substr(0, basename.find('.'))); + + if (!Raul::Symbol::is_valid(symbol)) { + message_dialog( + "Ingen bundle names must be valid symbols.", + "All characters must be _, a-z, A-Z, or 0-9, but the first may not be 0-9.", + Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); + continue; + } + + //_graph->set_property(uris.lv2_symbol, Atom(symbol.c_str())); + + bool confirm = true; + if (Glib::file_test(filename, Glib::FILE_TEST_IS_DIR)) { + if (Glib::file_test(Glib::build_filename(filename, "manifest.ttl"), + Glib::FILE_TEST_EXISTS)) { + int ret = message_dialog( + (boost::format("A bundle named \"%1%\" already exists." + " Replace it?") % basename).str(), + "", Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO); + confirm = (ret == Gtk::RESPONSE_YES); + } else { + int ret = message_dialog( + (boost::format("A directory named \"%1%\" already exists," + "but is not an Ingen bundle. " + "Save into it anyway?") % basename).str(), + "This will create at least 2 .ttl files in this directory," + "and possibly several more files and/or directories, recursively. " + "Existing files will be overwritten.", + Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO); + confirm = (ret == Gtk::RESPONSE_YES); + } + } else if (Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) { + int ret = message_dialog( + (boost::format("A file named \"%1%\" already exists. " + "Replace it with an Ingen bundle?") + % basename).str(), + "", Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO); + confirm = (ret == Gtk::RESPONSE_YES); + if (confirm) + ::g_remove(filename.c_str()); + } + + if (confirm) { + const Glib::ustring uri = Glib::filename_to_uri(filename); + _app->loader()->save_graph(_graph, uri); + const_cast(_graph.get())->set_property( + uris.ingen_document, + _app->forge().alloc_uri(uri.c_str()), + Resource::EXTERNAL); + _status_bar->push( + (boost::format("Saved %1% to %2%") % _graph->path().c_str() + % filename).str(), + STATUS_CONTEXT_GRAPH); + } + + _app->configuration()->set_graph_folder(dialog.get_current_folder()); + break; + } +} + +void +GraphBox::event_draw() +{ + Gtk::FileChooserDialog dialog("Draw to DOT", Gtk::FILE_CHOOSER_ACTION_SAVE); + if (_window) { + dialog.set_transient_for(*_window); + } + + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + Gtk::Button* save_button = dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); + save_button->property_has_default() = true; + + int result = dialog.run(); + + if (result == Gtk::RESPONSE_OK) { + std::string filename = dialog.get_filename(); + if (filename.find(".") == std::string::npos) + filename += ".dot"; + + bool confirm = true; + if (Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) { + int ret = message_dialog( + (boost::format("File exists! Overwrite %1%?") % filename).str(), + "", Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO); + confirm = (ret == Gtk::RESPONSE_YES); + } + + if (confirm) { + _view->canvas()->export_dot(filename.c_str()); + _status_bar->push( + (boost::format("Rendered %1% to %2%") + % _graph->path() % filename).str(), + STATUS_CONTEXT_GRAPH); + } + } +} + +void +GraphBox::event_copy() +{ + if (_view) + _view->canvas()->copy_selection(); +} + +void +GraphBox::event_paste() +{ + if (_view) + _view->canvas()->paste(); +} + +void +GraphBox::event_delete() +{ + if (_view) + _view->canvas()->destroy_selection(); +} + +void +GraphBox::event_select_all() +{ + if (_view) + _view->canvas()->select_all(); +} + +void +GraphBox::event_close() +{ + if (_window) { + _app->window_factory()->remove_graph_window(_window); + } +} + +void +GraphBox::event_quit() +{ + _app->quit(_window); +} + +void +GraphBox::event_zoom_in() +{ + _view->canvas()->set_font_size(_view->canvas()->get_font_size() + 1.0); +} + +void +GraphBox::event_zoom_out() +{ + _view->canvas()->set_font_size(_view->canvas()->get_font_size() - 1.0); +} + +void +GraphBox::event_zoom_normal() +{ + _view->canvas()->set_scale(1.0, _view->canvas()->get_default_font_size()); +} + +void +GraphBox::event_arrange() +{ + _view->canvas()->arrange(); +} + +void +GraphBox::event_fullscreen_toggled() +{ + // FIXME: ugh, use GTK signals to track state and know for sure + static bool is_fullscreen = false; + + if (_window) { + if (!is_fullscreen) { + _window->fullscreen(); + is_fullscreen = true; + } else { + _window->unfullscreen(); + is_fullscreen = false; + } + } +} + +void +GraphBox::event_status_bar_toggled() +{ + if (_menu_show_status_bar->get_active()) + _status_bar->show(); + else + _status_bar->hide(); +} + +void +GraphBox::event_human_names_toggled() +{ + _view->canvas()->show_human_names(_menu_human_names->get_active()); + if (_menu_human_names->get_active()) + _app->configuration()->set_name_style(Configuration::HUMAN); + else + _app->configuration()->set_name_style(Configuration::PATH); +} + +void +GraphBox::event_port_names_toggled() +{ + if (_menu_show_port_names->get_active()) { + _view->canvas()->set_direction(GANV_DIRECTION_RIGHT); + _view->canvas()->show_port_names(true); + } else { + _view->canvas()->set_direction(GANV_DIRECTION_DOWN); + _view->canvas()->show_port_names(false); + } +} + +} // namespace GUI +} // namespace Ingen diff --git a/src/gui/GraphBox.hpp b/src/gui/GraphBox.hpp new file mode 100644 index 00000000..e8ee3d8b --- /dev/null +++ b/src/gui/GraphBox.hpp @@ -0,0 +1,182 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_GUI_GRAPH_BOX_HPP +#define INGEN_GUI_GRAPH_BOX_HPP + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "raul/SharedPtr.hpp" + +#include "Window.hpp" + +namespace Raul { +class Atom; +class Path; +} + +namespace Ingen { + +namespace Client { +class GraphModel; +class PortModel; +class ObjectModel; +} + +namespace GUI { + +class BreadCrumbs; +class LoadGraphBox; +class LoadPluginWindow; +class NewSubgraphWindow; +class GraphDescriptionWindow; +class GraphView; +class GraphWindow; +class SubgraphModule; + +/** A window for a graph. + * + * \ingroup GUI + */ +class GraphBox : public Gtk::VBox +{ +public: + GraphBox(BaseObjectType* cobject, + const Glib::RefPtr& xml); + ~GraphBox(); + + static SharedPtr create( + App& app, SharedPtr graph); + + void init_box(App& app); + + void set_graph(SharedPtr graph, + SharedPtr view); + + void set_window(GraphWindow* win) { _window = win; } + + void show_documentation(const std::string& doc, bool html); + void hide_documentation(); + + SharedPtr graph() const { return _graph; } + SharedPtr view() const { return _view; } + + void show_port_status(const Client::PortModel* model, + const Raul::Atom& value); + + void set_graph_from_path(const Raul::Path& path, SharedPtr view); + + void object_entered(const Client::ObjectModel* model); + void object_left(const Client::ObjectModel* model); + +private: + void graph_port_added(SharedPtr port); + void graph_port_removed(SharedPtr port); + void show_status(const Client::ObjectModel* model); + + int message_dialog(const Glib::ustring& message, + const Glib::ustring& secondary_text, + Gtk::MessageType type, + Gtk::ButtonsType buttons); + + void event_import(); + void event_save(); + void event_save_as(); + void event_draw(); + void event_copy(); + void event_paste(); + void event_delete(); + void event_select_all(); + void event_close(); + void event_quit(); + void event_fullscreen_toggled(); + void event_status_bar_toggled(); + void event_human_names_toggled(); + void event_port_names_toggled(); + void event_zoom_in(); + void event_zoom_out(); + void event_zoom_normal(); + void event_arrange(); + void event_show_properties(); + void event_show_engine(); + void event_clipboard_changed(GdkEventOwnerChange* ev); + + App* _app; + SharedPtr _graph; + SharedPtr _view; + GraphWindow* _window; + + sigc::connection new_port_connection; + sigc::connection removed_port_connection; + sigc::connection edit_mode_connection; + + Gtk::MenuItem* _menu_import; + Gtk::MenuItem* _menu_save; + Gtk::MenuItem* _menu_save_as; + Gtk::MenuItem* _menu_draw; + Gtk::MenuItem* _menu_cut; + Gtk::MenuItem* _menu_copy; + Gtk::MenuItem* _menu_paste; + Gtk::MenuItem* _menu_delete; + Gtk::MenuItem* _menu_select_all; + Gtk::MenuItem* _menu_close; + Gtk::MenuItem* _menu_quit; + Gtk::CheckMenuItem* _menu_human_names; + Gtk::CheckMenuItem* _menu_show_port_names; + Gtk::CheckMenuItem* _menu_show_status_bar; + Gtk::MenuItem* _menu_zoom_in; + Gtk::MenuItem* _menu_zoom_out; + Gtk::MenuItem* _menu_zoom_normal; + Gtk::MenuItem* _menu_fullscreen; + Gtk::MenuItem* _menu_arrange; + Gtk::MenuItem* _menu_view_engine_window; + Gtk::MenuItem* _menu_view_control_window; + Gtk::MenuItem* _menu_view_graph_properties; + Gtk::MenuItem* _menu_view_messages_window; + Gtk::MenuItem* _menu_view_graph_tree_window; + Gtk::MenuItem* _menu_help_about; + + Gtk::VBox* _vbox; + Gtk::Alignment* _alignment; + BreadCrumbs* _breadcrumbs; + Gtk::Statusbar* _status_bar; + + Gtk::HPaned* _doc_paned; + Gtk::ScrolledWindow* _doc_scrolledwindow; + + sigc::connection _entered_connection; + sigc::connection _left_connection; + + /** Invisible bin used to store breadcrumbs when not shown by a view */ + Gtk::Alignment _breadcrumb_bin; + + bool _has_shown_documentation; + bool _enable_signal; +}; + +} // namespace GUI +} // namespace Ingen + +#endif // INGEN_GUI_GRAPH_BOX_HPP diff --git a/src/gui/GraphCanvas.cpp b/src/gui/GraphCanvas.cpp new file mode 100644 index 00000000..e6fe3db7 --- /dev/null +++ b/src/gui/GraphCanvas.cpp @@ -0,0 +1,900 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#include +#include +#include +#include + +#include +#include + +#include "ganv/Canvas.hpp" +#include "ganv/Circle.hpp" +#include "ingen/Builder.hpp" +#include "ingen/ClashAvoider.hpp" +#include "ingen/Interface.hpp" +#include "ingen/Log.hpp" +#include "ingen/World.hpp" +#include "ingen/client/ClientStore.hpp" +#include "ingen/client/BlockModel.hpp" +#include "ingen/client/GraphModel.hpp" +#include "ingen/client/PluginModel.hpp" +#include "ingen/serialisation/Serialiser.hpp" +#include "lv2/lv2plug.in/ns/ext/atom/atom.h" + +#include "App.hpp" +#include "Edge.hpp" +#include "GraphCanvas.hpp" +#include "GraphPortModule.hpp" +#include "GraphWindow.hpp" +#include "LoadPluginWindow.hpp" +#include "NewSubgraphWindow.hpp" +#include "NodeModule.hpp" +#include "Port.hpp" +#include "SubgraphModule.hpp" +#include "ThreadedLoader.hpp" +#include "WidgetFactory.hpp" +#include "WindowFactory.hpp" + +#define FOREACH_ITEM(iter, coll) \ + for (Items::const_iterator (iter) = coll.begin(); \ + (iter) != coll.end(); ++(iter)) + +using namespace std; + +namespace Ingen { + +using namespace Client; + +namespace GUI { + +GraphCanvas::GraphCanvas(App& app, + SharedPtr graph, + int width, + int height) + : Canvas(width, height) + , _app(app) + , _graph(graph) + , _auto_position_count(0) + , _last_click_x(0) + , _last_click_y(0) + , _paste_count(0) + , _menu(NULL) + , _internal_menu(NULL) + , _classless_menu(NULL) + , _plugin_menu(NULL) + , _human_names(true) +{ + Glib::RefPtr xml = WidgetFactory::create("canvas_menu"); + xml->get_widget("canvas_menu", _menu); + + xml->get_widget("canvas_menu_add_audio_input", _menu_add_audio_input); + xml->get_widget("canvas_menu_add_audio_output", _menu_add_audio_output); + xml->get_widget("canvas_menu_add_control_input", _menu_add_control_input); + xml->get_widget("canvas_menu_add_control_output", _menu_add_control_output); + xml->get_widget("canvas_menu_add_event_input", _menu_add_event_input); + xml->get_widget("canvas_menu_add_event_output", _menu_add_event_output); + xml->get_widget("canvas_menu_load_plugin", _menu_load_plugin); + xml->get_widget("canvas_menu_load_graph", _menu_load_graph); + xml->get_widget("canvas_menu_new_graph", _menu_new_graph); + xml->get_widget("canvas_menu_edit", _menu_edit); + + const URIs& uris = _app.uris(); + + // Add port menu items + _menu_add_audio_input->signal_activate().connect( + sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port), + "audio_in", "Audio In", uris.lv2_AudioPort, false)); + _menu_add_audio_output->signal_activate().connect( + sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port), + "audio_out", "Audio Out", uris.lv2_AudioPort, true)); + _menu_add_control_input->signal_activate().connect( + sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port), + "control_in", "Control In", uris.lv2_ControlPort, false)); + _menu_add_control_output->signal_activate().connect( + sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port), + "control_out", "Control Out", uris.lv2_ControlPort, true)); + _menu_add_event_input->signal_activate().connect( + sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port), + "event_in", "Event In", uris.atom_AtomPort, false)); + _menu_add_event_output->signal_activate().connect( + sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_port), + "event_out", "Event Out", uris.atom_AtomPort, true)); + + signal_event.connect( + sigc::mem_fun(this, &GraphCanvas::on_event)); + signal_connect.connect( + sigc::mem_fun(this, &GraphCanvas::connect)); + signal_disconnect.connect( + sigc::mem_fun(this, &GraphCanvas::disconnect)); + + // Connect to model signals to track state + _graph->signal_new_block().connect( + sigc::mem_fun(this, &GraphCanvas::add_block)); + _graph->signal_removed_block().connect( + sigc::mem_fun(this, &GraphCanvas::remove_block)); + _graph->signal_new_port().connect( + sigc::mem_fun(this, &GraphCanvas::add_port)); + _graph->signal_removed_port().connect( + sigc::mem_fun(this, &GraphCanvas::remove_port)); + _graph->signal_new_edge().connect( + sigc::mem_fun(this, &GraphCanvas::connection)); + _graph->signal_removed_edge().connect( + sigc::mem_fun(this, &GraphCanvas::disconnection)); + + _app.store()->signal_new_plugin().connect( + sigc::mem_fun(this, &GraphCanvas::add_plugin)); + + // Connect widget signals to do things + _menu_load_plugin->signal_activate().connect( + sigc::mem_fun(this, &GraphCanvas::menu_load_plugin)); + _menu_load_graph->signal_activate().connect( + sigc::mem_fun(this, &GraphCanvas::menu_load_graph)); + _menu_new_graph->signal_activate().connect( + sigc::mem_fun(this, &GraphCanvas::menu_new_graph)); +} + +void +GraphCanvas::show_menu(bool position, unsigned button, uint32_t time) +{ + if (!_internal_menu) + build_menus(); + + if (position) + _menu->popup(sigc::mem_fun(this, &GraphCanvas::auto_menu_position), button, time); + else + _menu->popup(button, time); +} + +void +GraphCanvas::build_menus() +{ + // Build (or clear existing) internal plugin menu + if (_internal_menu) { + _internal_menu->items().clear(); + } else { + _menu->items().push_back( + Gtk::Menu_Helpers::ImageMenuElem( + "I_nternal", + *(manage(new Gtk::Image(Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU))))); + Gtk::MenuItem* internal_menu_item = &(_menu->items().back()); + _internal_menu = Gtk::manage(new Gtk::Menu()); + internal_menu_item->set_submenu(*_internal_menu); + _menu->reorder_child(*internal_menu_item, 4); + } + + // Build skeleton LV2 plugin class heirarchy for 'Plugin' menu + if (!_plugin_menu) + build_plugin_menu(); + + // Build (or clear existing) uncategorized (classless, heh) plugins menu + if (_classless_menu) { + _classless_menu->items().clear(); + } else { + _plugin_menu->items().push_back(Gtk::Menu_Helpers::MenuElem("Uncategorized")); + Gtk::MenuItem* classless_menu_item = &(_plugin_menu->items().back()); + _classless_menu = Gtk::manage(new Gtk::Menu()); + classless_menu_item->set_submenu(*_classless_menu); + _classless_menu->hide(); + } + + // Add known plugins to menu heirarchy + SharedPtr plugins = _app.store()->plugins(); + for (ClientStore::Plugins::const_iterator i = plugins->begin(); i != plugins->end(); ++i) + add_plugin(i->second); +} + +/** Recursively build the plugin class menu heirarchy rooted at + * @a plugin class into @a menu + */ +size_t +GraphCanvas::build_plugin_class_menu( + Gtk::Menu* menu, + const LilvPluginClass* plugin_class, + const LilvPluginClasses* classes, + const LV2Children& children, + std::set& ancestors) +{ + size_t num_items = 0; + const LilvNode* class_uri = lilv_plugin_class_get_uri(plugin_class); + const char* class_uri_str = lilv_node_as_string(class_uri); + + const std::pair kids + = children.equal_range(class_uri_str); + + if (kids.first == children.end()) + return 0; + + // Add submenus + ancestors.insert(class_uri_str); + for (LV2Children::const_iterator i = kids.first; i != kids.second; ++i) { + const LilvPluginClass* c = i->second; + const char* sub_label_str = lilv_node_as_string(lilv_plugin_class_get_label(c)); + const char* sub_uri_str = lilv_node_as_string(lilv_plugin_class_get_uri(c)); + if (ancestors.find(sub_uri_str) != ancestors.end()) { + _app.log().warn(Raul::fmt("Infinite LV2 class recursion: %1% <: %2%\n") + % class_uri_str % sub_uri_str); + return 0; + } + + Gtk::Menu_Helpers::MenuElem menu_elem = Gtk::Menu_Helpers::MenuElem(sub_label_str); + menu->items().push_back(menu_elem); + Gtk::MenuItem* menu_item = &(menu->items().back()); + + Gtk::Menu* submenu = Gtk::manage(new Gtk::Menu()); + menu_item->set_submenu(*submenu); + + size_t num_child_items = build_plugin_class_menu( + submenu, c, classes, children, ancestors); + + _class_menus.insert(make_pair(sub_uri_str, MenuRecord(menu_item, submenu))); + if (num_child_items == 0) + menu_item->hide(); + + ++num_items; + } + ancestors.erase(class_uri_str); + + return num_items; +} + +void +GraphCanvas::build_plugin_menu() +{ + if (_plugin_menu) { + _plugin_menu->items().clear(); + } else { + _menu->items().push_back( + Gtk::Menu_Helpers::ImageMenuElem( + "_Plugin", + *(manage(new Gtk::Image(Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU))))); + Gtk::MenuItem* plugin_menu_item = &(_menu->items().back()); + _plugin_menu = Gtk::manage(new Gtk::Menu()); + plugin_menu_item->set_submenu(*_plugin_menu); + _menu->reorder_child(*plugin_menu_item, 5); + } + + const LilvWorld* world = PluginModel::lilv_world(); + const LilvPluginClass* lv2_plugin = lilv_world_get_plugin_class(world); + const LilvPluginClasses* classes = lilv_world_get_plugin_classes(world); + + LV2Children children; + LILV_FOREACH(plugin_classes, i, classes) { + const LilvPluginClass* c = lilv_plugin_classes_get(classes, i); + const LilvNode* p = lilv_plugin_class_get_parent_uri(c); + if (!p) + p = lilv_plugin_class_get_uri(lv2_plugin); + children.insert(make_pair(lilv_node_as_string(p), c)); + } + std::set ancestors; + build_plugin_class_menu(_plugin_menu, lv2_plugin, classes, children, ancestors); +} + +void +GraphCanvas::build() +{ + const Store::const_range kids = _app.store()->children_range(_graph); + + // Create modules for blocks + for (Store::const_iterator i = kids.first; i != kids.second; ++i) { + SharedPtr block = PtrCast(i->second); + if (block && block->parent() == _graph) + add_block(block); + } + + // Create pseudo modules for ports (ports on this canvas, not on our module) + for (BlockModel::Ports::const_iterator i = _graph->ports().begin(); + i != _graph->ports().end(); ++i) { + add_port(*i); + } + + // Create edges + for (GraphModel::Edges::const_iterator i = _graph->edges().begin(); + i != _graph->edges().end(); ++i) { + connection(PtrCast(i->second)); + } +} + +static void +show_module_human_names(GanvNode* node, void* data) +{ + bool b = *(bool*)data; + if (GANV_IS_MODULE(node)) { + Ganv::Module* module = Glib::wrap(GANV_MODULE(node)); + NodeModule* nmod = dynamic_cast(module); + if (nmod) + nmod->show_human_names(b); + + GraphPortModule* pmod = dynamic_cast(module); + if (pmod) + pmod->show_human_names(b); + } +} +void +GraphCanvas::show_human_names(bool b) +{ + _human_names = b; + for_each_node(show_module_human_names, &b); +} + +void +GraphCanvas::show_port_names(bool b) +{ + ganv_canvas_set_direction(gobj(), b ? GANV_DIRECTION_RIGHT : GANV_DIRECTION_DOWN); +} + +void +GraphCanvas::add_plugin(SharedPtr p) +{ + typedef ClassMenus::iterator iterator; + if (_internal_menu && p->type() == Plugin::Internal) { + _internal_menu->items().push_back( + Gtk::Menu_Helpers::MenuElem( + p->human_name(), + sigc::bind(sigc::mem_fun(this, &GraphCanvas::load_plugin), p))); + } else if (_plugin_menu && p->type() == Plugin::LV2 && p->lilv_plugin()) { + if (lilv_plugin_is_replaced(p->lilv_plugin())) { + //info << (boost::format("[Menu] LV2 plugin <%s> hidden") % p->uri()) << endl; + return; + } + + const LilvPluginClass* pc = lilv_plugin_get_class(p->lilv_plugin()); + const LilvNode* class_uri = lilv_plugin_class_get_uri(pc); + const char* class_uri_str = lilv_node_as_string(class_uri); + + Glib::RefPtr icon = _app.icon_from_path( + PluginModel::get_lv2_icon_path(p->lilv_plugin()), 16); + + pair range = _class_menus.equal_range(class_uri_str); + if (range.first == _class_menus.end() || range.first == range.second + || range.first->second.menu == _plugin_menu) { + _classless_menu->items().push_back( + Gtk::Menu_Helpers::MenuElem( + p->human_name(), + sigc::bind(sigc::mem_fun(this, &GraphCanvas::load_plugin), p))); + if (!_classless_menu->is_visible()) + _classless_menu->show(); + } else { + // For each menu that represents plugin's class (possibly several) + for (iterator i = range.first; i != range.second ; ++i) { + Gtk::Menu* menu = i->second.menu; + if (icon) { + Gtk::Image* image = new Gtk::Image(icon); + menu->items().push_back( + Gtk::Menu_Helpers::ImageMenuElem( + p->human_name(), *image, + sigc::bind(sigc::mem_fun(this, &GraphCanvas::load_plugin), p))); + } else { + menu->items().push_back( + Gtk::Menu_Helpers::MenuElem( + p->human_name(), + sigc::bind(sigc::mem_fun(this, &GraphCanvas::load_plugin), p))); + } + if (!i->second.item->is_visible()) + i->second.item->show(); + } + } + } +} + +void +GraphCanvas::add_block(SharedPtr bm) +{ + SharedPtr pm = PtrCast(bm); + NodeModule* module; + if (pm) { + module = SubgraphModule::create(*this, pm, _human_names); + } else { + module = NodeModule::create(*this, bm, _human_names); + //const PluginModel* plugm = dynamic_cast(nm->plugin()); + //if (plugm && !plugm->icon_path().empty()) + // module->set_icon(_app.icon_from_path(plugm->icon_path(), 100).operator->()); + } + + module->show(); + _views.insert(std::make_pair(bm, module)); + if (_pastees.find(bm->path()) != _pastees.end()) { + module->set_selected(true); + } +} + +void +GraphCanvas::remove_block(SharedPtr bm) +{ + Views::iterator i = _views.find(bm); + + if (i != _views.end()) { + const guint n_ports = i->second->num_ports(); + for (gint p = n_ports - 1; p >= 0; --p) { + delete i->second->get_port(p); + } + delete i->second; + _views.erase(i); + } +} + +void +GraphCanvas::add_port(SharedPtr pm) +{ + GraphPortModule* view = GraphPortModule::create(*this, pm, _human_names); + _views.insert(std::make_pair(pm, view)); + view->show(); +} + +void +GraphCanvas::remove_port(SharedPtr pm) +{ + Views::iterator i = _views.find(pm); + + // Port on this graph + if (i != _views.end()) { + delete i->second; + _views.erase(i); + + } else { + NodeModule* module = dynamic_cast(_views[pm->parent()]); + module->delete_port_view(pm); + } + + assert(_views.find(pm) == _views.end()); +} + +Ganv::Port* +GraphCanvas::get_port_view(SharedPtr port) +{ + Ganv::Module* module = _views[port]; + + // Port on this graph + if (module) { + GraphPortModule* ppm = dynamic_cast(module); + return ppm + ? *ppm->begin() + : dynamic_cast(module); + } else { + module = dynamic_cast(_views[port->parent()]); + if (module) { + for (Ganv::Module::iterator p = module->begin(); + p != module->end(); ++p) { + GUI::Port* pv = dynamic_cast(*p); + if (pv && pv->model() == port) + return pv; + } + } + } + + return NULL; +} + +void +GraphCanvas::connection(SharedPtr cm) +{ + Ganv::Port* const tail = get_port_view(cm->tail()); + Ganv::Port* const head = get_port_view(cm->head()); + + if (tail && head) { + new GUI::Edge(*this, cm, tail, head, tail->get_fill_color()); + } else { + _app.log().error(Raul::fmt("Unable to find ports to connect %1% => %2%\n") + % cm->tail_path() % cm->head_path()); + } +} + +void +GraphCanvas::disconnection(SharedPtr cm) +{ + Ganv::Port* const src = get_port_view(cm->tail()); + Ganv::Port* const dst = get_port_view(cm->head()); + + if (src && dst) { + remove_edge(src, dst); + } else { + _app.log().error(Raul::fmt("Unable to find ports to disconnect %1% => %2%\n") + % cm->tail_path() % cm->head_path()); + } +} + +void +GraphCanvas::connect(Ganv::Node* tail, + Ganv::Node* head) +{ + const Ingen::GUI::Port* const src + = dynamic_cast(tail); + + const Ingen::GUI::Port* const dst + = dynamic_cast(head); + + if (!src || !dst) + return; + + _app.interface()->connect(src->model()->path(), dst->model()->path()); +} + +void +GraphCanvas::disconnect(Ganv::Node* tail, + Ganv::Node* head) +{ + const Ingen::GUI::Port* const t = dynamic_cast(tail); + const Ingen::GUI::Port* const h = dynamic_cast(head); + + _app.interface()->disconnect(t->model()->path(), h->model()->path()); +} + +void +GraphCanvas::auto_menu_position(int& x, int& y, bool& push_in) +{ + std::pair scroll_offsets; + get_scroll_offsets(scroll_offsets.first, scroll_offsets.second); + + if (_auto_position_count > 0 && scroll_offsets != _auto_position_scroll_offsets) + _auto_position_count = 0; // scrolling happened since last time, reset + + const int cascade = (_auto_position_count > 0) ? (_auto_position_count * 32) : 0; + + x = 64 + cascade; + y = 64 + cascade; + push_in = true; + + _last_click_x = scroll_offsets.first + x; + _last_click_y = scroll_offsets.second + y; + + ++_auto_position_count; + _auto_position_scroll_offsets = scroll_offsets; +} + +bool +GraphCanvas::on_event(GdkEvent* event) +{ + assert(event); + + bool ret = false; + + switch (event->type) { + case GDK_BUTTON_PRESS: + if (event->button.button == 3) { + _auto_position_count = 0; + _last_click_x = (int)event->button.x; + _last_click_y = (int)event->button.y; + show_menu(false, event->button.button, event->button.time); + ret = true; + } + break; + + case GDK_KEY_PRESS: + switch (event->key.keyval) { + case GDK_Delete: + destroy_selection(); + ret = true; + break; + case GDK_Home: + scroll_to(0, 0); + break; + case GDK_space: + case GDK_Menu: + show_menu(true, 3, event->key.time); + default: break; + } + + default: break; + } + + return ret; +} + +void +GraphCanvas::clear_selection() +{ + GraphWindow* win = _app.window_factory()->graph_window(_graph); + if (win) { + win->hide_documentation(); + } + + Ganv::Canvas::clear_selection(); +} + +static void +destroy_node(GanvNode* node, void* data) +{ + if (!GANV_IS_MODULE(node)) { + return; + } + + App* app = (App*)data; + Ganv::Module* module = Glib::wrap(GANV_MODULE(node)); + NodeModule* node_module = dynamic_cast(module); + + if (node_module) { + app->interface()->del(node_module->block()->uri()); + } else { + GraphPortModule* port_module = dynamic_cast(module); + if (port_module) { + app->interface()->del(port_module->port()->uri()); + } + } +} + +static void +destroy_edge(GanvEdge* edge, void* data) +{ + App* app = (App*)data; + Ganv::Edge* edgemm = Glib::wrap(edge); + + Port* tail = dynamic_cast(edgemm->get_tail()); + Port* head = dynamic_cast(edgemm->get_head()); + app->interface()->disconnect(tail->model()->path(), head->model()->path()); +} + +void +GraphCanvas::destroy_selection() +{ + for_each_selected_node(destroy_node, &_app); + for_each_selected_edge(destroy_edge, &_app); +} + +static void +serialise_node(GanvNode* node, void* data) +{ + Serialisation::Serialiser* serialiser = (Serialisation::Serialiser*)data; + if (!GANV_IS_MODULE(node)) { + return; + } + + Ganv::Module* module = Glib::wrap(GANV_MODULE(node)); + NodeModule* node_module = dynamic_cast(module); + + if (node_module) { + serialiser->serialise(node_module->block()); + } else { + GraphPortModule* port_module = dynamic_cast(module); + if (port_module) { + serialiser->serialise(port_module->port()); + } + } +} + +static void +serialise_edge(GanvEdge* edge, void* data) +{ + Serialisation::Serialiser* serialiser = (Serialisation::Serialiser*)data; + if (!GANV_IS_EDGE(edge)) { + return; + } + + GUI::Edge* gedge = dynamic_cast(Glib::wrap(GANV_EDGE(edge))); + if (gedge) { + serialiser->serialise_edge(Sord::Node(), gedge->model()); + } +} + +void +GraphCanvas::copy_selection() +{ + static const char* base_uri = "http://drobilla.net/ns/ingen/selection/"; + Serialisation::Serialiser serialiser(*_app.world()); + serialiser.start_to_string(_graph->path(), base_uri); + + for_each_selected_node(serialise_node, &serialiser); + for_each_selected_edge(serialise_edge, &serialiser); + + const std::string result = serialiser.finish(); + _paste_count = 0; + + Glib::RefPtr clipboard = Gtk::Clipboard::get(); + clipboard->set_text(result); +} + +void +GraphCanvas::paste() +{ + Glib::ustring str = Gtk::Clipboard::get()->wait_for_text(); + SharedPtr parser = _app.loader()->parser(); + if (!parser) { + _app.log().error("Unable to load parser, paste unavailable\n"); + return; + } + + clear_selection(); + _pastees.clear(); + ++_paste_count; + + const URIs& uris = _app.uris(); + + Builder builder(_app.world()->uris(), *_app.interface()); + ClientStore clipboard(_app.world()->uris(), _app.log()); + clipboard.set_plugins(_app.store()->plugins()); + + // mkdir -p + string to_create = _graph->path().substr(1); + string created = "/"; + Resource::Properties props; + props.insert(make_pair(uris.rdf_type, + uris.ingen_Graph)); + props.insert(make_pair(uris.ingen_polyphony, + _app.forge().make(int32_t(_graph->internal_poly())))); + clipboard.put(GraphObject::root_uri(), props); + size_t first_slash; + while (to_create != "/" && !to_create.empty() + && (first_slash = to_create.find("/")) != string::npos) { + created += to_create.substr(0, first_slash); + assert(Raul::Path::is_valid(created)); + clipboard.put(GraphObject::path_to_uri(Raul::Path(created)), props); + to_create = to_create.substr(first_slash + 1); + } + + if (!_graph->path().is_root()) + clipboard.put(_graph->uri(), props); + + boost::optional parent; + boost::optional symbol; + + if (!_graph->path().is_root()) { + parent = _graph->path(); + } + + ClashAvoider avoider(*_app.store().get(), clipboard, &clipboard); + static const char* base_uri = "http://drobilla.net/ns/ingen/selection/"; + parser->parse_string(_app.world(), &avoider, str, base_uri, + parent, symbol); + + for (Store::iterator i = clipboard.begin(); i != clipboard.end(); ++i) { + if (_graph->path().is_root() && i->first.is_root()) + continue; + + GraphObject::Properties& props = i->second->properties(); + + GraphObject::Properties::iterator x = props.find(uris.ingen_canvasX); + if (x != i->second->properties().end()) + x->second = _app.forge().make( + x->second.get_float() + (20.0f * _paste_count)); + + GraphObject::Properties::iterator y = props.find(uris.ingen_canvasY); + if (y != i->second->properties().end()) + y->second = _app.forge().make( + y->second.get_float() + (20.0f * _paste_count)); + + builder.build(i->second); + _pastees.insert(i->first); + } + + builder.connect(PtrCast(clipboard.object(_graph->path()))); +} + +void +GraphCanvas::generate_port_name( + const string& sym_base, string& symbol, + const string& name_base, string& name) +{ + symbol = sym_base; + name = name_base; + + char num_buf[5]; + uint32_t i = 1; + for ( ; i < 9999; ++i) { + snprintf(num_buf, sizeof(num_buf), "%u", i); + symbol = sym_base + "_"; + symbol += num_buf; + if (!_graph->get_port(Raul::Symbol::symbolify(symbol))) + break; + } + + assert(Raul::Path::is_valid(string("/") + symbol)); + + name.append(" ").append(num_buf); +} + +void +GraphCanvas::menu_add_port(const string& sym_base, const string& name_base, + const Raul::URI& type, bool is_output) +{ + string sym, name; + generate_port_name(sym_base, sym, name_base, name); + const Raul::Path& path = _graph->path().child(Raul::Symbol(sym)); + + const URIs& uris = _app.uris(); + + Resource::Properties props = get_initial_data(); + props.insert(make_pair(uris.rdf_type, + _app.forge().alloc_uri(type))); + if (type == uris.atom_AtomPort) { + props.insert(make_pair(uris.atom_bufferType, + uris.atom_Sequence)); + } + props.insert(make_pair(uris.rdf_type, + is_output ? uris.lv2_OutputPort : uris.lv2_InputPort)); + props.insert(make_pair(uris.lv2_index, + _app.forge().make(int32_t(_graph->num_ports())))); + props.insert(make_pair(uris.lv2_name, + _app.forge().alloc(name.c_str()))); + _app.interface()->put(GraphObject::path_to_uri(path), props); +} + +void +GraphCanvas::load_plugin(WeakPtr weak_plugin) +{ + SharedPtr plugin = weak_plugin.lock(); + if (!plugin) + return; + + Raul::Symbol symbol = plugin->default_block_symbol(); + unsigned offset = _app.store()->child_name_offset(_graph->path(), symbol); + if (offset != 0) { + std::stringstream ss; + ss << symbol << "_" << offset; + symbol = Raul::Symbol(ss.str()); + } + + const URIs& uris = _app.uris(); + const Raul::Path path = _graph->path().child(symbol); + + // FIXME: polyphony? + GraphObject::Properties props = get_initial_data(); + props.insert(make_pair(uris.rdf_type, uris.ingen_Block)); + props.insert(make_pair(uris.ingen_prototype, + uris.forge.alloc_uri(plugin->uri()))); + _app.interface()->put(GraphObject::path_to_uri(path), props); +} + +/** Try to guess a suitable location for a new module. + */ +void +GraphCanvas::get_new_module_location(double& x, double& y) +{ + int scroll_x; + int scroll_y; + get_scroll_offsets(scroll_x, scroll_y); + x = scroll_x + 20; + y = scroll_y + 20; +} + +GraphObject::Properties +GraphCanvas::get_initial_data(Resource::Graph ctx) +{ + GraphObject::Properties result; + const URIs& uris = _app.uris(); + result.insert( + make_pair(uris.ingen_canvasX, + Resource::Property(_app.forge().make((float)_last_click_x), + ctx))); + result.insert( + make_pair(uris.ingen_canvasY, + Resource::Property(_app.forge().make((float)_last_click_y), + ctx))); + return result; +} + +void +GraphCanvas::menu_load_plugin() +{ + _app.window_factory()->present_load_plugin( + _graph, get_initial_data()); +} + +void +GraphCanvas::menu_load_graph() +{ + _app.window_factory()->present_load_subgraph( + _graph, get_initial_data(Resource::EXTERNAL)); +} + +void +GraphCanvas::menu_new_graph() +{ + _app.window_factory()->present_new_subgraph( + _graph, get_initial_data(Resource::EXTERNAL)); +} + +} // namespace GUI +} // namespace Ingen diff --git a/src/gui/GraphCanvas.hpp b/src/gui/GraphCanvas.hpp new file mode 100644 index 00000000..9144518a --- /dev/null +++ b/src/gui/GraphCanvas.hpp @@ -0,0 +1,174 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_GUI_GRAPHCANVAS_HPP +#define INGEN_GUI_GRAPHCANVAS_HPP + +#include +#include +#include + +#include + +#include "lilv/lilv.h" + +#include "ganv/Canvas.hpp" +#include "ganv/Module.hpp" +#include "raul/SharedPtr.hpp" +#include "raul/Path.hpp" + +#include "NodeModule.hpp" +#include "ingen/GraphObject.hpp" +#include "ingen/client/EdgeModel.hpp" + +namespace Ingen { + +namespace Client { class GraphModel; } + +namespace GUI { + +class NodeModule; + +/** Graph canvas widget. + * + * \ingroup GUI + */ +class GraphCanvas : public Ganv::Canvas +{ +public: + GraphCanvas(App& app, + SharedPtr graph, + int width, + int height); + + virtual ~GraphCanvas() {} + + App& app() { return _app; } + + void build(); + void show_human_names(bool show); + void show_port_names(bool show); + bool show_port_names() const { return _show_port_names; } + + void add_plugin(SharedPtr pm); + void add_block(SharedPtr bm); + void remove_block(SharedPtr bm); + void add_port(SharedPtr pm); + void remove_port(SharedPtr pm); + void connection(SharedPtr cm); + void disconnection(SharedPtr cm); + + void get_new_module_location(double& x, double& y); + + void clear_selection(); + void destroy_selection(); + void copy_selection(); + void paste(); + + void show_menu(bool position, unsigned button, uint32_t time); + + bool on_event(GdkEvent* event); + +private: + enum ControlType { NUMBER, BUTTON }; + void generate_port_name( + const std::string& sym_base, std::string& sym, + const std::string& name_base, std::string& name); + + void menu_add_port( + const std::string& sym_base, const std::string& name_base, + const Raul::URI& type, bool is_output); + + void menu_load_plugin(); + void menu_new_graph(); + void menu_load_graph(); + void load_plugin(WeakPtr plugin); + + void build_menus(); + + void build_internal_menu(); + void build_classless_menu(); + + void auto_menu_position(int& x, int& y, bool& push_in); + + typedef std::multimap LV2Children; + void build_plugin_menu(); + size_t build_plugin_class_menu( + Gtk::Menu* menu, + const LilvPluginClass* plugin_class, + const LilvPluginClasses* classes, + const LV2Children& children, + std::set& ancestors); + + GraphObject::Properties get_initial_data(Resource::Graph ctx=Resource::DEFAULT); + + Ganv::Port* get_port_view(SharedPtr port); + + void connect(Ganv::Node* src, + Ganv::Node* dst); + + void disconnect(Ganv::Node* src, + Ganv::Node* dst); + + App& _app; + SharedPtr _graph; + + typedef std::map, Ganv::Module*> Views; + Views _views; + + int _auto_position_count; + std::pair _auto_position_scroll_offsets; + + int _last_click_x; + int _last_click_y; + int _paste_count; + + // Track pasted objects so they can be selected when they arrive + std::set _pastees; + + struct MenuRecord { + MenuRecord(Gtk::MenuItem* i, Gtk::Menu* m) : item(i), menu(m) {} + Gtk::MenuItem* item; + Gtk::Menu* menu; + }; + + typedef std::multimap ClassMenus; + + ClassMenus _class_menus; + + Gtk::Menu* _menu; + Gtk::Menu* _internal_menu; + Gtk::Menu* _classless_menu; + Gtk::Menu* _plugin_menu; + Gtk::MenuItem* _menu_add_audio_input; + Gtk::MenuItem* _menu_add_audio_output; + Gtk::MenuItem* _menu_add_control_input; + Gtk::MenuItem* _menu_add_control_output; + Gtk::MenuItem* _menu_add_event_input; + Gtk::MenuItem* _menu_add_event_output; + Gtk::MenuItem* _menu_load_plugin; + Gtk::MenuItem* _menu_load_graph; + Gtk::MenuItem* _menu_new_graph; + Gtk::CheckMenuItem* _menu_edit; + + bool _human_names; + bool _show_port_names; +}; + +} // namespace GUI +} // namespace Ingen + +#endif // INGEN_GUI_GRAPHCANVAS_HPP diff --git a/src/gui/GraphPortModule.cpp b/src/gui/GraphPortModule.cpp new file mode 100644 index 00000000..38735088 --- /dev/null +++ b/src/gui/GraphPortModule.cpp @@ -0,0 +1,166 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#include +#include +#include + +#include "ingen/Interface.hpp" +#include "ingen/client/BlockModel.hpp" +#include "ingen/client/GraphModel.hpp" + +#include "App.hpp" +#include "Configuration.hpp" +#include "GraphCanvas.hpp" +#include "GraphPortModule.hpp" +#include "GraphWindow.hpp" +#include "Port.hpp" +#include "PortMenu.hpp" +#include "RenameWindow.hpp" +#include "WidgetFactory.hpp" +#include "WindowFactory.hpp" + +using namespace std; + +namespace Ingen { + +using namespace Client; + +namespace GUI { + +GraphPortModule::GraphPortModule(GraphCanvas& canvas, + SharedPtr model) + : Ganv::Module(canvas, "", 0, 0, false) // FIXME: coords? + , _model(model) +{ + assert(model); + + assert(PtrCast(model->parent())); + + set_stacked(model->polyphonic()); + + model->signal_property().connect( + sigc::mem_fun(this, &GraphPortModule::property_changed)); + + signal_moved().connect( + sigc::mem_fun(this, &GraphPortModule::store_location)); +} + +GraphPortModule* +GraphPortModule::create(GraphCanvas& canvas, + SharedPtr model, + bool human) +{ + GraphPortModule* ret = new GraphPortModule(canvas, model); + Port* port = Port::create(canvas.app(), *ret, model, human, true); + + ret->set_port(port); + + for (GraphObject::Properties::const_iterator m = model->properties().begin(); + m != model->properties().end(); ++m) + ret->property_changed(m->first, m->second); + + return ret; +} + +App& +GraphPortModule::app() const +{ + return ((GraphCanvas*)canvas())->app(); +} + +bool +GraphPortModule::show_menu(GdkEventButton* ev) +{ + return _port->show_menu(ev); +} + +void +GraphPortModule::store_location(double ax, double ay) +{ + const URIs& uris = app().uris(); + + const Raul::Atom x(app().forge().make(static_cast(ax))); + const Raul::Atom y(app().forge().make(static_cast(ay))); + + if (x != _model->get_property(uris.ingen_canvasX) || + y != _model->get_property(uris.ingen_canvasY)) + { + Resource::Properties remove; + remove.insert(make_pair(uris.ingen_canvasX, uris.wildcard)); + remove.insert(make_pair(uris.ingen_canvasY, uris.wildcard)); + Resource::Properties add; + add.insert(make_pair(uris.ingen_canvasX, + Resource::Property(x, Resource::INTERNAL))); + add.insert(make_pair(uris.ingen_canvasY, + Resource::Property(y, Resource::INTERNAL))); + app().interface()->delta(_model->uri(), remove, add); + } +} + +void +GraphPortModule::show_human_names(bool b) +{ + const URIs& uris = app().uris(); + const Raul::Atom& name = _model->get_property(uris.lv2_name); + if (b && name.type() == uris.forge.String) { + set_name(name.get_string()); + } else { + set_name(_model->symbol().c_str()); + } +} + +void +GraphPortModule::set_name(const std::string& n) +{ + _port->set_label(n.c_str()); +} + +void +GraphPortModule::property_changed(const Raul::URI& key, const Raul::Atom& value) +{ + const URIs& uris = app().uris(); + if (value.type() == uris.forge.Float) { + if (key == uris.ingen_canvasX) { + move_to(value.get_float(), get_y()); + } else if (key == uris.ingen_canvasY) { + move_to(get_x(), value.get_float()); + } + } else if (value.type() == uris.forge.String) { + if (key == uris.lv2_name + && app().configuration()->name_style() == Configuration::HUMAN) { + set_name(value.get_string()); + } else if (key == uris.lv2_symbol + && app().configuration()->name_style() == Configuration::PATH) { + set_name(value.get_string()); + } + } else if (value.type() == uris.forge.Bool) { + if (key == uris.ingen_polyphonic) { + set_stacked(value.get_bool()); + } + } +} + +void +GraphPortModule::set_selected(gboolean b) +{ + if (b != get_selected()) { + Module::set_selected(b); + } +} + +} // namespace GUI +} // namespace Ingen diff --git a/src/gui/GraphPortModule.hpp b/src/gui/GraphPortModule.hpp new file mode 100644 index 00000000..722f35c3 --- /dev/null +++ b/src/gui/GraphPortModule.hpp @@ -0,0 +1,83 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_GUI_GRAPHPORTMODULE_HPP +#define INGEN_GUI_GRAPHPORTMODULE_HPP + +#include + +#include + +#include "ganv/Module.hpp" +#include "raul/URI.hpp" + +#include "Port.hpp" + +namespace Raul { class Atom; } + +namespace Ingen { namespace Client { + class PortModel; +} } + +namespace Ingen { +namespace GUI { + +class GraphCanvas; +class Port; +class PortMenu; + +/** A "module" to represent a graph's port on its own canvas. + * + * Translation: This is the nameless single port pseudo module thingy. + * + * \ingroup GUI + */ +class GraphPortModule : public Ganv::Module +{ +public: + static GraphPortModule* create( + GraphCanvas& canvas, + SharedPtr model, + bool human); + + App& app() const; + + virtual void store_location(double x, double y); + void show_human_names(bool b); + + void set_name(const std::string& n); + + SharedPtr port() const { return _model; } + +protected: + GraphPortModule(GraphCanvas& canvas, + SharedPtr model); + + bool show_menu(GdkEventButton* ev); + void set_selected(gboolean b); + + void set_port(Port* port) { _port = port; } + + void property_changed(const Raul::URI& predicate, const Raul::Atom& value); + + SharedPtr _model; + Port* _port; +}; + +} // namespace GUI +} // namespace Ingen + +#endif // INGEN_GUI_GRAPHPORTMODULE_HPP diff --git a/src/gui/GraphTreeWindow.cpp b/src/gui/GraphTreeWindow.cpp new file mode 100644 index 00000000..7ddbb23a --- /dev/null +++ b/src/gui/GraphTreeWindow.cpp @@ -0,0 +1,234 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#include "App.hpp" +#include "GraphTreeWindow.hpp" +#include "SubgraphModule.hpp" +#include "WindowFactory.hpp" +#include "ingen/Interface.hpp" +#include "ingen/Log.hpp" +#include "ingen/client/ClientStore.hpp" +#include "ingen/client/GraphModel.hpp" +#include "raul/Path.hpp" + +using namespace std; + +namespace Ingen { + +using namespace Client; + +namespace GUI { + +GraphTreeWindow::GraphTreeWindow(BaseObjectType* cobject, + const Glib::RefPtr& xml) + : Window(cobject) + , _app(NULL) + , _enable_signal(true) +{ + xml->get_widget_derived("graphs_treeview", _graphs_treeview); + + _graph_treestore = Gtk::TreeStore::create(_graph_tree_columns); + _graphs_treeview->set_window(this); + _graphs_treeview->set_model(_graph_treestore); + Gtk::TreeViewColumn* name_col = Gtk::manage(new Gtk::TreeViewColumn( + "Graph", _graph_tree_columns.name_col)); + Gtk::TreeViewColumn* enabled_col = Gtk::manage(new Gtk::TreeViewColumn( + "Run", _graph_tree_columns.enabled_col)); + name_col->set_resizable(true); + name_col->set_expand(true); + + _graphs_treeview->append_column(*name_col); + _graphs_treeview->append_column(*enabled_col); + Gtk::CellRendererToggle* enabled_renderer = dynamic_cast( + _graphs_treeview->get_column_cell_renderer(1)); + enabled_renderer->property_activatable() = true; + + _graph_tree_selection = _graphs_treeview->get_selection(); + + _graphs_treeview->signal_row_activated().connect( + sigc::mem_fun(this, &GraphTreeWindow::event_graph_activated)); + enabled_renderer->signal_toggled().connect( + sigc::mem_fun(this, &GraphTreeWindow::event_graph_enabled_toggled)); + + _graphs_treeview->columns_autosize(); +} + +void +GraphTreeWindow::init(App& app, ClientStore& store) +{ + _app = &app; + store.signal_new_object().connect( + sigc::mem_fun(this, &GraphTreeWindow::new_object)); +} + +void +GraphTreeWindow::new_object(SharedPtr object) +{ + SharedPtr graph = PtrCast(object); + if (graph) + add_graph(graph); +} + +void +GraphTreeWindow::add_graph(SharedPtr pm) +{ + if (!pm->parent()) { + Gtk::TreeModel::iterator iter = _graph_treestore->append(); + Gtk::TreeModel::Row row = *iter; + if (pm->path().is_root()) { + row[_graph_tree_columns.name_col] = _app->interface()->uri(); + } else { + row[_graph_tree_columns.name_col] = pm->symbol().c_str(); + } + row[_graph_tree_columns.enabled_col] = pm->enabled(); + row[_graph_tree_columns.graph_model_col] = pm; + _graphs_treeview->expand_row(_graph_treestore->get_path(iter), true); + } else { + Gtk::TreeModel::Children children = _graph_treestore->children(); + Gtk::TreeModel::iterator c = find_graph(children, pm->parent()); + + if (c != children.end()) { + Gtk::TreeModel::iterator iter = _graph_treestore->append(c->children()); + Gtk::TreeModel::Row row = *iter; + row[_graph_tree_columns.name_col] = pm->symbol().c_str(); + row[_graph_tree_columns.enabled_col] = pm->enabled(); + row[_graph_tree_columns.graph_model_col] = pm; + _graphs_treeview->expand_row(_graph_treestore->get_path(iter), true); + } + } + + pm->signal_property().connect( + sigc::bind(sigc::mem_fun(this, &GraphTreeWindow::graph_property_changed), + pm)); + + pm->signal_moved().connect( + sigc::bind(sigc::mem_fun(this, &GraphTreeWindow::graph_moved), + pm)); + + pm->signal_destroyed().connect( + sigc::bind(sigc::mem_fun(this, &GraphTreeWindow::remove_graph), + pm)); +} + +void +GraphTreeWindow::remove_graph(SharedPtr pm) +{ + Gtk::TreeModel::iterator i = find_graph(_graph_treestore->children(), pm); + if (i != _graph_treestore->children().end()) + _graph_treestore->erase(i); +} + +Gtk::TreeModel::iterator +GraphTreeWindow::find_graph( + Gtk::TreeModel::Children root, + SharedPtr graph) +{ + for (Gtk::TreeModel::iterator c = root.begin(); c != root.end(); ++c) { + SharedPtr pm = (*c)[_graph_tree_columns.graph_model_col]; + if (graph == pm) { + return c; + } else if ((*c)->children().size() > 0) { + Gtk::TreeModel::iterator ret = find_graph(c->children(), graph); + if (ret != c->children().end()) + return ret; + } + } + return root.end(); +} + +/** Show the context menu for the selected graph in the graphs treeview. + */ +void +GraphTreeWindow::show_graph_menu(GdkEventButton* ev) +{ + Gtk::TreeModel::iterator active = _graph_tree_selection->get_selected(); + if (active) { + Gtk::TreeModel::Row row = *active; + SharedPtr pm = row[_graph_tree_columns.graph_model_col]; + if (pm) { + _app->log().warn("TODO: graph menu from tree window"); + } + } +} + +void +GraphTreeWindow::event_graph_activated(const Gtk::TreeModel::Path& path, Gtk::TreeView::Column* col) +{ + Gtk::TreeModel::iterator active = _graph_treestore->get_iter(path); + Gtk::TreeModel::Row row = *active; + SharedPtr pm = row[_graph_tree_columns.graph_model_col]; + + _app->window_factory()->present_graph(pm); +} + +void +GraphTreeWindow::event_graph_enabled_toggled(const Glib::ustring& path_str) +{ + Gtk::TreeModel::Path path(path_str); + Gtk::TreeModel::iterator active = _graph_treestore->get_iter(path); + Gtk::TreeModel::Row row = *active; + + SharedPtr pm = row[_graph_tree_columns.graph_model_col]; + assert(pm); + + if (_enable_signal) + _app->interface()->set_property( + pm->uri(), + _app->uris().ingen_enabled, + _app->forge().make((bool)!pm->enabled())); +} + +void +GraphTreeWindow::graph_property_changed(const Raul::URI& key, + const Raul::Atom& value, + SharedPtr graph) +{ + const URIs& uris = _app->uris(); + _enable_signal = false; + if (key == uris.ingen_enabled && value.type() == uris.forge.Bool) { + Gtk::TreeModel::iterator i = find_graph(_graph_treestore->children(), graph); + if (i != _graph_treestore->children().end()) { + Gtk::TreeModel::Row row = *i; + row[_graph_tree_columns.enabled_col] = value.get_bool(); + } else { + _app->log().error(Raul::fmt("Unable to find graph %1%\n") + % graph->path()); + } + } + _enable_signal = true; +} + +void +GraphTreeWindow::graph_moved(SharedPtr graph) +{ + _enable_signal = false; + + Gtk::TreeModel::iterator i + = find_graph(_graph_treestore->children(), graph); + + if (i != _graph_treestore->children().end()) { + Gtk::TreeModel::Row row = *i; + row[_graph_tree_columns.name_col] = graph->symbol().c_str(); + } else { + _app->log().error(Raul::fmt("Unable to find graph %1%\n") + % graph->path()); + } + + _enable_signal = true; +} + +} // namespace GUI +} // namespace Ingen diff --git a/src/gui/GraphTreeWindow.hpp b/src/gui/GraphTreeWindow.hpp new file mode 100644 index 00000000..3bd50b76 --- /dev/null +++ b/src/gui/GraphTreeWindow.hpp @@ -0,0 +1,123 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_GUI_GRAPHTREEWINDOW_HPP +#define INGEN_GUI_GRAPHTREEWINDOW_HPP + +#include +#include +#include +#include + +#include "Window.hpp" + +namespace Raul { class Path; } + +namespace Ingen { + +namespace Client { class ClientStore; class ObjectModel; } + +namespace GUI { + +class GraphWindow; +class GraphTreeView; + +/** Window with a TreeView of all loaded graphs. + * + * \ingroup GUI + */ +class GraphTreeWindow : public Window +{ +public: + GraphTreeWindow(BaseObjectType* cobject, + const Glib::RefPtr& xml); + + void init(App& app, Client::ClientStore& store); + + void new_object(SharedPtr object); + + void graph_property_changed(const Raul::URI& key, + const Raul::Atom& value, + SharedPtr gm); + + void graph_moved(SharedPtr graph); + + void add_graph(SharedPtr gm); + void remove_graph(SharedPtr gm); + void show_graph_menu(GdkEventButton* ev); + +protected: + void event_graph_activated(const Gtk::TreeModel::Path& path, + Gtk::TreeView::Column* col); + + void event_graph_enabled_toggled(const Glib::ustring& path_str); + + Gtk::TreeModel::iterator find_graph( + Gtk::TreeModel::Children root, + SharedPtr graph); + + GraphTreeView* _graphs_treeview; + + struct GraphTreeModelColumns : public Gtk::TreeModel::ColumnRecord + { + GraphTreeModelColumns() { + add(name_col); + add(enabled_col); + add(graph_model_col); + } + + Gtk::TreeModelColumn name_col; + Gtk::TreeModelColumn enabled_col; + Gtk::TreeModelColumn > graph_model_col; + }; + + App* _app; + GraphTreeModelColumns _graph_tree_columns; + Glib::RefPtr _graph_treestore; + Glib::RefPtr _graph_tree_selection; + bool _enable_signal; +}; + +/** Derived TreeView class to support context menus for graphs */ +class GraphTreeView : public Gtk::TreeView +{ +public: + GraphTreeView(BaseObjectType* cobject, + const Glib::RefPtr& xml) + : Gtk::TreeView(cobject) + , _window(NULL) + {} + + void set_window(GraphTreeWindow* win) { _window = win; } + + bool on_button_press_event(GdkEventButton* ev) { + bool ret = Gtk::TreeView::on_button_press_event(ev); + + if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3)) + _window->show_graph_menu(ev); + + return ret; + } + +private: + GraphTreeWindow* _window; + +}; // struct GraphTreeView + +} // namespace GUI +} // namespace Ingen + +#endif // INGEN_GUI_GRAPHTREEWINDOW_HPP diff --git a/src/gui/GraphView.cpp b/src/gui/GraphView.cpp new file mode 100644 index 00000000..119438e6 --- /dev/null +++ b/src/gui/GraphView.cpp @@ -0,0 +1,206 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#include +#include + +#include "ingen/Interface.hpp" +#include "ingen/client/GraphModel.hpp" + +#include "App.hpp" +#include "LoadPluginWindow.hpp" +#include "NewSubgraphWindow.hpp" +#include "GraphCanvas.hpp" +#include "GraphTreeWindow.hpp" +#include "GraphView.hpp" +#include "WidgetFactory.hpp" + +using namespace std; + +namespace Ingen { + +using namespace Client; + +namespace GUI { + +GraphView::GraphView(BaseObjectType* cobject, + const Glib::RefPtr& xml) + : Gtk::Box(cobject) + , _app(NULL) + , _breadcrumb_container(NULL) + , _enable_signal(true) +{ + property_visible() = false; + + xml->get_widget("graph_view_breadcrumb_container", _breadcrumb_container); + xml->get_widget("graph_view_toolbar", _toolbar); + xml->get_widget("graph_view_process_but", _process_but); + xml->get_widget("graph_view_poly_spin", _poly_spin); + xml->get_widget("graph_view_refresh_but", _refresh_but); + xml->get_widget("graph_view_save_but", _save_but); + xml->get_widget("graph_view_zoom_full_but", _zoom_full_but); + xml->get_widget("graph_view_zoom_normal_but", _zoom_normal_but); + xml->get_widget("graph_view_scrolledwindow", _canvas_scrolledwindow); + + _toolbar->set_toolbar_style(Gtk::TOOLBAR_ICONS); + _canvas_scrolledwindow->property_hadjustment().get_value()->set_step_increment(10); + _canvas_scrolledwindow->property_vadjustment().get_value()->set_step_increment(10); +} + +void +GraphView::init(App& app) +{ + _app = &app; +} + +void +GraphView::set_graph(SharedPtr graph) +{ + assert(!_canvas); // FIXME: remove + + assert(_breadcrumb_container); // ensure created + + _graph = graph; + _canvas = SharedPtr(new GraphCanvas(*_app, graph, 1600*2, 1200*2)); + _canvas->build(); + + _canvas_scrolledwindow->add(_canvas->widget()); + + _poly_spin->set_range(1, 128); + _poly_spin->set_increments(1, 4); + _poly_spin->set_value(graph->internal_poly()); + + for (GraphObject::Properties::const_iterator i = graph->properties().begin(); + i != graph->properties().end(); ++i) + property_changed(i->first, i->second); + + // Connect model signals to track state + graph->signal_property().connect( + sigc::mem_fun(this, &GraphView::property_changed)); + + // Connect widget signals to do things + _process_but->signal_toggled().connect( + sigc::mem_fun(this, &GraphView::process_toggled)); + _refresh_but->signal_clicked().connect( + sigc::mem_fun(this, &GraphView::refresh_clicked)); + + _zoom_normal_but->signal_clicked().connect(sigc::bind(sigc::mem_fun( + _canvas.get(), &GraphCanvas::set_zoom), 1.0)); + + _zoom_full_but->signal_clicked().connect( + sigc::mem_fun(_canvas.get(), &GraphCanvas::zoom_full)); + + _poly_spin->signal_value_changed().connect( + sigc::mem_fun(*this, &GraphView::poly_changed)); + + #if 0 + _canvas->signal_item_entered.connect( + sigc::mem_fun(*this, &GraphView::canvas_item_entered)); + + _canvas->signal_item_left.connect( + sigc::mem_fun(*this, &GraphView::canvas_item_left)); + #endif + + _canvas->widget().grab_focus(); +} + +SharedPtr +GraphView::create(App& app, SharedPtr graph) +{ + GraphView* result = NULL; + Glib::RefPtr xml = WidgetFactory::create("warehouse_win"); + xml->get_widget_derived("graph_view_box", result); + result->init(app); + result->set_graph(graph); + return SharedPtr(result); +} + +#if 0 +void +GraphView::canvas_item_entered(Gnome::Canvas::Item* item) +{ + NodeModule* m = dynamic_cast(item); + if (m) + signal_object_entered.emit(m->block().get()); + + const Port* p = dynamic_cast(item); + if (p) + signal_object_entered.emit(p->model().get()); +} + +void +GraphView::canvas_item_left(Gnome::Canvas::Item* item) +{ + NodeModule* m = dynamic_cast(item); + if (m) { + signal_object_left.emit(m->block().get()); + return; + } + + const Port* p = dynamic_cast(item); + if (p) + signal_object_left.emit(p->model().get()); +} +#endif + +void +GraphView::process_toggled() +{ + if (!_enable_signal) + return; + + _app->interface()->set_property( + _graph->uri(), + _app->uris().ingen_enabled, + _app->forge().make((bool)_process_but->get_active())); +} + +void +GraphView::poly_changed() +{ + const int poly = _poly_spin->get_value_as_int(); + if (_enable_signal && poly != (int)_graph->internal_poly()) { + _app->interface()->set_property( + _graph->uri(), + _app->uris().ingen_polyphony, + _app->forge().make(poly)); + } +} + +void +GraphView::refresh_clicked() +{ + _app->interface()->get(_graph->uri()); +} + +void +GraphView::property_changed(const Raul::URI& predicate, const Raul::Atom& value) +{ + _enable_signal = false; + if (predicate == _app->uris().ingen_enabled) { + if (value.type() == _app->uris().forge.Bool) { + _process_but->set_active(value.get_bool()); + } + } else if (predicate == _app->uris().ingen_polyphony) { + if (value.type() == _app->uris().forge.Int) { + _poly_spin->set_value(value.get_int32()); + } + } + _enable_signal = true; +} + +} // namespace GUI +} // namespace Ingen diff --git a/src/gui/GraphView.hpp b/src/gui/GraphView.hpp new file mode 100644 index 00000000..cae073af --- /dev/null +++ b/src/gui/GraphView.hpp @@ -0,0 +1,112 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_GUI_GRAPHVIEW_HPP +#define INGEN_GUI_GRAPHVIEW_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "raul/SharedPtr.hpp" +#include "raul/URI.hpp" + +namespace Raul { class Atom; } + +namespace Ingen { + +namespace Client { + class PortModel; + class MetadataModel; + class GraphModel; + class ObjectModel; +} + +namespace GUI { + +class App; +class LoadPluginWindow; +class NewSubgraphWindow; +class GraphCanvas; +class GraphDescriptionWindow; +class SubgraphModule; + +/** The graph specific contents of a GraphWindow (ie the canvas and whatever else). + * + * \ingroup GUI + */ +class GraphView : public Gtk::Box +{ +public: + GraphView(BaseObjectType* cobject, + const Glib::RefPtr& xml); + + void init(App& app); + + SharedPtr canvas() const { return _canvas; } + SharedPtr graph() const { return _graph; } + Gtk::ToolItem* breadcrumb_container() const { return _breadcrumb_container; } + + static SharedPtr create(App& app, + SharedPtr graph); + + sigc::signal signal_object_entered; + sigc::signal signal_object_left; + +private: + void set_graph(SharedPtr graph); + + void process_toggled(); + void poly_changed(); + void clear_clicked(); + void refresh_clicked(); + + #if 0 + void canvas_item_entered(Gnome::Canvas::Item* item); + void canvas_item_left(Gnome::Canvas::Item* item); + #endif + + void property_changed(const Raul::URI& predicate, const Raul::Atom& value); + + void zoom_full(); + + App* _app; + + SharedPtr _graph; + SharedPtr _canvas; + + Gtk::ScrolledWindow* _canvas_scrolledwindow; + Gtk::Toolbar* _toolbar; + Gtk::ToggleToolButton* _process_but; + Gtk::SpinButton* _poly_spin; + Gtk::ToolButton* _refresh_but; + Gtk::ToolButton* _save_but; + Gtk::ToolButton* _zoom_normal_but; + Gtk::ToolButton* _zoom_full_but; + Gtk::ToolItem* _breadcrumb_container; + + bool _enable_signal; +}; + +} // namespace GUI +} // namespace Ingen + +#endif // INGEN_GUI_GRAPHVIEW_HPP diff --git a/src/gui/GraphWindow.cpp b/src/gui/GraphWindow.cpp new file mode 100644 index 00000000..0767f76d --- /dev/null +++ b/src/gui/GraphWindow.cpp @@ -0,0 +1,77 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#include "ingen/client/ClientStore.hpp" +#include "ingen/client/GraphModel.hpp" + +#include "App.hpp" +#include "GraphCanvas.hpp" +#include "GraphView.hpp" +#include "GraphWindow.hpp" +#include "WindowFactory.hpp" + +namespace Ingen { +namespace GUI { + +GraphWindow::GraphWindow(BaseObjectType* cobject, + const Glib::RefPtr& xml) + : Window(cobject) + , _box(NULL) + , _position_stored(false) + , _x(0) + , _y(0) +{ + property_visible() = false; + + xml->get_widget_derived("graph_win_vbox", _box); + + set_title("Ingen"); +} + +GraphWindow::~GraphWindow() +{ + delete _box; +} + +void +GraphWindow::init_window(App& app) +{ + Window::init_window(app); + _box->init_box(app); + _box->set_window(this); +} + +void +GraphWindow::on_show() +{ + if (_position_stored) + move(_x, _y); + + Gtk::Window::on_show(); + + _box->view()->canvas()->widget().grab_focus(); +} + +void +GraphWindow::on_hide() +{ + _position_stored = true; + get_position(_x, _y); + Gtk::Window::on_hide(); +} + +} // namespace GUI +} // namespace Ingen diff --git a/src/gui/GraphWindow.hpp b/src/gui/GraphWindow.hpp new file mode 100644 index 00000000..794619b8 --- /dev/null +++ b/src/gui/GraphWindow.hpp @@ -0,0 +1,81 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_GUI_GRAPH_WINDOW_HPP +#define INGEN_GUI_GRAPH_WINDOW_HPP + +#include + +#include + +#include "raul/SharedPtr.hpp" + +#include "GraphBox.hpp" +#include "Window.hpp" + +namespace Ingen { + +namespace Client { + class GraphModel; +} + +namespace GUI { + +/** A window for a graph. + * + * \ingroup GUI + */ +class GraphWindow : public Window +{ +public: + GraphWindow(BaseObjectType* cobject, + const Glib::RefPtr& xml); + + ~GraphWindow(); + + void init_window(App& app); + + SharedPtr graph() const { return _box->graph(); } + GraphBox* box() const { return _box; } + + void show_documentation(const std::string& doc, bool html) { + _box->show_documentation(doc, html); + } + + void hide_documentation() { + _box->hide_documentation(); + } + + void show_port_status(const Client::PortModel* model, + const Raul::Atom& value) { + _box->show_port_status(model, value); + } + +protected: + void on_hide(); + void on_show(); + +private: + GraphBox* _box; + bool _position_stored; + int _x; + int _y; +}; + +} // namespace GUI +} // namespace Ingen + +#endif // INGEN_GUI_GRAPH_WINDOW_HPP diff --git a/src/gui/LoadGraphWindow.cpp b/src/gui/LoadGraphWindow.cpp new file mode 100644 index 00000000..9f4dde5c --- /dev/null +++ b/src/gui/LoadGraphWindow.cpp @@ -0,0 +1,246 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#include +#include +#include + +#include +#include + +#include "ingen/Interface.hpp" +#include "ingen/client/BlockModel.hpp" +#include "ingen/client/ClientStore.hpp" +#include "ingen/client/GraphModel.hpp" +#include "ingen/runtime_paths.hpp" + +#include "App.hpp" +#include "Configuration.hpp" +#include "LoadGraphWindow.hpp" +#include "GraphView.hpp" +#include "ThreadedLoader.hpp" + +using namespace std; + +namespace Ingen { + +using namespace Client; + +namespace GUI { + +LoadGraphWindow::LoadGraphWindow(BaseObjectType* cobject, + const Glib::RefPtr& xml) + : Gtk::FileChooserDialog(cobject) + , _app(NULL) + , _merge_ports(false) +{ + xml->get_widget("load_graph_symbol_label", _symbol_label); + xml->get_widget("load_graph_symbol_entry", _symbol_entry); + xml->get_widget("load_graph_ports_label", _ports_label); + xml->get_widget("load_graph_merge_ports_radio", _merge_ports_radio); + xml->get_widget("load_graph_insert_ports_radio", _insert_ports_radio); + xml->get_widget("load_graph_poly_voices_radio", _poly_voices_radio); + xml->get_widget("load_graph_poly_from_file_radio", _poly_from_file_radio); + xml->get_widget("load_graph_poly_spinbutton", _poly_spinbutton); + xml->get_widget("load_graph_ok_button", _ok_button); + xml->get_widget("load_graph_cancel_button", _cancel_button); + + _cancel_button->signal_clicked().connect( + sigc::mem_fun(this, &LoadGraphWindow::cancel_clicked)); + _ok_button->signal_clicked().connect( + sigc::mem_fun(this, &LoadGraphWindow::ok_clicked)); + _merge_ports_radio->signal_toggled().connect( + sigc::mem_fun(this, &LoadGraphWindow::merge_ports_selected)); + _insert_ports_radio->signal_toggled().connect( + sigc::mem_fun(this, &LoadGraphWindow::insert_ports_selected)); + _poly_from_file_radio->signal_toggled().connect(sigc::bind( + sigc::mem_fun(_poly_spinbutton, &Gtk::SpinButton::set_sensitive), + false)); + _poly_voices_radio->signal_toggled().connect(sigc::bind( + sigc::mem_fun(_poly_spinbutton, &Gtk::SpinButton::set_sensitive), + true)); + + signal_selection_changed().connect( + sigc::mem_fun(this, &LoadGraphWindow::selection_changed)); + + Gtk::FileFilter filt; + filt.add_pattern("*.ttl"); + filt.set_name("Ingen graph files (*.ttl)"); + filt.add_pattern("*.ingen"); + filt.set_name("Ingen bundles (*.ingen)"); + + set_filter(filt); + + property_select_multiple() = true; + + // Add global examples directory to "shortcut folders" (bookmarks) + const string examples_dir = Ingen::data_file_path("graphs"); + if (Glib::file_test(examples_dir, Glib::FILE_TEST_IS_DIR)) { + add_shortcut_folder(examples_dir); + } +} + +void +LoadGraphWindow::present(SharedPtr graph, + bool import, + GraphObject::Properties data) +{ + _import = import; + set_graph(graph); + _symbol_label->property_visible() = !import; + _symbol_entry->property_visible() = !import; + _ports_label->property_visible() = _import; + _merge_ports_radio->property_visible() = _import; + _insert_ports_radio->property_visible() = _import; + _initial_data = data; + Gtk::Window::present(); +} + +/** Sets the graph model for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +LoadGraphWindow::set_graph(SharedPtr graph) +{ + _graph = graph; + _symbol_entry->set_text(""); + _symbol_entry->set_sensitive(!_import); + _poly_spinbutton->set_value(graph->internal_poly()); +} + +void +LoadGraphWindow::on_show() +{ + if (_app->configuration()->graph_folder().length() > 0) + set_current_folder(_app->configuration()->graph_folder()); + Gtk::FileChooserDialog::on_show(); +} + +void +LoadGraphWindow::merge_ports_selected() +{ + _merge_ports = true; +} + +void +LoadGraphWindow::insert_ports_selected() +{ + _merge_ports = false; +} + +void +LoadGraphWindow::ok_clicked() +{ + if (!_graph) { + hide(); + return; + } + + const URIs& uris = _app->uris(); + + if (_poly_voices_radio->get_active()) + _initial_data.insert( + make_pair(uris.ingen_polyphony, + _app->forge().make(_poly_spinbutton->get_value_as_int()))); + + if (get_uri() == "") + return; + + if (_import) { + // If unset load_graph will load value + boost::optional parent; + boost::optional symbol; + if (!_graph->path().is_root()) { + parent = _graph->path().parent(); + symbol = _graph->symbol(); + } + + _app->loader()->load_graph(true, get_filename(), + parent, symbol, _initial_data); + + } else { + std::list uri_list = get_filenames(); + for (std::list::iterator i = uri_list.begin(); i != uri_list.end(); ++i) { + // Cascade + Raul::Atom& x = _initial_data.find(uris.ingen_canvasX)->second; + x = _app->forge().make(x.get_float() + 20.0f); + Raul::Atom& y = _initial_data.find(uris.ingen_canvasY)->second; + y = _app->forge().make(y.get_float() + 20.0f); + + Raul::Symbol symbol(symbol_from_filename(*i)); + if (uri_list.size() == 1 && _symbol_entry->get_text() != "") + symbol = Raul::Symbol::symbolify(_symbol_entry->get_text()); + + symbol = avoid_symbol_clash(symbol); + + _app->loader()->load_graph(false, *i, + _graph->path(), symbol, _initial_data); + } + } + + _graph.reset(); + hide(); +} + +void +LoadGraphWindow::cancel_clicked() +{ + _graph.reset(); + hide(); +} + +Raul::Symbol +LoadGraphWindow::symbol_from_filename(const Glib::ustring& filename) +{ + std::string symbol_str = Glib::path_get_basename(get_filename()); + symbol_str = symbol_str.substr(0, symbol_str.find('.')); + return Raul::Symbol::symbolify(symbol_str); +} + +Raul::Symbol +LoadGraphWindow::avoid_symbol_clash(const Raul::Symbol& symbol) +{ + unsigned offset = _app->store()->child_name_offset( + _graph->path(), symbol); + + if (offset != 0) { + std::stringstream ss; + ss << symbol << "_" << offset; + return Raul::Symbol(ss.str()); + } else { + return symbol; + } +} + +void +LoadGraphWindow::selection_changed() +{ + if (_import) + return; + + if (get_filenames().size() != 1) { + _symbol_entry->set_text(""); + _symbol_entry->set_sensitive(false); + } else { + _symbol_entry->set_text(avoid_symbol_clash( + symbol_from_filename(get_filename())).c_str()); + _symbol_entry->set_sensitive(true); + } +} + +} // namespace GUI +} // namespace Ingen diff --git a/src/gui/LoadGraphWindow.hpp b/src/gui/LoadGraphWindow.hpp new file mode 100644 index 00000000..2af8e9d2 --- /dev/null +++ b/src/gui/LoadGraphWindow.hpp @@ -0,0 +1,96 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_GUI_LOADGRAPHWINDOW_HPP +#define INGEN_GUI_LOADGRAPHWINDOW_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include "raul/SharedPtr.hpp" + +#include "ingen/GraphObject.hpp" + +namespace Ingen { + +namespace Client { class GraphModel; } + +namespace GUI { + +/** 'Load Graph' Window. + * + * Loaded from XML as a derived object. + * + * \ingroup GUI + */ +class LoadGraphWindow : public Gtk::FileChooserDialog +{ +public: + LoadGraphWindow(BaseObjectType* cobject, + const Glib::RefPtr& xml); + + void init(App& app) { _app = &app; } + + void set_graph(SharedPtr graph); + + void present(SharedPtr graph, + bool import, + GraphObject::Properties data); + +protected: + void on_show(); + +private: + void merge_ports_selected(); + void insert_ports_selected(); + + void selection_changed(); + void cancel_clicked(); + void ok_clicked(); + + Raul::Symbol symbol_from_filename(const Glib::ustring& filename); + Raul::Symbol avoid_symbol_clash(const Raul::Symbol& symbol); + + App* _app; + + GraphObject::Properties _initial_data; + + SharedPtr _graph; + + Gtk::Label* _symbol_label; + Gtk::Entry* _symbol_entry; + Gtk::Label* _ports_label; + Gtk::RadioButton* _merge_ports_radio; + Gtk::RadioButton* _insert_ports_radio; + Gtk::RadioButton* _poly_voices_radio; + Gtk::RadioButton* _poly_from_file_radio; + Gtk::SpinButton* _poly_spinbutton; + Gtk::Button* _ok_button; + Gtk::Button* _cancel_button; + + bool _import; + bool _merge_ports; +}; + +} // namespace GUI +} // namespace Ingen + +#endif // INGEN_GUI_LOADGRAPHWINDOW_HPP diff --git a/src/gui/LoadPatchWindow.cpp b/src/gui/LoadPatchWindow.cpp deleted file mode 100644 index 7ba348a6..00000000 --- a/src/gui/LoadPatchWindow.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#include -#include -#include - -#include -#include - -#include "ingen/Interface.hpp" -#include "ingen/client/BlockModel.hpp" -#include "ingen/client/ClientStore.hpp" -#include "ingen/client/PatchModel.hpp" -#include "ingen/runtime_paths.hpp" - -#include "App.hpp" -#include "Configuration.hpp" -#include "LoadPatchWindow.hpp" -#include "PatchView.hpp" -#include "ThreadedLoader.hpp" - -using namespace std; - -namespace Ingen { - -using namespace Client; - -namespace GUI { - -LoadPatchWindow::LoadPatchWindow(BaseObjectType* cobject, - const Glib::RefPtr& xml) - : Gtk::FileChooserDialog(cobject) - , _app(NULL) - , _merge_ports(false) -{ - xml->get_widget("load_patch_symbol_label", _symbol_label); - xml->get_widget("load_patch_symbol_entry", _symbol_entry); - xml->get_widget("load_patch_ports_label", _ports_label); - xml->get_widget("load_patch_merge_ports_radio", _merge_ports_radio); - xml->get_widget("load_patch_insert_ports_radio", _insert_ports_radio); - xml->get_widget("load_patch_poly_voices_radio", _poly_voices_radio); - xml->get_widget("load_patch_poly_from_file_radio", _poly_from_file_radio); - xml->get_widget("load_patch_poly_spinbutton", _poly_spinbutton); - xml->get_widget("load_patch_ok_button", _ok_button); - xml->get_widget("load_patch_cancel_button", _cancel_button); - - _cancel_button->signal_clicked().connect( - sigc::mem_fun(this, &LoadPatchWindow::cancel_clicked)); - _ok_button->signal_clicked().connect( - sigc::mem_fun(this, &LoadPatchWindow::ok_clicked)); - _merge_ports_radio->signal_toggled().connect( - sigc::mem_fun(this, &LoadPatchWindow::merge_ports_selected)); - _insert_ports_radio->signal_toggled().connect( - sigc::mem_fun(this, &LoadPatchWindow::insert_ports_selected)); - _poly_from_file_radio->signal_toggled().connect(sigc::bind( - sigc::mem_fun(_poly_spinbutton, &Gtk::SpinButton::set_sensitive), - false)); - _poly_voices_radio->signal_toggled().connect(sigc::bind( - sigc::mem_fun(_poly_spinbutton, &Gtk::SpinButton::set_sensitive), - true)); - - signal_selection_changed().connect( - sigc::mem_fun(this, &LoadPatchWindow::selection_changed)); - - Gtk::FileFilter filt; - filt.add_pattern("*.ttl"); - filt.set_name("Ingen patch files (*.ttl)"); - filt.add_pattern("*.ingen"); - filt.set_name("Ingen bundles (*.ingen)"); - - set_filter(filt); - - property_select_multiple() = true; - - // Add global examples directory to "shortcut folders" (bookmarks) - const string examples_dir = Ingen::data_file_path("patches"); - if (Glib::file_test(examples_dir, Glib::FILE_TEST_IS_DIR)) { - add_shortcut_folder(examples_dir); - } -} - -void -LoadPatchWindow::present(SharedPtr patch, - bool import, - GraphObject::Properties data) -{ - _import = import; - set_patch(patch); - _symbol_label->property_visible() = !import; - _symbol_entry->property_visible() = !import; - _ports_label->property_visible() = _import; - _merge_ports_radio->property_visible() = _import; - _insert_ports_radio->property_visible() = _import; - _initial_data = data; - Gtk::Window::present(); -} - -/** Sets the patch model for this window and initializes everything. - * - * This function MUST be called before using the window in any way! - */ -void -LoadPatchWindow::set_patch(SharedPtr patch) -{ - _patch = patch; - _symbol_entry->set_text(""); - _symbol_entry->set_sensitive(!_import); - _poly_spinbutton->set_value(patch->internal_poly()); -} - -void -LoadPatchWindow::on_show() -{ - if (_app->configuration()->patch_folder().length() > 0) - set_current_folder(_app->configuration()->patch_folder()); - Gtk::FileChooserDialog::on_show(); -} - -void -LoadPatchWindow::merge_ports_selected() -{ - _merge_ports = true; -} - -void -LoadPatchWindow::insert_ports_selected() -{ - _merge_ports = false; -} - -void -LoadPatchWindow::ok_clicked() -{ - if (!_patch) { - hide(); - return; - } - - const URIs& uris = _app->uris(); - - if (_poly_voices_radio->get_active()) - _initial_data.insert( - make_pair(uris.ingen_polyphony, - _app->forge().make(_poly_spinbutton->get_value_as_int()))); - - if (get_uri() == "") - return; - - if (_import) { - // If unset load_patch will load value - boost::optional parent; - boost::optional symbol; - if (!_patch->path().is_root()) { - parent = _patch->path().parent(); - symbol = _patch->symbol(); - } - - _app->loader()->load_patch(true, get_filename(), - parent, symbol, _initial_data); - - } else { - std::list uri_list = get_filenames(); - for (std::list::iterator i = uri_list.begin(); i != uri_list.end(); ++i) { - // Cascade - Raul::Atom& x = _initial_data.find(uris.ingen_canvasX)->second; - x = _app->forge().make(x.get_float() + 20.0f); - Raul::Atom& y = _initial_data.find(uris.ingen_canvasY)->second; - y = _app->forge().make(y.get_float() + 20.0f); - - Raul::Symbol symbol(symbol_from_filename(*i)); - if (uri_list.size() == 1 && _symbol_entry->get_text() != "") - symbol = Raul::Symbol::symbolify(_symbol_entry->get_text()); - - symbol = avoid_symbol_clash(symbol); - - _app->loader()->load_patch(false, *i, - _patch->path(), symbol, _initial_data); - } - } - - _patch.reset(); - hide(); -} - -void -LoadPatchWindow::cancel_clicked() -{ - _patch.reset(); - hide(); -} - -Raul::Symbol -LoadPatchWindow::symbol_from_filename(const Glib::ustring& filename) -{ - std::string symbol_str = Glib::path_get_basename(get_filename()); - symbol_str = symbol_str.substr(0, symbol_str.find('.')); - return Raul::Symbol::symbolify(symbol_str); -} - -Raul::Symbol -LoadPatchWindow::avoid_symbol_clash(const Raul::Symbol& symbol) -{ - unsigned offset = _app->store()->child_name_offset( - _patch->path(), symbol); - - if (offset != 0) { - std::stringstream ss; - ss << symbol << "_" << offset; - return Raul::Symbol(ss.str()); - } else { - return symbol; - } -} - -void -LoadPatchWindow::selection_changed() -{ - if (_import) - return; - - if (get_filenames().size() != 1) { - _symbol_entry->set_text(""); - _symbol_entry->set_sensitive(false); - } else { - _symbol_entry->set_text(avoid_symbol_clash( - symbol_from_filename(get_filename())).c_str()); - _symbol_entry->set_sensitive(true); - } -} - -} // namespace GUI -} // namespace Ingen diff --git a/src/gui/LoadPatchWindow.hpp b/src/gui/LoadPatchWindow.hpp deleted file mode 100644 index a919a648..00000000 --- a/src/gui/LoadPatchWindow.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#ifndef INGEN_GUI_LOADSUBPATCHWINDOW_HPP -#define INGEN_GUI_LOADSUBPATCHWINDOW_HPP - -#include -#include -#include -#include -#include -#include -#include - -#include "raul/SharedPtr.hpp" - -#include "ingen/GraphObject.hpp" - -namespace Ingen { - -namespace Client { class PatchModel; } - -namespace GUI { - -/** 'Add Subpatch' window. - * - * Loaded from XML as a derived object. - * - * \ingroup GUI - */ -class LoadPatchWindow : public Gtk::FileChooserDialog -{ -public: - LoadPatchWindow(BaseObjectType* cobject, - const Glib::RefPtr& xml); - - void init(App& app) { _app = &app; } - - void set_patch(SharedPtr patch); - - void present(SharedPtr patch, - bool import, - GraphObject::Properties data); - -protected: - void on_show(); - -private: - void merge_ports_selected(); - void insert_ports_selected(); - - void selection_changed(); - void cancel_clicked(); - void ok_clicked(); - - Raul::Symbol symbol_from_filename(const Glib::ustring& filename); - Raul::Symbol avoid_symbol_clash(const Raul::Symbol& symbol); - - App* _app; - - GraphObject::Properties _initial_data; - - SharedPtr _patch; - - Gtk::Label* _symbol_label; - Gtk::Entry* _symbol_entry; - Gtk::Label* _ports_label; - Gtk::RadioButton* _merge_ports_radio; - Gtk::RadioButton* _insert_ports_radio; - Gtk::RadioButton* _poly_voices_radio; - Gtk::RadioButton* _poly_from_file_radio; - Gtk::SpinButton* _poly_spinbutton; - Gtk::Button* _ok_button; - Gtk::Button* _cancel_button; - - bool _import; - bool _merge_ports; -}; - -} // namespace GUI -} // namespace Ingen - -#endif // INGEN_GUI_LOADSUBPATCHWINDOW_HPP diff --git a/src/gui/LoadPluginWindow.cpp b/src/gui/LoadPluginWindow.cpp index f5f7a7d7..c3e5b580 100644 --- a/src/gui/LoadPluginWindow.cpp +++ b/src/gui/LoadPluginWindow.cpp @@ -23,13 +23,13 @@ #include "ingen/Interface.hpp" #include "ingen/client/ClientStore.hpp" -#include "ingen/client/PatchModel.hpp" +#include "ingen/client/GraphModel.hpp" #include "App.hpp" #include "LoadPluginWindow.hpp" -#include "PatchCanvas.hpp" -#include "PatchView.hpp" -#include "PatchWindow.hpp" +#include "GraphCanvas.hpp" +#include "GraphView.hpp" +#include "GraphWindow.hpp" #include "ingen_config.h" @@ -115,10 +115,10 @@ LoadPluginWindow::LoadPluginWindow(BaseObjectType* cobject, } void -LoadPluginWindow::present(SharedPtr patch, +LoadPluginWindow::present(SharedPtr graph, GraphObject::Properties data) { - set_patch(patch); + set_graph(graph); _initial_data = data; Gtk::Window::present(); } @@ -134,7 +134,7 @@ LoadPluginWindow::name_changed() const string sym = _name_entry->get_text(); if (!Raul::Symbol::is_valid(sym)) { _add_button->property_sensitive() = false; - } else if (_app->store()->find(_patch->path().child(Raul::Symbol(sym))) + } else if (_app->store()->find(_graph->path().child(Raul::Symbol(sym))) != _app->store()->end()) { _add_button->property_sensitive() = false; } else { @@ -151,21 +151,21 @@ LoadPluginWindow::name_cleared(Gtk::EntryIconPosition pos, const GdkEventButton* } #endif // HAVE_NEW_GTKMM -/** Sets the patch controller for this window and initializes everything. +/** Sets the graph controller for this window and initializes everything. * * This function MUST be called before using the window in any way! */ void -LoadPluginWindow::set_patch(SharedPtr patch) +LoadPluginWindow::set_graph(SharedPtr graph) { - if (_patch) { - _patch = patch; + if (_graph) { + _graph = graph; plugin_selection_changed(); } else { - _patch = patch; + _graph = graph; } - /*if (patch->poly() <= 1) + /*if (graph->poly() <= 1) _polyphonic_checkbutton->property_sensitive() = false; else _polyphonic_checkbutton->property_sensitive() = true;*/ @@ -174,8 +174,8 @@ LoadPluginWindow::set_patch(SharedPtr patch) /** Populates the plugin list on the first show. * * This is done here instead of construction time as the list population is - * really expensive and bogs down creation of a patch. This is especially - * important when many patch notifications are sent at one time from the + * really expensive and bogs down creation of a graph. This is especially + * important when many graph notifications are sent at one time from the * engine. */ void @@ -237,8 +237,8 @@ LoadPluginWindow::set_row(Gtk::TreeModel::Row& row, case Plugin::Internal: row[_plugins_columns._col_type] = "Internal"; break; - case Plugin::Patch: - row[_plugins_columns._col_type] = "Patch"; + case Plugin::Graph: + row[_plugins_columns._col_type] = "Graph"; break; case Plugin::NIL: row[_plugins_columns._col_type] = "?"; @@ -292,7 +292,7 @@ LoadPluginWindow::plugin_selection_changed() boost::shared_ptr p = row.get_value( _plugins_columns._col_plugin); _name_offset = _app->store()->child_name_offset( - _patch->path(), p->default_block_symbol()); + _graph->path(), p->default_block_symbol()); _name_entry->set_text(generate_module_name(p, _name_offset)); _name_entry->set_sensitive(true); } else { @@ -342,7 +342,7 @@ LoadPluginWindow::load_plugin(const Gtk::TreeModel::iterator& iter) dialog.run(); } else { - Raul::Path path = _patch->path().child(Raul::Symbol::symbolify(name)); + Raul::Path path = _graph->path().child(Raul::Symbol::symbolify(name)); Resource::Properties props = _initial_data; props.insert(make_pair(uris.rdf_type, uris.ingen_Block)); diff --git a/src/gui/LoadPluginWindow.hpp b/src/gui/LoadPluginWindow.hpp index e9b874a2..ba574f12 100644 --- a/src/gui/LoadPluginWindow.hpp +++ b/src/gui/LoadPluginWindow.hpp @@ -28,16 +28,16 @@ #include "raul/SharedPtr.hpp" -#include "ingen_config.h" #include "ingen/GraphObject.hpp" #include "ingen/client/ClientStore.hpp" +#include "ingen_config.h" #include "Window.hpp" namespace Ingen { namespace Client { -class PatchModel; +class GraphModel; class PluginModel; } @@ -55,12 +55,12 @@ public: LoadPluginWindow(BaseObjectType* cobject, const Glib::RefPtr& xml); - void set_patch(SharedPtr patch); + void set_graph(SharedPtr graph); void set_plugins(SharedPtr plugins); void add_plugin(SharedPtr plugin); - void present(SharedPtr patch, + void present(SharedPtr graph, GraphObject::Properties data); protected: @@ -128,7 +128,7 @@ private: GraphObject::Properties _initial_data; - SharedPtr _patch; + SharedPtr _graph; typedef std::map Rows; Rows _rows; diff --git a/src/gui/MessagesWindow.hpp b/src/gui/MessagesWindow.hpp index ad3f92a1..8167e30a 100644 --- a/src/gui/MessagesWindow.hpp +++ b/src/gui/MessagesWindow.hpp @@ -31,7 +31,7 @@ namespace GUI { /** Messages Window. * * Loaded from XML as a derived object. - * This is shown when errors occur (e.g. during patch loading). + * This is shown when errors occur (e.g. during graph loading). * * \ingroup GUI */ diff --git a/src/gui/NewSubgraphWindow.cpp b/src/gui/NewSubgraphWindow.cpp new file mode 100644 index 00000000..0cc8da7a --- /dev/null +++ b/src/gui/NewSubgraphWindow.cpp @@ -0,0 +1,118 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#include + +#include "ingen/Interface.hpp" +#include "ingen/client/ClientStore.hpp" +#include "ingen/client/GraphModel.hpp" + +#include "App.hpp" +#include "NewSubgraphWindow.hpp" +#include "GraphView.hpp" + +using namespace std; + +namespace Ingen { +namespace GUI { + +NewSubgraphWindow::NewSubgraphWindow(BaseObjectType* cobject, + const Glib::RefPtr& xml) + : Window(cobject) +{ + xml->get_widget("new_subgraph_name_entry", _name_entry); + xml->get_widget("new_subgraph_message_label", _message_label); + xml->get_widget("new_subgraph_polyphony_spinbutton", _poly_spinbutton); + xml->get_widget("new_subgraph_ok_button", _ok_button); + xml->get_widget("new_subgraph_cancel_button", _cancel_button); + + _name_entry->signal_changed().connect(sigc::mem_fun(this, &NewSubgraphWindow::name_changed)); + _ok_button->signal_clicked().connect(sigc::mem_fun(this, &NewSubgraphWindow::ok_clicked)); + _cancel_button->signal_clicked().connect(sigc::mem_fun(this, &NewSubgraphWindow::cancel_clicked)); + + _ok_button->property_sensitive() = false; + + _poly_spinbutton->get_adjustment()->configure(1.0, 1.0, 128, 1.0, 10.0, 0); +} + +void +NewSubgraphWindow::present(SharedPtr graph, + GraphObject::Properties data) +{ + set_graph(graph); + _initial_data = data; + Gtk::Window::present(); +} + +/** Sets the graph controller for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +NewSubgraphWindow::set_graph(SharedPtr graph) +{ + _graph = graph; +} + +/** Called every time the user types into the name input box. + * Used to display warning messages, and enable/disable the OK button. + */ +void +NewSubgraphWindow::name_changed() +{ + string name = _name_entry->get_text(); + if (!Raul::Symbol::is_valid(name)) { + _message_label->set_text("Name contains invalid characters."); + _ok_button->property_sensitive() = false; + } else if (_app->store()->find(_graph->path().child(Raul::Symbol(name))) + != _app->store()->end()) { + _message_label->set_text("An object already exists with that name."); + _ok_button->property_sensitive() = false; + } else { + _message_label->set_text(""); + _ok_button->property_sensitive() = true; + } +} +void +NewSubgraphWindow::ok_clicked() +{ + const uint32_t poly = _poly_spinbutton->get_value_as_int(); + const Raul::Path path = _graph->path().child( + Raul::Symbol::symbolify(_name_entry->get_text())); + + // Create graph + Resource::Properties props; + props.insert(make_pair(_app->uris().rdf_type, _app->uris().ingen_Graph)); + props.insert(make_pair(_app->uris().ingen_polyphony, _app->forge().make(int32_t(poly)))); + props.insert(make_pair(_app->uris().ingen_enabled, _app->forge().make(bool(true)))); + _app->interface()->put(GraphObject::path_to_uri(path), props, Resource::INTERNAL); + + // Set external (block perspective) properties + props = _initial_data; + props.insert(make_pair(_app->uris().rdf_type, _app->uris().ingen_Graph)); + _app->interface()->put(GraphObject::path_to_uri(path), _initial_data, Resource::EXTERNAL); + + hide(); +} + +void +NewSubgraphWindow::cancel_clicked() +{ + hide(); +} + +} // namespace GUI +} // namespace Ingen diff --git a/src/gui/NewSubgraphWindow.hpp b/src/gui/NewSubgraphWindow.hpp new file mode 100644 index 00000000..721a0916 --- /dev/null +++ b/src/gui/NewSubgraphWindow.hpp @@ -0,0 +1,73 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_GUI_NEWSUBGRAPHWINDOW_HPP +#define INGEN_GUI_NEWSUBGRAPHWINDOW_HPP + +#include +#include +#include +#include +#include + +#include "raul/SharedPtr.hpp" + +#include "ingen/GraphObject.hpp" + +#include "Window.hpp" + +namespace Ingen { + +namespace Client { class GraphModel; } + +namespace GUI { + +/** 'New Subgraph' window. + * + * Loaded from XML as a derived object. + * + * \ingroup GUI + */ +class NewSubgraphWindow : public Window +{ +public: + NewSubgraphWindow(BaseObjectType* cobject, + const Glib::RefPtr& xml); + + void set_graph(SharedPtr graph); + + void present(SharedPtr graph, + GraphObject::Properties data); + +private: + void name_changed(); + void ok_clicked(); + void cancel_clicked(); + + GraphObject::Properties _initial_data; + SharedPtr _graph; + + Gtk::Entry* _name_entry; + Gtk::Label* _message_label; + Gtk::SpinButton* _poly_spinbutton; + Gtk::Button* _ok_button; + Gtk::Button* _cancel_button; +}; + +} // namespace GUI +} // namespace Ingen + +#endif // INGEN_GUI_NEWSUBGRAPHWINDOW_HPP diff --git a/src/gui/NewSubpatchWindow.cpp b/src/gui/NewSubpatchWindow.cpp deleted file mode 100644 index 1124afb3..00000000 --- a/src/gui/NewSubpatchWindow.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#include - -#include "ingen/Interface.hpp" -#include "ingen/client/ClientStore.hpp" -#include "ingen/client/PatchModel.hpp" - -#include "App.hpp" -#include "NewSubpatchWindow.hpp" -#include "PatchView.hpp" - -using namespace std; - -namespace Ingen { -namespace GUI { - -NewSubpatchWindow::NewSubpatchWindow(BaseObjectType* cobject, - const Glib::RefPtr& xml) - : Window(cobject) -{ - xml->get_widget("new_subpatch_name_entry", _name_entry); - xml->get_widget("new_subpatch_message_label", _message_label); - xml->get_widget("new_subpatch_polyphony_spinbutton", _poly_spinbutton); - xml->get_widget("new_subpatch_ok_button", _ok_button); - xml->get_widget("new_subpatch_cancel_button", _cancel_button); - - _name_entry->signal_changed().connect(sigc::mem_fun(this, &NewSubpatchWindow::name_changed)); - _ok_button->signal_clicked().connect(sigc::mem_fun(this, &NewSubpatchWindow::ok_clicked)); - _cancel_button->signal_clicked().connect(sigc::mem_fun(this, &NewSubpatchWindow::cancel_clicked)); - - _ok_button->property_sensitive() = false; - - _poly_spinbutton->get_adjustment()->configure(1.0, 1.0, 128, 1.0, 10.0, 0); -} - -void -NewSubpatchWindow::present(SharedPtr patch, - GraphObject::Properties data) -{ - set_patch(patch); - _initial_data = data; - Gtk::Window::present(); -} - -/** Sets the patch controller for this window and initializes everything. - * - * This function MUST be called before using the window in any way! - */ -void -NewSubpatchWindow::set_patch(SharedPtr patch) -{ - _patch = patch; -} - -/** Called every time the user types into the name input box. - * Used to display warning messages, and enable/disable the OK button. - */ -void -NewSubpatchWindow::name_changed() -{ - string name = _name_entry->get_text(); - if (!Raul::Symbol::is_valid(name)) { - _message_label->set_text("Name contains invalid characters."); - _ok_button->property_sensitive() = false; - } else if (_app->store()->find(_patch->path().child(Raul::Symbol(name))) - != _app->store()->end()) { - _message_label->set_text("An object already exists with that name."); - _ok_button->property_sensitive() = false; - } else { - _message_label->set_text(""); - _ok_button->property_sensitive() = true; - } -} - -void -NewSubpatchWindow::ok_clicked() -{ - const uint32_t poly = _poly_spinbutton->get_value_as_int(); - const Raul::Path path = _patch->path().child( - Raul::Symbol::symbolify(_name_entry->get_text())); - - // Create patch - Resource::Properties props; - props.insert(make_pair(_app->uris().rdf_type, _app->uris().ingen_Patch)); - props.insert(make_pair(_app->uris().ingen_polyphony, _app->forge().make(int32_t(poly)))); - props.insert(make_pair(_app->uris().ingen_enabled, _app->forge().make(bool(true)))); - _app->interface()->put(GraphObject::path_to_uri(path), props, Resource::INTERNAL); - - // Set external (block perspective) properties - props = _initial_data; - props.insert(make_pair(_app->uris().rdf_type, _app->uris().ingen_Patch)); - _app->interface()->put(GraphObject::path_to_uri(path), _initial_data, Resource::EXTERNAL); - - hide(); -} - -void -NewSubpatchWindow::cancel_clicked() -{ - hide(); -} - -} // namespace GUI -} // namespace Ingen diff --git a/src/gui/NewSubpatchWindow.hpp b/src/gui/NewSubpatchWindow.hpp deleted file mode 100644 index 20a27dc6..00000000 --- a/src/gui/NewSubpatchWindow.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#ifndef INGEN_GUI_NEWSUBPATCHWINDOW_HPP -#define INGEN_GUI_NEWSUBPATCHWINDOW_HPP - -#include -#include -#include -#include -#include - -#include "raul/SharedPtr.hpp" - -#include "ingen/GraphObject.hpp" - -#include "Window.hpp" - -namespace Ingen { - -namespace Client { class PatchModel; } - -namespace GUI { - -/** 'New Subpatch' window. - * - * Loaded from XML as a derived object. - * - * \ingroup GUI - */ -class NewSubpatchWindow : public Window -{ -public: - NewSubpatchWindow(BaseObjectType* cobject, - const Glib::RefPtr& xml); - - void set_patch(SharedPtr patch); - - void present(SharedPtr patch, - GraphObject::Properties data); - -private: - void name_changed(); - void ok_clicked(); - void cancel_clicked(); - - GraphObject::Properties _initial_data; - SharedPtr _patch; - - Gtk::Entry* _name_entry; - Gtk::Label* _message_label; - Gtk::SpinButton* _poly_spinbutton; - Gtk::Button* _ok_button; - Gtk::Button* _cancel_button; -}; - -} // namespace GUI -} // namespace Ingen - -#endif // INGEN_GUI_NEWSUBPATCHWINDOW_HPP diff --git a/src/gui/NodeModule.cpp b/src/gui/NodeModule.cpp index bbd569fc..5be945ce 100644 --- a/src/gui/NodeModule.cpp +++ b/src/gui/NodeModule.cpp @@ -24,7 +24,7 @@ #include "ingen/Interface.hpp" #include "ingen/Log.hpp" #include "ingen/client/BlockModel.hpp" -#include "ingen/client/PatchModel.hpp" +#include "ingen/client/GraphModel.hpp" #include "ingen/client/PluginModel.hpp" #include "ingen/client/PluginUI.hpp" #include "raul/Atom.hpp" @@ -33,11 +33,11 @@ #include "Configuration.hpp" #include "NodeMenu.hpp" #include "NodeModule.hpp" -#include "PatchCanvas.hpp" -#include "PatchWindow.hpp" +#include "GraphCanvas.hpp" +#include "GraphWindow.hpp" #include "Port.hpp" #include "RenameWindow.hpp" -#include "SubpatchModule.hpp" +#include "SubgraphModule.hpp" #include "WidgetFactory.hpp" #include "WindowFactory.hpp" @@ -49,7 +49,7 @@ using namespace Client; namespace GUI { -NodeModule::NodeModule(PatchCanvas& canvas, +NodeModule::NodeModule(GraphCanvas& canvas, SharedPtr block) : Ganv::Module(canvas, block->path().symbol(), 0, 0, true) , _block(block) @@ -98,14 +98,14 @@ NodeModule::show_menu(GdkEventButton* ev) } NodeModule* -NodeModule::create(PatchCanvas& canvas, +NodeModule::create(GraphCanvas& canvas, SharedPtr block, bool human) { - SharedPtr patch = PtrCast(block); + SharedPtr graph = PtrCast(block); - NodeModule* ret = (patch) - ? new SubpatchModule(canvas, patch) + NodeModule* ret = (graph) + ? new SubgraphModule(canvas, graph) : new NodeModule(canvas, block); for (GraphObject::Properties::const_iterator m = block->properties().begin(); @@ -127,7 +127,7 @@ NodeModule::create(PatchCanvas& canvas, App& NodeModule::app() const { - return ((PatchCanvas*)canvas())->app(); + return ((GraphCanvas*)canvas())->app(); } void @@ -432,7 +432,7 @@ NodeModule::set_selected(gboolean b) Ganv::Module::set_selected(b); #if 0 if (b) { - PatchWindow* win = app().window_factory()->parent_patch_window(block()); + GraphWindow* win = app().window_factory()->parent_graph_window(block()); if (win) { std::string doc; bool html = false; diff --git a/src/gui/NodeModule.hpp b/src/gui/NodeModule.hpp index 73295d1a..2d63b047 100644 --- a/src/gui/NodeModule.hpp +++ b/src/gui/NodeModule.hpp @@ -33,11 +33,11 @@ namespace Ingen { namespace Client { namespace Ingen { namespace GUI { -class PatchCanvas; +class GraphCanvas; class Port; class NodeMenu; -/** A module in a patch. +/** A module in a graphn. * * This base class is extended for various types of modules. * @@ -47,7 +47,7 @@ class NodeModule : public Ganv::Module { public: static NodeModule* create( - PatchCanvas& canvas, + GraphCanvas& canvas, SharedPtr block, bool human_names); @@ -66,7 +66,7 @@ public: SharedPtr block() const { return _block; } protected: - NodeModule(PatchCanvas& canvas, SharedPtr block); + NodeModule(GraphCanvas& canvas, SharedPtr block); virtual bool on_double_click(GdkEventButton* ev); diff --git a/src/gui/ObjectMenu.hpp b/src/gui/ObjectMenu.hpp index 6cb20e70..c4648443 100644 --- a/src/gui/ObjectMenu.hpp +++ b/src/gui/ObjectMenu.hpp @@ -31,7 +31,7 @@ namespace GUI { class ObjectControlWindow; class ObjectPropertiesWindow; -class PatchCanvas; +class GraphCanvas; /** Menu for a Object. * diff --git a/src/gui/PatchBox.cpp b/src/gui/PatchBox.cpp deleted file mode 100644 index ea3de513..00000000 --- a/src/gui/PatchBox.cpp +++ /dev/null @@ -1,706 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#include -#include -#include - -#include -#include -#include -#include - -#include "ingen/Interface.hpp" -#include "ingen/client/ClientStore.hpp" -#include "ingen/client/PatchModel.hpp" - -#include "App.hpp" -#include "BreadCrumbs.hpp" -#include "Configuration.hpp" -#include "ConnectWindow.hpp" -#include "LoadPatchWindow.hpp" -#include "LoadPluginWindow.hpp" -#include "MessagesWindow.hpp" -#include "NewSubpatchWindow.hpp" -#include "PatchCanvas.hpp" -#include "PatchTreeWindow.hpp" -#include "PatchView.hpp" -#include "PatchWindow.hpp" -#include "ThreadedLoader.hpp" -#include "WidgetFactory.hpp" -#include "WindowFactory.hpp" -#include "ingen_config.h" - -#ifdef HAVE_WEBKIT -#include -#endif - -namespace Ingen { - -using namespace Client; - -namespace GUI { - -static const int STATUS_CONTEXT_ENGINE = 0; -static const int STATUS_CONTEXT_PATCH = 1; -static const int STATUS_CONTEXT_HOVER = 2; - -PatchBox::PatchBox(BaseObjectType* cobject, - const Glib::RefPtr& xml) - : Gtk::VBox(cobject) - , _app(NULL) - , _window(NULL) - , _breadcrumbs(NULL) - , _has_shown_documentation(false) - , _enable_signal(true) -{ - property_visible() = false; - - xml->get_widget("patch_win_alignment", _alignment); - xml->get_widget("patch_win_status_bar", _status_bar); - //xml->get_widget("patch_win_status_bar", _status_bar); - //xml->get_widget("patch_open_menuitem", _menu_open); - xml->get_widget("patch_import_menuitem", _menu_import); - //xml->get_widget("patch_open_into_menuitem", _menu_open_into); - xml->get_widget("patch_save_menuitem", _menu_save); - xml->get_widget("patch_save_as_menuitem", _menu_save_as); - xml->get_widget("patch_draw_menuitem", _menu_draw); - xml->get_widget("patch_cut_menuitem", _menu_cut); - xml->get_widget("patch_copy_menuitem", _menu_copy); - xml->get_widget("patch_paste_menuitem", _menu_paste); - xml->get_widget("patch_delete_menuitem", _menu_delete); - xml->get_widget("patch_select_all_menuitem", _menu_select_all); - xml->get_widget("patch_close_menuitem", _menu_close); - xml->get_widget("patch_quit_menuitem", _menu_quit); - xml->get_widget("patch_view_control_window_menuitem", _menu_view_control_window); - xml->get_widget("patch_view_engine_window_menuitem", _menu_view_engine_window); - xml->get_widget("patch_properties_menuitem", _menu_view_patch_properties); - xml->get_widget("patch_fullscreen_menuitem", _menu_fullscreen); - xml->get_widget("patch_human_names_menuitem", _menu_human_names); - xml->get_widget("patch_show_port_names_menuitem", _menu_show_port_names); - xml->get_widget("patch_zoom_in_menuitem", _menu_zoom_in); - xml->get_widget("patch_zoom_out_menuitem", _menu_zoom_out); - xml->get_widget("patch_zoom_normal_menuitem", _menu_zoom_normal); - xml->get_widget("patch_status_bar_menuitem", _menu_show_status_bar); - xml->get_widget("patch_arrange_menuitem", _menu_arrange); - xml->get_widget("patch_view_messages_window_menuitem", _menu_view_messages_window); - xml->get_widget("patch_view_patch_tree_window_menuitem", _menu_view_patch_tree_window); - xml->get_widget("patch_help_about_menuitem", _menu_help_about); - xml->get_widget("patch_documentation_paned", _doc_paned); - xml->get_widget("patch_documentation_scrolledwindow", _doc_scrolledwindow); - - _menu_view_control_window->property_sensitive() = false; - _menu_import->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_import)); - _menu_save->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_save)); - _menu_save_as->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_save_as)); - _menu_draw->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_draw)); - _menu_copy->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_copy)); - _menu_paste->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_paste)); - _menu_delete->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_delete)); - _menu_select_all->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_select_all)); - _menu_close->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_close)); - _menu_quit->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_quit)); - _menu_fullscreen->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_fullscreen_toggled)); - _menu_human_names->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_human_names_toggled)); - _menu_show_status_bar->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_status_bar_toggled)); - _menu_show_port_names->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_port_names_toggled)); - _menu_arrange->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_arrange)); - _menu_quit->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_quit)); - _menu_zoom_in->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_zoom_in)); - _menu_zoom_out->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_zoom_out)); - _menu_zoom_normal->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_zoom_normal)); - _menu_view_engine_window->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_show_engine)); - _menu_view_patch_properties->signal_activate().connect( - sigc::mem_fun(this, &PatchBox::event_show_properties)); - - Glib::RefPtr clipboard = Gtk::Clipboard::get(); - clipboard->signal_owner_change().connect( - sigc::mem_fun(this, &PatchBox::event_clipboard_changed)); -} - -PatchBox::~PatchBox() -{ - delete _breadcrumbs; -} - -SharedPtr -PatchBox::create(App& app, SharedPtr patch) -{ - PatchBox* result = NULL; - Glib::RefPtr xml = WidgetFactory::create("patch_win"); - xml->get_widget_derived("patch_win_vbox", result); - result->init_box(app); - result->set_patch(patch, SharedPtr()); - return SharedPtr(result); -} - -void -PatchBox::init_box(App& app) -{ - _app = &app; - - std::string engine_name = _app->interface()->uri(); - if (engine_name == "http://drobilla.net/ns/ingen#internal") { - engine_name = "internal engine"; - } - _status_bar->push(std::string("Connected to ") + engine_name, STATUS_CONTEXT_ENGINE); - - _menu_view_messages_window->signal_activate().connect( - sigc::mem_fun(_app->messages_dialog(), &MessagesWindow::present)); - _menu_view_patch_tree_window->signal_activate().connect( - sigc::mem_fun(_app->patch_tree(), &PatchTreeWindow::present)); - - _menu_help_about->signal_activate().connect(sigc::hide_return( - sigc::mem_fun(_app, &App::show_about))); - - _breadcrumbs = new BreadCrumbs(*_app); - _breadcrumbs->signal_patch_selected.connect( - sigc::mem_fun(this, &PatchBox::set_patch_from_path)); -} - -void -PatchBox::set_patch_from_path(const Raul::Path& path, SharedPtr view) -{ - if (view) { - assert(view->patch()->path() == path); - _app->window_factory()->present_patch(view->patch(), _window, view); - } else { - SharedPtr model = PtrCast( - _app->store()->object(path)); - if (model) { - _app->window_factory()->present_patch(model, _window); - } - } -} - -/** Sets the patch for this box and initializes everything. - * - * If @a view is NULL, a new view will be created. - */ -void -PatchBox::set_patch(SharedPtr patch, - SharedPtr view) -{ - if (!patch || patch == _patch) - return; - - _enable_signal = false; - - new_port_connection.disconnect(); - removed_port_connection.disconnect(); - edit_mode_connection.disconnect(); - _entered_connection.disconnect(); - _left_connection.disconnect(); - - _status_bar->pop(STATUS_CONTEXT_PATCH); - - _patch = patch; - _view = view; - - if (!_view) - _view = _breadcrumbs->view(patch->path()); - - if (!_view) - _view = PatchView::create(*_app, patch); - - assert(_view); - - // Add view to our alignment - if (_view->get_parent()) - _view->get_parent()->remove(*_view.get()); - - _alignment->remove(); - _alignment->add(*_view.get()); - - if (_breadcrumbs->get_parent()) - _breadcrumbs->get_parent()->remove(*_breadcrumbs); - - _view->breadcrumb_container()->remove(); - _view->breadcrumb_container()->add(*_breadcrumbs); - _view->breadcrumb_container()->show(); - - _breadcrumbs->build(patch->path(), _view); - _breadcrumbs->show(); - - _menu_view_control_window->property_sensitive() = false; - - for (BlockModel::Ports::const_iterator p = patch->ports().begin(); - p != patch->ports().end(); ++p) { - if (_app->can_control(p->get())) { - _menu_view_control_window->property_sensitive() = true; - break; - } - } - - new_port_connection = patch->signal_new_port().connect( - sigc::mem_fun(this, &PatchBox::patch_port_added)); - removed_port_connection = patch->signal_removed_port().connect( - sigc::mem_fun(this, &PatchBox::patch_port_removed)); - - show(); - _alignment->show_all(); - hide_documentation(); - - _view->signal_object_entered.connect( - sigc::mem_fun(this, &PatchBox::object_entered)); - _view->signal_object_left.connect( - sigc::mem_fun(this, &PatchBox::object_left)); - - _enable_signal = true; -} - -void -PatchBox::patch_port_added(SharedPtr port) -{ - if (port->is_input() && _app->can_control(port.get())) { - _menu_view_control_window->property_sensitive() = true; - } -} - -void -PatchBox::patch_port_removed(SharedPtr port) -{ - if (!(port->is_input() && _app->can_control(port.get()))) - return; - - for (BlockModel::Ports::const_iterator i = _patch->ports().begin(); - i != _patch->ports().end(); ++i) { - if ((*i)->is_input() && _app->can_control(i->get())) { - _menu_view_control_window->property_sensitive() = true; - return; - } - } - - _menu_view_control_window->property_sensitive() = false; -} - -void -PatchBox::show_documentation(const std::string& doc, bool html) -{ -#ifdef HAVE_WEBKIT - WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new()); - webkit_web_view_load_html_string(view, doc.c_str(), ""); - _doc_scrolledwindow->add(*Gtk::manage(Glib::wrap(GTK_WIDGET(view)))); - _doc_scrolledwindow->show_all(); -#else - Gtk::TextView* view = Gtk::manage(new Gtk::TextView()); - view->get_buffer()->set_text(doc); - _doc_scrolledwindow->add(*view); - _doc_scrolledwindow->show_all(); -#endif - if (!_has_shown_documentation) { - const Gtk::Allocation allocation = get_allocation(); - _doc_paned->set_position(allocation.get_width() / 1.61803399); - } - _has_shown_documentation = true; -} - -void -PatchBox::hide_documentation() -{ - _doc_scrolledwindow->remove(); - _doc_scrolledwindow->hide(); - _doc_paned->set_position(INT_MAX); -} - -void -PatchBox::show_status(const ObjectModel* model) -{ - std::stringstream msg; - msg << model->path(); - - const PortModel* port = 0; - const BlockModel* block = 0; - - if ((port = dynamic_cast(model))) { - show_port_status(port, port->value()); - - } else if ((block = dynamic_cast(model))) { - const PluginModel* plugin = dynamic_cast(block->plugin()); - if (plugin) - msg << ((boost::format(" (%1%)") % plugin->human_name()).str()); - _status_bar->push(msg.str(), STATUS_CONTEXT_HOVER); - } -} - -void -PatchBox::show_port_status(const PortModel* port, const Raul::Atom& value) -{ - std::stringstream msg; - msg << port->path(); - - const BlockModel* parent = dynamic_cast(port->parent().get()); - if (parent) { - const PluginModel* plugin = dynamic_cast(parent->plugin()); - if (plugin) { - const std::string& human_name = plugin->port_human_name(port->index()); - if (!human_name.empty()) - msg << " (" << human_name << ")"; - } - } - - if (value.is_valid()) { - msg << " = " << _app->forge().str(value); - } - - _status_bar->pop(STATUS_CONTEXT_HOVER); - _status_bar->push(msg.str(), STATUS_CONTEXT_HOVER); -} - -void -PatchBox::object_entered(const ObjectModel* model) -{ - show_status(model); -} - -void -PatchBox::object_left(const ObjectModel* model) -{ - _status_bar->pop(STATUS_CONTEXT_PATCH); - _status_bar->pop(STATUS_CONTEXT_HOVER); -} - -void -PatchBox::event_show_engine() -{ - if (_patch) - _app->connect_window()->show(); -} - -void -PatchBox::event_clipboard_changed(GdkEventOwnerChange* ev) -{ - Glib::RefPtr clipboard = Gtk::Clipboard::get(); - _menu_paste->set_sensitive(clipboard->wait_is_text_available()); -} - -void -PatchBox::event_show_properties() -{ - _app->window_factory()->present_properties(_patch); -} - -void -PatchBox::event_import() -{ - _app->window_factory()->present_load_patch(_patch); -} - -void -PatchBox::event_save() -{ - const Raul::Atom& document = _patch->get_property(_app->uris().ingen_document); - if (!document.is_valid() || document.type() != _app->uris().forge.URI) { - event_save_as(); - } else { - _app->loader()->save_patch(_patch, document.get_uri()); - _status_bar->push( - (boost::format("Saved %1% to %2%") % _patch->path().c_str() - % document.get_uri()).str(), - STATUS_CONTEXT_PATCH); - } -} - -int -PatchBox::message_dialog(const Glib::ustring& message, - const Glib::ustring& secondary_text, - Gtk::MessageType type, - Gtk::ButtonsType buttons) -{ - Gtk::MessageDialog dialog(message, true, type, buttons, true); - dialog.set_secondary_text(secondary_text); - if (_window) { - dialog.set_transient_for(*_window); - } - return dialog.run(); -} - -void -PatchBox::event_save_as() -{ - const URIs& uris = _app->uris(); - while (true) { - Gtk::FileChooserDialog dialog("Save Patch", Gtk::FILE_CHOOSER_ACTION_SAVE); - if (_window) { - dialog.set_transient_for(*_window); - } - - dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - Gtk::Button* save_button = dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); - save_button->property_has_default() = true; - - Gtk::FileFilter filt; - filt.add_pattern("*.ingen"); - filt.set_name("Ingen bundles"); - dialog.set_filter(filt); - - // Set current folder to most sensible default - const Raul::Atom& document = _patch->get_property(uris.ingen_document); - if (document.type() == uris.forge.URI) - dialog.set_uri(document.get_uri()); - else if (_app->configuration()->patch_folder().length() > 0) - dialog.set_current_folder(_app->configuration()->patch_folder()); - - if (dialog.run() != Gtk::RESPONSE_OK) - break; - - std::string filename = dialog.get_filename(); - std::string basename = Glib::path_get_basename(filename); - - if (basename.find('.') == std::string::npos) { - filename += ".ingen"; - basename += ".ingen"; - } else if (filename.substr(filename.length() - 10) != ".ingen") { - message_dialog( - "Ingen patches must be saved to Ingen bundles (*.ingen).", - "", Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); - continue; - } - - const std::string symbol(basename.substr(0, basename.find('.'))); - - if (!Raul::Symbol::is_valid(symbol)) { - message_dialog( - "Ingen bundle names must be valid symbols.", - "All characters must be _, a-z, A-Z, or 0-9, but the first may not be 0-9.", - Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); - continue; - } - - //_patch->set_property(uris.lv2_symbol, Atom(symbol.c_str())); - - bool confirm = true; - if (Glib::file_test(filename, Glib::FILE_TEST_IS_DIR)) { - if (Glib::file_test(Glib::build_filename(filename, "manifest.ttl"), - Glib::FILE_TEST_EXISTS)) { - int ret = message_dialog( - (boost::format("A bundle named \"%1%\" already exists." - " Replace it?") % basename).str(), - "", Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO); - confirm = (ret == Gtk::RESPONSE_YES); - } else { - int ret = message_dialog( - (boost::format("A directory named \"%1%\" already exists," - "but is not an Ingen bundle. " - "Save into it anyway?") % basename).str(), - "This will create at least 2 .ttl files in this directory," - "and possibly several more files and/or directories, recursively. " - "Existing files will be overwritten.", - Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO); - confirm = (ret == Gtk::RESPONSE_YES); - } - } else if (Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) { - int ret = message_dialog( - (boost::format("A file named \"%1%\" already exists. " - "Replace it with an Ingen bundle?") - % basename).str(), - "", Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO); - confirm = (ret == Gtk::RESPONSE_YES); - if (confirm) - ::g_remove(filename.c_str()); - } - - if (confirm) { - const Glib::ustring uri = Glib::filename_to_uri(filename); - _app->loader()->save_patch(_patch, uri); - const_cast(_patch.get())->set_property( - uris.ingen_document, - _app->forge().alloc_uri(uri.c_str()), - Resource::EXTERNAL); - _status_bar->push( - (boost::format("Saved %1% to %2%") % _patch->path().c_str() - % filename).str(), - STATUS_CONTEXT_PATCH); - } - - _app->configuration()->set_patch_folder(dialog.get_current_folder()); - break; - } -} - -void -PatchBox::event_draw() -{ - Gtk::FileChooserDialog dialog("Draw to DOT", Gtk::FILE_CHOOSER_ACTION_SAVE); - if (_window) { - dialog.set_transient_for(*_window); - } - - dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - Gtk::Button* save_button = dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); - save_button->property_has_default() = true; - - int result = dialog.run(); - - if (result == Gtk::RESPONSE_OK) { - std::string filename = dialog.get_filename(); - if (filename.find(".") == std::string::npos) - filename += ".dot"; - - bool confirm = true; - if (Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) { - int ret = message_dialog( - (boost::format("File exists! Overwrite %1%?") % filename).str(), - "", Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO); - confirm = (ret == Gtk::RESPONSE_YES); - } - - if (confirm) { - _view->canvas()->export_dot(filename.c_str()); - _status_bar->push( - (boost::format("Rendered %1% to %2%") - % _patch->path() % filename).str(), - STATUS_CONTEXT_PATCH); - } - } -} - -void -PatchBox::event_copy() -{ - if (_view) - _view->canvas()->copy_selection(); -} - -void -PatchBox::event_paste() -{ - if (_view) - _view->canvas()->paste(); -} - -void -PatchBox::event_delete() -{ - if (_view) - _view->canvas()->destroy_selection(); -} - -void -PatchBox::event_select_all() -{ - if (_view) - _view->canvas()->select_all(); -} - -void -PatchBox::event_close() -{ - if (_window) { - _app->window_factory()->remove_patch_window(_window); - } -} - -void -PatchBox::event_quit() -{ - _app->quit(_window); -} - -void -PatchBox::event_zoom_in() -{ - _view->canvas()->set_font_size(_view->canvas()->get_font_size() + 1.0); -} - -void -PatchBox::event_zoom_out() -{ - _view->canvas()->set_font_size(_view->canvas()->get_font_size() - 1.0); -} - -void -PatchBox::event_zoom_normal() -{ - _view->canvas()->set_scale(1.0, _view->canvas()->get_default_font_size()); -} - -void -PatchBox::event_arrange() -{ - _view->canvas()->arrange(); -} - -void -PatchBox::event_fullscreen_toggled() -{ - // FIXME: ugh, use GTK signals to track state and know for sure - static bool is_fullscreen = false; - - if (_window) { - if (!is_fullscreen) { - _window->fullscreen(); - is_fullscreen = true; - } else { - _window->unfullscreen(); - is_fullscreen = false; - } - } -} - -void -PatchBox::event_status_bar_toggled() -{ - if (_menu_show_status_bar->get_active()) - _status_bar->show(); - else - _status_bar->hide(); -} - -void -PatchBox::event_human_names_toggled() -{ - _view->canvas()->show_human_names(_menu_human_names->get_active()); - if (_menu_human_names->get_active()) - _app->configuration()->set_name_style(Configuration::HUMAN); - else - _app->configuration()->set_name_style(Configuration::PATH); -} - -void -PatchBox::event_port_names_toggled() -{ - if (_menu_show_port_names->get_active()) { - _view->canvas()->set_direction(GANV_DIRECTION_RIGHT); - _view->canvas()->show_port_names(true); - } else { - _view->canvas()->set_direction(GANV_DIRECTION_DOWN); - _view->canvas()->show_port_names(false); - } -} - -} // namespace GUI -} // namespace Ingen diff --git a/src/gui/PatchBox.hpp b/src/gui/PatchBox.hpp deleted file mode 100644 index f69f98b7..00000000 --- a/src/gui/PatchBox.hpp +++ /dev/null @@ -1,182 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#ifndef INGEN_GUI_PATCH_BOX_HPP -#define INGEN_GUI_PATCH_BOX_HPP - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "raul/SharedPtr.hpp" - -#include "Window.hpp" - -namespace Raul { -class Atom; -class Path; -} - -namespace Ingen { - -namespace Client { -class PatchModel; -class PortModel; -class ObjectModel; -} - -namespace GUI { - -class BreadCrumbs; -class LoadPatchBox; -class LoadPluginWindow; -class NewSubpatchWindow; -class PatchDescriptionWindow; -class PatchView; -class PatchWindow; -class SubpatchModule; - -/** A window for a patch. - * - * \ingroup GUI - */ -class PatchBox : public Gtk::VBox -{ -public: - PatchBox(BaseObjectType* cobject, - const Glib::RefPtr& xml); - ~PatchBox(); - - static SharedPtr create( - App& app, SharedPtr patch); - - void init_box(App& app); - - void set_patch(SharedPtr pc, - SharedPtr view); - - void set_window(PatchWindow* win) { _window = win; } - - void show_documentation(const std::string& doc, bool html); - void hide_documentation(); - - SharedPtr patch() const { return _patch; } - SharedPtr view() const { return _view; } - - void show_port_status(const Client::PortModel* model, - const Raul::Atom& value); - - void set_patch_from_path(const Raul::Path& path, SharedPtr view); - - void object_entered(const Client::ObjectModel* model); - void object_left(const Client::ObjectModel* model); - -private: - void patch_port_added(SharedPtr port); - void patch_port_removed(SharedPtr port); - void show_status(const Client::ObjectModel* model); - - int message_dialog(const Glib::ustring& message, - const Glib::ustring& secondary_text, - Gtk::MessageType type, - Gtk::ButtonsType buttons); - - void event_import(); - void event_save(); - void event_save_as(); - void event_draw(); - void event_copy(); - void event_paste(); - void event_delete(); - void event_select_all(); - void event_close(); - void event_quit(); - void event_fullscreen_toggled(); - void event_status_bar_toggled(); - void event_human_names_toggled(); - void event_port_names_toggled(); - void event_zoom_in(); - void event_zoom_out(); - void event_zoom_normal(); - void event_arrange(); - void event_show_properties(); - void event_show_engine(); - void event_clipboard_changed(GdkEventOwnerChange* ev); - - App* _app; - SharedPtr _patch; - SharedPtr _view; - PatchWindow* _window; - - sigc::connection new_port_connection; - sigc::connection removed_port_connection; - sigc::connection edit_mode_connection; - - Gtk::MenuItem* _menu_import; - Gtk::MenuItem* _menu_save; - Gtk::MenuItem* _menu_save_as; - Gtk::MenuItem* _menu_draw; - Gtk::MenuItem* _menu_cut; - Gtk::MenuItem* _menu_copy; - Gtk::MenuItem* _menu_paste; - Gtk::MenuItem* _menu_delete; - Gtk::MenuItem* _menu_select_all; - Gtk::MenuItem* _menu_close; - Gtk::MenuItem* _menu_quit; - Gtk::CheckMenuItem* _menu_human_names; - Gtk::CheckMenuItem* _menu_show_port_names; - Gtk::CheckMenuItem* _menu_show_status_bar; - Gtk::MenuItem* _menu_zoom_in; - Gtk::MenuItem* _menu_zoom_out; - Gtk::MenuItem* _menu_zoom_normal; - Gtk::MenuItem* _menu_fullscreen; - Gtk::MenuItem* _menu_arrange; - Gtk::MenuItem* _menu_view_engine_window; - Gtk::MenuItem* _menu_view_control_window; - Gtk::MenuItem* _menu_view_patch_properties; - Gtk::MenuItem* _menu_view_messages_window; - Gtk::MenuItem* _menu_view_patch_tree_window; - Gtk::MenuItem* _menu_help_about; - - Gtk::VBox* _vbox; - Gtk::Alignment* _alignment; - BreadCrumbs* _breadcrumbs; - Gtk::Statusbar* _status_bar; - - Gtk::HPaned* _doc_paned; - Gtk::ScrolledWindow* _doc_scrolledwindow; - - sigc::connection _entered_connection; - sigc::connection _left_connection; - - /** Invisible bin used to store breadcrumbs when not shown by a view */ - Gtk::Alignment _breadcrumb_bin; - - bool _has_shown_documentation; - bool _enable_signal; -}; - -} // namespace GUI -} // namespace Ingen - -#endif // INGEN_GUI_PATCH_BOX_HPP diff --git a/src/gui/PatchCanvas.cpp b/src/gui/PatchCanvas.cpp deleted file mode 100644 index d680a9b8..00000000 --- a/src/gui/PatchCanvas.cpp +++ /dev/null @@ -1,900 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#include -#include -#include -#include - -#include -#include - -#include "ganv/Canvas.hpp" -#include "ganv/Circle.hpp" -#include "ingen/Builder.hpp" -#include "ingen/ClashAvoider.hpp" -#include "ingen/Interface.hpp" -#include "ingen/Log.hpp" -#include "ingen/World.hpp" -#include "ingen/client/ClientStore.hpp" -#include "ingen/client/BlockModel.hpp" -#include "ingen/client/PatchModel.hpp" -#include "ingen/client/PluginModel.hpp" -#include "ingen/serialisation/Serialiser.hpp" -#include "lv2/lv2plug.in/ns/ext/atom/atom.h" - -#include "App.hpp" -#include "Edge.hpp" -#include "LoadPluginWindow.hpp" -#include "NewSubpatchWindow.hpp" -#include "NodeModule.hpp" -#include "PatchCanvas.hpp" -#include "PatchPortModule.hpp" -#include "PatchWindow.hpp" -#include "Port.hpp" -#include "SubpatchModule.hpp" -#include "ThreadedLoader.hpp" -#include "WidgetFactory.hpp" -#include "WindowFactory.hpp" - -#define FOREACH_ITEM(iter, coll) \ - for (Items::const_iterator (iter) = coll.begin(); \ - (iter) != coll.end(); ++(iter)) - -using namespace std; - -namespace Ingen { - -using namespace Client; - -namespace GUI { - -PatchCanvas::PatchCanvas(App& app, - SharedPtr patch, - int width, - int height) - : Canvas(width, height) - , _app(app) - , _patch(patch) - , _auto_position_count(0) - , _last_click_x(0) - , _last_click_y(0) - , _paste_count(0) - , _menu(NULL) - , _internal_menu(NULL) - , _classless_menu(NULL) - , _plugin_menu(NULL) - , _human_names(true) -{ - Glib::RefPtr xml = WidgetFactory::create("canvas_menu"); - xml->get_widget("canvas_menu", _menu); - - xml->get_widget("canvas_menu_add_audio_input", _menu_add_audio_input); - xml->get_widget("canvas_menu_add_audio_output", _menu_add_audio_output); - xml->get_widget("canvas_menu_add_control_input", _menu_add_control_input); - xml->get_widget("canvas_menu_add_control_output", _menu_add_control_output); - xml->get_widget("canvas_menu_add_event_input", _menu_add_event_input); - xml->get_widget("canvas_menu_add_event_output", _menu_add_event_output); - xml->get_widget("canvas_menu_load_plugin", _menu_load_plugin); - xml->get_widget("canvas_menu_load_patch", _menu_load_patch); - xml->get_widget("canvas_menu_new_patch", _menu_new_patch); - xml->get_widget("canvas_menu_edit", _menu_edit); - - const URIs& uris = _app.uris(); - - // Add port menu items - _menu_add_audio_input->signal_activate().connect( - sigc::bind(sigc::mem_fun(this, &PatchCanvas::menu_add_port), - "audio_in", "Audio In", uris.lv2_AudioPort, false)); - _menu_add_audio_output->signal_activate().connect( - sigc::bind(sigc::mem_fun(this, &PatchCanvas::menu_add_port), - "audio_out", "Audio Out", uris.lv2_AudioPort, true)); - _menu_add_control_input->signal_activate().connect( - sigc::bind(sigc::mem_fun(this, &PatchCanvas::menu_add_port), - "control_in", "Control In", uris.lv2_ControlPort, false)); - _menu_add_control_output->signal_activate().connect( - sigc::bind(sigc::mem_fun(this, &PatchCanvas::menu_add_port), - "control_out", "Control Out", uris.lv2_ControlPort, true)); - _menu_add_event_input->signal_activate().connect( - sigc::bind(sigc::mem_fun(this, &PatchCanvas::menu_add_port), - "event_in", "Event In", uris.atom_AtomPort, false)); - _menu_add_event_output->signal_activate().connect( - sigc::bind(sigc::mem_fun(this, &PatchCanvas::menu_add_port), - "event_out", "Event Out", uris.atom_AtomPort, true)); - - signal_event.connect( - sigc::mem_fun(this, &PatchCanvas::on_event)); - signal_connect.connect( - sigc::mem_fun(this, &PatchCanvas::connect)); - signal_disconnect.connect( - sigc::mem_fun(this, &PatchCanvas::disconnect)); - - // Connect to model signals to track state - _patch->signal_new_block().connect( - sigc::mem_fun(this, &PatchCanvas::add_block)); - _patch->signal_removed_block().connect( - sigc::mem_fun(this, &PatchCanvas::remove_block)); - _patch->signal_new_port().connect( - sigc::mem_fun(this, &PatchCanvas::add_port)); - _patch->signal_removed_port().connect( - sigc::mem_fun(this, &PatchCanvas::remove_port)); - _patch->signal_new_edge().connect( - sigc::mem_fun(this, &PatchCanvas::connection)); - _patch->signal_removed_edge().connect( - sigc::mem_fun(this, &PatchCanvas::disconnection)); - - _app.store()->signal_new_plugin().connect( - sigc::mem_fun(this, &PatchCanvas::add_plugin)); - - // Connect widget signals to do things - _menu_load_plugin->signal_activate().connect( - sigc::mem_fun(this, &PatchCanvas::menu_load_plugin)); - _menu_load_patch->signal_activate().connect( - sigc::mem_fun(this, &PatchCanvas::menu_load_patch)); - _menu_new_patch->signal_activate().connect( - sigc::mem_fun(this, &PatchCanvas::menu_new_patch)); -} - -void -PatchCanvas::show_menu(bool position, unsigned button, uint32_t time) -{ - if (!_internal_menu) - build_menus(); - - if (position) - _menu->popup(sigc::mem_fun(this, &PatchCanvas::auto_menu_position), button, time); - else - _menu->popup(button, time); -} - -void -PatchCanvas::build_menus() -{ - // Build (or clear existing) internal plugin menu - if (_internal_menu) { - _internal_menu->items().clear(); - } else { - _menu->items().push_back( - Gtk::Menu_Helpers::ImageMenuElem( - "I_nternal", - *(manage(new Gtk::Image(Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU))))); - Gtk::MenuItem* internal_menu_item = &(_menu->items().back()); - _internal_menu = Gtk::manage(new Gtk::Menu()); - internal_menu_item->set_submenu(*_internal_menu); - _menu->reorder_child(*internal_menu_item, 4); - } - - // Build skeleton LV2 plugin class heirarchy for 'Plugin' menu - if (!_plugin_menu) - build_plugin_menu(); - - // Build (or clear existing) uncategorized (classless, heh) plugins menu - if (_classless_menu) { - _classless_menu->items().clear(); - } else { - _plugin_menu->items().push_back(Gtk::Menu_Helpers::MenuElem("Uncategorized")); - Gtk::MenuItem* classless_menu_item = &(_plugin_menu->items().back()); - _classless_menu = Gtk::manage(new Gtk::Menu()); - classless_menu_item->set_submenu(*_classless_menu); - _classless_menu->hide(); - } - - // Add known plugins to menu heirarchy - SharedPtr plugins = _app.store()->plugins(); - for (ClientStore::Plugins::const_iterator i = plugins->begin(); i != plugins->end(); ++i) - add_plugin(i->second); -} - -/** Recursively build the plugin class menu heirarchy rooted at - * @a plugin class into @a menu - */ -size_t -PatchCanvas::build_plugin_class_menu( - Gtk::Menu* menu, - const LilvPluginClass* plugin_class, - const LilvPluginClasses* classes, - const LV2Children& children, - std::set& ancestors) -{ - size_t num_items = 0; - const LilvNode* class_uri = lilv_plugin_class_get_uri(plugin_class); - const char* class_uri_str = lilv_node_as_string(class_uri); - - const std::pair kids - = children.equal_range(class_uri_str); - - if (kids.first == children.end()) - return 0; - - // Add submenus - ancestors.insert(class_uri_str); - for (LV2Children::const_iterator i = kids.first; i != kids.second; ++i) { - const LilvPluginClass* c = i->second; - const char* sub_label_str = lilv_node_as_string(lilv_plugin_class_get_label(c)); - const char* sub_uri_str = lilv_node_as_string(lilv_plugin_class_get_uri(c)); - if (ancestors.find(sub_uri_str) != ancestors.end()) { - _app.log().warn(Raul::fmt("Infinite LV2 class recursion: %1% <: %2%\n") - % class_uri_str % sub_uri_str); - return 0; - } - - Gtk::Menu_Helpers::MenuElem menu_elem = Gtk::Menu_Helpers::MenuElem(sub_label_str); - menu->items().push_back(menu_elem); - Gtk::MenuItem* menu_item = &(menu->items().back()); - - Gtk::Menu* submenu = Gtk::manage(new Gtk::Menu()); - menu_item->set_submenu(*submenu); - - size_t num_child_items = build_plugin_class_menu( - submenu, c, classes, children, ancestors); - - _class_menus.insert(make_pair(sub_uri_str, MenuRecord(menu_item, submenu))); - if (num_child_items == 0) - menu_item->hide(); - - ++num_items; - } - ancestors.erase(class_uri_str); - - return num_items; -} - -void -PatchCanvas::build_plugin_menu() -{ - if (_plugin_menu) { - _plugin_menu->items().clear(); - } else { - _menu->items().push_back( - Gtk::Menu_Helpers::ImageMenuElem( - "_Plugin", - *(manage(new Gtk::Image(Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU))))); - Gtk::MenuItem* plugin_menu_item = &(_menu->items().back()); - _plugin_menu = Gtk::manage(new Gtk::Menu()); - plugin_menu_item->set_submenu(*_plugin_menu); - _menu->reorder_child(*plugin_menu_item, 5); - } - - const LilvWorld* world = PluginModel::lilv_world(); - const LilvPluginClass* lv2_plugin = lilv_world_get_plugin_class(world); - const LilvPluginClasses* classes = lilv_world_get_plugin_classes(world); - - LV2Children children; - LILV_FOREACH(plugin_classes, i, classes) { - const LilvPluginClass* c = lilv_plugin_classes_get(classes, i); - const LilvNode* p = lilv_plugin_class_get_parent_uri(c); - if (!p) - p = lilv_plugin_class_get_uri(lv2_plugin); - children.insert(make_pair(lilv_node_as_string(p), c)); - } - std::set ancestors; - build_plugin_class_menu(_plugin_menu, lv2_plugin, classes, children, ancestors); -} - -void -PatchCanvas::build() -{ - const Store::const_range kids = _app.store()->children_range(_patch); - - // Create modules for blocks - for (Store::const_iterator i = kids.first; i != kids.second; ++i) { - SharedPtr block = PtrCast(i->second); - if (block && block->parent() == _patch) - add_block(block); - } - - // Create pseudo modules for ports (ports on this canvas, not on our module) - for (BlockModel::Ports::const_iterator i = _patch->ports().begin(); - i != _patch->ports().end(); ++i) { - add_port(*i); - } - - // Create edges - for (PatchModel::Edges::const_iterator i = _patch->edges().begin(); - i != _patch->edges().end(); ++i) { - connection(PtrCast(i->second)); - } -} - -static void -show_module_human_names(GanvNode* node, void* data) -{ - bool b = *(bool*)data; - if (GANV_IS_MODULE(node)) { - Ganv::Module* module = Glib::wrap(GANV_MODULE(node)); - NodeModule* nmod = dynamic_cast(module); - if (nmod) - nmod->show_human_names(b); - - PatchPortModule* pmod = dynamic_cast(module); - if (pmod) - pmod->show_human_names(b); - } -} -void -PatchCanvas::show_human_names(bool b) -{ - _human_names = b; - for_each_node(show_module_human_names, &b); -} - -void -PatchCanvas::show_port_names(bool b) -{ - ganv_canvas_set_direction(gobj(), b ? GANV_DIRECTION_RIGHT : GANV_DIRECTION_DOWN); -} - -void -PatchCanvas::add_plugin(SharedPtr p) -{ - typedef ClassMenus::iterator iterator; - if (_internal_menu && p->type() == Plugin::Internal) { - _internal_menu->items().push_back( - Gtk::Menu_Helpers::MenuElem( - p->human_name(), - sigc::bind(sigc::mem_fun(this, &PatchCanvas::load_plugin), p))); - } else if (_plugin_menu && p->type() == Plugin::LV2 && p->lilv_plugin()) { - if (lilv_plugin_is_replaced(p->lilv_plugin())) { - //info << (boost::format("[Menu] LV2 plugin <%s> hidden") % p->uri()) << endl; - return; - } - - const LilvPluginClass* pc = lilv_plugin_get_class(p->lilv_plugin()); - const LilvNode* class_uri = lilv_plugin_class_get_uri(pc); - const char* class_uri_str = lilv_node_as_string(class_uri); - - Glib::RefPtr icon = _app.icon_from_path( - PluginModel::get_lv2_icon_path(p->lilv_plugin()), 16); - - pair range = _class_menus.equal_range(class_uri_str); - if (range.first == _class_menus.end() || range.first == range.second - || range.first->second.menu == _plugin_menu) { - _classless_menu->items().push_back( - Gtk::Menu_Helpers::MenuElem( - p->human_name(), - sigc::bind(sigc::mem_fun(this, &PatchCanvas::load_plugin), p))); - if (!_classless_menu->is_visible()) - _classless_menu->show(); - } else { - // For each menu that represents plugin's class (possibly several) - for (iterator i = range.first; i != range.second ; ++i) { - Gtk::Menu* menu = i->second.menu; - if (icon) { - Gtk::Image* image = new Gtk::Image(icon); - menu->items().push_back( - Gtk::Menu_Helpers::ImageMenuElem( - p->human_name(), *image, - sigc::bind(sigc::mem_fun(this, &PatchCanvas::load_plugin), p))); - } else { - menu->items().push_back( - Gtk::Menu_Helpers::MenuElem( - p->human_name(), - sigc::bind(sigc::mem_fun(this, &PatchCanvas::load_plugin), p))); - } - if (!i->second.item->is_visible()) - i->second.item->show(); - } - } - } -} - -void -PatchCanvas::add_block(SharedPtr bm) -{ - SharedPtr pm = PtrCast(bm); - NodeModule* module; - if (pm) { - module = SubpatchModule::create(*this, pm, _human_names); - } else { - module = NodeModule::create(*this, bm, _human_names); - //const PluginModel* plugm = dynamic_cast(nm->plugin()); - //if (plugm && !plugm->icon_path().empty()) - // module->set_icon(_app.icon_from_path(plugm->icon_path(), 100).operator->()); - } - - module->show(); - _views.insert(std::make_pair(bm, module)); - if (_pastees.find(bm->path()) != _pastees.end()) { - module->set_selected(true); - } -} - -void -PatchCanvas::remove_block(SharedPtr bm) -{ - Views::iterator i = _views.find(bm); - - if (i != _views.end()) { - const guint n_ports = i->second->num_ports(); - for (gint p = n_ports - 1; p >= 0; --p) { - delete i->second->get_port(p); - } - delete i->second; - _views.erase(i); - } -} - -void -PatchCanvas::add_port(SharedPtr pm) -{ - PatchPortModule* view = PatchPortModule::create(*this, pm, _human_names); - _views.insert(std::make_pair(pm, view)); - view->show(); -} - -void -PatchCanvas::remove_port(SharedPtr pm) -{ - Views::iterator i = _views.find(pm); - - // Port on this patch - if (i != _views.end()) { - delete i->second; - _views.erase(i); - - } else { - NodeModule* module = dynamic_cast(_views[pm->parent()]); - module->delete_port_view(pm); - } - - assert(_views.find(pm) == _views.end()); -} - -Ganv::Port* -PatchCanvas::get_port_view(SharedPtr port) -{ - Ganv::Module* module = _views[port]; - - // Port on this patch - if (module) { - PatchPortModule* ppm = dynamic_cast(module); - return ppm - ? *ppm->begin() - : dynamic_cast(module); - } else { - module = dynamic_cast(_views[port->parent()]); - if (module) { - for (Ganv::Module::iterator p = module->begin(); - p != module->end(); ++p) { - GUI::Port* pv = dynamic_cast(*p); - if (pv && pv->model() == port) - return pv; - } - } - } - - return NULL; -} - -void -PatchCanvas::connection(SharedPtr cm) -{ - Ganv::Port* const tail = get_port_view(cm->tail()); - Ganv::Port* const head = get_port_view(cm->head()); - - if (tail && head) { - new GUI::Edge(*this, cm, tail, head, tail->get_fill_color()); - } else { - _app.log().error(Raul::fmt("Unable to find ports to connect %1% => %2%\n") - % cm->tail_path() % cm->head_path()); - } -} - -void -PatchCanvas::disconnection(SharedPtr cm) -{ - Ganv::Port* const src = get_port_view(cm->tail()); - Ganv::Port* const dst = get_port_view(cm->head()); - - if (src && dst) { - remove_edge(src, dst); - } else { - _app.log().error(Raul::fmt("Unable to find ports to disconnect %1% => %2%\n") - % cm->tail_path() % cm->head_path()); - } -} - -void -PatchCanvas::connect(Ganv::Node* tail, - Ganv::Node* head) -{ - const Ingen::GUI::Port* const src - = dynamic_cast(tail); - - const Ingen::GUI::Port* const dst - = dynamic_cast(head); - - if (!src || !dst) - return; - - _app.interface()->connect(src->model()->path(), dst->model()->path()); -} - -void -PatchCanvas::disconnect(Ganv::Node* tail, - Ganv::Node* head) -{ - const Ingen::GUI::Port* const t = dynamic_cast(tail); - const Ingen::GUI::Port* const h = dynamic_cast(head); - - _app.interface()->disconnect(t->model()->path(), h->model()->path()); -} - -void -PatchCanvas::auto_menu_position(int& x, int& y, bool& push_in) -{ - std::pair scroll_offsets; - get_scroll_offsets(scroll_offsets.first, scroll_offsets.second); - - if (_auto_position_count > 0 && scroll_offsets != _auto_position_scroll_offsets) - _auto_position_count = 0; // scrolling happened since last time, reset - - const int cascade = (_auto_position_count > 0) ? (_auto_position_count * 32) : 0; - - x = 64 + cascade; - y = 64 + cascade; - push_in = true; - - _last_click_x = scroll_offsets.first + x; - _last_click_y = scroll_offsets.second + y; - - ++_auto_position_count; - _auto_position_scroll_offsets = scroll_offsets; -} - -bool -PatchCanvas::on_event(GdkEvent* event) -{ - assert(event); - - bool ret = false; - - switch (event->type) { - case GDK_BUTTON_PRESS: - if (event->button.button == 3) { - _auto_position_count = 0; - _last_click_x = (int)event->button.x; - _last_click_y = (int)event->button.y; - show_menu(false, event->button.button, event->button.time); - ret = true; - } - break; - - case GDK_KEY_PRESS: - switch (event->key.keyval) { - case GDK_Delete: - destroy_selection(); - ret = true; - break; - case GDK_Home: - scroll_to(0, 0); - break; - case GDK_space: - case GDK_Menu: - show_menu(true, 3, event->key.time); - default: break; - } - - default: break; - } - - return ret; -} - -void -PatchCanvas::clear_selection() -{ - PatchWindow* win = _app.window_factory()->patch_window(_patch); - if (win) { - win->hide_documentation(); - } - - Ganv::Canvas::clear_selection(); -} - -static void -destroy_node(GanvNode* node, void* data) -{ - if (!GANV_IS_MODULE(node)) { - return; - } - - App* app = (App*)data; - Ganv::Module* module = Glib::wrap(GANV_MODULE(node)); - NodeModule* node_module = dynamic_cast(module); - - if (node_module) { - app->interface()->del(node_module->block()->uri()); - } else { - PatchPortModule* port_module = dynamic_cast(module); - if (port_module) { - app->interface()->del(port_module->port()->uri()); - } - } -} - -static void -destroy_edge(GanvEdge* edge, void* data) -{ - App* app = (App*)data; - Ganv::Edge* edgemm = Glib::wrap(edge); - - Port* tail = dynamic_cast(edgemm->get_tail()); - Port* head = dynamic_cast(edgemm->get_head()); - app->interface()->disconnect(tail->model()->path(), head->model()->path()); -} - -void -PatchCanvas::destroy_selection() -{ - for_each_selected_node(destroy_node, &_app); - for_each_selected_edge(destroy_edge, &_app); -} - -static void -serialise_node(GanvNode* node, void* data) -{ - Serialisation::Serialiser* serialiser = (Serialisation::Serialiser*)data; - if (!GANV_IS_MODULE(node)) { - return; - } - - Ganv::Module* module = Glib::wrap(GANV_MODULE(node)); - NodeModule* node_module = dynamic_cast(module); - - if (node_module) { - serialiser->serialise(node_module->block()); - } else { - PatchPortModule* port_module = dynamic_cast(module); - if (port_module) { - serialiser->serialise(port_module->port()); - } - } -} - -static void -serialise_edge(GanvEdge* edge, void* data) -{ - Serialisation::Serialiser* serialiser = (Serialisation::Serialiser*)data; - if (!GANV_IS_EDGE(edge)) { - return; - } - - GUI::Edge* gedge = dynamic_cast(Glib::wrap(GANV_EDGE(edge))); - if (gedge) { - serialiser->serialise_edge(Sord::Node(), gedge->model()); - } -} - -void -PatchCanvas::copy_selection() -{ - static const char* base_uri = "http://drobilla.net/ns/ingen/selection/"; - Serialisation::Serialiser serialiser(*_app.world()); - serialiser.start_to_string(_patch->path(), base_uri); - - for_each_selected_node(serialise_node, &serialiser); - for_each_selected_edge(serialise_edge, &serialiser); - - const std::string result = serialiser.finish(); - _paste_count = 0; - - Glib::RefPtr clipboard = Gtk::Clipboard::get(); - clipboard->set_text(result); -} - -void -PatchCanvas::paste() -{ - Glib::ustring str = Gtk::Clipboard::get()->wait_for_text(); - SharedPtr parser = _app.loader()->parser(); - if (!parser) { - _app.log().error("Unable to load parser, paste unavailable\n"); - return; - } - - clear_selection(); - _pastees.clear(); - ++_paste_count; - - const URIs& uris = _app.uris(); - - Builder builder(_app.world()->uris(), *_app.interface()); - ClientStore clipboard(_app.world()->uris(), _app.log()); - clipboard.set_plugins(_app.store()->plugins()); - - // mkdir -p - string to_create = _patch->path().substr(1); - string created = "/"; - Resource::Properties props; - props.insert(make_pair(uris.rdf_type, - uris.ingen_Patch)); - props.insert(make_pair(uris.ingen_polyphony, - _app.forge().make(int32_t(_patch->internal_poly())))); - clipboard.put(GraphObject::root_uri(), props); - size_t first_slash; - while (to_create != "/" && !to_create.empty() - && (first_slash = to_create.find("/")) != string::npos) { - created += to_create.substr(0, first_slash); - assert(Raul::Path::is_valid(created)); - clipboard.put(GraphObject::path_to_uri(Raul::Path(created)), props); - to_create = to_create.substr(first_slash + 1); - } - - if (!_patch->path().is_root()) - clipboard.put(_patch->uri(), props); - - boost::optional parent; - boost::optional symbol; - - if (!_patch->path().is_root()) { - parent = _patch->path(); - } - - ClashAvoider avoider(*_app.store().get(), clipboard, &clipboard); - static const char* base_uri = "http://drobilla.net/ns/ingen/selection/"; - parser->parse_string(_app.world(), &avoider, str, base_uri, - parent, symbol); - - for (Store::iterator i = clipboard.begin(); i != clipboard.end(); ++i) { - if (_patch->path().is_root() && i->first.is_root()) - continue; - - GraphObject::Properties& props = i->second->properties(); - - GraphObject::Properties::iterator x = props.find(uris.ingen_canvasX); - if (x != i->second->properties().end()) - x->second = _app.forge().make( - x->second.get_float() + (20.0f * _paste_count)); - - GraphObject::Properties::iterator y = props.find(uris.ingen_canvasY); - if (y != i->second->properties().end()) - y->second = _app.forge().make( - y->second.get_float() + (20.0f * _paste_count)); - - builder.build(i->second); - _pastees.insert(i->first); - } - - builder.connect(PtrCast(clipboard.object(_patch->path()))); -} - -void -PatchCanvas::generate_port_name( - const string& sym_base, string& symbol, - const string& name_base, string& name) -{ - symbol = sym_base; - name = name_base; - - char num_buf[5]; - uint32_t i = 1; - for ( ; i < 9999; ++i) { - snprintf(num_buf, sizeof(num_buf), "%u", i); - symbol = sym_base + "_"; - symbol += num_buf; - if (!_patch->get_port(Raul::Symbol::symbolify(symbol))) - break; - } - - assert(Raul::Path::is_valid(string("/") + symbol)); - - name.append(" ").append(num_buf); -} - -void -PatchCanvas::menu_add_port(const string& sym_base, const string& name_base, - const Raul::URI& type, bool is_output) -{ - string sym, name; - generate_port_name(sym_base, sym, name_base, name); - const Raul::Path& path = _patch->path().child(Raul::Symbol(sym)); - - const URIs& uris = _app.uris(); - - Resource::Properties props = get_initial_data(); - props.insert(make_pair(uris.rdf_type, - _app.forge().alloc_uri(type))); - if (type == uris.atom_AtomPort) { - props.insert(make_pair(uris.atom_bufferType, - uris.atom_Sequence)); - } - props.insert(make_pair(uris.rdf_type, - is_output ? uris.lv2_OutputPort : uris.lv2_InputPort)); - props.insert(make_pair(uris.lv2_index, - _app.forge().make(int32_t(_patch->num_ports())))); - props.insert(make_pair(uris.lv2_name, - _app.forge().alloc(name.c_str()))); - _app.interface()->put(GraphObject::path_to_uri(path), props); -} - -void -PatchCanvas::load_plugin(WeakPtr weak_plugin) -{ - SharedPtr plugin = weak_plugin.lock(); - if (!plugin) - return; - - Raul::Symbol symbol = plugin->default_block_symbol(); - unsigned offset = _app.store()->child_name_offset(_patch->path(), symbol); - if (offset != 0) { - std::stringstream ss; - ss << symbol << "_" << offset; - symbol = Raul::Symbol(ss.str()); - } - - const URIs& uris = _app.uris(); - const Raul::Path path = _patch->path().child(symbol); - - // FIXME: polyphony? - GraphObject::Properties props = get_initial_data(); - props.insert(make_pair(uris.rdf_type, uris.ingen_Block)); - props.insert(make_pair(uris.ingen_prototype, - uris.forge.alloc_uri(plugin->uri()))); - _app.interface()->put(GraphObject::path_to_uri(path), props); -} - -/** Try to guess a suitable location for a new module. - */ -void -PatchCanvas::get_new_module_location(double& x, double& y) -{ - int scroll_x; - int scroll_y; - get_scroll_offsets(scroll_x, scroll_y); - x = scroll_x + 20; - y = scroll_y + 20; -} - -GraphObject::Properties -PatchCanvas::get_initial_data(Resource::Graph ctx) -{ - GraphObject::Properties result; - const URIs& uris = _app.uris(); - result.insert( - make_pair(uris.ingen_canvasX, - Resource::Property(_app.forge().make((float)_last_click_x), - ctx))); - result.insert( - make_pair(uris.ingen_canvasY, - Resource::Property(_app.forge().make((float)_last_click_y), - ctx))); - return result; -} - -void -PatchCanvas::menu_load_plugin() -{ - _app.window_factory()->present_load_plugin( - _patch, get_initial_data()); -} - -void -PatchCanvas::menu_load_patch() -{ - _app.window_factory()->present_load_subpatch( - _patch, get_initial_data(Resource::EXTERNAL)); -} - -void -PatchCanvas::menu_new_patch() -{ - _app.window_factory()->present_new_subpatch( - _patch, get_initial_data(Resource::EXTERNAL)); -} - -} // namespace GUI -} // namespace Ingen diff --git a/src/gui/PatchCanvas.hpp b/src/gui/PatchCanvas.hpp deleted file mode 100644 index 04c30ed3..00000000 --- a/src/gui/PatchCanvas.hpp +++ /dev/null @@ -1,174 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#ifndef INGEN_GUI_PATCHCANVAS_HPP -#define INGEN_GUI_PATCHCANVAS_HPP - -#include -#include -#include - -#include - -#include "lilv/lilv.h" - -#include "ganv/Canvas.hpp" -#include "ganv/Module.hpp" -#include "raul/SharedPtr.hpp" -#include "raul/Path.hpp" - -#include "ingen/client/EdgeModel.hpp" -#include "ingen/GraphObject.hpp" -#include "NodeModule.hpp" - -namespace Ingen { - -namespace Client { class PatchModel; } - -namespace GUI { - -class NodeModule; - -/** Patch canvas widget. - * - * \ingroup GUI - */ -class PatchCanvas : public Ganv::Canvas -{ -public: - PatchCanvas(App& app, - SharedPtr patch, - int width, - int height); - - virtual ~PatchCanvas() {} - - App& app() { return _app; } - - void build(); - void show_human_names(bool show); - void show_port_names(bool show); - bool show_port_names() const { return _show_port_names; } - - void add_plugin(SharedPtr pm); - void add_block(SharedPtr bm); - void remove_block(SharedPtr bm); - void add_port(SharedPtr pm); - void remove_port(SharedPtr pm); - void connection(SharedPtr cm); - void disconnection(SharedPtr cm); - - void get_new_module_location(double& x, double& y); - - void clear_selection(); - void destroy_selection(); - void copy_selection(); - void paste(); - - void show_menu(bool position, unsigned button, uint32_t time); - - bool on_event(GdkEvent* event); - -private: - enum ControlType { NUMBER, BUTTON }; - void generate_port_name( - const std::string& sym_base, std::string& sym, - const std::string& name_base, std::string& name); - - void menu_add_port( - const std::string& sym_base, const std::string& name_base, - const Raul::URI& type, bool is_output); - - void menu_load_plugin(); - void menu_new_patch(); - void menu_load_patch(); - void load_plugin(WeakPtr plugin); - - void build_menus(); - - void build_internal_menu(); - void build_classless_menu(); - - void auto_menu_position(int& x, int& y, bool& push_in); - - typedef std::multimap LV2Children; - void build_plugin_menu(); - size_t build_plugin_class_menu( - Gtk::Menu* menu, - const LilvPluginClass* plugin_class, - const LilvPluginClasses* classes, - const LV2Children& children, - std::set& ancestors); - - GraphObject::Properties get_initial_data(Resource::Graph ctx=Resource::DEFAULT); - - Ganv::Port* get_port_view(SharedPtr port); - - void connect(Ganv::Node* src, - Ganv::Node* dst); - - void disconnect(Ganv::Node* src, - Ganv::Node* dst); - - App& _app; - SharedPtr _patch; - - typedef std::map, Ganv::Module*> Views; - Views _views; - - int _auto_position_count; - std::pair _auto_position_scroll_offsets; - - int _last_click_x; - int _last_click_y; - int _paste_count; - - // Track pasted objects so they can be selected when they arrive - std::set _pastees; - - struct MenuRecord { - MenuRecord(Gtk::MenuItem* i, Gtk::Menu* m) : item(i), menu(m) {} - Gtk::MenuItem* item; - Gtk::Menu* menu; - }; - - typedef std::multimap ClassMenus; - - ClassMenus _class_menus; - - Gtk::Menu* _menu; - Gtk::Menu* _internal_menu; - Gtk::Menu* _classless_menu; - Gtk::Menu* _plugin_menu; - Gtk::MenuItem* _menu_add_audio_input; - Gtk::MenuItem* _menu_add_audio_output; - Gtk::MenuItem* _menu_add_control_input; - Gtk::MenuItem* _menu_add_control_output; - Gtk::MenuItem* _menu_add_event_input; - Gtk::MenuItem* _menu_add_event_output; - Gtk::MenuItem* _menu_load_plugin; - Gtk::MenuItem* _menu_load_patch; - Gtk::MenuItem* _menu_new_patch; - Gtk::CheckMenuItem* _menu_edit; - - bool _human_names; - bool _show_port_names; -}; - -} // namespace GUI -} // namespace Ingen - -#endif // INGEN_GUI_PATCHCANVAS_HPP diff --git a/src/gui/PatchPortModule.cpp b/src/gui/PatchPortModule.cpp deleted file mode 100644 index ec0e6a04..00000000 --- a/src/gui/PatchPortModule.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#include -#include -#include - -#include "ingen/Interface.hpp" -#include "ingen/client/BlockModel.hpp" -#include "ingen/client/PatchModel.hpp" - -#include "App.hpp" -#include "Configuration.hpp" -#include "PatchCanvas.hpp" -#include "PatchPortModule.hpp" -#include "PatchWindow.hpp" -#include "Port.hpp" -#include "PortMenu.hpp" -#include "RenameWindow.hpp" -#include "WidgetFactory.hpp" -#include "WindowFactory.hpp" - -using namespace std; - -namespace Ingen { - -using namespace Client; - -namespace GUI { - -PatchPortModule::PatchPortModule(PatchCanvas& canvas, - SharedPtr model) - : Ganv::Module(canvas, "", 0, 0, false) // FIXME: coords? - , _model(model) -{ - assert(model); - - assert(PtrCast(model->parent())); - - set_stacked(model->polyphonic()); - - model->signal_property().connect( - sigc::mem_fun(this, &PatchPortModule::property_changed)); - - signal_moved().connect( - sigc::mem_fun(this, &PatchPortModule::store_location)); -} - -PatchPortModule* -PatchPortModule::create(PatchCanvas& canvas, - SharedPtr model, - bool human) -{ - PatchPortModule* ret = new PatchPortModule(canvas, model); - Port* port = Port::create(canvas.app(), *ret, model, human, true); - - ret->set_port(port); - - for (GraphObject::Properties::const_iterator m = model->properties().begin(); - m != model->properties().end(); ++m) - ret->property_changed(m->first, m->second); - - return ret; -} - -App& -PatchPortModule::app() const -{ - return ((PatchCanvas*)canvas())->app(); -} - -bool -PatchPortModule::show_menu(GdkEventButton* ev) -{ - return _port->show_menu(ev); -} - -void -PatchPortModule::store_location(double ax, double ay) -{ - const URIs& uris = app().uris(); - - const Raul::Atom x(app().forge().make(static_cast(ax))); - const Raul::Atom y(app().forge().make(static_cast(ay))); - - if (x != _model->get_property(uris.ingen_canvasX) || - y != _model->get_property(uris.ingen_canvasY)) - { - Resource::Properties remove; - remove.insert(make_pair(uris.ingen_canvasX, uris.wildcard)); - remove.insert(make_pair(uris.ingen_canvasY, uris.wildcard)); - Resource::Properties add; - add.insert(make_pair(uris.ingen_canvasX, - Resource::Property(x, Resource::INTERNAL))); - add.insert(make_pair(uris.ingen_canvasY, - Resource::Property(y, Resource::INTERNAL))); - app().interface()->delta(_model->uri(), remove, add); - } -} - -void -PatchPortModule::show_human_names(bool b) -{ - const URIs& uris = app().uris(); - const Raul::Atom& name = _model->get_property(uris.lv2_name); - if (b && name.type() == uris.forge.String) { - set_name(name.get_string()); - } else { - set_name(_model->symbol().c_str()); - } -} - -void -PatchPortModule::set_name(const std::string& n) -{ - _port->set_label(n.c_str()); -} - -void -PatchPortModule::property_changed(const Raul::URI& key, const Raul::Atom& value) -{ - const URIs& uris = app().uris(); - if (value.type() == uris.forge.Float) { - if (key == uris.ingen_canvasX) { - move_to(value.get_float(), get_y()); - } else if (key == uris.ingen_canvasY) { - move_to(get_x(), value.get_float()); - } - } else if (value.type() == uris.forge.String) { - if (key == uris.lv2_name - && app().configuration()->name_style() == Configuration::HUMAN) { - set_name(value.get_string()); - } else if (key == uris.lv2_symbol - && app().configuration()->name_style() == Configuration::PATH) { - set_name(value.get_string()); - } - } else if (value.type() == uris.forge.Bool) { - if (key == uris.ingen_polyphonic) { - set_stacked(value.get_bool()); - } - } -} - -void -PatchPortModule::set_selected(gboolean b) -{ - if (b != get_selected()) { - Module::set_selected(b); - } -} - -} // namespace GUI -} // namespace Ingen diff --git a/src/gui/PatchPortModule.hpp b/src/gui/PatchPortModule.hpp deleted file mode 100644 index b48bbfc4..00000000 --- a/src/gui/PatchPortModule.hpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#ifndef INGEN_GUI_PATCHPORTMODULE_HPP -#define INGEN_GUI_PATCHPORTMODULE_HPP - -#include - -#include - -#include "ganv/Module.hpp" -#include "raul/URI.hpp" - -#include "Port.hpp" - -namespace Raul { class Atom; } - -namespace Ingen { namespace Client { - class PortModel; -} } - -namespace Ingen { -namespace GUI { - -class PatchCanvas; -class Port; -class PortMenu; - -/** A "module" to represent a patch's port on its own canvas. - * - * Translation: This is the nameless single port pseudo module thingy. - * - * \ingroup GUI - */ -class PatchPortModule : public Ganv::Module -{ -public: - static PatchPortModule* create( - PatchCanvas& canvas, - SharedPtr model, - bool human); - - App& app() const; - - virtual void store_location(double x, double y); - void show_human_names(bool b); - - void set_name(const std::string& n); - - SharedPtr port() const { return _model; } - -protected: - PatchPortModule(PatchCanvas& canvas, - SharedPtr model); - - bool show_menu(GdkEventButton* ev); - void set_selected(gboolean b); - - void set_port(Port* port) { _port = port; } - - void property_changed(const Raul::URI& predicate, const Raul::Atom& value); - - SharedPtr _model; - Port* _port; -}; - -} // namespace GUI -} // namespace Ingen - -#endif // INGEN_GUI_PATCHPORTMODULE_HPP diff --git a/src/gui/PatchTreeWindow.cpp b/src/gui/PatchTreeWindow.cpp deleted file mode 100644 index 00b96926..00000000 --- a/src/gui/PatchTreeWindow.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#include "App.hpp" -#include "PatchTreeWindow.hpp" -#include "SubpatchModule.hpp" -#include "WindowFactory.hpp" -#include "ingen/Interface.hpp" -#include "ingen/Log.hpp" -#include "ingen/client/ClientStore.hpp" -#include "ingen/client/PatchModel.hpp" -#include "raul/Path.hpp" - -using namespace std; - -namespace Ingen { - -using namespace Client; - -namespace GUI { - -PatchTreeWindow::PatchTreeWindow(BaseObjectType* cobject, - const Glib::RefPtr& xml) - : Window(cobject) - , _app(NULL) - , _enable_signal(true) -{ - xml->get_widget_derived("patches_treeview", _patches_treeview); - - _patch_treestore = Gtk::TreeStore::create(_patch_tree_columns); - _patches_treeview->set_window(this); - _patches_treeview->set_model(_patch_treestore); - Gtk::TreeViewColumn* name_col = Gtk::manage(new Gtk::TreeViewColumn( - "Patch", _patch_tree_columns.name_col)); - Gtk::TreeViewColumn* enabled_col = Gtk::manage(new Gtk::TreeViewColumn( - "Run", _patch_tree_columns.enabled_col)); - name_col->set_resizable(true); - name_col->set_expand(true); - - _patches_treeview->append_column(*name_col); - _patches_treeview->append_column(*enabled_col); - Gtk::CellRendererToggle* enabled_renderer = dynamic_cast( - _patches_treeview->get_column_cell_renderer(1)); - enabled_renderer->property_activatable() = true; - - _patch_tree_selection = _patches_treeview->get_selection(); - - _patches_treeview->signal_row_activated().connect( - sigc::mem_fun(this, &PatchTreeWindow::event_patch_activated)); - enabled_renderer->signal_toggled().connect( - sigc::mem_fun(this, &PatchTreeWindow::event_patch_enabled_toggled)); - - _patches_treeview->columns_autosize(); -} - -void -PatchTreeWindow::init(App& app, ClientStore& store) -{ - _app = &app; - store.signal_new_object().connect( - sigc::mem_fun(this, &PatchTreeWindow::new_object)); -} - -void -PatchTreeWindow::new_object(SharedPtr object) -{ - SharedPtr patch = PtrCast(object); - if (patch) - add_patch(patch); -} - -void -PatchTreeWindow::add_patch(SharedPtr pm) -{ - if (!pm->parent()) { - Gtk::TreeModel::iterator iter = _patch_treestore->append(); - Gtk::TreeModel::Row row = *iter; - if (pm->path().is_root()) { - row[_patch_tree_columns.name_col] = _app->interface()->uri(); - } else { - row[_patch_tree_columns.name_col] = pm->symbol().c_str(); - } - row[_patch_tree_columns.enabled_col] = pm->enabled(); - row[_patch_tree_columns.patch_model_col] = pm; - _patches_treeview->expand_row(_patch_treestore->get_path(iter), true); - } else { - Gtk::TreeModel::Children children = _patch_treestore->children(); - Gtk::TreeModel::iterator c = find_patch(children, pm->parent()); - - if (c != children.end()) { - Gtk::TreeModel::iterator iter = _patch_treestore->append(c->children()); - Gtk::TreeModel::Row row = *iter; - row[_patch_tree_columns.name_col] = pm->symbol().c_str(); - row[_patch_tree_columns.enabled_col] = pm->enabled(); - row[_patch_tree_columns.patch_model_col] = pm; - _patches_treeview->expand_row(_patch_treestore->get_path(iter), true); - } - } - - pm->signal_property().connect( - sigc::bind(sigc::mem_fun(this, &PatchTreeWindow::patch_property_changed), - pm)); - - pm->signal_moved().connect( - sigc::bind(sigc::mem_fun(this, &PatchTreeWindow::patch_moved), - pm)); - - pm->signal_destroyed().connect( - sigc::bind(sigc::mem_fun(this, &PatchTreeWindow::remove_patch), - pm)); -} - -void -PatchTreeWindow::remove_patch(SharedPtr pm) -{ - Gtk::TreeModel::iterator i = find_patch(_patch_treestore->children(), pm); - if (i != _patch_treestore->children().end()) - _patch_treestore->erase(i); -} - -Gtk::TreeModel::iterator -PatchTreeWindow::find_patch( - Gtk::TreeModel::Children root, - SharedPtr patch) -{ - for (Gtk::TreeModel::iterator c = root.begin(); c != root.end(); ++c) { - SharedPtr pm = (*c)[_patch_tree_columns.patch_model_col]; - if (patch == pm) { - return c; - } else if ((*c)->children().size() > 0) { - Gtk::TreeModel::iterator ret = find_patch(c->children(), patch); - if (ret != c->children().end()) - return ret; - } - } - return root.end(); -} - -/** Show the context menu for the selected patch in the patches treeview. - */ -void -PatchTreeWindow::show_patch_menu(GdkEventButton* ev) -{ - Gtk::TreeModel::iterator active = _patch_tree_selection->get_selected(); - if (active) { - Gtk::TreeModel::Row row = *active; - SharedPtr pm = row[_patch_tree_columns.patch_model_col]; - if (pm) { - _app->log().warn("TODO: patch menu from tree window"); - } - } -} - -void -PatchTreeWindow::event_patch_activated(const Gtk::TreeModel::Path& path, Gtk::TreeView::Column* col) -{ - Gtk::TreeModel::iterator active = _patch_treestore->get_iter(path); - Gtk::TreeModel::Row row = *active; - SharedPtr pm = row[_patch_tree_columns.patch_model_col]; - - _app->window_factory()->present_patch(pm); -} - -void -PatchTreeWindow::event_patch_enabled_toggled(const Glib::ustring& path_str) -{ - Gtk::TreeModel::Path path(path_str); - Gtk::TreeModel::iterator active = _patch_treestore->get_iter(path); - Gtk::TreeModel::Row row = *active; - - SharedPtr pm = row[_patch_tree_columns.patch_model_col]; - assert(pm); - - if (_enable_signal) - _app->interface()->set_property( - pm->uri(), - _app->uris().ingen_enabled, - _app->forge().make((bool)!pm->enabled())); -} - -void -PatchTreeWindow::patch_property_changed(const Raul::URI& key, - const Raul::Atom& value, - SharedPtr patch) -{ - const URIs& uris = _app->uris(); - _enable_signal = false; - if (key == uris.ingen_enabled && value.type() == uris.forge.Bool) { - Gtk::TreeModel::iterator i = find_patch(_patch_treestore->children(), patch); - if (i != _patch_treestore->children().end()) { - Gtk::TreeModel::Row row = *i; - row[_patch_tree_columns.enabled_col] = value.get_bool(); - } else { - _app->log().error(Raul::fmt("Unable to find patch %1%\n") - % patch->path()); - } - } - _enable_signal = true; -} - -void -PatchTreeWindow::patch_moved(SharedPtr patch) -{ - _enable_signal = false; - - Gtk::TreeModel::iterator i - = find_patch(_patch_treestore->children(), patch); - - if (i != _patch_treestore->children().end()) { - Gtk::TreeModel::Row row = *i; - row[_patch_tree_columns.name_col] = patch->symbol().c_str(); - } else { - _app->log().error(Raul::fmt("Unable to find patch %1%\n") - % patch->path()); - } - - _enable_signal = true; -} - -} // namespace GUI -} // namespace Ingen diff --git a/src/gui/PatchTreeWindow.hpp b/src/gui/PatchTreeWindow.hpp deleted file mode 100644 index 86e10370..00000000 --- a/src/gui/PatchTreeWindow.hpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#ifndef INGEN_GUI_PATCHTREEWINDOW_HPP -#define INGEN_GUI_PATCHTREEWINDOW_HPP - -#include -#include -#include -#include - -#include "Window.hpp" - -namespace Raul { class Path; } - -namespace Ingen { - -namespace Client { class ClientStore; class ObjectModel; } - -namespace GUI { - -class PatchWindow; -class PatchTreeView; - -/** Window with a TreeView of all loaded patches. - * - * \ingroup GUI - */ -class PatchTreeWindow : public Window -{ -public: - PatchTreeWindow(BaseObjectType* cobject, - const Glib::RefPtr& xml); - - void init(App& app, Client::ClientStore& store); - - void new_object(SharedPtr object); - - void patch_property_changed(const Raul::URI& key, const Raul::Atom& value, - SharedPtr pm); - - void patch_moved(SharedPtr patch); - - void add_patch(SharedPtr pm); - void remove_patch(SharedPtr pm); - void show_patch_menu(GdkEventButton* ev); - -protected: - void event_patch_activated(const Gtk::TreeModel::Path& path, Gtk::TreeView::Column* col); - void event_patch_enabled_toggled(const Glib::ustring& path_str); - - Gtk::TreeModel::iterator find_patch( - Gtk::TreeModel::Children root, - SharedPtr patch); - - PatchTreeView* _patches_treeview; - - struct PatchTreeModelColumns : public Gtk::TreeModel::ColumnRecord - { - PatchTreeModelColumns() { - add(name_col); - add(enabled_col); - add(patch_model_col); - } - - Gtk::TreeModelColumn name_col; - Gtk::TreeModelColumn enabled_col; - Gtk::TreeModelColumn > patch_model_col; - }; - - App* _app; - PatchTreeModelColumns _patch_tree_columns; - Glib::RefPtr _patch_treestore; - Glib::RefPtr _patch_tree_selection; - bool _enable_signal; -}; - -/** Derived TreeView class to support context menus for patches */ -class PatchTreeView : public Gtk::TreeView -{ -public: - PatchTreeView(BaseObjectType* cobject, - const Glib::RefPtr& xml) - : Gtk::TreeView(cobject) - , _window(NULL) - {} - - void set_window(PatchTreeWindow* win) { _window = win; } - - bool on_button_press_event(GdkEventButton* ev) { - bool ret = Gtk::TreeView::on_button_press_event(ev); - - if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3)) - _window->show_patch_menu(ev); - - return ret; - } - -private: - PatchTreeWindow* _window; - -}; // struct PatchTreeView - -} // namespace GUI -} // namespace Ingen - -#endif // INGEN_GUI_PATCHTREEWINDOW_HPP diff --git a/src/gui/PatchView.cpp b/src/gui/PatchView.cpp deleted file mode 100644 index efb37d11..00000000 --- a/src/gui/PatchView.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#include -#include - -#include "ingen/Interface.hpp" -#include "ingen/client/PatchModel.hpp" - -#include "App.hpp" -#include "LoadPluginWindow.hpp" -#include "NewSubpatchWindow.hpp" -#include "PatchCanvas.hpp" -#include "PatchTreeWindow.hpp" -#include "PatchView.hpp" -#include "WidgetFactory.hpp" - -using namespace std; - -namespace Ingen { - -using namespace Client; - -namespace GUI { - -PatchView::PatchView(BaseObjectType* cobject, - const Glib::RefPtr& xml) - : Gtk::Box(cobject) - , _app(NULL) - , _breadcrumb_container(NULL) - , _enable_signal(true) -{ - property_visible() = false; - - xml->get_widget("patch_view_breadcrumb_container", _breadcrumb_container); - xml->get_widget("patch_view_toolbar", _toolbar); - xml->get_widget("patch_view_process_but", _process_but); - xml->get_widget("patch_view_poly_spin", _poly_spin); - xml->get_widget("patch_view_refresh_but", _refresh_but); - xml->get_widget("patch_view_save_but", _save_but); - xml->get_widget("patch_view_zoom_full_but", _zoom_full_but); - xml->get_widget("patch_view_zoom_normal_but", _zoom_normal_but); - xml->get_widget("patch_view_scrolledwindow", _canvas_scrolledwindow); - - _toolbar->set_toolbar_style(Gtk::TOOLBAR_ICONS); - _canvas_scrolledwindow->property_hadjustment().get_value()->set_step_increment(10); - _canvas_scrolledwindow->property_vadjustment().get_value()->set_step_increment(10); -} - -void -PatchView::init(App& app) -{ - _app = &app; -} - -void -PatchView::set_patch(SharedPtr patch) -{ - assert(!_canvas); // FIXME: remove - - assert(_breadcrumb_container); // ensure created - - _patch = patch; - _canvas = SharedPtr(new PatchCanvas(*_app, patch, 1600*2, 1200*2)); - _canvas->build(); - - _canvas_scrolledwindow->add(_canvas->widget()); - - _poly_spin->set_range(1, 128); - _poly_spin->set_increments(1, 4); - _poly_spin->set_value(patch->internal_poly()); - - for (GraphObject::Properties::const_iterator i = patch->properties().begin(); - i != patch->properties().end(); ++i) - property_changed(i->first, i->second); - - // Connect model signals to track state - patch->signal_property().connect( - sigc::mem_fun(this, &PatchView::property_changed)); - - // Connect widget signals to do things - _process_but->signal_toggled().connect( - sigc::mem_fun(this, &PatchView::process_toggled)); - _refresh_but->signal_clicked().connect( - sigc::mem_fun(this, &PatchView::refresh_clicked)); - - _zoom_normal_but->signal_clicked().connect(sigc::bind(sigc::mem_fun( - _canvas.get(), &PatchCanvas::set_zoom), 1.0)); - - _zoom_full_but->signal_clicked().connect( - sigc::mem_fun(_canvas.get(), &PatchCanvas::zoom_full)); - - _poly_spin->signal_value_changed().connect( - sigc::mem_fun(*this, &PatchView::poly_changed)); - - #if 0 - _canvas->signal_item_entered.connect( - sigc::mem_fun(*this, &PatchView::canvas_item_entered)); - - _canvas->signal_item_left.connect( - sigc::mem_fun(*this, &PatchView::canvas_item_left)); - #endif - - _canvas->widget().grab_focus(); -} - -SharedPtr -PatchView::create(App& app, SharedPtr patch) -{ - PatchView* result = NULL; - Glib::RefPtr xml = WidgetFactory::create("warehouse_win"); - xml->get_widget_derived("patch_view_box", result); - result->init(app); - result->set_patch(patch); - return SharedPtr(result); -} - -#if 0 -void -PatchView::canvas_item_entered(Gnome::Canvas::Item* item) -{ - NodeModule* m = dynamic_cast(item); - if (m) - signal_object_entered.emit(m->block().get()); - - const Port* p = dynamic_cast(item); - if (p) - signal_object_entered.emit(p->model().get()); -} - -void -PatchView::canvas_item_left(Gnome::Canvas::Item* item) -{ - NodeModule* m = dynamic_cast(item); - if (m) { - signal_object_left.emit(m->block().get()); - return; - } - - const Port* p = dynamic_cast(item); - if (p) - signal_object_left.emit(p->model().get()); -} -#endif - -void -PatchView::process_toggled() -{ - if (!_enable_signal) - return; - - _app->interface()->set_property( - _patch->uri(), - _app->uris().ingen_enabled, - _app->forge().make((bool)_process_but->get_active())); -} - -void -PatchView::poly_changed() -{ - const int poly = _poly_spin->get_value_as_int(); - if (_enable_signal && poly != (int)_patch->internal_poly()) { - _app->interface()->set_property( - _patch->uri(), - _app->uris().ingen_polyphony, - _app->forge().make(poly)); - } -} - -void -PatchView::refresh_clicked() -{ - _app->interface()->get(_patch->uri()); -} - -void -PatchView::property_changed(const Raul::URI& predicate, const Raul::Atom& value) -{ - _enable_signal = false; - if (predicate == _app->uris().ingen_enabled) { - if (value.type() == _app->uris().forge.Bool) { - _process_but->set_active(value.get_bool()); - } - } else if (predicate == _app->uris().ingen_polyphony) { - if (value.type() == _app->uris().forge.Int) { - _poly_spin->set_value(value.get_int32()); - } - } - _enable_signal = true; -} - -} // namespace GUI -} // namespace Ingen diff --git a/src/gui/PatchView.hpp b/src/gui/PatchView.hpp deleted file mode 100644 index 14183a89..00000000 --- a/src/gui/PatchView.hpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#ifndef INGEN_GUI_PATCHVIEW_HPP -#define INGEN_GUI_PATCHVIEW_HPP - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "raul/SharedPtr.hpp" -#include "raul/URI.hpp" - -namespace Raul { class Atom; } - -namespace Ingen { - -namespace Client { - class PortModel; - class MetadataModel; - class PatchModel; - class ObjectModel; -} - -namespace GUI { - -class App; -class LoadPluginWindow; -class NewSubpatchWindow; -class PatchCanvas; -class PatchDescriptionWindow; -class SubpatchModule; - -/** The patch specific contents of a PatchWindow (ie the canvas and whatever else). - * - * \ingroup GUI - */ -class PatchView : public Gtk::Box -{ -public: - PatchView(BaseObjectType* cobject, - const Glib::RefPtr& xml); - - void init(App& app); - - SharedPtr canvas() const { return _canvas; } - SharedPtr patch() const { return _patch; } - Gtk::ToolItem* breadcrumb_container() const { return _breadcrumb_container; } - - static SharedPtr create(App& app, - SharedPtr patch); - - sigc::signal signal_object_entered; - sigc::signal signal_object_left; - -private: - void set_patch(SharedPtr patch); - - void process_toggled(); - void poly_changed(); - void clear_clicked(); - void refresh_clicked(); - - #if 0 - void canvas_item_entered(Gnome::Canvas::Item* item); - void canvas_item_left(Gnome::Canvas::Item* item); - #endif - - void property_changed(const Raul::URI& predicate, const Raul::Atom& value); - - void zoom_full(); - - App* _app; - - SharedPtr _patch; - SharedPtr _canvas; - - Gtk::ScrolledWindow* _canvas_scrolledwindow; - Gtk::Toolbar* _toolbar; - Gtk::ToggleToolButton* _process_but; - Gtk::SpinButton* _poly_spin; - Gtk::ToolButton* _refresh_but; - Gtk::ToolButton* _save_but; - Gtk::ToolButton* _zoom_normal_but; - Gtk::ToolButton* _zoom_full_but; - Gtk::ToolItem* _breadcrumb_container; - - bool _enable_signal; -}; - -} // namespace GUI -} // namespace Ingen - -#endif // INGEN_GUI_PATCHVIEW_HPP diff --git a/src/gui/PatchWindow.cpp b/src/gui/PatchWindow.cpp deleted file mode 100644 index 9b3d1a97..00000000 --- a/src/gui/PatchWindow.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#include "ingen/client/ClientStore.hpp" -#include "ingen/client/PatchModel.hpp" - -#include "App.hpp" -#include "PatchCanvas.hpp" -#include "PatchView.hpp" -#include "PatchWindow.hpp" -#include "WindowFactory.hpp" - -namespace Ingen { -namespace GUI { - -PatchWindow::PatchWindow(BaseObjectType* cobject, - const Glib::RefPtr& xml) - : Window(cobject) - , _box(NULL) - , _position_stored(false) - , _x(0) - , _y(0) -{ - property_visible() = false; - - xml->get_widget_derived("patch_win_vbox", _box); - - set_title("Ingen"); -} - -PatchWindow::~PatchWindow() -{ - delete _box; -} - -void -PatchWindow::init_window(App& app) -{ - Window::init_window(app); - _box->init_box(app); - _box->set_window(this); -} - -void -PatchWindow::on_show() -{ - if (_position_stored) - move(_x, _y); - - Gtk::Window::on_show(); - - _box->view()->canvas()->widget().grab_focus(); -} - -void -PatchWindow::on_hide() -{ - _position_stored = true; - get_position(_x, _y); - Gtk::Window::on_hide(); -} - -} // namespace GUI -} // namespace Ingen diff --git a/src/gui/PatchWindow.hpp b/src/gui/PatchWindow.hpp deleted file mode 100644 index b3213327..00000000 --- a/src/gui/PatchWindow.hpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#ifndef INGEN_GUI_PATCH_WINDOW_HPP -#define INGEN_GUI_PATCH_WINDOW_HPP - -#include - -#include - -#include "raul/SharedPtr.hpp" - -#include "PatchBox.hpp" -#include "Window.hpp" - -namespace Ingen { - -namespace Client { - class PatchModel; -} - -namespace GUI { - -/** A window for a patch. - * - * \ingroup GUI - */ -class PatchWindow : public Window -{ -public: - PatchWindow(BaseObjectType* cobject, - const Glib::RefPtr& xml); - - ~PatchWindow(); - - void init_window(App& app); - - SharedPtr patch() const { return _box->patch(); } - PatchBox* box() const { return _box; } - - void show_documentation(const std::string& doc, bool html) { - _box->show_documentation(doc, html); - } - - void hide_documentation() { - _box->hide_documentation(); - } - - void show_port_status(const Client::PortModel* model, - const Raul::Atom& value) { - _box->show_port_status(model, value); - } - -protected: - void on_hide(); - void on_show(); - -private: - PatchBox* _box; - bool _position_stored; - int _x; - int _y; -}; - -} // namespace GUI -} // namespace Ingen - -#endif // INGEN_GUI_PATCH_WINDOW_HPP diff --git a/src/gui/Port.cpp b/src/gui/Port.cpp index 88d81fcd..f747234a 100644 --- a/src/gui/Port.cpp +++ b/src/gui/Port.cpp @@ -20,12 +20,12 @@ #include "ganv/Module.hpp" #include "ingen/Interface.hpp" #include "ingen/Log.hpp" -#include "ingen/client/PatchModel.hpp" +#include "ingen/client/GraphModel.hpp" #include "ingen/client/PortModel.hpp" #include "App.hpp" #include "Configuration.hpp" -#include "PatchWindow.hpp" +#include "GraphWindow.hpp" #include "Port.hpp" #include "PortMenu.hpp" #include "WidgetFactory.hpp" @@ -156,7 +156,7 @@ Port::on_value_changed(GVariant* value) } if (_entered) { - PatchBox* box = get_patch_box(); + GraphBox* box = get_graph_box(); if (box) { box->show_port_status(model().get(), atom); } @@ -202,17 +202,17 @@ Port::build_enum_menu() bool Port::on_event(GdkEvent* ev) { - PatchBox* box = NULL; + GraphBox* box = NULL; switch (ev->type) { case GDK_ENTER_NOTIFY: _entered = true; - if ((box = get_patch_box())) { + if ((box = get_graph_box())) { box->object_entered(model().get()); } break; case GDK_LEAVE_NOTIFY: _entered = false; - if ((box = get_patch_box())) { + if ((box = get_graph_box())) { box->object_left(model().get()); } break; @@ -306,15 +306,15 @@ Port::disconnected_from(SharedPtr port) } } -PatchBox* -Port::get_patch_box() const +GraphBox* +Port::get_graph_box() const { - SharedPtr patch = PtrCast(model()->parent()); - if (!patch) { - patch = PtrCast(model()->parent()->parent()); + SharedPtr graph = PtrCast(model()->parent()); + if (!graph) { + graph = PtrCast(model()->parent()->parent()); } - return _app.window_factory()->patch_box(patch); + return _app.window_factory()->graph_box(graph); } void @@ -355,7 +355,7 @@ Port::set_selected(gboolean b) SharedPtr pm = _port_model.lock(); if (pm && b) { SharedPtr block = PtrCast(pm->parent()); - PatchWindow* win = _app.window_factory()->parent_patch_window(block); + GraphWindow* win = _app.window_factory()->parent_graph_window(block); if (win && block->plugin_model()) { const std::string& doc = block->plugin_model()->port_documentation( pm->index()); diff --git a/src/gui/Port.hpp b/src/gui/Port.hpp index 6552ba8d..2aab66eb 100644 --- a/src/gui/Port.hpp +++ b/src/gui/Port.hpp @@ -38,7 +38,7 @@ namespace Client { class PortModel; } namespace GUI { class App; -class PatchBox; +class GraphBox; /** A Port on an Module. * @@ -75,7 +75,7 @@ private: bool flip = false); Gtk::Menu* build_enum_menu(); - PatchBox* get_patch_box() const; + GraphBox* get_graph_box() const; void property_changed(const Raul::URI& key, const Raul::Atom& value); void moved(); diff --git a/src/gui/PortMenu.cpp b/src/gui/PortMenu.cpp index a23e3b84..3b51976f 100644 --- a/src/gui/PortMenu.cpp +++ b/src/gui/PortMenu.cpp @@ -17,7 +17,7 @@ #include #include "ingen/Interface.hpp" -#include "ingen/client/PatchModel.hpp" +#include "ingen/client/GraphModel.hpp" #include "ingen/client/PortModel.hpp" #include "raul/SharedPtr.hpp" @@ -34,7 +34,7 @@ namespace GUI { PortMenu::PortMenu(BaseObjectType* cobject, const Glib::RefPtr& xml) : ObjectMenu(cobject, xml) - , _is_patch_port(false) + , _is_graph_port(false) { xml->get_widget("object_menu", _port_menu); xml->get_widget("port_set_min_menuitem", _set_min_menuitem); @@ -44,12 +44,12 @@ PortMenu::PortMenu(BaseObjectType* cobject, } void -PortMenu::init(App& app, SharedPtr port, bool is_patch_port) +PortMenu::init(App& app, SharedPtr port, bool is_graph_port) { const URIs& uris = app.uris(); ObjectMenu::init(app, port); - _is_patch_port = is_patch_port; + _is_graph_port = is_graph_port; _set_min_menuitem->signal_activate().connect( sigc::mem_fun(this, &PortMenu::on_menu_set_min)); @@ -64,9 +64,9 @@ PortMenu::init(App& app, SharedPtr port, bool is_patch_port) sigc::mem_fun(this, &PortMenu::on_menu_expose)); const bool is_control = app.can_control(port.get()) && port->is_numeric(); - const bool is_on_patch = PtrCast(port->parent()); + const bool is_on_graph = PtrCast(port->parent()); - if (!_is_patch_port) { + if (!_is_graph_port) { _polyphonic_menuitem->set_sensitive(false); _rename_menuitem->set_sensitive(false); _destroy_menuitem->set_sensitive(false); @@ -76,10 +76,10 @@ PortMenu::init(App& app, SharedPtr port, bool is_patch_port) _polyphonic_menuitem->hide(); } - _reset_range_menuitem->set_visible(is_control && !is_on_patch); + _reset_range_menuitem->set_visible(is_control && !is_on_graph); _set_max_menuitem->set_visible(is_control); _set_min_menuitem->set_visible(is_control); - _expose_menuitem->set_visible(!is_on_patch); + _expose_menuitem->set_visible(!is_on_graph); _learn_menuitem->set_visible(is_control); _unlearn_menuitem->set_visible(is_control); @@ -89,7 +89,7 @@ PortMenu::init(App& app, SharedPtr port, bool is_patch_port) void PortMenu::on_menu_disconnect() { - if (_is_patch_port) { + if (_is_graph_port) { _app->interface()->disconnect_all( _object->parent()->path(), _object->path()); } else { diff --git a/src/gui/PortMenu.hpp b/src/gui/PortMenu.hpp index 598afaa5..34f2c315 100644 --- a/src/gui/PortMenu.hpp +++ b/src/gui/PortMenu.hpp @@ -41,7 +41,7 @@ public: void init(App& app, SharedPtr port, - bool is_patch_port = false); + bool is_graph_port = false); private: void on_menu_disconnect(); @@ -56,7 +56,7 @@ private: Gtk::MenuItem* _reset_range_menuitem; Gtk::MenuItem* _expose_menuitem; - bool _is_patch_port; + bool _is_graph_port; }; } // namespace GUI diff --git a/src/gui/SubgraphModule.cpp b/src/gui/SubgraphModule.cpp new file mode 100644 index 00000000..4860098e --- /dev/null +++ b/src/gui/SubgraphModule.cpp @@ -0,0 +1,109 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#include +#include + +#include "ingen/Interface.hpp" +#include "ingen/client/GraphModel.hpp" + +#include "App.hpp" +#include "NodeModule.hpp" +#include "GraphCanvas.hpp" +#include "GraphWindow.hpp" +#include "Port.hpp" +#include "SubgraphModule.hpp" +#include "WindowFactory.hpp" + +using namespace std; + +namespace Ingen { + +using namespace Client; + +namespace GUI { + +SubgraphModule::SubgraphModule(GraphCanvas& canvas, + SharedPtr graph) + : NodeModule(canvas, graph) + , _graph(graph) +{ + assert(graph); +} + +bool +SubgraphModule::on_double_click(GdkEventButton* event) +{ + assert(_graph); + + SharedPtr parent = PtrCast(_graph->parent()); + + GraphWindow* const preferred = ( (parent && (event->state & GDK_SHIFT_MASK)) + ? NULL + : app().window_factory()->graph_window(parent) ); + + app().window_factory()->present_graph(_graph, preferred); + return true; +} + +void +SubgraphModule::store_location(double ax, double ay) +{ + const URIs& uris = app().uris(); + + const Raul::Atom x(app().forge().make(static_cast(ax))); + const Raul::Atom y(app().forge().make(static_cast(ay))); + + if (x != _block->get_property(uris.ingen_canvasX) || + y != _block->get_property(uris.ingen_canvasY)) + { + Resource::Properties remove; + remove.insert(make_pair(uris.ingen_canvasX, uris.wildcard)); + remove.insert(make_pair(uris.ingen_canvasY, uris.wildcard)); + Resource::Properties add; + add.insert(make_pair(uris.ingen_canvasX, + Resource::Property(x, Resource::EXTERNAL))); + add.insert(make_pair(uris.ingen_canvasY, + Resource::Property(y, Resource::EXTERNAL))); + app().interface()->delta(_block->uri(), remove, add); + } +} + +/** Browse to this graph in current (parent's) window + * (unless an existing window is displaying it) + */ +void +SubgraphModule::browse_to_graph() +{ + assert(_graph->parent()); + + SharedPtr parent = PtrCast(_graph->parent()); + + GraphWindow* const preferred = (parent) + ? app().window_factory()->graph_window(parent) + : NULL; + + app().window_factory()->present_graph(_graph, preferred); +} + +void +SubgraphModule::menu_remove() +{ + app().interface()->del(_graph->uri()); +} + +} // namespace GUI +} // namespace Ingen diff --git a/src/gui/SubgraphModule.hpp b/src/gui/SubgraphModule.hpp new file mode 100644 index 00000000..569e0fd8 --- /dev/null +++ b/src/gui/SubgraphModule.hpp @@ -0,0 +1,64 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_GUI_SUBGRAPHMODULE_HPP +#define INGEN_GUI_SUBGRAPHMODULE_HPP + +#include "raul/SharedPtr.hpp" + +#include "NodeModule.hpp" +#include "GraphPortModule.hpp" + +namespace Ingen { namespace Client { + class GraphModel; + class GraphWindow; + class PortModel; +} } + +namespace Ingen { +namespace GUI { + +class GraphCanvas; + +/** A module to represent a subgraph + * + * \ingroup GUI + */ +class SubgraphModule : public NodeModule +{ +public: + SubgraphModule(GraphCanvas& canvas, + SharedPtr controller); + + virtual ~SubgraphModule() {} + + bool on_double_click(GdkEventButton* ev); + + void store_location(double x, double y); + + void browse_to_graph(); + void menu_remove(); + + SharedPtr graph() const { return _graph; } + +protected: + SharedPtr _graph; +}; + +} // namespace GUI +} // namespace Ingen + +#endif // INGEN_GUI_SUBGRAPHMODULE_HPP diff --git a/src/gui/SubpatchModule.cpp b/src/gui/SubpatchModule.cpp deleted file mode 100644 index efd29805..00000000 --- a/src/gui/SubpatchModule.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#include -#include - -#include "ingen/Interface.hpp" -#include "ingen/client/PatchModel.hpp" - -#include "App.hpp" -#include "NodeModule.hpp" -#include "PatchCanvas.hpp" -#include "PatchWindow.hpp" -#include "Port.hpp" -#include "SubpatchModule.hpp" -#include "WindowFactory.hpp" - -using namespace std; - -namespace Ingen { - -using namespace Client; - -namespace GUI { - -SubpatchModule::SubpatchModule(PatchCanvas& canvas, - SharedPtr patch) - : NodeModule(canvas, patch) - , _patch(patch) -{ - assert(patch); -} - -bool -SubpatchModule::on_double_click(GdkEventButton* event) -{ - assert(_patch); - - SharedPtr parent = PtrCast(_patch->parent()); - - PatchWindow* const preferred = ( (parent && (event->state & GDK_SHIFT_MASK)) - ? NULL - : app().window_factory()->patch_window(parent) ); - - app().window_factory()->present_patch(_patch, preferred); - return true; -} - -void -SubpatchModule::store_location(double ax, double ay) -{ - const URIs& uris = app().uris(); - - const Raul::Atom x(app().forge().make(static_cast(ax))); - const Raul::Atom y(app().forge().make(static_cast(ay))); - - if (x != _block->get_property(uris.ingen_canvasX) || - y != _block->get_property(uris.ingen_canvasY)) - { - Resource::Properties remove; - remove.insert(make_pair(uris.ingen_canvasX, uris.wildcard)); - remove.insert(make_pair(uris.ingen_canvasY, uris.wildcard)); - Resource::Properties add; - add.insert(make_pair(uris.ingen_canvasX, - Resource::Property(x, Resource::EXTERNAL))); - add.insert(make_pair(uris.ingen_canvasY, - Resource::Property(y, Resource::EXTERNAL))); - app().interface()->delta(_block->uri(), remove, add); - } -} - -/** Browse to this patch in current (parent's) window - * (unless an existing window is displaying it) - */ -void -SubpatchModule::browse_to_patch() -{ - assert(_patch->parent()); - - SharedPtr parent = PtrCast(_patch->parent()); - - PatchWindow* const preferred = (parent) - ? app().window_factory()->patch_window(parent) - : NULL; - - app().window_factory()->present_patch(_patch, preferred); -} - -void -SubpatchModule::menu_remove() -{ - app().interface()->del(_patch->uri()); -} - -} // namespace GUI -} // namespace Ingen diff --git a/src/gui/SubpatchModule.hpp b/src/gui/SubpatchModule.hpp deleted file mode 100644 index 8d7dbecc..00000000 --- a/src/gui/SubpatchModule.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#ifndef INGEN_GUI_SUBPATCHMODULE_HPP -#define INGEN_GUI_SUBPATCHMODULE_HPP - -#include "raul/SharedPtr.hpp" - -#include "NodeModule.hpp" -#include "PatchPortModule.hpp" - -namespace Ingen { namespace Client { - class PatchModel; - class PatchWindow; - class PortModel; -} } - -namespace Ingen { -namespace GUI { - -class PatchCanvas; - -/** A module to represent a subpatch - * - * \ingroup GUI - */ -class SubpatchModule : public NodeModule -{ -public: - SubpatchModule(PatchCanvas& canvas, - SharedPtr controller); - - virtual ~SubpatchModule() {} - - bool on_double_click(GdkEventButton* ev); - - void store_location(double x, double y); - - void browse_to_patch(); - void menu_remove(); - - SharedPtr patch() const { return _patch; } - -protected: - SharedPtr _patch; -}; - -} // namespace GUI -} // namespace Ingen - -#endif // INGEN_GUI_SUBPATCHMODULE_HPP diff --git a/src/gui/ThreadedLoader.cpp b/src/gui/ThreadedLoader.cpp index bc7aa19c..cec9a4c9 100644 --- a/src/gui/ThreadedLoader.cpp +++ b/src/gui/ThreadedLoader.cpp @@ -19,7 +19,7 @@ #include "ingen/Log.hpp" #include "ingen/Module.hpp" #include "ingen/World.hpp" -#include "ingen/client/PatchModel.hpp" +#include "ingen/client/GraphModel.hpp" #include "App.hpp" #include "ThreadedLoader.hpp" @@ -39,7 +39,7 @@ ThreadedLoader::ThreadedLoader(App& app, SharedPtr engine) if (parser()) { start(); } else { - app.log().warn("Parser unavailable, patch loading disabled\n"); + app.log().warn("Parser unavailable, graph loading disabled\n"); } } @@ -74,7 +74,7 @@ ThreadedLoader::_run() } void -ThreadedLoader::load_patch(bool merge, +ThreadedLoader::load_graph(bool merge, const Glib::ustring& document_uri, optional engine_parent, optional engine_symbol, @@ -108,13 +108,13 @@ ThreadedLoader::load_patch(bool merge, } void -ThreadedLoader::save_patch(SharedPtr model, +ThreadedLoader::save_graph(SharedPtr model, const string& filename) { _mutex.lock(); _events.push_back(sigc::hide_return(sigc::bind( - sigc::mem_fun(this, &ThreadedLoader::save_patch_event), + sigc::mem_fun(this, &ThreadedLoader::save_graph_event), model, filename))); _mutex.unlock(); @@ -122,7 +122,7 @@ ThreadedLoader::save_patch(SharedPtr model, } void -ThreadedLoader::save_patch_event(SharedPtr model, +ThreadedLoader::save_graph_event(SharedPtr model, const string& filename) { if (_app.serialiser()) { diff --git a/src/gui/ThreadedLoader.hpp b/src/gui/ThreadedLoader.hpp index 273c72f9..162e7cc7 100644 --- a/src/gui/ThreadedLoader.hpp +++ b/src/gui/ThreadedLoader.hpp @@ -33,11 +33,11 @@ namespace Ingen { namespace GUI { -/** Thread for loading patch files. +/** Thread for loading graph files. * * This is a seperate thread so it can send all the loading message without * blocking everything else, so the app can respond to the incoming events - * caused as a result of the patch loading, while the patch loads. + * caused as a result of the graph loading, while the graph loads. * * Implemented as a slave with a list of closures (events) which processes * all events in the (mutex protected) list each time it's whipped. @@ -52,19 +52,19 @@ public: ~ThreadedLoader(); - void load_patch(bool merge, + void load_graph(bool merge, const Glib::ustring& document_uri, boost::optional engine_parent, boost::optional engine_symbol, boost::optional engine_data); - void save_patch(SharedPtr model, + void save_graph(SharedPtr model, const std::string& filename); SharedPtr parser(); private: - void save_patch_event(SharedPtr model, + void save_graph_event(SharedPtr model, const std::string& filename); /** Returns nothing and takes no parameters (because they have all been bound) */ diff --git a/src/gui/WindowFactory.cpp b/src/gui/WindowFactory.cpp index 1f0e0310..884313fd 100644 --- a/src/gui/WindowFactory.cpp +++ b/src/gui/WindowFactory.cpp @@ -16,14 +16,14 @@ #include -#include "ingen/client/PatchModel.hpp" +#include "ingen/client/GraphModel.hpp" #include "App.hpp" -#include "LoadPatchWindow.hpp" +#include "LoadGraphWindow.hpp" #include "LoadPluginWindow.hpp" -#include "NewSubpatchWindow.hpp" -#include "PatchView.hpp" -#include "PatchWindow.hpp" +#include "NewSubgraphWindow.hpp" +#include "GraphView.hpp" +#include "GraphWindow.hpp" #include "PropertiesWindow.hpp" #include "RenameWindow.hpp" #include "WidgetFactory.hpp" @@ -41,58 +41,58 @@ WindowFactory::WindowFactory(App& app) : _app(app) , _main_box(NULL) , _load_plugin_win(NULL) - , _load_patch_win(NULL) - , _new_subpatch_win(NULL) + , _load_graph_win(NULL) + , _new_subgraph_win(NULL) , _properties_win(NULL) { WidgetFactory::get_widget_derived("load_plugin_win", _load_plugin_win); - WidgetFactory::get_widget_derived("load_patch_win", _load_patch_win); - WidgetFactory::get_widget_derived("new_subpatch_win", _new_subpatch_win); + WidgetFactory::get_widget_derived("load_graph_win", _load_graph_win); + WidgetFactory::get_widget_derived("new_subgraph_win", _new_subgraph_win); WidgetFactory::get_widget_derived("properties_win", _properties_win); WidgetFactory::get_widget_derived("rename_win", _rename_win); _load_plugin_win->init_window(app); - _load_patch_win->init(app); - _new_subpatch_win->init_window(app); + _load_graph_win->init(app); + _new_subgraph_win->init_window(app); _properties_win->init_window(app); _rename_win->init_window(app); } WindowFactory::~WindowFactory() { - for (PatchWindowMap::iterator i = _patch_windows.begin(); - i != _patch_windows.end(); ++i) + for (GraphWindowMap::iterator i = _graph_windows.begin(); + i != _graph_windows.end(); ++i) delete i->second; } void WindowFactory::clear() { - for (PatchWindowMap::iterator i = _patch_windows.begin(); - i != _patch_windows.end(); ++i) + for (GraphWindowMap::iterator i = _graph_windows.begin(); + i != _graph_windows.end(); ++i) delete i->second; - _patch_windows.clear(); + _graph_windows.clear(); } -/** Returns the number of Patch windows currently visible. +/** Returns the number of Graph windows currently visible. */ size_t -WindowFactory::num_open_patch_windows() +WindowFactory::num_open_graph_windows() { size_t ret = 0; - for (PatchWindowMap::iterator i = _patch_windows.begin(); - i != _patch_windows.end(); ++i) + for (GraphWindowMap::iterator i = _graph_windows.begin(); + i != _graph_windows.end(); ++i) if (i->second->is_visible()) ++ret; return ret; } -PatchBox* -WindowFactory::patch_box(SharedPtr patch) +GraphBox* +WindowFactory::graph_box(SharedPtr graph) { - PatchWindow* window = patch_window(patch); + GraphWindow* window = graph_window(graph); if (window) { return window->box(); } else { @@ -100,87 +100,87 @@ WindowFactory::patch_box(SharedPtr patch) } } -PatchWindow* -WindowFactory::patch_window(SharedPtr patch) +GraphWindow* +WindowFactory::graph_window(SharedPtr graph) { - if (!patch) + if (!graph) return NULL; - PatchWindowMap::iterator w = _patch_windows.find(patch->path()); + GraphWindowMap::iterator w = _graph_windows.find(graph->path()); - return (w == _patch_windows.end()) ? NULL : w->second; + return (w == _graph_windows.end()) ? NULL : w->second; } -PatchWindow* -WindowFactory::parent_patch_window(SharedPtr block) +GraphWindow* +WindowFactory::parent_graph_window(SharedPtr block) { if (!block) return NULL; - return patch_window(PtrCast(block->parent())); + return graph_window(PtrCast(block->parent())); } -/** Present a PatchWindow for a Patch. +/** Present a GraphWindow for a Graph. * - * If @a preferred is not NULL, it will be set to display @a patch if the patch + * If @a preferred is not NULL, it will be set to display @a graph if the graph * does not already have a visible window, otherwise that window will be * presented and @a preferred left unmodified. */ void -WindowFactory::present_patch(SharedPtr patch, - PatchWindow* preferred, - SharedPtr view) +WindowFactory::present_graph(SharedPtr graph, + GraphWindow* preferred, + SharedPtr view) { - assert(!view || view->patch() == patch); + assert(!view || view->graph() == graph); - PatchWindowMap::iterator w = _patch_windows.find(patch->path()); + GraphWindowMap::iterator w = _graph_windows.find(graph->path()); - if (w != _patch_windows.end()) { + if (w != _graph_windows.end()) { (*w).second->present(); } else if (preferred) { - w = _patch_windows.find(preferred->patch()->path()); + w = _graph_windows.find(preferred->graph()->path()); assert((*w).second == preferred); - preferred->box()->set_patch(patch, view); - _patch_windows.erase(w); - _patch_windows[patch->path()] = preferred; + preferred->box()->set_graph(graph, view); + _graph_windows.erase(w); + _graph_windows[graph->path()] = preferred; preferred->present(); } else { - PatchWindow* win = new_patch_window(patch, view); + GraphWindow* win = new_graph_window(graph, view); win->present(); } } -PatchWindow* -WindowFactory::new_patch_window(SharedPtr patch, - SharedPtr view) +GraphWindow* +WindowFactory::new_graph_window(SharedPtr graph, + SharedPtr view) { - assert(!view || view->patch() == patch); + assert(!view || view->graph() == graph); - PatchWindow* win = NULL; - WidgetFactory::get_widget_derived("patch_win", win); + GraphWindow* win = NULL; + WidgetFactory::get_widget_derived("graph_win", win); win->init_window(_app); - win->box()->set_patch(patch, view); - _patch_windows[patch->path()] = win; + win->box()->set_graph(graph, view); + _graph_windows[graph->path()] = win; win->signal_delete_event().connect(sigc::bind<0>( - sigc::mem_fun(this, &WindowFactory::remove_patch_window), win)); + sigc::mem_fun(this, &WindowFactory::remove_graph_window), win)); return win; } bool -WindowFactory::remove_patch_window(PatchWindow* win, GdkEventAny* ignored) +WindowFactory::remove_graph_window(GraphWindow* win, GdkEventAny* ignored) { - if (_patch_windows.size() <= 1) + if (_graph_windows.size() <= 1) return !_app.quit(win); - PatchWindowMap::iterator w = _patch_windows.find(win->patch()->path()); + GraphWindowMap::iterator w = _graph_windows.find(win->graph()->path()); assert((*w).second == win); - _patch_windows.erase(w); + _graph_windows.erase(w); delete win; @@ -188,12 +188,12 @@ WindowFactory::remove_patch_window(PatchWindow* win, GdkEventAny* ignored) } void -WindowFactory::present_load_plugin(SharedPtr patch, +WindowFactory::present_load_plugin(SharedPtr graph, GraphObject::Properties data) { - PatchWindowMap::iterator w = _patch_windows.find(patch->path()); + GraphWindowMap::iterator w = _graph_windows.find(graph->path()); - if (w != _patch_windows.end()) + if (w != _graph_windows.end()) _load_plugin_win->set_transient_for(*w->second); _load_plugin_win->set_modal(false); @@ -204,54 +204,54 @@ WindowFactory::present_load_plugin(SharedPtr patch, _load_plugin_win->set_default_size(width - width / 8, height / 2); } _load_plugin_win->set_title( - string("Load Plugin - ") + patch->path() + " - Ingen"); - _load_plugin_win->present(patch, data); + string("Load Plugin - ") + graph->path() + " - Ingen"); + _load_plugin_win->present(graph, data); } void -WindowFactory::present_load_patch(SharedPtr patch, +WindowFactory::present_load_graph(SharedPtr graph, GraphObject::Properties data) { - PatchWindowMap::iterator w = _patch_windows.find(patch->path()); + GraphWindowMap::iterator w = _graph_windows.find(graph->path()); - if (w != _patch_windows.end()) - _load_patch_win->set_transient_for(*w->second); + if (w != _graph_windows.end()) + _load_graph_win->set_transient_for(*w->second); - _load_patch_win->present(patch, true, data); + _load_graph_win->present(graph, true, data); } void -WindowFactory::present_load_subpatch(SharedPtr patch, +WindowFactory::present_load_subgraph(SharedPtr graph, GraphObject::Properties data) { - PatchWindowMap::iterator w = _patch_windows.find(patch->path()); + GraphWindowMap::iterator w = _graph_windows.find(graph->path()); - if (w != _patch_windows.end()) - _load_patch_win->set_transient_for(*w->second); + if (w != _graph_windows.end()) + _load_graph_win->set_transient_for(*w->second); - _load_patch_win->present(patch, false, data); + _load_graph_win->present(graph, false, data); } void -WindowFactory::present_new_subpatch(SharedPtr patch, +WindowFactory::present_new_subgraph(SharedPtr graph, GraphObject::Properties data) { - PatchWindowMap::iterator w = _patch_windows.find(patch->path()); + GraphWindowMap::iterator w = _graph_windows.find(graph->path()); - if (w != _patch_windows.end()) - _new_subpatch_win->set_transient_for(*w->second); + if (w != _graph_windows.end()) + _new_subgraph_win->set_transient_for(*w->second); - _new_subpatch_win->present(patch, data); + _new_subgraph_win->present(graph, data); } void WindowFactory::present_rename(SharedPtr object) { - PatchWindowMap::iterator w = _patch_windows.find(object->path()); - if (w == _patch_windows.end()) - w = _patch_windows.find(object->path().parent()); + GraphWindowMap::iterator w = _graph_windows.find(object->path()); + if (w == _graph_windows.end()) + w = _graph_windows.find(object->path().parent()); - if (w != _patch_windows.end()) + if (w != _graph_windows.end()) _rename_win->set_transient_for(*w->second); _rename_win->present(object); @@ -260,13 +260,13 @@ WindowFactory::present_rename(SharedPtr object) void WindowFactory::present_properties(SharedPtr object) { - PatchWindowMap::iterator w = _patch_windows.find(object->path()); - if (w == _patch_windows.end()) - w = _patch_windows.find(object->path().parent()); - if (w == _patch_windows.end()) - w = _patch_windows.find(object->path().parent().parent()); + GraphWindowMap::iterator w = _graph_windows.find(object->path()); + if (w == _graph_windows.end()) + w = _graph_windows.find(object->path().parent()); + if (w == _graph_windows.end()) + w = _graph_windows.find(object->path().parent().parent()); - if (w != _patch_windows.end()) + if (w != _graph_windows.end()) _properties_win->set_transient_for(*w->second); _properties_win->present(object); diff --git a/src/gui/WindowFactory.hpp b/src/gui/WindowFactory.hpp index 465bfa80..46c8b39a 100644 --- a/src/gui/WindowFactory.hpp +++ b/src/gui/WindowFactory.hpp @@ -27,19 +27,19 @@ namespace Ingen { namespace Client { class BlockModel; class ObjectModel; -class PatchModel; +class GraphModel; } namespace GUI { class App; -class LoadPatchWindow; +class GraphBox; +class GraphView; +class GraphWindow; +class LoadGraphWindow; class LoadPluginWindow; -class NewSubpatchWindow; +class NewSubgraphWindow; class PropertiesWindow; -class PatchBox; -class PatchView; -class PatchWindow; class RenameWindow; /** Manager/Factory for all windows. @@ -53,44 +53,44 @@ public: explicit WindowFactory(App& app); ~WindowFactory(); - size_t num_open_patch_windows(); + size_t num_open_graph_windows(); - PatchBox* patch_box(SharedPtr patch); - PatchWindow* patch_window(SharedPtr patch); - PatchWindow* parent_patch_window(SharedPtr block); + GraphBox* graph_box(SharedPtr graph); + GraphWindow* graph_window(SharedPtr graph); + GraphWindow* parent_graph_window(SharedPtr block); - void present_patch( - SharedPtr model, - PatchWindow* preferred = NULL, - SharedPtr view = SharedPtr()); + void present_graph( + SharedPtr model, + GraphWindow* preferred = NULL, + SharedPtr view = SharedPtr()); typedef GraphObject::Properties Properties; - void present_load_plugin(SharedPtr patch, Properties data=Properties()); - void present_load_patch(SharedPtr patch, Properties data=Properties()); - void present_load_subpatch(SharedPtr patch, Properties data=Properties()); - void present_new_subpatch(SharedPtr patch, Properties data=Properties()); + void present_load_plugin(SharedPtr graph, Properties data=Properties()); + void present_load_graph(SharedPtr graph, Properties data=Properties()); + void present_load_subgraph(SharedPtr graph, Properties data=Properties()); + void present_new_subgraph(SharedPtr graph, Properties data=Properties()); void present_rename(SharedPtr object); void present_properties(SharedPtr object); - bool remove_patch_window(PatchWindow* win, GdkEventAny* ignored = NULL); + bool remove_graph_window(GraphWindow* win, GdkEventAny* ignored = NULL); - void set_main_box(PatchBox* box) { _main_box = box; } + void set_main_box(GraphBox* box) { _main_box = box; } void clear(); private: - typedef std::map PatchWindowMap; + typedef std::map GraphWindowMap; - PatchWindow* new_patch_window(SharedPtr patch, - SharedPtr view); + GraphWindow* new_graph_window(SharedPtr graph, + SharedPtr view); App& _app; - PatchBox* _main_box; - PatchWindowMap _patch_windows; + GraphBox* _main_box; + GraphWindowMap _graph_windows; LoadPluginWindow* _load_plugin_win; - LoadPatchWindow* _load_patch_win; - NewSubpatchWindow* _new_subpatch_win; + LoadGraphWindow* _load_graph_win; + NewSubgraphWindow* _new_subgraph_win; PropertiesWindow* _properties_win; RenameWindow* _rename_win; }; diff --git a/src/gui/ingen_gui.ui b/src/gui/ingen_gui.ui index ed393082..3f939608 100644 --- a/src/gui/ingen_gui.ui +++ b/src/gui/ingen_gui.ui @@ -168,25 +168,25 @@ Contributors: - - _Load Patch... + + _Load Graph... True False False True False - + - - _New Patch... + + _New Graph... True False False True False - + @@ -209,7 +209,7 @@ Contributors: True False - <b>Patch Search Path: </b> + <b>Graph Search Path: </b> True @@ -232,7 +232,7 @@ Contributors: True False - <i>Example: /foo/bar:/home/john/patches:/usr/share/om/patches</i> + <i>Example: /foo/bar:/home/user/graphs</i> True @@ -684,9 +684,9 @@ Contributors: connect_connect_button - + False - Load Patch - Ingen + Load Graph - Ingen center-on-parent dialog @@ -699,7 +699,7 @@ Contributors: False end - + gtk-cancel True True @@ -715,7 +715,7 @@ Contributors: - + gtk-open True True @@ -754,7 +754,7 @@ Contributors: 12 12 - + True False 0 @@ -769,7 +769,7 @@ Contributors: - + Load from _File True True @@ -778,7 +778,7 @@ Contributors: False True True - load_patch_poly_voices_radio + load_graph_poly_voices_radio 2 @@ -790,7 +790,7 @@ Contributors: - + True False 0 @@ -804,7 +804,7 @@ Contributors: - + _Insert new ports True True @@ -813,7 +813,7 @@ Contributors: False True True - load_patch_merge_ports_radio + load_graph_merge_ports_radio 2 @@ -824,7 +824,7 @@ Contributors: - + _Merge with existing ports True True @@ -849,7 +849,7 @@ Contributors: False 6 - + _Voices: True True @@ -867,7 +867,7 @@ Contributors: - + True True @@ -890,14 +890,14 @@ Contributors: - + True False 0 _Symbol: True True - load_patch_symbol_entry + load_graph_symbol_entry GTK_FILL @@ -905,7 +905,7 @@ Contributors: - + True True @@ -929,8 +929,8 @@ Contributors: - load_patch_cancel_button - load_patch_ok_button + load_graph_cancel_button + load_graph_ok_button @@ -1236,11 +1236,11 @@ Contributors: - + 320 False 8 - Create Subpatch - Ingen + Create Subgraph - Ingen False center-on-parent dialog @@ -1261,7 +1261,7 @@ Contributors: 0 _Symbol: True - new_subpatch_name_entry + new_subgraph_name_entry GTK_FILL @@ -1276,7 +1276,7 @@ Contributors: 0 _Polyphony: True - new_subpatch_polyphony_spinbutton + new_subgraph_polyphony_spinbutton 1 @@ -1287,7 +1287,7 @@ Contributors: - + True True @@ -1305,7 +1305,7 @@ Contributors: - + True True @@ -1326,7 +1326,7 @@ Contributors: - + True False True @@ -1344,7 +1344,7 @@ Contributors: 4 end - + gtk-cancel True True @@ -1359,7 +1359,7 @@ Contributors: - + gtk-ok True True @@ -1516,12 +1516,12 @@ Contributors: - + 320 340 False 8 - Patches - Ingen + Graphs - Ingen True @@ -1529,7 +1529,7 @@ Contributors: 3 in - + True True True @@ -1538,13 +1538,13 @@ Contributors: - + False Ingen 776 480 - + True False @@ -1552,17 +1552,17 @@ Contributors: True False - + True False False _File True - + False - + _Import... True False @@ -1570,7 +1570,7 @@ Contributors: True False - + @@ -1580,7 +1580,7 @@ Contributors: - + gtk-save True False @@ -1588,11 +1588,11 @@ Contributors: True True - + - + Save _As... True False @@ -1600,11 +1600,11 @@ Contributors: True False - + - + _Draw... True False @@ -1612,7 +1612,7 @@ Contributors: True False - + @@ -1622,14 +1622,14 @@ Contributors: - + gtk-close True False False True True - + @@ -1639,14 +1639,14 @@ Contributors: - + gtk-quit True False False True True - + @@ -1670,7 +1670,7 @@ Contributors: - + gtk-cut True False @@ -1678,11 +1678,11 @@ Contributors: False True True - + - + gtk-copy True False @@ -1690,11 +1690,11 @@ Contributors: True True - + - + gtk-paste True False @@ -1703,11 +1703,11 @@ Contributors: True True - + - + gtk-delete True False @@ -1715,11 +1715,11 @@ Contributors: True True - + - + gtk-select-all True False @@ -1727,7 +1727,7 @@ Contributors: True True - + @@ -1737,7 +1737,7 @@ Contributors: - + Arrange True False @@ -1754,7 +1754,7 @@ Contributors: - + C_ontrols... True False @@ -1762,11 +1762,11 @@ Contributors: True False - + - + gtk-properties True False @@ -1774,7 +1774,7 @@ Contributors: True True - + @@ -1782,17 +1782,17 @@ Contributors: - + True False False _View True - + False - + True False False @@ -1803,7 +1803,7 @@ Contributors: - + True False False @@ -1814,7 +1814,7 @@ Contributors: - + True False False @@ -1831,7 +1831,7 @@ Contributors: - + gtk-zoom-in True False @@ -1842,7 +1842,7 @@ Contributors: - + gtk-zoom-out True False @@ -1853,7 +1853,7 @@ Contributors: - + gtk-zoom-100 True False @@ -1870,7 +1870,7 @@ Contributors: - + gtk-fullscreen True False @@ -1878,7 +1878,7 @@ Contributors: True True - + @@ -1897,7 +1897,7 @@ Contributors: False - + _Engine True False @@ -1905,23 +1905,23 @@ Contributors: True False - + - - _Patch Tree + + _Graph Tree True False False True False - + - + _Messages True False @@ -1929,7 +1929,7 @@ Contributors: True False - + @@ -1964,7 +1964,7 @@ Contributors: - + gtk-about True False @@ -1986,11 +1986,11 @@ Contributors: - + True False - + True False @@ -2003,7 +2003,7 @@ Contributors: - + False in @@ -2023,7 +2023,7 @@ Contributors: - + True False 2 @@ -2610,7 +2610,7 @@ Contributors: - + True False @@ -2624,7 +2624,7 @@ Contributors: icons 1 - + True False False @@ -2644,14 +2644,14 @@ Contributors: - + True False icons False 1 - + True False False @@ -2688,7 +2688,7 @@ Contributors: False False - + True True 1 @@ -2710,7 +2710,7 @@ Contributors: - + True False False @@ -2731,7 +2731,7 @@ Contributors: - + True False False @@ -2743,7 +2743,7 @@ Contributors: - + True False False @@ -2756,7 +2756,7 @@ Contributors: - + True False False @@ -2783,7 +2783,7 @@ Contributors: - + True True True diff --git a/src/gui/ingen_gui_lv2.cpp b/src/gui/ingen_gui_lv2.cpp index 937ecd38..d66405fb 100644 --- a/src/gui/ingen_gui_lv2.cpp +++ b/src/gui/ingen_gui_lv2.cpp @@ -19,15 +19,15 @@ #include "ingen/AtomWriter.hpp" #include "ingen/World.hpp" #include "ingen/client/ClientStore.hpp" -#include "ingen/client/PatchModel.hpp" +#include "ingen/client/GraphModel.hpp" #include "ingen/client/SigClientInterface.hpp" #include "ingen/runtime_paths.hpp" #include "lv2/lv2plug.in/ns/extensions/ui/ui.h" #include "App.hpp" -#include "PatchBox.hpp" +#include "GraphBox.hpp" -#define INGEN_LV2_UI_URI "http://drobilla.net/ns/ingen#PatchUIGtk2" +#define INGEN_LV2_UI_URI "http://drobilla.net/ns/ingen#GraphUIGtk2" /** A sink that writes atoms to a port via the UI extension. */ struct IngenLV2AtomSink : public Ingen::AtomSink { @@ -68,7 +68,7 @@ struct IngenLV2UI { Ingen::World* world; IngenLV2AtomSink* sink; SharedPtr app; - SharedPtr view; + SharedPtr view; SharedPtr engine; SharedPtr reader; SharedPtr client; @@ -135,20 +135,20 @@ instantiate(const LV2UI_Descriptor* descriptor, // Request plugins ui->world->interface()->get(Raul::URI("ingen:plugins")); - // Create empty root patch model + // Create empty root graph model Ingen::Resource::Properties props; props.insert(std::make_pair(ui->app->uris().rdf_type, - ui->app->uris().ingen_Patch)); + ui->app->uris().ingen_Graph)); ui->app->store()->put(Ingen::GraphObject::root_uri(), props); - // Create a PatchBox for the root and set as the UI widget - SharedPtr root = PtrCast( + // Create a GraphBox for the root and set as the UI widget + SharedPtr root = PtrCast( ui->app->store()->object(Raul::Path("/"))); - ui->view = Ingen::GUI::PatchBox::create(*ui->app, root); + ui->view = Ingen::GUI::GraphBox::create(*ui->app, root); ui->view->unparent(); *widget = ui->view->gobj(); - // Request the actual root patch + // Request the actual root graph ui->world->interface()->get(Ingen::GraphObject::root_uri()); return ui; diff --git a/src/gui/wscript b/src/gui/wscript index 7702bd4f..7d022b27 100644 --- a/src/gui/wscript +++ b/src/gui/wscript @@ -32,25 +32,25 @@ def build(bld): Configuration.cpp ConnectWindow.cpp Edge.cpp - LoadPatchWindow.cpp + GraphBox.cpp + GraphCanvas.cpp + GraphPortModule.cpp + GraphTreeWindow.cpp + GraphView.cpp + GraphWindow.cpp + LoadGraphWindow.cpp LoadPluginWindow.cpp MessagesWindow.cpp - NewSubpatchWindow.cpp + NewSubgraphWindow.cpp NodeMenu.cpp NodeModule.cpp ObjectMenu.cpp - PatchBox.cpp - PatchCanvas.cpp - PatchPortModule.cpp - PatchTreeWindow.cpp - PatchView.cpp - PatchWindow.cpp Port.cpp PortMenu.cpp PortPropertiesWindow.cpp PropertiesWindow.cpp RenameWindow.cpp - SubpatchModule.cpp + SubgraphModule.cpp ThreadedLoader.cpp WidgetFactory.cpp Window.cpp -- cgit v1.2.1