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/AtomWriter.cpp | 4 +- src/Builder.cpp | 2 +- src/ClashAvoider.cpp | 4 +- src/Configuration.cpp | 14 +- src/Resource.cpp | 14 +- src/URIs.cpp | 2 +- src/client/ClientStore.cpp | 66 +-- src/client/GraphModel.cpp | 173 +++++++ src/client/PatchModel.cpp | 173 ------- src/client/PluginModel.cpp | 2 +- src/client/wscript | 2 +- 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 +- src/ingen/main.cpp | 2 +- src/serialisation/Parser.cpp | 58 +-- src/serialisation/Serialiser.cpp | 108 ++--- src/server/BlockImpl.cpp | 6 +- src/server/BlockImpl.hpp | 20 +- src/server/Broadcaster.hpp | 4 +- src/server/CompiledGraph.hpp | 74 +++ src/server/CompiledPatch.hpp | 74 --- src/server/ControlBindings.cpp | 2 +- src/server/DirectDriver.hpp | 2 +- src/server/Driver.hpp | 6 +- src/server/DuplexPort.cpp | 16 +- src/server/DuplexPort.hpp | 10 +- src/server/Engine.cpp | 38 +- src/server/Engine.hpp | 8 +- src/server/EnginePort.hpp | 8 +- src/server/EventWriter.cpp | 4 +- src/server/EventWriter.hpp | 2 +- src/server/GraphImpl.cpp | 381 +++++++++++++++ src/server/GraphImpl.hpp | 171 +++++++ src/server/GraphObjectImpl.cpp | 8 +- src/server/GraphObjectImpl.hpp | 10 +- src/server/GraphPlugin.hpp | 63 +++ src/server/InputPort.cpp | 6 +- src/server/InputPort.hpp | 2 +- src/server/InternalPlugin.cpp | 2 +- src/server/InternalPlugin.hpp | 2 +- src/server/JackDriver.cpp | 72 +-- src/server/JackDriver.hpp | 10 +- src/server/LV2Block.cpp | 12 +- src/server/LV2Block.hpp | 8 +- src/server/LV2Plugin.cpp | 2 +- src/server/LV2Plugin.hpp | 4 +- src/server/OutputPort.cpp | 2 +- src/server/PatchImpl.cpp | 381 --------------- src/server/PatchImpl.hpp | 171 ------- src/server/PatchPlugin.hpp | 63 --- src/server/PluginImpl.hpp | 6 +- src/server/Worker.cpp | 6 +- src/server/events.hpp | 2 +- src/server/events/Connect.cpp | 38 +- src/server/events/Connect.hpp | 8 +- src/server/events/CreateBlock.cpp | 26 +- src/server/events/CreateBlock.hpp | 10 +- src/server/events/CreateGraph.cpp | 123 +++++ src/server/events/CreateGraph.hpp | 62 +++ src/server/events/CreatePatch.cpp | 123 ----- src/server/events/CreatePatch.hpp | 62 --- src/server/events/CreatePort.cpp | 44 +- src/server/events/CreatePort.hpp | 10 +- src/server/events/Delete.cpp | 16 +- src/server/events/Delete.hpp | 8 +- src/server/events/Delta.cpp | 40 +- src/server/events/Delta.hpp | 8 +- src/server/events/Disconnect.cpp | 42 +- src/server/events/Disconnect.hpp | 15 +- src/server/events/DisconnectAll.cpp | 20 +- src/server/events/DisconnectAll.hpp | 10 +- src/server/events/Get.cpp | 36 +- src/server/events/Move.cpp | 2 +- src/server/events/Move.hpp | 4 +- src/server/ingen_lv2.cpp | 120 ++--- src/server/internals/Controller.cpp | 2 +- src/server/internals/Controller.hpp | 2 +- src/server/internals/Delay.cpp | 4 +- src/server/internals/Delay.hpp | 2 +- src/server/internals/Note.cpp | 4 +- src/server/internals/Note.hpp | 2 +- src/server/internals/Trigger.cpp | 2 +- src/server/internals/Trigger.hpp | 2 +- src/server/wscript | 4 +- 142 files changed, 5677 insertions(+), 5674 deletions(-) create mode 100644 src/client/GraphModel.cpp delete mode 100644 src/client/PatchModel.cpp 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 create mode 100644 src/server/CompiledGraph.hpp delete mode 100644 src/server/CompiledPatch.hpp create mode 100644 src/server/GraphImpl.cpp create mode 100644 src/server/GraphImpl.hpp create mode 100644 src/server/GraphPlugin.hpp delete mode 100644 src/server/PatchImpl.cpp delete mode 100644 src/server/PatchImpl.hpp delete mode 100644 src/server/PatchPlugin.hpp create mode 100644 src/server/events/CreateGraph.cpp create mode 100644 src/server/events/CreateGraph.hpp delete mode 100644 src/server/events/CreatePatch.cpp delete mode 100644 src/server/events/CreatePatch.hpp (limited to 'src') diff --git a/src/AtomWriter.cpp b/src/AtomWriter.cpp index 466c6a7e..34ea62d0 100644 --- a/src/AtomWriter.cpp +++ b/src/AtomWriter.cpp @@ -213,14 +213,14 @@ AtomWriter::disconnect(const Raul::Path& tail, } void -AtomWriter::disconnect_all(const Raul::Path& parent_patch_path, +AtomWriter::disconnect_all(const Raul::Path& graph, const Raul::Path& path) { LV2_Atom_Forge_Frame msg; lv2_atom_forge_blank(&_forge, &msg, next_id(), _uris.patch_Delete); lv2_atom_forge_property_head(&_forge, _uris.patch_subject, 0); - forge_uri(GraphObject::path_to_uri(parent_patch_path)); + forge_uri(GraphObject::path_to_uri(graph)); lv2_atom_forge_property_head(&_forge, _uris.patch_body, 0); LV2_Atom_Forge_Frame edge; diff --git a/src/Builder.cpp b/src/Builder.cpp index f0edd438..49f5d76b 100644 --- a/src/Builder.cpp +++ b/src/Builder.cpp @@ -41,7 +41,7 @@ Builder::build(SharedPtr object) void Builder::connect(SharedPtr object) { - if (object->graph_type() == GraphObject::PATCH) { + if (object->graph_type() == GraphObject::GRAPH) { for (GraphObject::Edges::const_iterator i = object->edges().begin(); i != object->edges().end(); ++i) { _interface.connect(i->second->tail_path(), i->second->head_path()); diff --git a/src/ClashAvoider.cpp b/src/ClashAvoider.cpp index 13afc283..fce60291 100644 --- a/src/ClashAvoider.cpp +++ b/src/ClashAvoider.cpp @@ -170,10 +170,10 @@ ClashAvoider::disconnect(const Raul::Path& tail, } void -ClashAvoider::disconnect_all(const Raul::Path& parent_patch, +ClashAvoider::disconnect_all(const Raul::Path& graph, const Raul::Path& path) { - _target.disconnect_all(map_path(parent_patch), map_path(path)); + _target.disconnect_all(map_path(graph), map_path(path)); } void diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 4db54b65..2a5e69f7 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -27,11 +27,11 @@ Configuration::Configuration() "clients, can communicate with the engine via any supported protocol, or host the\n" "engine in the same process. Many clients can connect to an engine at once.\n\n" "Examples:\n" - " ingen -e # Run an engine, listen for connections\n" - " ingen -g # Run a GUI, connect to running engine\n" - " ingen -eg # Run an engine and a GUI in one process\n" - " ingen -egl patch.ttl # Run an engine and a GUI and load a patch file\n" - " ingen -egl patch.ingen # Run an engine and a GUI and load a patch bundle") + " ingen -e # Run an engine, listen for connections\n" + " ingen -g # Run a GUI, connect to running engine\n" + " ingen -eg # Run an engine and a GUI in one process\n" + " ingen -egl foo.ttl # Run an engine and a GUI and load a graph\n" + " ingen -egl foo.ingen # Run an engine and a GUI and load a graph") { add("client-port", 'C', "Client port", INT, Value()); add("connect", 'c', "Connect to engine URI", STRING, Value("unix:///tmp/ingen.sock")); @@ -43,9 +43,9 @@ Configuration::Configuration() add("jack-client", 'n', "JACK client name", STRING, Value("ingen")); add("jack-server", 's', "JACK server name", STRING, Value("")); add("uuid", 'u', "JACK session UUID", STRING, Value()); - add("load", 'l', "Load patch", STRING, Value()); + add("load", 'l', "Load graph", STRING, Value()); add("packet-size", 'k', "Maximum UDP packet size", INT, Value(4096)); - add("path", 'L', "Target path for loaded patch", STRING, Value()); + add("path", 'L', "Target path for loaded graph", STRING, Value()); add("queue-size", 'q', "Event queue size", INT, Value(4096)); add("run", 'r', "Run script", STRING, Value()); } diff --git a/src/Resource.cpp b/src/Resource.cpp index a317ff67..7db46a81 100644 --- a/src/Resource.cpp +++ b/src/Resource.cpp @@ -110,7 +110,7 @@ Resource::get_property(const Raul::URI& uri) const bool Resource::type(const URIs& uris, const Properties& properties, - bool& patch, + bool& graph, bool& block, bool& port, bool& is_output) @@ -118,15 +118,15 @@ Resource::type(const URIs& uris, typedef Resource::Properties::const_iterator iterator; const std::pair types_range = properties.equal_range(uris.rdf_type); - patch = block = port = is_output = false; + graph = block = port = is_output = false; for (iterator i = types_range.first; i != types_range.second; ++i) { const Raul::Atom& atom = i->second; if (atom.type() != uris.forge.URI && atom.type() != uris.forge.URID) { continue; // Non-URI type, ignore garbage data } - if (atom == uris.ingen_Patch) { - patch = true; + if (atom == uris.ingen_Graph) { + graph = true; } else if (atom == uris.ingen_Block) { block = true; } else if (atom == uris.lv2_InputPort) { @@ -138,13 +138,13 @@ Resource::type(const URIs& uris, } } - if (patch && block && !port) { // => patch + if (graph && block && !port) { // => graph block = false; return true; - } else if (port && (patch || block)) { // nonsense + } else if (port && (graph || block)) { // nonsense port = false; return false; - } else if (patch || block || port) { // recognized type + } else if (graph || block || port) { // recognized type return true; } else { // unknown return false; diff --git a/src/URIs.cpp b/src/URIs.cpp index 227b6162..78f57f58 100644 --- a/src/URIs.cpp +++ b/src/URIs.cpp @@ -57,8 +57,8 @@ URIs::URIs(Forge& f, URIMap* map) , doap_name (forge, map, "http://usefulinc.com/ns/doap#name") , ingen_Block (forge, map, NS_INGEN "Block") , ingen_Edge (forge, map, NS_INGEN "Edge") + , ingen_Graph (forge, map, NS_INGEN "Graph") , ingen_Internal (forge, map, NS_INGEN "Internal") - , ingen_Patch (forge, map, NS_INGEN "Patch") , ingen_activity (forge, map, NS_INGEN "activity") , ingen_block (forge, map, NS_INGEN "block") , ingen_broadcast (forge, map, NS_INGEN "broadcast") diff --git a/src/client/ClientStore.cpp b/src/client/ClientStore.cpp index 07b44b84..6d4cbfd4 100644 --- a/src/client/ClientStore.cpp +++ b/src/client/ClientStore.cpp @@ -19,7 +19,7 @@ #include "ingen/client/EdgeModel.hpp" #include "ingen/client/BlockModel.hpp" #include "ingen/client/ObjectModel.hpp" -#include "ingen/client/PatchModel.hpp" +#include "ingen/client/GraphModel.hpp" #include "ingen/client/PluginModel.hpp" #include "ingen/client/PortModel.hpp" #include "ingen/client/SigClientInterface.hpp" @@ -223,9 +223,9 @@ ClientStore::put(const Raul::URI& uri, std::cerr << "}" << endl; #endif - bool is_patch, is_block, is_port, is_output; + bool is_graph, is_block, is_port, is_output; Resource::type(uris(), properties, - is_patch, is_block, is_port, is_output); + is_graph, is_block, is_port, is_output); // Check if uri is a plugin Iterator t = properties.find(_uris.rdf_type); @@ -233,8 +233,8 @@ ClientStore::put(const Raul::URI& uri, const Raul::Atom& type(t->second); const Raul::URI type_uri(type.get_uri()); const Plugin::Type plugin_type(Plugin::type_from_uri(type_uri)); - if (plugin_type == Plugin::Patch) { - is_patch = true; + if (plugin_type == Plugin::Graph) { + is_graph = true; } else if (plugin_type != Plugin::NIL) { SharedPtr p( new PluginModel(uris(), uri, type_uri, properties)); @@ -258,11 +258,11 @@ ClientStore::put(const Raul::URI& uri, } if (path.is_root()) { - is_patch = true; + is_graph = true; } - if (is_patch) { - SharedPtr model(new PatchModel(uris(), path)); + if (is_graph) { + SharedPtr model(new GraphModel(uris(), path)); model->set_properties(properties); add_object(model); } else if (is_block) { @@ -373,29 +373,29 @@ ClientStore::set_property(const Raul::URI& subject_uri, } } -SharedPtr -ClientStore::connection_patch(const Raul::Path& tail_path, +SharedPtr +ClientStore::connection_graph(const Raul::Path& tail_path, const Raul::Path& head_path) { - SharedPtr patch; + SharedPtr graph; if (tail_path.parent() == head_path.parent()) - patch = PtrCast(_object(tail_path.parent())); + graph = PtrCast(_object(tail_path.parent())); - if (!patch && tail_path.parent() == head_path.parent().parent()) - patch = PtrCast(_object(tail_path.parent())); + if (!graph && tail_path.parent() == head_path.parent().parent()) + graph = PtrCast(_object(tail_path.parent())); - if (!patch && tail_path.parent().parent() == head_path.parent()) - patch = PtrCast(_object(head_path.parent())); + if (!graph && tail_path.parent().parent() == head_path.parent()) + graph = PtrCast(_object(head_path.parent())); - if (!patch) - patch = PtrCast(_object(tail_path.parent().parent())); + if (!graph) + graph = PtrCast(_object(tail_path.parent().parent())); - if (!patch) - _log.error(Raul::fmt("Unable to find path for edge %1% => %2%\n") + if (!graph) + _log.error(Raul::fmt("Unable to find graph for edge %1% => %2%\n") % tail_path % head_path); - return patch; + return graph; } bool @@ -406,13 +406,13 @@ ClientStore::attempt_connection(const Raul::Path& tail_path, SharedPtr head = PtrCast(_object(head_path)); if (tail && head) { - SharedPtr patch = connection_patch(tail_path, head_path); + SharedPtr graph = connection_graph(tail_path, head_path); SharedPtr cm(new EdgeModel(tail, head)); tail->connected_to(head); head->connected_to(tail); - patch->add_edge(cm); + graph->add_edge(cm); return true; } else { _log.warn(Raul::fmt("Failed to connect %1% => %2%\n") @@ -441,26 +441,26 @@ ClientStore::disconnect(const Raul::Path& src_path, if (head) head->disconnected_from(tail); - SharedPtr patch = connection_patch(src_path, dst_path); - if (patch) - patch->remove_edge(tail.get(), head.get()); + SharedPtr graph = connection_graph(src_path, dst_path); + if (graph) + graph->remove_edge(tail.get(), head.get()); } void -ClientStore::disconnect_all(const Raul::Path& parent_patch, +ClientStore::disconnect_all(const Raul::Path& parent_graph, const Raul::Path& path) { - SharedPtr patch = PtrCast(_object(parent_patch)); + SharedPtr graph = PtrCast(_object(parent_graph)); SharedPtr object = _object(path); - if (!patch || !object) { + if (!graph || !object) { _log.error(Raul::fmt("Bad disconnect all notification %1% in %2%\n") - % path % parent_patch); + % path % parent_graph); return; } - const PatchModel::Edges edges = patch->edges(); - for (PatchModel::Edges::const_iterator i = edges.begin(); + const GraphModel::Edges edges = graph->edges(); + for (GraphModel::Edges::const_iterator i = edges.begin(); i != edges.end(); ++i) { SharedPtr c = PtrCast(i->second); if (c->tail()->parent() == object @@ -469,7 +469,7 @@ ClientStore::disconnect_all(const Raul::Path& parent_patch, || c->head()->path() == path) { c->tail()->disconnected_from(c->head()); c->head()->disconnected_from(c->tail()); - patch->remove_edge(c->tail().get(), c->head().get()); + graph->remove_edge(c->tail().get(), c->head().get()); } } } diff --git a/src/client/GraphModel.cpp b/src/client/GraphModel.cpp new file mode 100644 index 00000000..88943978 --- /dev/null +++ b/src/client/GraphModel.cpp @@ -0,0 +1,173 @@ +/* + 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/URIs.hpp" +#include "ingen/client/BlockModel.hpp" +#include "ingen/client/ClientStore.hpp" +#include "ingen/client/EdgeModel.hpp" +#include "ingen/client/GraphModel.hpp" + +using namespace std; + +namespace Ingen { +namespace Client { + +void +GraphModel::add_child(SharedPtr c) +{ + assert(c->parent().get() == this); + + SharedPtr pm = PtrCast(c); + if (pm) { + add_port(pm); + return; + } + + SharedPtr bm = PtrCast(c); + if (bm) { + _signal_new_block.emit(bm); + } +} + +bool +GraphModel::remove_child(SharedPtr o) +{ + assert(o->path().is_child_of(path())); + assert(o->parent().get() == this); + + // Remove any connections which referred to this object, + // since they can't possibly exist anymore + for (Edges::iterator j = _edges.begin(); j != _edges.end();) { + Edges::iterator next = j; + ++next; + + SharedPtr cm = PtrCast(j->second); + assert(cm); + + if (cm->tail_path().parent() == o->path() + || cm->tail_path() == o->path() + || cm->head_path().parent() == o->path() + || cm->head_path() == o->path()) { + _signal_removed_edge.emit(cm); + _edges.erase(j); // cuts our reference + } + j = next; + } + + SharedPtr pm = PtrCast(o); + if (pm) + remove_port(pm); + + SharedPtr bm = PtrCast(o); + if (bm) { + _signal_removed_block.emit(bm); + } + + return true; +} + +void +GraphModel::clear() +{ + _edges.clear(); + + BlockModel::clear(); + + assert(_edges.empty()); + assert(_ports.empty()); +} + +SharedPtr +GraphModel::get_edge(const GraphObject* tail, const GraphObject* head) +{ + Edges::iterator i = _edges.find(make_pair(tail, head)); + if (i != _edges.end()) + return PtrCast(i->second); + else + return SharedPtr(); +} + +/** Add a connection to this graph. + * + * A reference to @a cm is taken, released on deletion or removal. + * If @a cm only contains paths (not pointers to the actual ports), the ports + * will be found and set. The ports referred to not existing as children of + * this graph is a fatal error. + */ +void +GraphModel::add_edge(SharedPtr cm) +{ + // Store should have 'resolved' the connection already + assert(cm); + assert(cm->tail()); + assert(cm->head()); + assert(cm->tail()->parent()); + assert(cm->head()->parent()); + assert(cm->tail_path() != cm->head_path()); + assert(cm->tail()->parent().get() == this + || cm->tail()->parent()->parent().get() == this); + assert(cm->head()->parent().get() == this + || cm->head()->parent()->parent().get() == this); + + SharedPtr existing = get_edge( + cm->tail().get(), cm->head().get()); + + if (existing) { + assert(cm->tail() == existing->tail()); + assert(cm->head() == existing->head()); + } else { + _edges.insert(make_pair(make_pair(cm->tail().get(), + cm->head().get()), cm)); + _signal_new_edge.emit(cm); + } +} + +void +GraphModel::remove_edge(const GraphObject* tail, const GraphObject* head) +{ + Edges::iterator i = _edges.find(make_pair(tail, head)); + if (i != _edges.end()) { + SharedPtr c = PtrCast(i->second); + _signal_removed_edge.emit(c); + _edges.erase(i); + } +} + +bool +GraphModel::enabled() const +{ + const Raul::Atom& enabled = get_property(_uris.ingen_enabled); + return (enabled.is_valid() && enabled.get_bool()); +} + +uint32_t +GraphModel::internal_poly() const +{ + const Raul::Atom& poly = get_property(_uris.ingen_polyphony); + return poly.is_valid() ? poly.get_int32() : 1; +} + +bool +GraphModel::polyphonic() const +{ + const Raul::Atom& poly = get_property(_uris.ingen_polyphonic); + return poly.is_valid() && poly.get_bool(); +} + +} // namespace Client +} // namespace Ingen diff --git a/src/client/PatchModel.cpp b/src/client/PatchModel.cpp deleted file mode 100644 index 9b622cda..00000000 --- a/src/client/PatchModel.cpp +++ /dev/null @@ -1,173 +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/client/ClientStore.hpp" -#include "ingen/client/EdgeModel.hpp" -#include "ingen/client/BlockModel.hpp" -#include "ingen/client/PatchModel.hpp" -#include "ingen/URIs.hpp" - -using namespace std; - -namespace Ingen { -namespace Client { - -void -PatchModel::add_child(SharedPtr c) -{ - assert(c->parent().get() == this); - - SharedPtr pm = PtrCast(c); - if (pm) { - add_port(pm); - return; - } - - SharedPtr bm = PtrCast(c); - if (bm) { - _signal_new_block.emit(bm); - } -} - -bool -PatchModel::remove_child(SharedPtr o) -{ - assert(o->path().is_child_of(path())); - assert(o->parent().get() == this); - - // Remove any connections which referred to this object, - // since they can't possibly exist anymore - for (Edges::iterator j = _edges.begin(); j != _edges.end();) { - Edges::iterator next = j; - ++next; - - SharedPtr cm = PtrCast(j->second); - assert(cm); - - if (cm->tail_path().parent() == o->path() - || cm->tail_path() == o->path() - || cm->head_path().parent() == o->path() - || cm->head_path() == o->path()) { - _signal_removed_edge.emit(cm); - _edges.erase(j); // cuts our reference - } - j = next; - } - - SharedPtr pm = PtrCast(o); - if (pm) - remove_port(pm); - - SharedPtr bm = PtrCast(o); - if (bm) { - _signal_removed_block.emit(bm); - } - - return true; -} - -void -PatchModel::clear() -{ - _edges.clear(); - - BlockModel::clear(); - - assert(_edges.empty()); - assert(_ports.empty()); -} - -SharedPtr -PatchModel::get_edge(const GraphObject* tail, const GraphObject* head) -{ - Edges::iterator i = _edges.find(make_pair(tail, head)); - if (i != _edges.end()) - return PtrCast(i->second); - else - return SharedPtr(); -} - -/** Add a connection to this patch. - * - * A reference to @a cm is taken, released on deletion or removal. - * If @a cm only contains paths (not pointers to the actual ports), the ports - * will be found and set. The ports referred to not existing as children of - * this patch is a fatal error. - */ -void -PatchModel::add_edge(SharedPtr cm) -{ - // Store should have 'resolved' the connection already - assert(cm); - assert(cm->tail()); - assert(cm->head()); - assert(cm->tail()->parent()); - assert(cm->head()->parent()); - assert(cm->tail_path() != cm->head_path()); - assert(cm->tail()->parent().get() == this - || cm->tail()->parent()->parent().get() == this); - assert(cm->head()->parent().get() == this - || cm->head()->parent()->parent().get() == this); - - SharedPtr existing = get_edge( - cm->tail().get(), cm->head().get()); - - if (existing) { - assert(cm->tail() == existing->tail()); - assert(cm->head() == existing->head()); - } else { - _edges.insert(make_pair(make_pair(cm->tail().get(), - cm->head().get()), cm)); - _signal_new_edge.emit(cm); - } -} - -void -PatchModel::remove_edge(const GraphObject* tail, const GraphObject* head) -{ - Edges::iterator i = _edges.find(make_pair(tail, head)); - if (i != _edges.end()) { - SharedPtr c = PtrCast(i->second); - _signal_removed_edge.emit(c); - _edges.erase(i); - } -} - -bool -PatchModel::enabled() const -{ - const Raul::Atom& enabled = get_property(_uris.ingen_enabled); - return (enabled.is_valid() && enabled.get_bool()); -} - -uint32_t -PatchModel::internal_poly() const -{ - const Raul::Atom& poly = get_property(_uris.ingen_polyphony); - return poly.is_valid() ? poly.get_int32() : 1; -} - -bool -PatchModel::polyphonic() const -{ - const Raul::Atom& poly = get_property(_uris.ingen_polyphonic); - return poly.is_valid() && poly.get_bool(); -} - -} // namespace Client -} // namespace Ingen diff --git a/src/client/PluginModel.cpp b/src/client/PluginModel.cpp index 53736a3e..371e6b46 100644 --- a/src/client/PluginModel.cpp +++ b/src/client/PluginModel.cpp @@ -24,7 +24,7 @@ #include "raul/Atom.hpp" #include "raul/Path.hpp" -#include "ingen/client/PatchModel.hpp" +#include "ingen/client/GraphModel.hpp" #include "ingen/client/PluginModel.hpp" #include "ingen/client/PluginUI.hpp" diff --git a/src/client/wscript b/src/client/wscript index c85ee5ab..c2b12ef3 100644 --- a/src/client/wscript +++ b/src/client/wscript @@ -14,8 +14,8 @@ def build(bld): obj.source = ''' BlockModel.cpp ClientStore.cpp + GraphModel.cpp ObjectModel.cpp - PatchModel.cpp PluginModel.cpp PluginUI.cpp PortModel.cpp 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 diff --git a/src/ingen/main.cpp b/src/ingen/main.cpp index 44f042a4..a0b0dbbe 100644 --- a/src/ingen/main.cpp +++ b/src/ingen/main.cpp @@ -151,7 +151,7 @@ main(int argc, char** argv) world->engine()->activate(); } - // Load a patch + // Load a graph if (conf.option("load").is_valid() || !conf.files().empty()) { boost::optional parent; boost::optional symbol; diff --git a/src/serialisation/Parser.cpp b/src/serialisation/Parser.cpp index 900aba02..9a5c52ed 100644 --- a/src/serialisation/Parser.cpp +++ b/src/serialisation/Parser.cpp @@ -179,7 +179,7 @@ parse( boost::optional data = boost::optional()); static boost::optional -parse_patch( +parse_graph( World* world, Interface* target, Sord::Model& model, @@ -212,7 +212,7 @@ parse_edges( Interface* target, Sord::Model& model, const Sord::Node& subject, - const Raul::Path& patch); + const Raul::Path& graph); static boost::optional parse_block(Ingen::World* world, @@ -263,10 +263,10 @@ parse_block(Ingen::World* world, serd_env_free(env); Sord::URI sub_node(*world->rdf_world(), sub_file); - parse_patch(world, target, sub_model, sub_node, + parse_graph(world, target, sub_model, sub_node, path.parent(), Raul::Symbol(path.symbol())); - parse_patch(world, target, model, subject, + parse_graph(world, target, model, subject, path.parent(), Raul::Symbol(path.symbol())); } else { Resource::Properties props = get_properties(world, model, subject); @@ -278,7 +278,7 @@ parse_block(Ingen::World* world, } static boost::optional -parse_patch(Ingen::World* world, +parse_graph(Ingen::World* world, Ingen::Interface* target, Sord::Model& model, const Sord::Node& subject_node, @@ -292,7 +292,7 @@ parse_patch(Ingen::World* world, const Sord::URI ingen_polyphony(*world->rdf_world(), uris.ingen_polyphony); const Sord::URI lv2_port(*world->rdf_world(), LV2_CORE__port); - const Sord::Node& patch = subject_node; + const Sord::Node& graph = subject_node; const Sord::Node nil; const Glib::ustring base_uri = model.base_uri().to_string(); @@ -304,25 +304,25 @@ parse_patch(Ingen::World* world, const std::string basename = get_basename(base_uri); } - string patch_path_str = relative_uri(base_uri, subject_node.to_string(), true); + string graph_path_str = relative_uri(base_uri, subject_node.to_string(), true); if (parent && a_symbol) - patch_path_str = parent->child(*a_symbol); + graph_path_str = parent->child(*a_symbol); - if (!Raul::Path::is_valid(patch_path_str)) { - world->log().error(Raul::fmt("Patch %1% has invalid path\n") - % patch_path_str); + if (!Raul::Path::is_valid(graph_path_str)) { + world->log().error(Raul::fmt("Graph %1% has invalid path\n") + % graph_path_str); return boost::optional(); } - // Create patch - Raul::Path patch_path(patch_path_str); + // Create graph + Raul::Path graph_path(graph_path_str); Resource::Properties props = get_properties(world, model, subject_node); - target->put(GraphObject::path_to_uri(patch_path), props); + target->put(GraphObject::path_to_uri(graph_path), props); - // For each block in this patch + // For each block in this graph for (Sord::Iter n = model.find(subject_node, ingen_block, nil); !n.end(); ++n) { Sord::Node node = n.get_object(); - const Raul::Path block_path = patch_path.child( + const Raul::Path block_path = graph_path.child( Raul::Symbol(get_basename(node.to_string()))); // Parse and create block @@ -348,16 +348,16 @@ parse_patch(Ingen::World* world, } } - // For each port on this patch + // For each port on this graph typedef std::map PortRecords; PortRecords ports; - for (Sord::Iter p = model.find(patch, lv2_port, nil); !p.end(); ++p) { + for (Sord::Iter p = model.find(graph, lv2_port, nil); !p.end(); ++p) { Sord::Node port = p.get_object(); // Get all properties uint32_t index = 0; boost::optional port_record = get_port( - world, model, port, patch_path, index); + world, model, port, graph_path, index); if (!port_record) { world->log().error(Raul::fmt("Invalid port %1%\n") % port); return boost::optional(); @@ -373,9 +373,9 @@ parse_patch(Ingen::World* world, i->second.second); } - parse_edges(world, target, model, subject_node, patch_path); + parse_edges(world, target, model, subject_node, graph_path); - return patch_path; + return graph_path; } static bool @@ -479,7 +479,7 @@ parse(Ingen::World* world, { URIs& uris = world->uris(); - const Sord::URI patch_class (*world->rdf_world(), uris.ingen_Patch); + const Sord::URI graph_class (*world->rdf_world(), uris.ingen_Graph); const Sord::URI block_class (*world->rdf_world(), uris.ingen_Block); const Sord::URI edge_class (*world->rdf_world(), uris.ingen_Edge); const Sord::URI internal_class(*world->rdf_world(), uris.ingen_Internal); @@ -489,9 +489,9 @@ parse(Ingen::World* world, const Sord::URI rdf_type (*world->rdf_world(), uris.rdf_type); const Sord::Node nil; - // Parse explicit subject patch + // Parse explicit subject graph if (subject.is_valid()) { - return parse_patch(world, target, model, subject, parent, symbol, data); + return parse_graph(world, target, model, subject, parent, symbol, data); } // Get all subjects and their types (?subject a ?type) @@ -519,8 +519,8 @@ parse(Ingen::World* world, boost::optional ret; const Raul::Path path( relative_uri( model.base_uri().to_string(), s.to_string(), true)); - if (types.find(patch_class) != types.end()) { - ret = parse_patch(world, target, model, s, parent, symbol, data); + if (types.find(graph_class) != types.end()) { + ret = parse_graph(world, target, model, s, parent, symbol, data); } else if (types.find(block_class) != types.end()) { ret = parse_block(world, target, model, s, path, data); } else if (types.find(in_port_class) != types.end() || @@ -539,7 +539,7 @@ parse(Ingen::World* world, return boost::optional(); } -/** Parse a patch from RDF into a Interface (engine or client). +/** Parse a graph from RDF into a Interface (engine or client). * @return whether or not load was successful. */ bool @@ -551,7 +551,7 @@ Parser::parse_file(Ingen::World* world, boost::optional data) { if (Glib::file_test(path, Glib::FILE_TEST_IS_DIR)) { - // This is a bundle, append "/name.ttl" to get patch file path + // This is a bundle, append "/name.ttl" to get graph file path path = Glib::build_filename(path, get_basename(path) + ".ttl"); } @@ -572,7 +572,7 @@ Parser::parse_file(Ingen::World* world, SerdNode base_node = serd_node_from_string(SERD_URI, uri_c_str); SerdEnv* env = serd_env_new(&base_node); - // Load patch file into model + // Load graph file into model Sord::Model model(*world->rdf_world(), uri, SORD_SPO|SORD_PSO, false); model.load_file(env, SERD_TURTLE, uri); diff --git a/src/serialisation/Serialiser.cpp b/src/serialisation/Serialiser.cpp index a9d49fe3..e1b1548d 100644 --- a/src/serialisation/Serialiser.cpp +++ b/src/serialisation/Serialiser.cpp @@ -66,7 +66,7 @@ struct Serialiser::Impl { void start_to_filename(const std::string& filename); - void serialise_patch(SharedPtr p, + void serialise_graph(SharedPtr p, const Sord::Node& id); void serialise_block(SharedPtr n, @@ -80,14 +80,14 @@ struct Serialiser::Impl { void serialise_properties(Sord::Node id, const Resource::Properties& props); - void write_bundle(SharedPtr patch, + void write_bundle(SharedPtr graph, const std::string& uri); Sord::Node path_rdf_node(const Raul::Path& path); void write_manifest(const std::string& bundle_path, - SharedPtr patch, - const std::string& patch_symbol); + SharedPtr graph, + const std::string& graph_symbol); void serialise_edge(const Sord::Node& parent, SharedPtr c) @@ -124,8 +124,8 @@ Serialiser::to_file(SharedPtr object, void Serialiser::Impl::write_manifest(const std::string& bundle_path, - SharedPtr patch, - const std::string& patch_symbol) + SharedPtr graph, + const std::string& graph_symbol) { const string manifest_path(Glib::build_filename(bundle_path, "manifest.ttl")); const string binary_path(Glib::Module::build_path("", "ingen_lv2")); @@ -135,12 +135,12 @@ Serialiser::Impl::write_manifest(const std::string& bundle_path, Sord::World& world = _model->world(); const URIs& uris = _world.uris(); - const string filename(patch_symbol + ".ttl"); + const string filename(graph_symbol + ".ttl"); const Sord::URI subject(world, filename, _base_uri); _model->add_statement(subject, Sord::URI(world, uris.rdf_type), - Sord::URI(world, uris.ingen_Patch)); + Sord::URI(world, uris.ingen_Graph)); _model->add_statement(subject, Sord::URI(world, uris.rdf_type), Sord::URI(world, uris.lv2_Plugin)); @@ -158,14 +158,14 @@ Serialiser::Impl::write_manifest(const std::string& bundle_path, } void -Serialiser::write_bundle(SharedPtr patch, +Serialiser::write_bundle(SharedPtr graph, const std::string& path) { - me->write_bundle(patch, path); + me->write_bundle(graph, path); } void -Serialiser::Impl::write_bundle(SharedPtr patch, +Serialiser::Impl::write_bundle(SharedPtr graph, const std::string& a_path) { std::string path = Glib::filename_from_uri(a_path); @@ -186,12 +186,12 @@ Serialiser::Impl::write_bundle(SharedPtr patch, start_to_filename(root_file); const Raul::Path old_root_path = _root_path; - _root_path = patch->path(); - serialise_patch(patch, Sord::URI(_model->world(), root_file, _base_uri)); + _root_path = graph->path(); + serialise_graph(graph, Sord::URI(_model->world(), root_file, _base_uri)); _root_path = old_root_path; finish(); - write_manifest(path, patch, symbol); + write_manifest(path, graph, symbol); } string @@ -284,8 +284,8 @@ Serialiser::serialise(SharedPtr object) throw (std::logic_err if (!me->_model) throw std::logic_error("serialise called without serialisation in progress"); - if (object->graph_type() == GraphObject::PATCH) { - me->serialise_patch(object, me->path_rdf_node(object->path())); + if (object->graph_type() == GraphObject::GRAPH) { + me->serialise_graph(object, me->path_rdf_node(object->path())); } else if (object->graph_type() == GraphObject::BLOCK) { const Sord::URI plugin_id(me->_model->world(), object->plugin()->uri()); me->serialise_block(object, plugin_id, me->path_rdf_node(object->path())); @@ -300,122 +300,122 @@ Serialiser::serialise(SharedPtr object) throw (std::logic_err } void -Serialiser::Impl::serialise_patch(SharedPtr patch, - const Sord::Node& patch_id) +Serialiser::Impl::serialise_graph(SharedPtr graph, + const Sord::Node& graph_id) { Sord::World& world = _model->world(); const URIs& uris = _world.uris(); - _model->add_statement(patch_id, + _model->add_statement(graph_id, Sord::URI(world, uris.rdf_type), - Sord::URI(world, uris.ingen_Patch)); + Sord::URI(world, uris.ingen_Graph)); - _model->add_statement(patch_id, + _model->add_statement(graph_id, Sord::URI(world, uris.rdf_type), Sord::URI(world, uris.lv2_Plugin)); - _model->add_statement(patch_id, + _model->add_statement(graph_id, Sord::URI(world, uris.lv2_extensionData), Sord::URI(world, LV2_STATE__interface)); - _model->add_statement(patch_id, + _model->add_statement(graph_id, Sord::URI(world, LV2_UI__ui), - Sord::URI(world, "http://drobilla.net/ns/ingen#PatchUIGtk2")); + Sord::URI(world, "http://drobilla.net/ns/ingen#GraphUIGtk2")); // Always write a symbol (required by Ingen) Raul::Symbol symbol("_"); - GraphObject::Properties::const_iterator s = patch->properties().find(uris.lv2_symbol); - if (s == patch->properties().end() + GraphObject::Properties::const_iterator s = graph->properties().find(uris.lv2_symbol); + if (s == graph->properties().end() || !s->second.type() == _world.forge().String || !Raul::Symbol::is_valid(s->second.get_string())) { const std::string base = Glib::path_get_basename( _model->base_uri().to_c_string()); symbol = Raul::Symbol::symbolify(base.substr(0, base.find('.'))); _model->add_statement( - patch_id, + graph_id, Sord::URI(world, uris.lv2_symbol), Sord::Literal(world, symbol.c_str())); } else { symbol = Raul::Symbol::symbolify(s->second.get_string()); } - // If the patch has no doap:name (required by LV2), use the symbol - if (patch->properties().find(uris.doap_name) == patch->properties().end()) - _model->add_statement(patch_id, + // If the graph has no doap:name (required by LV2), use the symbol + if (graph->properties().find(uris.doap_name) == graph->properties().end()) + _model->add_statement(graph_id, Sord::URI(world, uris.doap_name), Sord::Literal(world, symbol.c_str())); - const GraphObject::Properties props = patch->properties(Resource::INTERNAL); - serialise_properties(patch_id, props); + const GraphObject::Properties props = graph->properties(Resource::INTERNAL); + serialise_properties(graph_id, props); - const Store::const_range kids = _world.store()->children_range(patch); + const Store::const_range kids = _world.store()->children_range(graph); for (Store::const_iterator n = kids.first; n != kids.second; ++n) { - if (n->first.parent() != patch->path()) + if (n->first.parent() != graph->path()) continue; - if (n->second->graph_type() == GraphObject::PATCH) { - SharedPtr subpatch = n->second; + if (n->second->graph_type() == GraphObject::GRAPH) { + SharedPtr subgraph = n->second; SerdURI base_uri; serd_uri_parse((const uint8_t*)_base_uri.c_str(), &base_uri); - const string sub_bundle_path = subpatch->path().substr(1) + ".ingen"; + const string sub_bundle_path = subgraph->path().substr(1) + ".ingen"; - SerdURI subpatch_uri; - SerdNode subpatch_node = serd_node_new_uri_from_string( + SerdURI subgraph_uri; + SerdNode subgraph_node = serd_node_new_uri_from_string( (const uint8_t*)sub_bundle_path.c_str(), &base_uri, - &subpatch_uri); + &subgraph_uri); - const Sord::URI subpatch_id(world, (const char*)subpatch_node.buf); + const Sord::URI subgraph_id(world, (const char*)subgraph_node.buf); // Save our state std::string my_base_uri = _base_uri; Sord::Model* my_model = _model; // Write child bundle within this bundle - write_bundle(subpatch, subpatch_id.to_string()); + write_bundle(subgraph, subgraph_id.to_string()); // Restore our state _base_uri = my_base_uri; _model = my_model; - // Serialise reference to patch block - const Sord::Node block_id(path_rdf_node(subpatch->path())); - _model->add_statement(patch_id, + // Serialise reference to graph block + const Sord::Node block_id(path_rdf_node(subgraph->path())); + _model->add_statement(graph_id, Sord::URI(world, uris.ingen_block), block_id); - serialise_block(subpatch, subpatch_id, block_id); + serialise_block(subgraph, subgraph_id, block_id); } else if (n->second->graph_type() == GraphObject::BLOCK) { SharedPtr block = n->second; const Sord::URI class_id(world, block->plugin()->uri()); const Sord::Node block_id(path_rdf_node(n->second->path())); - _model->add_statement(patch_id, + _model->add_statement(graph_id, Sord::URI(world, uris.ingen_block), block_id); serialise_block(block, class_id, block_id); } } - for (uint32_t i = 0; i < patch->num_ports(); ++i) { - GraphObject* p = patch->port(i); + for (uint32_t i = 0; i < graph->num_ports(); ++i) { + GraphObject* p = graph->port(i); const Sord::Node port_id = path_rdf_node(p->path()); - // Ensure lv2:name always exists so Patch is a valid LV2 plugin + // Ensure lv2:name always exists so Graph is a valid LV2 plugin if (p->properties().find(uris.lv2_name) == p->properties().end()) p->set_property(uris.lv2_name, _world.forge().alloc(p->symbol().c_str())); - _model->add_statement(patch_id, + _model->add_statement(graph_id, Sord::URI(world, LV2_CORE__port), port_id); serialise_port(p, Resource::INTERNAL, port_id); } - for (GraphObject::Edges::const_iterator c = patch->edges().begin(); - c != patch->edges().end(); ++c) { - serialise_edge(patch_id, c->second); + for (GraphObject::Edges::const_iterator c = graph->edges().begin(); + c != graph->edges().end(); ++c) { + serialise_edge(graph_id, c->second); } } diff --git a/src/server/BlockImpl.cpp b/src/server/BlockImpl.cpp index 7d99ca28..2ccb0e2f 100644 --- a/src/server/BlockImpl.cpp +++ b/src/server/BlockImpl.cpp @@ -22,7 +22,7 @@ #include "Buffer.hpp" #include "Engine.hpp" #include "BlockImpl.hpp" -#include "PatchImpl.hpp" +#include "GraphImpl.hpp" #include "PluginImpl.hpp" #include "PortImpl.hpp" #include "ProcessContext.hpp" @@ -36,7 +36,7 @@ namespace Server { BlockImpl::BlockImpl(PluginImpl* plugin, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, SampleRate srate) : GraphObjectImpl(plugin->uris(), parent, symbol) , _plugin(plugin) @@ -58,7 +58,7 @@ BlockImpl::~BlockImpl() } if (is_linked()) { - parent_patch()->remove_block(*this); + parent_graph()->remove_block(*this); } delete _ports; diff --git a/src/server/BlockImpl.hpp b/src/server/BlockImpl.hpp index fd2af927..12318d60 100644 --- a/src/server/BlockImpl.hpp +++ b/src/server/BlockImpl.hpp @@ -43,12 +43,12 @@ namespace Server { class Buffer; class BufferFactory; class Context; -class PatchImpl; +class GraphImpl; class PluginImpl; class PortImpl; class ProcessContext; -/** A Block in a Patch (which is also a Block). +/** A Block in a Graph (which is also a Block). * * This is what is often called a "Module" in modular synthesizers. A Block is * a unit with input/output ports, a process() method, and some other things. @@ -56,13 +56,13 @@ class ProcessContext; * \ingroup engine */ class BlockImpl : public GraphObjectImpl - , public boost::intrusive::slist_base_hook<> // In PatchImpl + , public boost::intrusive::slist_base_hook<> // In GraphImpl { public: BlockImpl(PluginImpl* plugin, const Raul::Symbol& symbol, bool poly, - PatchImpl* parent, + GraphImpl* parent, SampleRate rate); virtual ~BlockImpl(); @@ -72,7 +72,7 @@ public: /** Activate this Block. * * This function must be called in a non-realtime thread before it is - * inserted in to a patch. Any non-realtime actions that need to be + * inserted in to a graph. Any non-realtime actions that need to be * done before the Block is ready for use should be done here. */ virtual void activate(BufferFactory& bufs); @@ -80,7 +80,7 @@ public: /** Deactivate this Block. * * This function must be called in a non-realtime thread after the - * block has been removed from its patch (i.e. processing is finished). + * block has been removed from its graph (i.e. processing is finished). */ virtual void deactivate(); @@ -130,12 +130,12 @@ public: ProcessContext& context, Raul::Maid& maid, uint32_t poly); /** Information about the Plugin this Block is an instance of. - * Not the best name - not all blocks come from plugins (e.g. Patch) + * Not the best name - not all blocks come from plugins (e.g. Graph) */ virtual PluginImpl* plugin_impl() const { return _plugin; } /** Information about the Plugin this Block is an instance of. - * Not the best name - not all blocks come from plugins (ie Patch) + * Not the best name - not all blocks come from plugins (ie Graph) */ virtual const Plugin* plugin() const; @@ -146,8 +146,8 @@ public: LV2_URID type, uint32_t size); - /** The Patch this Block belongs to. */ - inline PatchImpl* parent_patch() const { return (PatchImpl*)_parent; } + /** The Graph this Block belongs to. */ + inline GraphImpl* parent_graph() const { return (GraphImpl*)_parent; } Context::ID context() const { return _context; } uint32_t num_ports() const { return _ports ? _ports->size() : 0; } diff --git a/src/server/Broadcaster.hpp b/src/server/Broadcaster.hpp index 0bc7576a..3af4e5b7 100644 --- a/src/server/Broadcaster.hpp +++ b/src/server/Broadcaster.hpp @@ -89,9 +89,9 @@ public: BROADCAST(disconnect, tail, head); } - void disconnect_all(const Raul::Path& parent_patch_path, + void disconnect_all(const Raul::Path& graph, const Raul::Path& path) { - BROADCAST(disconnect_all, parent_patch_path, path); + BROADCAST(disconnect_all, graph, path); } void set_property(const Raul::URI& subject, diff --git a/src/server/CompiledGraph.hpp b/src/server/CompiledGraph.hpp new file mode 100644 index 00000000..024aa919 --- /dev/null +++ b/src/server/CompiledGraph.hpp @@ -0,0 +1,74 @@ +/* + 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_ENGINE_COMPILEDGRAPH_HPP +#define INGEN_ENGINE_COMPILEDGRAPH_HPP + +#include +#include + +#include "raul/Disposable.hpp" +#include "raul/Noncopyable.hpp" + +namespace Ingen { +namespace Server { + +class EdgeImpl; +class BlockImpl; + +/** All information required about a block to execute it in an audio thread. + */ +class CompiledBlock { +public: + CompiledBlock(BlockImpl* b, size_t np, const std::list& d) + : _block(b), _n_providers(np) + { + // Copy to a vector for maximum iteration speed and cache optimization + // (Need to take a copy anyway) + + _dependants.reserve(d.size()); + for (std::list::const_iterator i = d.begin(); i != d.end(); ++i) + _dependants.push_back(*i); + } + + BlockImpl* block() const { return _block; } + size_t n_providers() const { return _n_providers; } + const std::vector& dependants() const { return _dependants; } + +private: + BlockImpl* _block; + size_t _n_providers; ///< Number of input ready signals to trigger run + std::vector _dependants; ///< Blocks this one's output ports are connected to +}; + +/** A graph ``compiled'' into a flat structure with the correct order so + * the audio thread(s) can execute it without threading problems (since + * the preprocessor thread modifies the graph). + * + * The blocks contained here are sorted in the order they must be executed. + * The parallel processing algorithm guarantees no block will be executed + * before its providers, using this order as well as semaphores. + */ +class CompiledGraph : public std::vector + , public Raul::Disposable + , public Raul::Noncopyable +{ +}; + +} // namespace Server +} // namespace Ingen + +#endif // INGEN_ENGINE_COMPILEDGRAPH_HPP diff --git a/src/server/CompiledPatch.hpp b/src/server/CompiledPatch.hpp deleted file mode 100644 index 15d1137a..00000000 --- a/src/server/CompiledPatch.hpp +++ /dev/null @@ -1,74 +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_ENGINE_COMPILEDPATCH_HPP -#define INGEN_ENGINE_COMPILEDPATCH_HPP - -#include -#include - -#include "raul/Disposable.hpp" -#include "raul/Noncopyable.hpp" - -namespace Ingen { -namespace Server { - -class EdgeImpl; -class BlockImpl; - -/** All information required about a block to execute it in an audio thread. - */ -class CompiledBlock { -public: - CompiledBlock(BlockImpl* b, size_t np, const std::list& d) - : _block(b), _n_providers(np) - { - // Copy to a vector for maximum iteration speed and cache optimization - // (Need to take a copy anyway) - - _dependants.reserve(d.size()); - for (std::list::const_iterator i = d.begin(); i != d.end(); ++i) - _dependants.push_back(*i); - } - - BlockImpl* block() const { return _block; } - size_t n_providers() const { return _n_providers; } - const std::vector& dependants() const { return _dependants; } - -private: - BlockImpl* _block; - size_t _n_providers; ///< Number of input ready signals to trigger run - std::vector _dependants; ///< Blocks this one's output ports are connected to -}; - -/** A patch ``compiled'' into a flat structure with the correct order so - * the audio thread(s) can execute it without threading problems (since - * the preprocessor thread modifies the graph). - * - * The blocks contained here are sorted in the order they must be executed. - * The parallel processing algorithm guarantees no block will be executed - * before its providers, using this order as well as semaphores. - */ -class CompiledPatch : public std::vector - , public Raul::Disposable - , public Raul::Noncopyable -{ -}; - -} // namespace Server -} // namespace Ingen - -#endif // INGEN_ENGINE_COMPILEDPATCH_HPP diff --git a/src/server/ControlBindings.cpp b/src/server/ControlBindings.cpp index de6818ff..e8f595fa 100644 --- a/src/server/ControlBindings.cpp +++ b/src/server/ControlBindings.cpp @@ -429,7 +429,7 @@ ControlBindings::pre_process(ProcessContext& context, Buffer* buffer) void ControlBindings::post_process(ProcessContext& context, Buffer* buffer) { - // TODO: merge buffer's existing contents (anything send to it in the patch) + // TODO: merge buffer's existing contents (anything send to it in the graph) buffer->copy(context, _feedback.get()); } diff --git a/src/server/DirectDriver.hpp b/src/server/DirectDriver.hpp index 76cd3cbc..5fde93d9 100644 --- a/src/server/DirectDriver.hpp +++ b/src/server/DirectDriver.hpp @@ -38,7 +38,7 @@ public: virtual void deactivate() {} - virtual EnginePort* create_port(DuplexPort* patch_port) { + virtual EnginePort* create_port(DuplexPort* graph_port) { return NULL; } diff --git a/src/server/Driver.hpp b/src/server/Driver.hpp index e038b2bc..e5c62623 100644 --- a/src/server/Driver.hpp +++ b/src/server/Driver.hpp @@ -34,7 +34,7 @@ class EnginePort; /** Engine driver base class. * - * A Driver is, from the perspective of GraphObjects (blocks, patches, ports) + * A Driver is, from the perspective of GraphObjects (blocks, graphs, ports) * an interface for managing system ports. An implementation of Driver * basically needs to manage EnginePorts, and handle writing/reading data * to/from them. @@ -54,12 +54,12 @@ public: /** Create a port ready to be inserted with add_input (non realtime). * May return NULL if the Driver can not create the port for some reason. */ - virtual EnginePort* create_port(DuplexPort* patch_port) = 0; + virtual EnginePort* create_port(DuplexPort* graph_port) = 0; /** Find a system port by path. */ virtual EnginePort* get_port(const Raul::Path& path) = 0; - /** Add a system visible port (e.g. a port on the root patch). */ + /** Add a system visible port (e.g. a port on the root graph). */ virtual void add_port(ProcessContext& context, EnginePort* port) = 0; /** Remove a system visible port. diff --git a/src/server/DuplexPort.cpp b/src/server/DuplexPort.cpp index 43197844..34c9b590 100644 --- a/src/server/DuplexPort.cpp +++ b/src/server/DuplexPort.cpp @@ -18,8 +18,8 @@ #include "Buffer.hpp" #include "DuplexPort.hpp" +#include "GraphImpl.hpp" #include "OutputPort.hpp" -#include "PatchImpl.hpp" using namespace std; @@ -49,7 +49,7 @@ DuplexPort::DuplexPort(BufferFactory& bufs, DuplexPort::~DuplexPort() { if (is_linked()) { - parent_patch()->remove_port(*this); + parent_graph()->remove_port(*this); } } @@ -69,34 +69,34 @@ DuplexPort::get_buffers(BufferFactory& bufs, uint32_t DuplexPort::max_tail_poly(Context& context) const { - return parent_patch()->internal_poly_process(); + return parent_graph()->internal_poly_process(); } -/** Prepare for the execution of parent patch */ +/** Prepare for the execution of parent graph */ void DuplexPort::pre_process(Context& context) { if (_is_output) { - /* This is a patch output, which is an input from the internal + /* This is a graph output, which is an input from the internal perspective. Prepare buffers for write so plugins can deliver to them */ for (uint32_t v = 0; v < _poly; ++v) { _buffers->at(v)->prepare_write(context); } } else { - /* This is a a patch input, which is an output from the internal + /* This is a a graph input, which is an output from the internal perspective. Do whatever a normal block's input port does to prepare input for reading. */ InputPort::pre_process(context); } } -/** Finalize after the execution of parent patch (deliver outputs) */ +/** Finalize after the execution of parent graph (deliver outputs) */ void DuplexPort::post_process(Context& context) { if (_is_output) { - /* This is a patch output, which is an input from the internal + /* This is a graph output, which is an input from the internal perspective. Mix down input delivered by plugins so output (external perspective) is ready. */ InputPort::pre_process(context); diff --git a/src/server/DuplexPort.hpp b/src/server/DuplexPort.hpp index 25d389c5..55ba8fa0 100644 --- a/src/server/DuplexPort.hpp +++ b/src/server/DuplexPort.hpp @@ -28,18 +28,18 @@ namespace Server { class BlockImpl; -/** A duplex Port (both an InputPort and an OutputPort on a Patch) +/** A duplex Port (both an InputPort and an OutputPort on a Graph) * - * This is used for Patch ports, since they need to appear as both an input and + * This is used for Graph ports, since they need to appear as both an input and * an output port based on context. There are no actual duplex ports in Ingen, - * a Port is either an Input or Output. This class only exists to allow Patch - * outputs to appear as inputs from within that Patch, and vice versa. + * a Port is either an Input or Output. This class only exists to allow Graph + * outputs to appear as inputs from within that Graph, and vice versa. * * \ingroup engine */ class DuplexPort : public InputPort , public OutputPort - , public boost::intrusive::slist_base_hook<> // In PatchImpl + , public boost::intrusive::slist_base_hook<> // In GraphImpl { public: DuplexPort(BufferFactory& bufs, diff --git a/src/server/Engine.cpp b/src/server/Engine.cpp index eada608a..7c053884 100644 --- a/src/server/Engine.cpp +++ b/src/server/Engine.cpp @@ -34,7 +34,7 @@ #include "Engine.hpp" #include "Event.hpp" #include "EventWriter.hpp" -#include "PatchImpl.hpp" +#include "GraphImpl.hpp" #include "PostProcessor.hpp" #include "PreProcessor.hpp" #include "ProcessContext.hpp" @@ -59,7 +59,7 @@ Engine::Engine(Ingen::World* world) , _pre_processor(new PreProcessor()) , _post_processor(new PostProcessor(*this)) , _event_writer(new EventWriter(*this)) - , _root_patch(NULL) + , _root_graph(NULL) , _worker(new Worker(world->log(), event_queue_size())) , _process_context(*this) , _quit_flag(false) @@ -185,20 +185,20 @@ Engine::activate() const Ingen::URIs& uris = world()->uris(); Forge& forge = world()->forge(); - // Create root patch - if (!_root_patch) { - _root_patch = new PatchImpl( + // Create root graph + if (!_root_graph) { + _root_graph = new GraphImpl( *this, Raul::Symbol("root"), 1, NULL, _driver->sample_rate(), 1); - _root_patch->set_property( + _root_graph->set_property( uris.rdf_type, - Resource::Property(uris.ingen_Patch, Resource::INTERNAL)); - _root_patch->set_property( + Resource::Property(uris.ingen_Graph, Resource::INTERNAL)); + _root_graph->set_property( uris.ingen_polyphony, Resource::Property(_world->forge().make(int32_t(1)), Resource::INTERNAL)); - _root_patch->activate(*_buffer_factory); - _world->store()->add(_root_patch); - _root_patch->compiled_patch(_root_patch->compile()); + _root_graph->activate(*_buffer_factory); + _world->store()->add(_root_graph); + _root_graph->compiled_graph(_root_graph->compile()); ProcessContext context(*this); @@ -249,7 +249,7 @@ Engine::activate() } _driver->activate(); - _root_patch->enable(); + _root_graph->enable(); ThreadManager::single_threaded = false; @@ -265,8 +265,8 @@ Engine::deactivate() _driver->deactivate(); } - if (_root_patch) { - _root_patch->deactivate(); + if (_root_graph) { + _root_graph->deactivate(); } ThreadManager::single_threaded = true; @@ -279,7 +279,7 @@ Engine::run(uint32_t sample_count) // Apply control bindings to input control_bindings()->pre_process( - _process_context, _root_patch->port_impl(0)->buffer(0).get()); + _process_context, _root_graph->port_impl(0)->buffer(0).get()); post_processor()->set_end_time(_process_context.end()); @@ -287,14 +287,14 @@ Engine::run(uint32_t sample_count) // (Aiming for jitter-free 1 block event latency, ideally) const unsigned n_processed_events = process_events(); - // Run root patch - if (_root_patch) { - _root_patch->process(_process_context); + // Run root graph + if (_root_graph) { + _root_graph->process(_process_context); } // Emit control binding feedback control_bindings()->post_process( - _process_context, _root_patch->port_impl(1)->buffer(0).get()); + _process_context, _root_graph->port_impl(1)->buffer(0).get()); return n_processed_events; } diff --git a/src/server/Engine.hpp b/src/server/Engine.hpp index 66930938..2d49bde0 100644 --- a/src/server/Engine.hpp +++ b/src/server/Engine.hpp @@ -34,17 +34,17 @@ class World; namespace Server { +class BlockFactory; class Broadcaster; class BufferFactory; class ControlBindings; class Driver; class Event; class EventWriter; -class BlockFactory; +class GraphImpl; class PostProcessor; class PreProcessor; class ProcessContext; -class PatchImpl; class Worker; /** @@ -98,7 +98,7 @@ public: ControlBindings* control_bindings() const { return _control_bindings; } Driver* driver() const { return _driver.get(); } Log& log() const { return _world->log(); } - PatchImpl* root_patch() const { return _root_patch; } + GraphImpl* root_graph() const { return _root_graph; } PostProcessor* post_processor() const { return _post_processor; } Raul::Maid* maid() const { return _maid; } Worker* worker() const { return _worker; } @@ -121,7 +121,7 @@ private: PreProcessor* _pre_processor; PostProcessor* _post_processor; EventWriter* _event_writer; - PatchImpl* _root_patch; + GraphImpl* _root_graph; Worker* _worker; ProcessContext _process_context; diff --git a/src/server/EnginePort.hpp b/src/server/EnginePort.hpp index 3bda2998..7154920b 100644 --- a/src/server/EnginePort.hpp +++ b/src/server/EnginePort.hpp @@ -37,7 +37,7 @@ class EnginePort : public Raul::Noncopyable { public: explicit EnginePort(DuplexPort* port) - : _patch_port(port) + : _graph_port(port) , _buffer(NULL) , _handle(NULL) {} @@ -47,11 +47,11 @@ public: void* buffer() const { return _buffer; } void* handle() const { return _handle; } - DuplexPort* patch_port() const { return _patch_port; } - bool is_input() const { return _patch_port->is_input(); } + DuplexPort* graph_port() const { return _graph_port; } + bool is_input() const { return _graph_port->is_input(); } protected: - DuplexPort* _patch_port; + DuplexPort* _graph_port; void* _buffer; void* _handle; }; diff --git a/src/server/EventWriter.cpp b/src/server/EventWriter.cpp index b4f95294..2b1b1bf6 100644 --- a/src/server/EventWriter.cpp +++ b/src/server/EventWriter.cpp @@ -103,12 +103,12 @@ EventWriter::disconnect(const Raul::Path& src, } void -EventWriter::disconnect_all(const Raul::Path& patch_path, +EventWriter::disconnect_all(const Raul::Path& graph, const Raul::Path& path) { _engine.enqueue_event( new Events::DisconnectAll(_engine, _respondee, _request_id, now(), - patch_path, path)); + graph, path)); } void diff --git a/src/server/EventWriter.hpp b/src/server/EventWriter.hpp index 67b3b83b..5c44c5b6 100644 --- a/src/server/EventWriter.hpp +++ b/src/server/EventWriter.hpp @@ -79,7 +79,7 @@ public: virtual void del(const Raul::URI& uri); - virtual void disconnect_all(const Raul::Path& parent_patch_path, + virtual void disconnect_all(const Raul::Path& graph, const Raul::Path& path); virtual void get(const Raul::URI& uri); diff --git a/src/server/GraphImpl.cpp b/src/server/GraphImpl.cpp new file mode 100644 index 00000000..81c69b46 --- /dev/null +++ b/src/server/GraphImpl.cpp @@ -0,0 +1,381 @@ +/* + 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/Log.hpp" +#include "ingen/URIs.hpp" +#include "ingen/World.hpp" + +#include "BlockImpl.hpp" +#include "BufferFactory.hpp" +#include "DuplexPort.hpp" +#include "EdgeImpl.hpp" +#include "Engine.hpp" +#include "GraphImpl.hpp" +#include "GraphPlugin.hpp" +#include "PortImpl.hpp" +#include "ThreadManager.hpp" + +using namespace std; + +namespace Ingen { +namespace Server { + +GraphImpl::GraphImpl(Engine& engine, + const Raul::Symbol& symbol, + uint32_t poly, + GraphImpl* parent, + SampleRate srate, + uint32_t internal_poly) + : BlockImpl(new GraphPlugin(engine.world()->uris(), + engine.world()->uris().ingen_Graph, + Raul::Symbol("graph"), + "Ingen Graph"), + symbol, poly, parent, srate) + , _engine(engine) + , _poly_pre(internal_poly) + , _poly_process(internal_poly) + , _compiled_graph(NULL) + , _process(false) +{ + assert(internal_poly >= 1); + assert(internal_poly <= 128); +} + +GraphImpl::~GraphImpl() +{ + delete _compiled_graph; + delete _plugin; +} + +void +GraphImpl::activate(BufferFactory& bufs) +{ + BlockImpl::activate(bufs); + + for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { + i->activate(bufs); + } + + assert(_activated); +} + +void +GraphImpl::deactivate() +{ + if (_activated) { + BlockImpl::deactivate(); + + for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { + if (i->activated()) { + i->deactivate(); + } + } + } +} + +void +GraphImpl::disable(ProcessContext& context) +{ + _process = false; + for (Ports::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + i->clear_buffers(); + } +} + +bool +GraphImpl::prepare_internal_poly(BufferFactory& bufs, uint32_t poly) +{ + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + + // TODO: Subgraph dynamic polyphony (i.e. changing port polyphony) + + for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { + i->prepare_poly(bufs, poly); + } + + _poly_pre = poly; + return true; +} + +bool +GraphImpl::apply_internal_poly(ProcessContext& context, + BufferFactory& bufs, + Raul::Maid& maid, + uint32_t poly) +{ + // TODO: Subgraph dynamic polyphony (i.e. changing port polyphony) + + for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { + i->apply_poly(context, maid, poly); + } + + for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { + for (uint32_t j = 0; j < i->num_ports(); ++j) { + PortImpl* const port = i->port_impl(j); + if (port->is_input() && dynamic_cast(port)->direct_connect()) + port->setup_buffers(bufs, port->poly(), true); + port->connect_buffers(); + } + } + + const bool polyphonic = parent_graph() && (poly == parent_graph()->internal_poly_process()); + for (Ports::iterator i = _outputs.begin(); i != _outputs.end(); ++i) + i->setup_buffers(bufs, polyphonic ? poly : 1, true); + + _poly_process = poly; + return true; +} + +/** Run the graph for the specified number of frames. + * + * Calls all Blocks in (roughly, if parallel) the order _compiled_graph specifies. + */ +void +GraphImpl::process(ProcessContext& context) +{ + if (!_process) + return; + + BlockImpl::pre_process(context); + + if (_compiled_graph && _compiled_graph->size() > 0) { + // Run all blocks + for (size_t i = 0; i < _compiled_graph->size(); ++i) { + (*_compiled_graph)[i].block()->process(context); + } + } + + BlockImpl::post_process(context); +} + +void +GraphImpl::set_buffer_size(Context& context, + BufferFactory& bufs, + LV2_URID type, + uint32_t size) +{ + BlockImpl::set_buffer_size(context, bufs, type, size); + + for (size_t i = 0; i < _compiled_graph->size(); ++i) + (*_compiled_graph)[i].block()->set_buffer_size(context, bufs, type, size); +} + +// Graph specific stuff + +/** Add a block. + * Preprocessing thread only. + */ +void +GraphImpl::add_block(BlockImpl& block) +{ + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + _blocks.push_front(block); +} + +/** Remove a block. + * Preprocessing thread only. + */ +void +GraphImpl::remove_block(BlockImpl& block) +{ + _blocks.erase(_blocks.iterator_to(block)); +} + +void +GraphImpl::add_edge(SharedPtr c) +{ + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + _edges.insert(make_pair(make_pair(c->tail(), c->head()), c)); +} + +/** Remove a edge. + * Preprocessing thread only. + */ +SharedPtr +GraphImpl::remove_edge(const PortImpl* tail, const PortImpl* dst_port) +{ + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + Edges::iterator i = _edges.find(make_pair(tail, dst_port)); + if (i != _edges.end()) { + SharedPtr c = PtrCast(i->second); + _edges.erase(i); + return c; + } else { + return SharedPtr(); + } +} + +bool +GraphImpl::has_edge(const PortImpl* tail, const PortImpl* dst_port) const +{ + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + Edges::const_iterator i = _edges.find(make_pair(tail, dst_port)); + return (i != _edges.end()); +} + +uint32_t +GraphImpl::num_ports_non_rt() const +{ + ThreadManager::assert_not_thread(THREAD_PROCESS); + return _inputs.size() + _outputs.size(); +} + +/** Create a port. Not realtime safe. + */ +DuplexPort* +GraphImpl::create_port(BufferFactory& bufs, + const Raul::Symbol& symbol, + PortType type, + LV2_URID buffer_type, + uint32_t buffer_size, + bool is_output, + bool polyphonic) +{ + if (type == PortType::UNKNOWN) { + bufs.engine().log().error(Raul::fmt("Unknown port type %1%\n") + % type.uri()); + return NULL; + } + + Raul::Atom value; + if (type == PortType::CONTROL || type == PortType::CV) + value = bufs.forge().make(0.0f); + + return new DuplexPort(bufs, this, symbol, num_ports_non_rt(), polyphonic, _polyphony, + type, buffer_type, value, buffer_size, is_output); +} + +/** Remove port from ports list used in pre-processing thread. + * + * Port is not removed from ports array for process thread (which could be + * simultaneously running). + * + * Realtime safe. Preprocessing thread only. + */ +void +GraphImpl::remove_port(DuplexPort& port) +{ + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + + if (port.is_input()) { + _inputs.erase(_inputs.iterator_to(port)); + } else { + _outputs.erase(_outputs.iterator_to(port)); + } +} + +/** Remove all ports from ports list used in pre-processing thread. + * + * Ports are not removed from ports array for process thread (which could be + * simultaneously running). Returned is a (inputs, outputs) pair. + * + * Realtime safe. Preprocessing thread only. + */ +void +GraphImpl::clear_ports() +{ + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + + _inputs.clear(); + _outputs.clear(); +} + +Raul::Array* +GraphImpl::build_ports_array() +{ + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + + const size_t n = _inputs.size() + _outputs.size(); + Raul::Array* const result = new Raul::Array(n); + + size_t i = 0; + + for (Ports::iterator p = _inputs.begin(); p != _inputs.end(); ++p, ++i) + result->at(i) = &*p; + + for (Ports::iterator p = _outputs.begin(); p != _outputs.end(); ++p, ++i) + result->at(i) = &*p; + + assert(i == n); + + return result; +} + +static inline void +compile_recursive(BlockImpl* n, CompiledGraph* output) +{ + if (n == NULL || n->traversed()) + return; + + n->traversed(true); + assert(output != NULL); + + for (std::list::iterator i = n->providers().begin(); + i != n->providers().end(); ++i) + if (!(*i)->traversed()) + compile_recursive(*i, output); + + output->push_back(CompiledBlock(n, n->providers().size(), n->dependants())); +} + +/** Find the process order for this Graph. + * + * The process order is a flat list that the graph will execute in order + * when its run() method is called. Return value is a newly allocated list + * which the caller is reponsible to delete. Note that this function does + * NOT actually set the process order, it is returned so it can be inserted + * at the beginning of an audio cycle (by various Events). + * + * Not realtime safe. + */ +CompiledGraph* +GraphImpl::compile() +{ + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + + CompiledGraph* const compiled_graph = new CompiledGraph(); + + for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { + i->traversed(false); + } + + for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { + // Either a sink or connected to our output ports: + if (!i->traversed() && i->dependants().empty()) { + compile_recursive(&*i, compiled_graph); + } + } + + // Traverse any blocks we didn't hit yet + for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { + if (!i->traversed()) { + compile_recursive(&*i, compiled_graph); + } + } + + if (compiled_graph->size() != _blocks.size()) { + _engine.log().error(Raul::fmt("Failed to compile graph %1%\n") % _path); + delete compiled_graph; + return NULL; + } + + return compiled_graph; +} + +} // namespace Server +} // namespace Ingen diff --git a/src/server/GraphImpl.hpp b/src/server/GraphImpl.hpp new file mode 100644 index 00000000..1eb0945e --- /dev/null +++ b/src/server/GraphImpl.hpp @@ -0,0 +1,171 @@ +/* + 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_ENGINE_GRAPHIMPL_HPP +#define INGEN_ENGINE_GRAPHIMPL_HPP + +#include + +#include "BlockImpl.hpp" +#include "CompiledGraph.hpp" +#include "DuplexPort.hpp" +#include "PluginImpl.hpp" +#include "PortType.hpp" +#include "ThreadManager.hpp" + +namespace Ingen { + +class Edge; + +namespace Server { + +class CompiledGraph; +class Context; +class EdgeImpl; +class Engine; +class ProcessContext; + +/** A group of blocks in a graph, possibly polyphonic. + * + * Note that this is also a Block, just one which contains Blocks. + * Therefore infinite subgraphing is possible, of polyphonic + * graphes of polyphonic blocks etc. etc. + * + * \ingroup engine + */ +class GraphImpl : public BlockImpl +{ +public: + GraphImpl(Engine& engine, + const Raul::Symbol& symbol, + uint32_t poly, + GraphImpl* parent, + SampleRate srate, + uint32_t local_poly); + + virtual ~GraphImpl(); + + virtual GraphType graph_type() const { return GRAPH; } + + void activate(BufferFactory& bufs); + void deactivate(); + + void process(ProcessContext& context); + + void set_buffer_size(Context& context, + BufferFactory& bufs, + LV2_URID type, + uint32_t size); + + /** Prepare for a new (internal) polyphony value. + * + * Preprocessor thread, poly is actually applied by apply_internal_poly. + * \return true on success. + */ + bool prepare_internal_poly(BufferFactory& bufs, uint32_t poly); + + /** Apply a new (internal) polyphony value. + * + * Audio thread. + * + * \param context Process context + * \param bufs New set of buffers + * \param poly Must be < the most recent value passed to prepare_internal_poly. + * \param maid Any objects no longer needed will be pushed to this + */ + bool apply_internal_poly(ProcessContext& context, + BufferFactory& bufs, + Raul::Maid& maid, + uint32_t poly); + + // Graph specific stuff not inherited from Block + + typedef boost::intrusive::slist< + BlockImpl, boost::intrusive::constant_time_size > Blocks; + + void add_block(BlockImpl& block); + void remove_block(BlockImpl& block); + + Blocks& blocks() { return _blocks; } + const Blocks& blocks() const { return _blocks; } + + uint32_t num_ports_non_rt() const; + + DuplexPort* create_port(BufferFactory& bufs, + const Raul::Symbol& symbol, + PortType type, + LV2_URID buffer_type, + uint32_t buffer_size, + bool is_output, + bool polyphonic); + + typedef boost::intrusive::slist< + DuplexPort, boost::intrusive::constant_time_size > Ports; + + void add_input(DuplexPort& port) { + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + _inputs.push_front(port); + } + + void add_output(DuplexPort& port) { + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + _outputs.push_front(port); + } + + void remove_port(DuplexPort& port); + void clear_ports(); + + void add_edge(SharedPtr c); + + SharedPtr remove_edge(const PortImpl* tail, + const PortImpl* head); + + bool has_edge(const PortImpl* tail, const PortImpl* head) const; + + CompiledGraph* compiled_graph() { return _compiled_graph; } + void compiled_graph(CompiledGraph* cp) { _compiled_graph = cp; } + + Raul::Array* external_ports() { return _ports; } + void external_ports(Raul::Array* pa) { _ports = pa; } + + CompiledGraph* compile(); + Raul::Array* build_ports_array(); + + /** Whether to run this graph's DSP bits in the audio thread */ + bool enabled() const { return _process; } + void enable() { _process = true; } + void disable(ProcessContext& context); + + uint32_t internal_poly() const { return _poly_pre; } + uint32_t internal_poly_process() const { return _poly_process; } + + Engine& engine() { return _engine; } + +private: + Engine& _engine; + uint32_t _poly_pre; ///< Pre-process thread only + uint32_t _poly_process; ///< Process thread only + CompiledGraph* _compiled_graph; ///< Process thread only + Ports _inputs; ///< Pre-process thread only + Ports _outputs; ///< Pre-process thread only + Blocks _blocks; ///< Pre-process thread only + bool _process; +}; + +} // namespace Server +} // namespace Ingen + +#endif // INGEN_ENGINE_GRAPHIMPL_HPP diff --git a/src/server/GraphObjectImpl.cpp b/src/server/GraphObjectImpl.cpp index d5608b0f..2df7943f 100644 --- a/src/server/GraphObjectImpl.cpp +++ b/src/server/GraphObjectImpl.cpp @@ -14,8 +14,8 @@ along with Ingen. If not, see . */ +#include "GraphImpl.hpp" #include "GraphObjectImpl.hpp" -#include "PatchImpl.hpp" #include "ThreadManager.hpp" using namespace std; @@ -42,10 +42,10 @@ GraphObjectImpl::get_property(const Raul::URI& key) const return (i != properties().end()) ? i->second : null_atom; } -PatchImpl* -GraphObjectImpl::parent_patch() const +GraphImpl* +GraphObjectImpl::parent_graph() const { - return dynamic_cast((BlockImpl*)_parent); + return dynamic_cast((BlockImpl*)_parent); } } // namespace Server diff --git a/src/server/GraphObjectImpl.hpp b/src/server/GraphObjectImpl.hpp index 5388981f..07a59727 100644 --- a/src/server/GraphObjectImpl.hpp +++ b/src/server/GraphObjectImpl.hpp @@ -35,12 +35,12 @@ namespace Shared { class URIs; } namespace Server { -class PatchImpl; +class BufferFactory; class Context; +class GraphImpl; class ProcessContext; -class BufferFactory; -/** An object on the audio graph (a Patch, Block, or Port). +/** An object on the audio graph (a Graph, Block, or Port). * * Each of these is a Raul::Deletable and so can be deleted in a realtime safe * way from anywhere, and they all have a map of variable for clients to store @@ -70,8 +70,8 @@ public: const Raul::Atom& get_property(const Raul::URI& key) const; - /** The Patch this object is a child of. */ - virtual PatchImpl* parent_patch() const; + /** The Graph this object is a child of. */ + virtual GraphImpl* parent_graph() const; const Raul::Path& path() const { return _path; } diff --git a/src/server/GraphPlugin.hpp b/src/server/GraphPlugin.hpp new file mode 100644 index 00000000..3b1e9bfa --- /dev/null +++ b/src/server/GraphPlugin.hpp @@ -0,0 +1,63 @@ +/* + 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_ENGINE_GRAPHPLUGIN_HPP +#define INGEN_ENGINE_GRAPHPLUGIN_HPP + +#include +#include "PluginImpl.hpp" + +namespace Ingen { +namespace Server { + +class BlockImpl; + +/** Implementation of a Graph plugin. + * + * Graphs don't actually work like this yet... + */ +class GraphPlugin : public PluginImpl +{ +public: + GraphPlugin(URIs& uris, + const Raul::URI& uri, + const Raul::Symbol& symbol, + const std::string& name) + : PluginImpl(uris, Plugin::Graph, uri) + {} + + BlockImpl* instantiate(BufferFactory& bufs, + const Raul::Symbol& symbol, + bool polyphonic, + GraphImpl* parent, + Engine& engine) + { + return NULL; + } + + const Raul::Symbol symbol() const { return Raul::Symbol("graph"); } + const std::string name() const { return "Ingen Graph"; } + +private: + const std::string _symbol; + const std::string _name; +}; + +} // namespace Server +} // namespace Ingen + +#endif // INGEN_ENGINE_GRAPHPLUGIN_HPP + diff --git a/src/server/InputPort.cpp b/src/server/InputPort.cpp index fff29f30..e2f97896 100644 --- a/src/server/InputPort.cpp +++ b/src/server/InputPort.cpp @@ -25,9 +25,9 @@ #include "BufferFactory.hpp" #include "EdgeImpl.hpp" #include "Engine.hpp" +#include "GraphImpl.hpp" #include "InputPort.hpp" #include "OutputPort.hpp" -#include "PatchImpl.hpp" #include "ProcessContext.hpp" #include "mix.hpp" @@ -50,7 +50,7 @@ InputPort::InputPort(BufferFactory& bufs, { const Ingen::URIs& uris = bufs.uris(); - if (parent->graph_type() != GraphObject::PATCH) { + if (parent->graph_type() != GraphObject::GRAPH) { add_property(uris.rdf_type, uris.lv2_InputPort); } @@ -159,7 +159,7 @@ InputPort::remove_edge(ProcessContext& context, const OutputPort* tail) uint32_t InputPort::max_tail_poly(Context& context) const { - return parent_block()->parent_patch()->internal_poly_process(); + return parent_block()->parent_graph()->internal_poly_process(); } static void diff --git a/src/server/InputPort.hpp b/src/server/InputPort.hpp index 40650415..7a4c7669 100644 --- a/src/server/InputPort.hpp +++ b/src/server/InputPort.hpp @@ -36,7 +36,7 @@ class BlockImpl; class OutputPort; class ProcessContext; -/** An input port on a Block or Patch. +/** An input port on a Block or Graph. * * All ports have a Buffer, but the actual contents (data) of that buffer may be * set directly to the incoming edge's buffer if there's only one inbound diff --git a/src/server/InternalPlugin.cpp b/src/server/InternalPlugin.cpp index 0e15fd9d..39e32580 100644 --- a/src/server/InternalPlugin.cpp +++ b/src/server/InternalPlugin.cpp @@ -46,7 +46,7 @@ BlockImpl* InternalPlugin::instantiate(BufferFactory& bufs, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, Engine& engine) { assert(_type == Internal); diff --git a/src/server/InternalPlugin.hpp b/src/server/InternalPlugin.hpp index 29753c69..5bd842dd 100644 --- a/src/server/InternalPlugin.hpp +++ b/src/server/InternalPlugin.hpp @@ -44,7 +44,7 @@ public: BlockImpl* instantiate(BufferFactory& bufs, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, Engine& engine); const Raul::Symbol symbol() const { return _symbol; } diff --git a/src/server/JackDriver.cpp b/src/server/JackDriver.cpp index b950c350..5f1ba1d3 100644 --- a/src/server/JackDriver.cpp +++ b/src/server/JackDriver.cpp @@ -35,8 +35,8 @@ #include "Buffer.hpp" #include "DuplexPort.hpp" #include "Engine.hpp" +#include "GraphImpl.hpp" #include "JackDriver.hpp" -#include "PatchImpl.hpp" #include "PortImpl.hpp" #include "ThreadManager.hpp" #include "util.hpp" @@ -182,7 +182,7 @@ EnginePort* JackDriver::get_port(const Raul::Path& path) { for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { - if (i->patch_port()->path() == path) { + if (i->graph_port()->path() == path) { return &*i; } } @@ -207,10 +207,10 @@ JackDriver::register_port(EnginePort& port) { jack_port_t* jack_port = jack_port_register( _client, - port.patch_port()->path().substr(1).c_str(), - (port.patch_port()->is_a(PortType::AUDIO) + port.graph_port()->path().substr(1).c_str(), + (port.graph_port()->is_a(PortType::AUDIO) ? JACK_DEFAULT_AUDIO_TYPE : JACK_DEFAULT_MIDI_TYPE), - (port.patch_port()->is_input() + (port.graph_port()->is_input() ? JackPortIsInput : JackPortIsOutput), 0); @@ -241,16 +241,16 @@ JackDriver::rename_port(const Raul::Path& old_path, } EnginePort* -JackDriver::create_port(DuplexPort* patch_port) +JackDriver::create_port(DuplexPort* graph_port) { - if (patch_port && - (patch_port->is_a(PortType::AUDIO) || - (patch_port->is_a(PortType::ATOM) && - patch_port->buffer_type() == _engine.world()->uris().atom_Sequence))) { - EnginePort* eport = new EnginePort(patch_port); + if (graph_port && + (graph_port->is_a(PortType::AUDIO) || + (graph_port->is_a(PortType::ATOM) && + graph_port->buffer_type() == _engine.world()->uris().atom_Sequence))) { + EnginePort* eport = new EnginePort(graph_port); register_port(*eport); - patch_port->setup_buffers(*_engine.buffer_factory(), - patch_port->poly(), + graph_port->setup_buffers(*_engine.buffer_factory(), + graph_port->poly(), false); return eport; } else { @@ -263,33 +263,33 @@ JackDriver::pre_process_port(ProcessContext& context, EnginePort* port) { const SampleCount nframes = context.nframes(); jack_port_t* jack_port = (jack_port_t*)port->handle(); - PortImpl* patch_port = port->patch_port(); + PortImpl* graph_port = port->graph_port(); void* buffer = jack_port_get_buffer(jack_port, nframes); port->set_buffer(buffer); - if (!patch_port->is_input()) { - patch_port->buffer(0)->clear(); + if (!graph_port->is_input()) { + graph_port->buffer(0)->clear(); return; } - if (patch_port->is_a(PortType::AUDIO)) { - Buffer* patch_buf = patch_port->buffer(0).get(); - memcpy(patch_buf->samples(), buffer, nframes * sizeof(float)); + if (graph_port->is_a(PortType::AUDIO)) { + Buffer* graph_buf = graph_port->buffer(0).get(); + memcpy(graph_buf->samples(), buffer, nframes * sizeof(float)); - } else if (patch_port->buffer_type() == patch_port->bufs().uris().atom_Sequence) { - Buffer* patch_buf = (Buffer*)patch_port->buffer(0).get(); + } else if (graph_port->buffer_type() == graph_port->bufs().uris().atom_Sequence) { + Buffer* graph_buf = (Buffer*)graph_port->buffer(0).get(); const jack_nframes_t event_count = jack_midi_get_event_count(buffer); - patch_buf->prepare_write(context); + graph_buf->prepare_write(context); - // Copy events from Jack port buffer into patch port buffer + // Copy events from Jack port buffer into graph port buffer for (jack_nframes_t i = 0; i < event_count; ++i) { jack_midi_event_t ev; jack_midi_event_get(&ev, buffer, i); - if (!patch_buf->append_event( + if (!graph_buf->append_event( ev.time, ev.size, _midi_event_type, ev.buffer)) { _engine.log().warn("Failed to write to MIDI buffer, events lost!\n"); } @@ -302,10 +302,10 @@ JackDriver::post_process_port(ProcessContext& context, EnginePort* port) { const SampleCount nframes = context.nframes(); jack_port_t* jack_port = (jack_port_t*)port->handle(); - PortImpl* patch_port = port->patch_port(); + PortImpl* graph_port = port->graph_port(); void* buffer = port->buffer(); - if (patch_port->is_input()) { + if (graph_port->is_input()) { return; } @@ -315,16 +315,16 @@ JackDriver::post_process_port(ProcessContext& context, EnginePort* port) port->set_buffer(buffer); } - patch_port->post_process(context); - Buffer* const patch_buf = patch_port->buffer(0).get(); - if (patch_port->is_a(PortType::AUDIO)) { - memcpy(buffer, patch_buf->samples(), nframes * sizeof(Sample)); - } else if (patch_port->buffer_type() == patch_port->bufs().uris().atom_Sequence) { + graph_port->post_process(context); + Buffer* const graph_buf = graph_port->buffer(0).get(); + if (graph_port->is_a(PortType::AUDIO)) { + memcpy(buffer, graph_buf->samples(), nframes * sizeof(Sample)); + } else if (graph_port->buffer_type() == graph_port->bufs().uris().atom_Sequence) { jack_midi_clear_buffer(buffer); - LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)patch_buf->atom(); + LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)graph_buf->atom(); LV2_ATOM_SEQUENCE_FOREACH(seq, ev) { const uint8_t* buf = (const uint8_t*)LV2_ATOM_BODY(&ev->body); - if (ev->body.type == patch_port->bufs().uris().midi_MidiEvent) { + if (ev->body.type == graph_port->bufs().uris().midi_MidiEvent) { jack_midi_event_write(buffer, ev->time.frames, buf, ev->body.size); } } @@ -388,9 +388,9 @@ JackDriver::_shutdown_cb() int JackDriver::_block_length_cb(jack_nframes_t nframes) { - if (_engine.root_patch()) { + if (_engine.root_graph()) { _block_length = nframes; - _engine.root_patch()->set_buffer_size( + _engine.root_graph()->set_buffer_size( _engine.process_context(), *_engine.buffer_factory(), PortType::AUDIO, _engine.buffer_factory()->audio_buffer_size(nframes)); } @@ -409,7 +409,7 @@ JackDriver::_session_cb(jack_session_event_t* event) SharedPtr serialiser = _engine.world()->serialiser(); if (serialiser) { - SharedPtr root(_engine.root_patch(), NullDeleter); + SharedPtr root(_engine.root_graph(), NullDeleter); serialiser->write_bundle(root, string("file://") + event->session_dir); } diff --git a/src/server/JackDriver.hpp b/src/server/JackDriver.hpp index c9bda939..8ea84fd6 100644 --- a/src/server/JackDriver.hpp +++ b/src/server/JackDriver.hpp @@ -38,16 +38,16 @@ namespace Raul { class Path; } namespace Ingen { namespace Server { -class Engine; -class PatchImpl; -class PortImpl; class DuplexPort; +class Engine; +class GraphImpl; class JackDriver; +class PortImpl; /** The Jack Driver. * * The process callback here drives the entire audio thread by "pulling" - * events from queues, processing them, running the patches, and passing + * events from queues, processing them, running the graphes, and passing * events along to the PostProcessor. * * \ingroup engine @@ -67,7 +67,7 @@ public: void enable(); void disable(); - EnginePort* create_port(DuplexPort* patch_port); + EnginePort* create_port(DuplexPort* graph_port); EnginePort* get_port(const Raul::Path& path); void rename_port(const Raul::Path& old_path, const Raul::Path& new_path); diff --git a/src/server/LV2Block.cpp b/src/server/LV2Block.cpp index d26f7417..e121f270 100644 --- a/src/server/LV2Block.cpp +++ b/src/server/LV2Block.cpp @@ -32,11 +32,11 @@ #include "Buffer.hpp" #include "Driver.hpp" #include "Engine.hpp" +#include "GraphImpl.hpp" #include "InputPort.hpp" #include "LV2Block.hpp" #include "LV2Plugin.hpp" #include "OutputPort.hpp" -#include "PatchImpl.hpp" #include "ProcessContext.hpp" using namespace std; @@ -52,7 +52,7 @@ namespace Server { LV2Block::LV2Block(LV2Plugin* plugin, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, SampleRate srate) : BlockImpl(plugin, symbol, polyphonic, parent, srate) , _lv2_plugin(plugin) @@ -78,7 +78,7 @@ LV2Block::make_instance(URIs& uris, _lv2_plugin->lilv_plugin(), rate, _features->array()); if (!inst) { - parent_patch()->engine().log().error( + parent_graph()->engine().log().error( Raul::fmt("Failed to instantiate <%1%>\n") % _lv2_plugin->uri().c_str()); return SharedPtr(); @@ -119,7 +119,7 @@ LV2Block::make_instance(URIs& uris, } else if (type == _uris.lv2_CVPort) { port->set_type(PortType::CV, 0); } else { - parent_patch()->engine().log().error( + parent_graph()->engine().log().error( Raul::fmt("%1% auto-morphed to unknown type %2%\n") % port->path().c_str() % type); return SharedPtr(); @@ -304,7 +304,7 @@ LV2Block::instantiate(BufferFactory& bufs) } if (port_type == PortType::UNKNOWN || direction == UNKNOWN) { - parent_patch()->engine().log().error( + parent_graph()->engine().log().error( Raul::fmt("<%1%> port %2% has unknown type or direction\n") % _lv2_plugin->uri().c_str() % port_sym.c_str()); ret = false; @@ -422,7 +422,7 @@ LV2Block::work(uint32_t size, const void* data) if (_worker_iface) { LV2_Handle inst = lilv_instance_get_handle(instance(0)); if (_worker_iface->work(inst, work_respond, this, size, data)) { - parent_patch()->engine().log().error( + parent_graph()->engine().log().error( Raul::fmt("Error calling %1% work method\n") % _path); } } diff --git a/src/server/LV2Block.hpp b/src/server/LV2Block.hpp index 3746b201..2e45d350 100644 --- a/src/server/LV2Block.hpp +++ b/src/server/LV2Block.hpp @@ -39,10 +39,10 @@ class LV2Block : public BlockImpl { public: LV2Block(LV2Plugin* plugin, - const Raul::Symbol& symbol, - bool polyphonic, - PatchImpl* parent, - SampleRate srate); + const Raul::Symbol& symbol, + bool polyphonic, + GraphImpl* parent, + SampleRate srate); ~LV2Block(); diff --git a/src/server/LV2Plugin.cpp b/src/server/LV2Plugin.cpp index 0febfc7d..cc0aee4c 100644 --- a/src/server/LV2Plugin.cpp +++ b/src/server/LV2Plugin.cpp @@ -60,7 +60,7 @@ BlockImpl* LV2Plugin::instantiate(BufferFactory& bufs, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, Engine& engine) { LV2Block* b = new LV2Block( diff --git a/src/server/LV2Plugin.hpp b/src/server/LV2Plugin.hpp index ed26b4ae..bec1b588 100644 --- a/src/server/LV2Plugin.hpp +++ b/src/server/LV2Plugin.hpp @@ -29,7 +29,7 @@ namespace Ingen { namespace Server { -class PatchImpl; +class GraphImpl; class BlockImpl; /** Implementation of an LV2 plugin (loaded shared library). @@ -42,7 +42,7 @@ public: BlockImpl* instantiate(BufferFactory& bufs, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, Engine& engine); const Raul::Symbol symbol() const; diff --git a/src/server/OutputPort.cpp b/src/server/OutputPort.cpp index 1fa53451..48f7eb22 100644 --- a/src/server/OutputPort.cpp +++ b/src/server/OutputPort.cpp @@ -38,7 +38,7 @@ OutputPort::OutputPort(BufferFactory& bufs, size_t buffer_size) : PortImpl(bufs, parent, symbol, index, poly, type, buffer_type, value, buffer_size) { - if (parent->graph_type() != GraphObject::PATCH) { + if (parent->graph_type() != GraphObject::GRAPH) { add_property(bufs.uris().rdf_type, bufs.uris().lv2_OutputPort); } diff --git a/src/server/PatchImpl.cpp b/src/server/PatchImpl.cpp deleted file mode 100644 index ae16c634..00000000 --- a/src/server/PatchImpl.cpp +++ /dev/null @@ -1,381 +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/Log.hpp" -#include "ingen/URIs.hpp" -#include "ingen/World.hpp" - -#include "BlockImpl.hpp" -#include "BufferFactory.hpp" -#include "DuplexPort.hpp" -#include "EdgeImpl.hpp" -#include "Engine.hpp" -#include "PatchImpl.hpp" -#include "PatchPlugin.hpp" -#include "PortImpl.hpp" -#include "ThreadManager.hpp" - -using namespace std; - -namespace Ingen { -namespace Server { - -PatchImpl::PatchImpl(Engine& engine, - const Raul::Symbol& symbol, - uint32_t poly, - PatchImpl* parent, - SampleRate srate, - uint32_t internal_poly) - : BlockImpl(new PatchPlugin(engine.world()->uris(), - engine.world()->uris().ingen_Patch, - Raul::Symbol("patch"), - "Ingen Patch"), - symbol, poly, parent, srate) - , _engine(engine) - , _poly_pre(internal_poly) - , _poly_process(internal_poly) - , _compiled_patch(NULL) - , _process(false) -{ - assert(internal_poly >= 1); - assert(internal_poly <= 128); -} - -PatchImpl::~PatchImpl() -{ - delete _compiled_patch; - delete _plugin; -} - -void -PatchImpl::activate(BufferFactory& bufs) -{ - BlockImpl::activate(bufs); - - for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { - i->activate(bufs); - } - - assert(_activated); -} - -void -PatchImpl::deactivate() -{ - if (_activated) { - BlockImpl::deactivate(); - - for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { - if (i->activated()) { - i->deactivate(); - } - } - } -} - -void -PatchImpl::disable(ProcessContext& context) -{ - _process = false; - for (Ports::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { - i->clear_buffers(); - } -} - -bool -PatchImpl::prepare_internal_poly(BufferFactory& bufs, uint32_t poly) -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - - // TODO: Subpatch dynamic polyphony (i.e. changing port polyphony) - - for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { - i->prepare_poly(bufs, poly); - } - - _poly_pre = poly; - return true; -} - -bool -PatchImpl::apply_internal_poly(ProcessContext& context, - BufferFactory& bufs, - Raul::Maid& maid, - uint32_t poly) -{ - // TODO: Subpatch dynamic polyphony (i.e. changing port polyphony) - - for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { - i->apply_poly(context, maid, poly); - } - - for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { - for (uint32_t j = 0; j < i->num_ports(); ++j) { - PortImpl* const port = i->port_impl(j); - if (port->is_input() && dynamic_cast(port)->direct_connect()) - port->setup_buffers(bufs, port->poly(), true); - port->connect_buffers(); - } - } - - const bool polyphonic = parent_patch() && (poly == parent_patch()->internal_poly_process()); - for (Ports::iterator i = _outputs.begin(); i != _outputs.end(); ++i) - i->setup_buffers(bufs, polyphonic ? poly : 1, true); - - _poly_process = poly; - return true; -} - -/** Run the patch for the specified number of frames. - * - * Calls all Blocks in (roughly, if parallel) the order _compiled_patch specifies. - */ -void -PatchImpl::process(ProcessContext& context) -{ - if (!_process) - return; - - BlockImpl::pre_process(context); - - if (_compiled_patch && _compiled_patch->size() > 0) { - // Run all blocks - for (size_t i = 0; i < _compiled_patch->size(); ++i) { - (*_compiled_patch)[i].block()->process(context); - } - } - - BlockImpl::post_process(context); -} - -void -PatchImpl::set_buffer_size(Context& context, - BufferFactory& bufs, - LV2_URID type, - uint32_t size) -{ - BlockImpl::set_buffer_size(context, bufs, type, size); - - for (size_t i = 0; i < _compiled_patch->size(); ++i) - (*_compiled_patch)[i].block()->set_buffer_size(context, bufs, type, size); -} - -// Patch specific stuff - -/** Add a block. - * Preprocessing thread only. - */ -void -PatchImpl::add_block(BlockImpl& block) -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - _blocks.push_front(block); -} - -/** Remove a block. - * Preprocessing thread only. - */ -void -PatchImpl::remove_block(BlockImpl& block) -{ - _blocks.erase(_blocks.iterator_to(block)); -} - -void -PatchImpl::add_edge(SharedPtr c) -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - _edges.insert(make_pair(make_pair(c->tail(), c->head()), c)); -} - -/** Remove a edge. - * Preprocessing thread only. - */ -SharedPtr -PatchImpl::remove_edge(const PortImpl* tail, const PortImpl* dst_port) -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - Edges::iterator i = _edges.find(make_pair(tail, dst_port)); - if (i != _edges.end()) { - SharedPtr c = PtrCast(i->second); - _edges.erase(i); - return c; - } else { - return SharedPtr(); - } -} - -bool -PatchImpl::has_edge(const PortImpl* tail, const PortImpl* dst_port) const -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - Edges::const_iterator i = _edges.find(make_pair(tail, dst_port)); - return (i != _edges.end()); -} - -uint32_t -PatchImpl::num_ports_non_rt() const -{ - ThreadManager::assert_not_thread(THREAD_PROCESS); - return _inputs.size() + _outputs.size(); -} - -/** Create a port. Not realtime safe. - */ -DuplexPort* -PatchImpl::create_port(BufferFactory& bufs, - const Raul::Symbol& symbol, - PortType type, - LV2_URID buffer_type, - uint32_t buffer_size, - bool is_output, - bool polyphonic) -{ - if (type == PortType::UNKNOWN) { - bufs.engine().log().error(Raul::fmt("Unknown port type %1%\n") - % type.uri()); - return NULL; - } - - Raul::Atom value; - if (type == PortType::CONTROL || type == PortType::CV) - value = bufs.forge().make(0.0f); - - return new DuplexPort(bufs, this, symbol, num_ports_non_rt(), polyphonic, _polyphony, - type, buffer_type, value, buffer_size, is_output); -} - -/** Remove port from ports list used in pre-processing thread. - * - * Port is not removed from ports array for process thread (which could be - * simultaneously running). - * - * Realtime safe. Preprocessing thread only. - */ -void -PatchImpl::remove_port(DuplexPort& port) -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - - if (port.is_input()) { - _inputs.erase(_inputs.iterator_to(port)); - } else { - _outputs.erase(_outputs.iterator_to(port)); - } -} - -/** Remove all ports from ports list used in pre-processing thread. - * - * Ports are not removed from ports array for process thread (which could be - * simultaneously running). Returned is a (inputs, outputs) pair. - * - * Realtime safe. Preprocessing thread only. - */ -void -PatchImpl::clear_ports() -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - - _inputs.clear(); - _outputs.clear(); -} - -Raul::Array* -PatchImpl::build_ports_array() -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - - const size_t n = _inputs.size() + _outputs.size(); - Raul::Array* const result = new Raul::Array(n); - - size_t i = 0; - - for (Ports::iterator p = _inputs.begin(); p != _inputs.end(); ++p, ++i) - result->at(i) = &*p; - - for (Ports::iterator p = _outputs.begin(); p != _outputs.end(); ++p, ++i) - result->at(i) = &*p; - - assert(i == n); - - return result; -} - -static inline void -compile_recursive(BlockImpl* n, CompiledPatch* output) -{ - if (n == NULL || n->traversed()) - return; - - n->traversed(true); - assert(output != NULL); - - for (std::list::iterator i = n->providers().begin(); - i != n->providers().end(); ++i) - if (!(*i)->traversed()) - compile_recursive(*i, output); - - output->push_back(CompiledBlock(n, n->providers().size(), n->dependants())); -} - -/** Find the process order for this Patch. - * - * The process order is a flat list that the patch will execute in order - * when its run() method is called. Return value is a newly allocated list - * which the caller is reponsible to delete. Note that this function does - * NOT actually set the process order, it is returned so it can be inserted - * at the beginning of an audio cycle (by various Events). - * - * Not realtime safe. - */ -CompiledPatch* -PatchImpl::compile() -{ - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - - CompiledPatch* const compiled_patch = new CompiledPatch(); - - for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { - i->traversed(false); - } - - for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { - // Either a sink or connected to our output ports: - if (!i->traversed() && i->dependants().empty()) { - compile_recursive(&*i, compiled_patch); - } - } - - // Traverse any blocks we didn't hit yet - for (Blocks::iterator i = _blocks.begin(); i != _blocks.end(); ++i) { - if (!i->traversed()) { - compile_recursive(&*i, compiled_patch); - } - } - - if (compiled_patch->size() != _blocks.size()) { - _engine.log().error(Raul::fmt("Failed to compile patch %1%\n") % _path); - delete compiled_patch; - return NULL; - } - - return compiled_patch; -} - -} // namespace Server -} // namespace Ingen diff --git a/src/server/PatchImpl.hpp b/src/server/PatchImpl.hpp deleted file mode 100644 index fa212b1a..00000000 --- a/src/server/PatchImpl.hpp +++ /dev/null @@ -1,171 +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_ENGINE_PATCHIMPL_HPP -#define INGEN_ENGINE_PATCHIMPL_HPP - -#include - -#include "BlockImpl.hpp" -#include "CompiledPatch.hpp" -#include "DuplexPort.hpp" -#include "PluginImpl.hpp" -#include "PortType.hpp" -#include "ThreadManager.hpp" - -namespace Ingen { - -class Edge; - -namespace Server { - -class CompiledPatch; -class EdgeImpl; -class Context; -class Engine; -class ProcessContext; - -/** A group of blocks in a graph, possibly polyphonic. - * - * Note that this is also a Block, just one which contains Blocks. - * Therefore infinite subpatching is possible, of polyphonic - * patches of polyphonic blocks etc. etc. - * - * \ingroup engine - */ -class PatchImpl : public BlockImpl -{ -public: - PatchImpl(Engine& engine, - const Raul::Symbol& symbol, - uint32_t poly, - PatchImpl* parent, - SampleRate srate, - uint32_t local_poly); - - virtual ~PatchImpl(); - - virtual GraphType graph_type() const { return PATCH; } - - void activate(BufferFactory& bufs); - void deactivate(); - - void process(ProcessContext& context); - - void set_buffer_size(Context& context, - BufferFactory& bufs, - LV2_URID type, - uint32_t size); - - /** Prepare for a new (internal) polyphony value. - * - * Preprocessor thread, poly is actually applied by apply_internal_poly. - * \return true on success. - */ - bool prepare_internal_poly(BufferFactory& bufs, uint32_t poly); - - /** Apply a new (internal) polyphony value. - * - * Audio thread. - * - * \param context Process context - * \param bufs New set of buffers - * \param poly Must be < the most recent value passed to prepare_internal_poly. - * \param maid Any objects no longer needed will be pushed to this - */ - bool apply_internal_poly(ProcessContext& context, - BufferFactory& bufs, - Raul::Maid& maid, - uint32_t poly); - - // Patch specific stuff not inherited from Block - - typedef boost::intrusive::slist< - BlockImpl, boost::intrusive::constant_time_size > Blocks; - - void add_block(BlockImpl& block); - void remove_block(BlockImpl& block); - - Blocks& blocks() { return _blocks; } - const Blocks& blocks() const { return _blocks; } - - uint32_t num_ports_non_rt() const; - - DuplexPort* create_port(BufferFactory& bufs, - const Raul::Symbol& symbol, - PortType type, - LV2_URID buffer_type, - uint32_t buffer_size, - bool is_output, - bool polyphonic); - - typedef boost::intrusive::slist< - DuplexPort, boost::intrusive::constant_time_size > Ports; - - void add_input(DuplexPort& port) { - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - _inputs.push_front(port); - } - - void add_output(DuplexPort& port) { - ThreadManager::assert_thread(THREAD_PRE_PROCESS); - _outputs.push_front(port); - } - - void remove_port(DuplexPort& port); - void clear_ports(); - - void add_edge(SharedPtr c); - - SharedPtr remove_edge(const PortImpl* tail, - const PortImpl* head); - - bool has_edge(const PortImpl* tail, const PortImpl* head) const; - - CompiledPatch* compiled_patch() { return _compiled_patch; } - void compiled_patch(CompiledPatch* cp) { _compiled_patch = cp; } - - Raul::Array* external_ports() { return _ports; } - void external_ports(Raul::Array* pa) { _ports = pa; } - - CompiledPatch* compile(); - Raul::Array* build_ports_array(); - - /** Whether to run this patch's DSP bits in the audio thread */ - bool enabled() const { return _process; } - void enable() { _process = true; } - void disable(ProcessContext& context); - - uint32_t internal_poly() const { return _poly_pre; } - uint32_t internal_poly_process() const { return _poly_process; } - - Engine& engine() { return _engine; } - -private: - Engine& _engine; - uint32_t _poly_pre; ///< Pre-process thread only - uint32_t _poly_process; ///< Process thread only - CompiledPatch* _compiled_patch; ///< Process thread only - Ports _inputs; ///< Pre-process thread only - Ports _outputs; ///< Pre-process thread only - Blocks _blocks; ///< Pre-process thread only - bool _process; -}; - -} // namespace Server -} // namespace Ingen - -#endif // INGEN_ENGINE_PATCHIMPL_HPP diff --git a/src/server/PatchPlugin.hpp b/src/server/PatchPlugin.hpp deleted file mode 100644 index 1fd9069f..00000000 --- a/src/server/PatchPlugin.hpp +++ /dev/null @@ -1,63 +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_ENGINE_PATCHPLUGIN_HPP -#define INGEN_ENGINE_PATCHPLUGIN_HPP - -#include -#include "PluginImpl.hpp" - -namespace Ingen { -namespace Server { - -class BlockImpl; - -/** Implementation of a Patch plugin. - * - * Patches don't actually work like this yet... - */ -class PatchPlugin : public PluginImpl -{ -public: - PatchPlugin(URIs& uris, - const Raul::URI& uri, - const Raul::Symbol& symbol, - const std::string& name) - : PluginImpl(uris, Plugin::Patch, uri) - {} - - BlockImpl* instantiate(BufferFactory& bufs, - const Raul::Symbol& symbol, - bool polyphonic, - PatchImpl* parent, - Engine& engine) - { - return NULL; - } - - const Raul::Symbol symbol() const { return Raul::Symbol("patch"); } - const std::string name() const { return "Ingen Patch"; } - -private: - const std::string _symbol; - const std::string _name; -}; - -} // namespace Server -} // namespace Ingen - -#endif // INGEN_ENGINE_PATCHPLUGIN_HPP - diff --git a/src/server/PluginImpl.hpp b/src/server/PluginImpl.hpp index 624b3f6d..342225ef 100644 --- a/src/server/PluginImpl.hpp +++ b/src/server/PluginImpl.hpp @@ -35,7 +35,7 @@ namespace Server { class BlockImpl; class BufferFactory; class Engine; -class PatchImpl; +class GraphImpl; /** Implementation of a plugin (internal code, or a loaded shared library). * @@ -55,8 +55,8 @@ public: virtual BlockImpl* instantiate(BufferFactory& bufs, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, - Engine& engine) = 0; + GraphImpl* parent, + Engine& engine) = 0; virtual const Raul::Symbol symbol() const = 0; diff --git a/src/server/Worker.cpp b/src/server/Worker.cpp index 6a39cba8..9fbc4825 100644 --- a/src/server/Worker.cpp +++ b/src/server/Worker.cpp @@ -20,8 +20,8 @@ #include "Driver.hpp" #include "Engine.hpp" +#include "GraphImpl.hpp" #include "LV2Block.hpp" -#include "PatchImpl.hpp" #include "Worker.hpp" namespace Ingen { @@ -40,7 +40,7 @@ schedule(LV2_Worker_Schedule_Handle handle, const void* data) { LV2Block* block = (LV2Block*)handle; - Engine& engine = block->parent_patch()->engine(); + Engine& engine = block->parent_graph()->engine(); Worker* worker = engine.worker(); return worker->request(block, size, data); @@ -51,7 +51,7 @@ Worker::request(LV2Block* block, uint32_t size, const void* data) { - Engine& engine = block->parent_patch()->engine(); + Engine& engine = block->parent_graph()->engine(); if (_requests.write_space() < sizeof(MessageHeader) + size) { engine.log().error("Work request ring overflow\n"); return LV2_WORKER_ERR_NO_SPACE; diff --git a/src/server/events.hpp b/src/server/events.hpp index 95f3d35f..24ac8593 100644 --- a/src/server/events.hpp +++ b/src/server/events.hpp @@ -19,7 +19,7 @@ #include "events/Connect.hpp" #include "events/CreateBlock.hpp" -#include "events/CreatePatch.hpp" +#include "events/CreateGraph.hpp" #include "events/CreatePort.hpp" #include "events/Delete.hpp" #include "events/Delta.hpp" diff --git a/src/server/events/Connect.cpp b/src/server/events/Connect.cpp index db8e044f..eeaa1904 100644 --- a/src/server/events/Connect.cpp +++ b/src/server/events/Connect.cpp @@ -24,9 +24,9 @@ #include "Connect.hpp" #include "EdgeImpl.hpp" #include "Engine.hpp" +#include "GraphImpl.hpp" #include "InputPort.hpp" #include "OutputPort.hpp" -#include "PatchImpl.hpp" #include "PortImpl.hpp" #include "types.hpp" @@ -43,9 +43,9 @@ Connect::Connect(Engine& engine, : Event(engine, client, id, timestamp) , _tail_path(tail_path) , _head_path(head_path) - , _patch(NULL) + , _graph(NULL) , _head(NULL) - , _compiled_patch(NULL) + , _compiled_graph(NULL) , _buffers(NULL) {} @@ -86,23 +86,23 @@ Connect::pre_process() return Event::pre_process_done(TYPE_MISMATCH, _head_path); } - if (tail_block->parent_patch() != head_block->parent_patch()) { - // Edge to a patch port from inside the patch + if (tail_block->parent_graph() != head_block->parent_graph()) { + // Edge to a graph port from inside the graph assert(tail_block->parent() == head_block || head_block->parent() == tail_block); if (tail_block->parent() == head_block) { - _patch = dynamic_cast(head_block); + _graph = dynamic_cast(head_block); } else { - _patch = dynamic_cast(tail_block); + _graph = dynamic_cast(tail_block); } - } else if (tail_block == head_block && dynamic_cast(tail_block)) { - // Edge from a patch input to a patch output (pass through) - _patch = dynamic_cast(tail_block); + } else if (tail_block == head_block && dynamic_cast(tail_block)) { + // Edge from a graph input to a graph output (pass through) + _graph = dynamic_cast(tail_block); } else { // Normal edge between blocks with the same parent - _patch = tail_block->parent_patch(); + _graph = tail_block->parent_graph(); } - if (_patch->has_edge(tail_output, _head)) { + if (_graph->has_edge(tail_output, _head)) { return Event::pre_process_done(EXISTS, _head_path); } @@ -113,8 +113,8 @@ Connect::pre_process() { Glib::RWLock::ReaderLock wlock(_engine.store()->lock()); - /* Need to be careful about patch port edges here and adding a - block's parent as a dependant/provider, or adding a patch as its own + /* Need to be careful about graph port edges here and adding a + block's parent as a dependant/provider, or adding a graph as its own provider... */ if (tail_block != head_block && tail_block->parent() == head_block->parent()) { @@ -122,7 +122,7 @@ Connect::pre_process() tail_block->dependants().push_back(head_block); } - _patch->add_edge(_edge); + _graph->add_edge(_edge); _head->increment_num_edges(); } @@ -132,8 +132,8 @@ Connect::pre_process() _head->poly(), false); - if (_patch->enabled()) { - _compiled_patch = _patch->compile(); + if (_graph->enabled()) { + _compiled_graph = _graph->compile(); } return Event::pre_process_done(SUCCESS); @@ -146,8 +146,8 @@ Connect::execute(ProcessContext& context) _head->add_edge(context, _edge.get()); _engine.maid()->dispose(_head->set_buffers(context, _buffers)); _head->connect_buffers(); - _engine.maid()->dispose(_patch->compiled_patch()); - _patch->compiled_patch(_compiled_patch); + _engine.maid()->dispose(_graph->compiled_graph()); + _graph->compiled_graph(_compiled_graph); } } diff --git a/src/server/events/Connect.hpp b/src/server/events/Connect.hpp index 8d75d2da..445ee80e 100644 --- a/src/server/events/Connect.hpp +++ b/src/server/events/Connect.hpp @@ -30,11 +30,11 @@ template class Array; namespace Ingen { namespace Server { -class CompiledPatch; +class CompiledGraph; class EdgeImpl; class InputPort; class OutputPort; -class PatchImpl; +class GraphImpl; namespace Events { @@ -59,9 +59,9 @@ public: private: const Raul::Path _tail_path; const Raul::Path _head_path; - PatchImpl* _patch; + GraphImpl* _graph; InputPort* _head; - CompiledPatch* _compiled_patch; + CompiledGraph* _compiled_graph; SharedPtr _edge; Raul::Array* _buffers; }; diff --git a/src/server/events/CreateBlock.cpp b/src/server/events/CreateBlock.cpp index 73ff7ba2..bc234b97 100644 --- a/src/server/events/CreateBlock.cpp +++ b/src/server/events/CreateBlock.cpp @@ -24,7 +24,7 @@ #include "Broadcaster.hpp" #include "CreateBlock.hpp" #include "Engine.hpp" -#include "PatchImpl.hpp" +#include "GraphImpl.hpp" #include "PluginImpl.hpp" #include "PortImpl.hpp" @@ -41,9 +41,9 @@ CreateBlock::CreateBlock(Engine& engine, : Event(engine, client, id, timestamp) , _path(path) , _properties(properties) - , _patch(NULL) + , _graph(NULL) , _block(NULL) - , _compiled_patch(NULL) + , _compiled_graph(NULL) {} bool @@ -69,8 +69,8 @@ CreateBlock::pre_process() return Event::pre_process_done(EXISTS, _path); } - _patch = dynamic_cast(_engine.store()->get(_path.parent())); - if (!_patch) { + _graph = dynamic_cast(_engine.store()->get(_path.parent())); + if (!_graph) { return Event::pre_process_done(PARENT_NOT_FOUND, _path.parent()); } @@ -89,7 +89,7 @@ CreateBlock::pre_process() if (!(_block = plugin->instantiate(*_engine.buffer_factory(), Raul::Symbol(_path.symbol()), polyphonic, - _patch, + _graph, _engine))) { return Event::pre_process_done(CREATION_FAILED, _path); } @@ -97,15 +97,15 @@ CreateBlock::pre_process() _block->properties().insert(_properties.begin(), _properties.end()); _block->activate(*_engine.buffer_factory()); - // Add block to the store and the patch's pre-processor only block list - _patch->add_block(*_block); + // Add block to the store and the graph's pre-processor only block list + _graph->add_block(*_block); _engine.store()->add(_block); - /* Compile patch with new block added for insertion in audio thread + /* Compile graph with new block added for insertion in audio thread TODO: Since the block is not connected at this point, a full compilation could be avoided and the block simply appended. */ - if (_patch->enabled()) { - _compiled_patch = _patch->compile(); + if (_graph->enabled()) { + _compiled_graph = _graph->compile(); } _update.push_back(make_pair(_block->uri(), _block->properties())); @@ -124,8 +124,8 @@ void CreateBlock::execute(ProcessContext& context) { if (_block) { - _engine.maid()->dispose(_patch->compiled_patch()); - _patch->compiled_patch(_compiled_patch); + _engine.maid()->dispose(_graph->compiled_graph()); + _graph->compiled_graph(_compiled_graph); } } diff --git a/src/server/events/CreateBlock.hpp b/src/server/events/CreateBlock.hpp index ea3c4b5c..da444b1f 100644 --- a/src/server/events/CreateBlock.hpp +++ b/src/server/events/CreateBlock.hpp @@ -28,12 +28,12 @@ namespace Ingen { namespace Server { class BlockImpl; -class CompiledPatch; -class PatchImpl; +class CompiledGraph; +class GraphImpl; namespace Events { -/** An event to load a Block and insert it into a Patch. +/** An event to load a Block and insert it into a Graph. * * \ingroup engine */ @@ -58,9 +58,9 @@ private: Raul::Path _path; Resource::Properties _properties; Update _update; - PatchImpl* _patch; + GraphImpl* _graph; BlockImpl* _block; - CompiledPatch* _compiled_patch; + CompiledGraph* _compiled_graph; }; } // namespace Events diff --git a/src/server/events/CreateGraph.cpp b/src/server/events/CreateGraph.cpp new file mode 100644 index 00000000..bfe08043 --- /dev/null +++ b/src/server/events/CreateGraph.cpp @@ -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 . +*/ + +#include "ingen/Store.hpp" +#include "ingen/URIs.hpp" +#include "raul/Maid.hpp" +#include "raul/Path.hpp" + +#include "Broadcaster.hpp" +#include "Driver.hpp" +#include "Engine.hpp" +#include "GraphImpl.hpp" +#include "events/CreateGraph.hpp" + +namespace Ingen { +namespace Server { +namespace Events { + +CreateGraph::CreateGraph(Engine& engine, + SharedPtr client, + int32_t id, + SampleCount timestamp, + const Raul::Path& path, + const Resource::Properties& properties) + : Event(engine, client, id, timestamp) + , _path(path) + , _properties(properties) + , _graph(NULL) + , _parent(NULL) + , _compiled_graph(NULL) +{ +} + +bool +CreateGraph::pre_process() +{ + if (_path.is_root() || _engine.store()->get(_path)) { + return Event::pre_process_done(EXISTS, _path); + } + + _parent = dynamic_cast(_engine.store()->get(_path.parent())); + if (!_parent) { + return Event::pre_process_done(PARENT_NOT_FOUND, _path.parent()); + } + + const Ingen::URIs& uris = _engine.world()->uris(); + + typedef Resource::Properties::const_iterator iterator; + + uint32_t ext_poly = 1; + uint32_t int_poly = 1; + iterator p = _properties.find(uris.ingen_polyphony); + if (p != _properties.end() && p->second.type() == uris.forge.Int) { + int_poly = p->second.get_int32(); + } + + if (int_poly < 1 || int_poly > 128) { + return Event::pre_process_done(INVALID_POLY, _path); + } + + if (int_poly == _parent->internal_poly()) { + ext_poly = int_poly; + } + + const Raul::Symbol symbol((_path.is_root()) ? "root" : _path.symbol()); + _graph = new GraphImpl(_engine, symbol, ext_poly, _parent, + _engine.driver()->sample_rate(), int_poly); + _graph->properties().insert(_properties.begin(), _properties.end()); + _graph->add_property(uris.rdf_type, uris.ingen_Graph); + _graph->add_property(uris.rdf_type, + Resource::Property(uris.ingen_Block, Resource::EXTERNAL)); + + _parent->add_block(*_graph); + if (_parent->enabled()) { + _graph->enable(); + _compiled_graph = _parent->compile(); + } + + _graph->activate(*_engine.buffer_factory()); + + // Insert into Store + _engine.store()->add(_graph); + + _update = _graph->properties(); + + return Event::pre_process_done(SUCCESS); +} + +void +CreateGraph::execute(ProcessContext& context) +{ + if (_graph) { + assert(_parent); + assert(!_path.is_root()); + _engine.maid()->dispose(_parent->compiled_graph()); + _parent->compiled_graph(_compiled_graph); + } +} + +void +CreateGraph::post_process() +{ + if (!respond()) { + _engine.broadcaster()->put(GraphObject::path_to_uri(_path), _update); + } +} + +} // namespace Events +} // namespace Server +} // namespace Ingen diff --git a/src/server/events/CreateGraph.hpp b/src/server/events/CreateGraph.hpp new file mode 100644 index 00000000..0f6a95dd --- /dev/null +++ b/src/server/events/CreateGraph.hpp @@ -0,0 +1,62 @@ +/* + 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_EVENTS_CREATEGRAPH_HPP +#define INGEN_EVENTS_CREATEGRAPH_HPP + +#include "Event.hpp" +#include "ingen/Resource.hpp" + +namespace Ingen { +namespace Server { + +class GraphImpl; +class CompiledGraph; + +namespace Events { + +/** Creates a new Graph. + * + * \ingroup engine + */ +class CreateGraph : public Event +{ +public: + CreateGraph(Engine& engine, + SharedPtr client, + int32_t id, + SampleCount timestamp, + const Raul::Path& path, + const Resource::Properties& properties); + + bool pre_process(); + void execute(ProcessContext& context); + void post_process(); + +private: + const Raul::Path _path; + Resource::Properties _properties; + Resource::Properties _update; + GraphImpl* _graph; + GraphImpl* _parent; + CompiledGraph* _compiled_graph; +}; + +} // namespace Events +} // namespace Server +} // namespace Ingen + +#endif // INGEN_EVENTS_CREATEGRAPH_HPP diff --git a/src/server/events/CreatePatch.cpp b/src/server/events/CreatePatch.cpp deleted file mode 100644 index e9adc547..00000000 --- a/src/server/events/CreatePatch.cpp +++ /dev/null @@ -1,123 +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/Store.hpp" -#include "ingen/URIs.hpp" -#include "raul/Maid.hpp" -#include "raul/Path.hpp" - -#include "events/CreatePatch.hpp" -#include "Broadcaster.hpp" -#include "Driver.hpp" -#include "Engine.hpp" -#include "PatchImpl.hpp" - -namespace Ingen { -namespace Server { -namespace Events { - -CreatePatch::CreatePatch(Engine& engine, - SharedPtr client, - int32_t id, - SampleCount timestamp, - const Raul::Path& path, - const Resource::Properties& properties) - : Event(engine, client, id, timestamp) - , _path(path) - , _properties(properties) - , _patch(NULL) - , _parent(NULL) - , _compiled_patch(NULL) -{ -} - -bool -CreatePatch::pre_process() -{ - if (_path.is_root() || _engine.store()->get(_path)) { - return Event::pre_process_done(EXISTS, _path); - } - - _parent = dynamic_cast(_engine.store()->get(_path.parent())); - if (!_parent) { - return Event::pre_process_done(PARENT_NOT_FOUND, _path.parent()); - } - - const Ingen::URIs& uris = _engine.world()->uris(); - - typedef Resource::Properties::const_iterator iterator; - - uint32_t ext_poly = 1; - uint32_t int_poly = 1; - iterator p = _properties.find(uris.ingen_polyphony); - if (p != _properties.end() && p->second.type() == uris.forge.Int) { - int_poly = p->second.get_int32(); - } - - if (int_poly < 1 || int_poly > 128) { - return Event::pre_process_done(INVALID_POLY, _path); - } - - if (int_poly == _parent->internal_poly()) { - ext_poly = int_poly; - } - - const Raul::Symbol symbol((_path.is_root()) ? "root" : _path.symbol()); - _patch = new PatchImpl(_engine, symbol, ext_poly, _parent, - _engine.driver()->sample_rate(), int_poly); - _patch->properties().insert(_properties.begin(), _properties.end()); - _patch->add_property(uris.rdf_type, uris.ingen_Patch); - _patch->add_property(uris.rdf_type, - Resource::Property(uris.ingen_Block, Resource::EXTERNAL)); - - _parent->add_block(*_patch); - if (_parent->enabled()) { - _patch->enable(); - _compiled_patch = _parent->compile(); - } - - _patch->activate(*_engine.buffer_factory()); - - // Insert into Store - _engine.store()->add(_patch); - - _update = _patch->properties(); - - return Event::pre_process_done(SUCCESS); -} - -void -CreatePatch::execute(ProcessContext& context) -{ - if (_patch) { - assert(_parent); - assert(!_path.is_root()); - _engine.maid()->dispose(_parent->compiled_patch()); - _parent->compiled_patch(_compiled_patch); - } -} - -void -CreatePatch::post_process() -{ - if (!respond()) { - _engine.broadcaster()->put(GraphObject::path_to_uri(_path), _update); - } -} - -} // namespace Events -} // namespace Server -} // namespace Ingen diff --git a/src/server/events/CreatePatch.hpp b/src/server/events/CreatePatch.hpp deleted file mode 100644 index be19d54e..00000000 --- a/src/server/events/CreatePatch.hpp +++ /dev/null @@ -1,62 +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_EVENTS_CREATEPATCH_HPP -#define INGEN_EVENTS_CREATEPATCH_HPP - -#include "Event.hpp" -#include "ingen/Resource.hpp" - -namespace Ingen { -namespace Server { - -class PatchImpl; -class CompiledPatch; - -namespace Events { - -/** Creates a new Patch. - * - * \ingroup engine - */ -class CreatePatch : public Event -{ -public: - CreatePatch(Engine& engine, - SharedPtr client, - int32_t id, - SampleCount timestamp, - const Raul::Path& path, - const Resource::Properties& properties); - - bool pre_process(); - void execute(ProcessContext& context); - void post_process(); - -private: - const Raul::Path _path; - Resource::Properties _properties; - Resource::Properties _update; - PatchImpl* _patch; - PatchImpl* _parent; - CompiledPatch* _compiled_patch; -}; - -} // namespace Events -} // namespace Server -} // namespace Ingen - -#endif // INGEN_EVENTS_CREATEPATCH_HPP diff --git a/src/server/events/CreatePort.cpp b/src/server/events/CreatePort.cpp index 49ceed95..a32faaee 100644 --- a/src/server/events/CreatePort.cpp +++ b/src/server/events/CreatePort.cpp @@ -29,7 +29,7 @@ #include "Driver.hpp" #include "DuplexPort.hpp" #include "Engine.hpp" -#include "PatchImpl.hpp" +#include "GraphImpl.hpp" #include "PortImpl.hpp" namespace Ingen { @@ -47,8 +47,8 @@ CreatePort::CreatePort(Engine& engine, , _path(path) , _port_type(PortType::UNKNOWN) , _buf_type(0) - , _patch(NULL) - , _patch_port(NULL) + , _graph(NULL) + , _graph_port(NULL) , _ports_array(NULL) , _old_ports_array(NULL) , _engine_port(NULL) @@ -102,7 +102,7 @@ CreatePort::pre_process() return Event::pre_process_done(PARENT_NOT_FOUND, _path.parent()); } - if (!(_patch = dynamic_cast(parent))) { + if (!(_graph = dynamic_cast(parent))) { return Event::pre_process_done(INVALID_PARENT_PATH, _path.parent()); } @@ -110,7 +110,7 @@ CreatePort::pre_process() const BufferFactory& buffer_factory = *_engine.buffer_factory(); const uint32_t buf_size = buffer_factory.default_size(_buf_type); - const int32_t old_n_ports = _patch->num_ports_non_rt(); + const int32_t old_n_ports = _graph->num_ports_non_rt(); typedef Resource::Properties::const_iterator PropIter; @@ -130,34 +130,34 @@ CreatePort::pre_process() poly_i->second.type() == uris.forge.Bool && poly_i->second.get_bool()); - if (!(_patch_port = _patch->create_port( + if (!(_graph_port = _graph->create_port( *_engine.buffer_factory(), Raul::Symbol(_path.symbol()), _port_type, _buf_type, buf_size, _is_output, polyphonic))) { return Event::pre_process_done(CREATION_FAILED, _path); } - _patch_port->properties().insert(_properties.begin(), _properties.end()); + _graph_port->properties().insert(_properties.begin(), _properties.end()); - _engine.store()->add(_patch_port); + _engine.store()->add(_graph_port); if (_is_output) { - _patch->add_output(*_patch_port); + _graph->add_output(*_graph_port); } else { - _patch->add_input(*_patch_port); + _graph->add_input(*_graph_port); } - if (!_patch->parent()) { + if (!_graph->parent()) { _engine_port = _engine.driver()->create_port( - dynamic_cast(_patch_port)); + dynamic_cast(_graph_port)); } _ports_array = new Raul::Array(old_n_ports + 1, NULL); - _update = _patch_port->properties(); + _update = _graph_port->properties(); - assert(_patch_port->index() == (uint32_t)index_i->second.get_int32()); - assert(_patch->num_ports_non_rt() == (uint32_t)old_n_ports + 1); - assert(_patch_port->index() == (uint32_t)old_n_ports); - assert(_ports_array->size() == _patch->num_ports_non_rt()); - assert(_patch_port->index() < _ports_array->size()); + assert(_graph_port->index() == (uint32_t)index_i->second.get_int32()); + assert(_graph->num_ports_non_rt() == (uint32_t)old_n_ports + 1); + assert(_graph_port->index() == (uint32_t)old_n_ports); + assert(_ports_array->size() == _graph->num_ports_non_rt()); + assert(_graph_port->index() < _ports_array->size()); return Event::pre_process_done(SUCCESS); } @@ -165,15 +165,15 @@ void CreatePort::execute(ProcessContext& context) { if (!_status) { - _old_ports_array = _patch->external_ports(); + _old_ports_array = _graph->external_ports(); if (_old_ports_array) { for (uint32_t i = 0; i < _old_ports_array->size(); ++i) { (*_ports_array)[i] = (*_old_ports_array)[i]; } } - assert(!(*_ports_array)[_patch_port->index()]); - (*_ports_array)[_patch_port->index()] = _patch_port; - _patch->external_ports(_ports_array); + assert(!(*_ports_array)[_graph_port->index()]); + (*_ports_array)[_graph_port->index()] = _graph_port; + _graph->external_ports(_ports_array); if (_engine_port) { _engine.driver()->add_port(context, _engine_port); diff --git a/src/server/events/CreatePort.hpp b/src/server/events/CreatePort.hpp index c8e4c695..d35b58af 100644 --- a/src/server/events/CreatePort.hpp +++ b/src/server/events/CreatePort.hpp @@ -30,12 +30,12 @@ namespace Server { class DuplexPort; class EnginePort; -class PatchImpl; +class GraphImpl; class PortImpl; namespace Events { -/** An event to add a Port to a Patch. +/** An event to add a Port to a Graph. * * \ingroup engine */ @@ -58,9 +58,9 @@ private: Raul::Path _path; PortType _port_type; LV2_URID _buf_type; - PatchImpl* _patch; - DuplexPort* _patch_port; - Raul::Array* _ports_array; ///< New external port array for Patch + GraphImpl* _graph; + DuplexPort* _graph_port; + Raul::Array* _ports_array; ///< New external port array for Graph Raul::Array* _old_ports_array; EnginePort* _engine_port; ///< Driver port if on the root Resource::Properties _properties; diff --git a/src/server/events/Delete.cpp b/src/server/events/Delete.cpp index dbda331c..a6207ba1 100644 --- a/src/server/events/Delete.cpp +++ b/src/server/events/Delete.cpp @@ -26,7 +26,7 @@ #include "Driver.hpp" #include "Engine.hpp" #include "EnginePort.hpp" -#include "PatchImpl.hpp" +#include "GraphImpl.hpp" #include "PluginImpl.hpp" #include "PortImpl.hpp" @@ -43,7 +43,7 @@ Delete::Delete(Engine& engine, , _uri(uri) , _engine_port(NULL) , _ports_array(NULL) - , _compiled_patch(NULL) + , _compiled_graph(NULL) , _disconnect_event(NULL) , _lock(engine.store()->lock(), Glib::NOT_LOCK) { @@ -81,7 +81,7 @@ Delete::pre_process() return Event::pre_process_done(NOT_DELETABLE, _path); } - PatchImpl* parent = _block ? _block->parent_patch() : _port->parent_patch(); + GraphImpl* parent = _block ? _block->parent_graph() : _port->parent_graph(); if (!parent) { return Event::pre_process_done(INTERNAL_ERROR, _path); } @@ -94,7 +94,7 @@ Delete::pre_process() _disconnect_event->pre_process(); if (parent->enabled()) { - _compiled_patch = parent->compile(); + _compiled_graph = parent->compile(); } } else if (_port) { parent->remove_port(*_port); @@ -102,7 +102,7 @@ Delete::pre_process() _disconnect_event->pre_process(); if (parent->enabled()) { - _compiled_patch = parent->compile(); + _compiled_graph = parent->compile(); _ports_array = parent->build_ports_array(); assert(_ports_array->size() == parent->num_ports_non_rt()); } @@ -122,7 +122,7 @@ Delete::execute(ProcessContext& context) _disconnect_event->execute(context); } - PatchImpl* parent = _block ? _block->parent_patch() : _port->parent_patch(); + GraphImpl* parent = _block ? _block->parent_graph() : _port->parent_graph(); if (_port) { _engine.maid()->dispose(parent->external_ports()); parent->external_ports(_ports_array); @@ -133,8 +133,8 @@ Delete::execute(ProcessContext& context) } if (parent) { - _engine.maid()->dispose(parent->compiled_patch()); - parent->compiled_patch(_compiled_patch); + _engine.maid()->dispose(parent->compiled_graph()); + parent->compiled_graph(_compiled_graph); } } diff --git a/src/server/events/Delete.hpp b/src/server/events/Delete.hpp index c14c5567..74046f82 100644 --- a/src/server/events/Delete.hpp +++ b/src/server/events/Delete.hpp @@ -20,7 +20,7 @@ #include "ingen/Store.hpp" #include "Event.hpp" -#include "PatchImpl.hpp" +#include "GraphImpl.hpp" #include "ControlBindings.hpp" namespace Raul { @@ -31,7 +31,7 @@ namespace Ingen { namespace Server { class BlockImpl; -class CompiledPatch; +class CompiledGraph; class DuplexPort; class EnginePort; class PortImpl; @@ -75,8 +75,8 @@ private: SharedPtr _block; ///< Non-NULL iff a block SharedPtr _port; ///< Non-NULL iff a port EnginePort* _engine_port; - Raul::Array* _ports_array; ///< New (external) ports for Patch - CompiledPatch* _compiled_patch; ///< Patch's new process order + Raul::Array* _ports_array; ///< New (external) ports for Graph + CompiledGraph* _compiled_graph; ///< Graph's new process order DisconnectAll* _disconnect_event; SharedPtr _removed_bindings; diff --git a/src/server/events/Delta.cpp b/src/server/events/Delta.cpp index 3b31cedb..06bd150c 100644 --- a/src/server/events/Delta.cpp +++ b/src/server/events/Delta.cpp @@ -25,11 +25,11 @@ #include "Broadcaster.hpp" #include "ControlBindings.hpp" #include "CreateBlock.hpp" -#include "CreatePatch.hpp" +#include "CreateGraph.hpp" #include "CreatePort.hpp" #include "Delta.hpp" #include "Engine.hpp" -#include "PatchImpl.hpp" +#include "GraphImpl.hpp" #include "PluginImpl.hpp" #include "PortImpl.hpp" #include "PortType.hpp" @@ -59,8 +59,8 @@ Delta::Delta(Engine& engine, , _properties(properties) , _remove(remove) , _object(NULL) - , _patch(NULL) - , _compiled_patch(NULL) + , _graph(NULL) + , _compiled_graph(NULL) , _context(context) , _create(create) { @@ -122,11 +122,11 @@ Delta::pre_process() if (is_graph_object && !_object) { Raul::Path path(GraphObject::uri_to_path(_subject)); - bool is_patch = false, is_block = false, is_port = false, is_output = false; - Ingen::Resource::type(uris, _properties, is_patch, is_block, is_port, is_output); + bool is_graph = false, is_block = false, is_port = false, is_output = false; + Ingen::Resource::type(uris, _properties, is_graph, is_block, is_port, is_output); - if (is_patch) { - _create_event = new CreatePatch( + if (is_graph) { + _create_event = new CreateGraph( _engine, _request_client, _request_id, _time, path, _properties); } else if (is_block) { _create_event = new CreateBlock( @@ -194,13 +194,13 @@ Delta::pre_process() _status = BAD_OBJECT_TYPE; } } - } else if ((_patch = dynamic_cast(_object))) { + } else if ((_graph = dynamic_cast(_object))) { if (key == uris.ingen_enabled) { if (value.type() == uris.forge.Bool) { op = ENABLE; // FIXME: defer this until all other metadata has been processed - if (value.get_bool() && !_patch->enabled()) - _compiled_patch = _patch->compile(); + if (value.get_bool() && !_graph->enabled()) + _compiled_graph = _graph->compile(); } else { _status = BAD_VALUE_TYPE; } @@ -210,7 +210,7 @@ Delta::pre_process() _status = INVALID_POLY; } else { op = POLYPHONY; - _patch->prepare_internal_poly( + _graph->prepare_internal_poly( *_engine.buffer_factory(), value.get_int32()); } } else { @@ -218,7 +218,7 @@ Delta::pre_process() } } } else if (key == uris.ingen_polyphonic) { - PatchImpl* parent = dynamic_cast(obj->parent()); + GraphImpl* parent = dynamic_cast(obj->parent()); if (parent) { if (value.type() == uris.forge.Bool) { op = POLYPHONIC; @@ -286,17 +286,17 @@ Delta::execute(ProcessContext& context) break; case ENABLE: if (value.get_bool()) { - if (_compiled_patch) { - _engine.maid()->dispose(_patch->compiled_patch()); - _patch->compiled_patch(_compiled_patch); + if (_compiled_graph) { + _engine.maid()->dispose(_graph->compiled_graph()); + _graph->compiled_graph(_compiled_graph); } - _patch->enable(); + _graph->enable(); } else { - _patch->disable(context); + _graph->disable(context); } break; case POLYPHONIC: { - PatchImpl* parent = reinterpret_cast(object->parent()); + GraphImpl* parent = reinterpret_cast(object->parent()); if (value.get_bool()) { object->apply_poly( context, *_engine.maid(), parent->internal_poly_process()); @@ -305,7 +305,7 @@ Delta::execute(ProcessContext& context) } } break; case POLYPHONY: - if (!_patch->apply_internal_poly(context, + if (!_graph->apply_internal_poly(context, *_engine.buffer_factory(), *_engine.maid(), value.get_int32())) { diff --git a/src/server/events/Delta.hpp b/src/server/events/Delta.hpp index 6bb6508a..c3a28fbb 100644 --- a/src/server/events/Delta.hpp +++ b/src/server/events/Delta.hpp @@ -30,9 +30,9 @@ class Resource; namespace Server { -class CompiledPatch; +class CompiledGraph; class Engine; -class PatchImpl; +class GraphImpl; class ProcessContext; namespace Events { @@ -105,8 +105,8 @@ private: Resource::Properties _properties; Resource::Properties _remove; Ingen::Resource* _object; - PatchImpl* _patch; - CompiledPatch* _compiled_patch; + GraphImpl* _graph; + CompiledGraph* _compiled_graph; Resource::Graph _context; ControlBindings::Key _binding; bool _create; diff --git a/src/server/events/Disconnect.cpp b/src/server/events/Disconnect.cpp index 9cf2974a..914e3375 100644 --- a/src/server/events/Disconnect.cpp +++ b/src/server/events/Disconnect.cpp @@ -27,9 +27,9 @@ #include "DuplexPort.hpp" #include "EdgeImpl.hpp" #include "Engine.hpp" +#include "GraphImpl.hpp" #include "InputPort.hpp" #include "OutputPort.hpp" -#include "PatchImpl.hpp" #include "PortImpl.hpp" #include "ProcessContext.hpp" #include "ThreadManager.hpp" @@ -48,21 +48,21 @@ Disconnect::Disconnect(Engine& engine, : Event(engine, client, id, timestamp) , _tail_path(tail_path) , _head_path(head_path) - , _patch(NULL) + , _graph(NULL) , _impl(NULL) - , _compiled_patch(NULL) + , _compiled_graph(NULL) { } Disconnect::Impl::Impl(Engine& e, - PatchImpl* patch, + GraphImpl* graph, OutputPort* s, InputPort* d) : _engine(e) , _src_output_port(s) , _dst_input_port(d) - , _patch(patch) - , _edge(patch->remove_edge(_src_output_port, _dst_input_port)) + , _graph(graph) + , _edge(graph->remove_edge(_src_output_port, _dst_input_port)) , _buffers(NULL) { ThreadManager::assert_thread(THREAD_PRE_PROCESS); @@ -133,25 +133,25 @@ Disconnect::pre_process() BlockImpl* const src_block = tail->parent_block(); BlockImpl* const dst_block = head->parent_block(); - if (src_block->parent_patch() != dst_block->parent_patch()) { - // Edge to a patch port from inside the patch + if (src_block->parent_graph() != dst_block->parent_graph()) { + // Edge to a graph port from inside the graph assert(src_block->parent() == dst_block || dst_block->parent() == src_block); if (src_block->parent() == dst_block) { - _patch = dynamic_cast(dst_block); + _graph = dynamic_cast(dst_block); } else { - _patch = dynamic_cast(src_block); + _graph = dynamic_cast(src_block); } - } else if (src_block == dst_block && dynamic_cast(src_block)) { - // Edge from a patch input to a patch output (pass through) - _patch = dynamic_cast(src_block); + } else if (src_block == dst_block && dynamic_cast(src_block)) { + // Edge from a graph input to a graph output (pass through) + _graph = dynamic_cast(src_block); } else { // Normal edge between blocks with the same parent - _patch = src_block->parent_patch(); + _graph = src_block->parent_graph(); } - assert(_patch); + assert(_graph); - if (!_patch->has_edge(tail, head)) { + if (!_graph->has_edge(tail, head)) { return Event::pre_process_done(NOT_FOUND, _head_path); } @@ -160,12 +160,12 @@ Disconnect::pre_process() } _impl = new Impl(_engine, - _patch, + _graph, dynamic_cast(tail), dynamic_cast(head)); - if (_patch->enabled()) - _compiled_patch = _patch->compile(); + if (_graph->enabled()) + _compiled_graph = _graph->compile(); return Event::pre_process_done(SUCCESS); } @@ -207,8 +207,8 @@ Disconnect::execute(ProcessContext& context) return; } - _engine.maid()->dispose(_patch->compiled_patch()); - _patch->compiled_patch(_compiled_patch); + _engine.maid()->dispose(_graph->compiled_graph()); + _graph->compiled_graph(_compiled_graph); } } diff --git a/src/server/events/Disconnect.hpp b/src/server/events/Disconnect.hpp index b008025a..feb1d17f 100644 --- a/src/server/events/Disconnect.hpp +++ b/src/server/events/Disconnect.hpp @@ -18,10 +18,11 @@ #define INGEN_EVENTS_DISCONNECT_HPP #include "raul/Path.hpp" + +#include "BufferFactory.hpp" #include "Event.hpp" +#include "GraphImpl.hpp" #include "types.hpp" -#include "PatchImpl.hpp" -#include "BufferFactory.hpp" namespace Raul { template class Array; @@ -30,7 +31,7 @@ template class Array; namespace Ingen { namespace Server { -class CompiledPatch; +class CompiledGraph; class InputPort; class OutputPort; class PortImpl; @@ -58,7 +59,7 @@ public: class Impl { public: Impl(Engine& e, - PatchImpl* patch, + GraphImpl* graph, OutputPort* s, InputPort* d); @@ -70,7 +71,7 @@ public: Engine& _engine; OutputPort* _src_output_port; InputPort* _dst_input_port; - PatchImpl* _patch; + GraphImpl* _graph; SharedPtr _edge; Raul::Array* _buffers; }; @@ -78,9 +79,9 @@ public: private: const Raul::Path _tail_path; const Raul::Path _head_path; - PatchImpl* _patch; + GraphImpl* _graph; Impl* _impl; - CompiledPatch* _compiled_patch; + CompiledGraph* _compiled_graph; }; } // namespace Events diff --git a/src/server/events/DisconnectAll.cpp b/src/server/events/DisconnectAll.cpp index 4169622d..dbff2ab3 100644 --- a/src/server/events/DisconnectAll.cpp +++ b/src/server/events/DisconnectAll.cpp @@ -28,9 +28,9 @@ #include "Broadcaster.hpp" #include "EdgeImpl.hpp" #include "Engine.hpp" +#include "GraphImpl.hpp" #include "InputPort.hpp" #include "OutputPort.hpp" -#include "PatchImpl.hpp" #include "PortImpl.hpp" #include "events/Disconnect.hpp" #include "events/DisconnectAll.hpp" @@ -52,7 +52,7 @@ DisconnectAll::DisconnectAll(Engine& engine, , _parent(NULL) , _block(NULL) , _port(NULL) - , _compiled_patch(NULL) + , _compiled_graph(NULL) , _deleting(false) { } @@ -60,7 +60,7 @@ DisconnectAll::DisconnectAll(Engine& engine, /** Internal version for use by other events. */ DisconnectAll::DisconnectAll(Engine& engine, - PatchImpl* parent, + GraphImpl* parent, GraphObject* object) : Event(engine) , _parent_path(parent->path()) @@ -68,7 +68,7 @@ DisconnectAll::DisconnectAll(Engine& engine, , _parent(parent) , _block(dynamic_cast(object)) , _port(dynamic_cast(object)) - , _compiled_patch(NULL) + , _compiled_graph(NULL) , _deleting(true) { } @@ -87,7 +87,7 @@ DisconnectAll::pre_process() if (!_deleting) { lock.acquire(); - _parent = dynamic_cast(_engine.store()->get(_parent_path)); + _parent = dynamic_cast(_engine.store()->get(_parent_path)); if (!_parent) { return Event::pre_process_done(PARENT_NOT_FOUND, _parent_path); } @@ -98,8 +98,8 @@ DisconnectAll::pre_process() return Event::pre_process_done(NOT_FOUND, _path); } - if (object->parent_patch() != _parent - && object->parent()->parent_patch() != _parent) { + if (object->parent_graph() != _parent + && object->parent()->parent_graph() != _parent) { return Event::pre_process_done(INVALID_PARENT_PATH, _parent_path); } @@ -138,7 +138,7 @@ DisconnectAll::pre_process() } if (!_deleting && _parent->enabled()) - _compiled_patch = _parent->compile(); + _compiled_graph = _parent->compile(); return Event::pre_process_done(SUCCESS); } @@ -153,8 +153,8 @@ DisconnectAll::execute(ProcessContext& context) } } - _engine.maid()->dispose(_parent->compiled_patch()); - _parent->compiled_patch(_compiled_patch); + _engine.maid()->dispose(_parent->compiled_graph()); + _parent->compiled_graph(_compiled_graph); } void diff --git a/src/server/events/DisconnectAll.hpp b/src/server/events/DisconnectAll.hpp index 68ba8ebe..8a785722 100644 --- a/src/server/events/DisconnectAll.hpp +++ b/src/server/events/DisconnectAll.hpp @@ -28,8 +28,8 @@ namespace Ingen { namespace Server { class BlockImpl; -class CompiledPatch; -class PatchImpl; +class CompiledGraph; +class GraphImpl; class PortImpl; namespace Events { @@ -51,7 +51,7 @@ public: const Raul::Path& object); DisconnectAll(Engine& engine, - PatchImpl* parent, + GraphImpl* parent, GraphObject* object); ~DisconnectAll(); @@ -65,11 +65,11 @@ private: Raul::Path _parent_path; Raul::Path _path; - PatchImpl* _parent; + GraphImpl* _parent; BlockImpl* _block; PortImpl* _port; Impls _impls; - CompiledPatch* _compiled_patch; + CompiledGraph* _compiled_graph; bool _deleting; }; diff --git a/src/server/events/Get.cpp b/src/server/events/Get.cpp index 24b4daae..c452328e 100644 --- a/src/server/events/Get.cpp +++ b/src/server/events/Get.cpp @@ -26,7 +26,7 @@ #include "Driver.hpp" #include "Engine.hpp" #include "Get.hpp" -#include "PatchImpl.hpp" +#include "GraphImpl.hpp" #include "PluginImpl.hpp" #include "PortImpl.hpp" @@ -35,7 +35,7 @@ namespace Server { namespace Events { static void -send_patch(Interface* client, const PatchImpl* patch); +send_graph(Interface* client, const GraphImpl* graph); Get::Get(Engine& engine, SharedPtr client, @@ -87,8 +87,8 @@ static void send_block(Interface* client, const BlockImpl* block) { PluginImpl* const plugin = block->plugin_impl(); - if (plugin->type() == Plugin::Patch) { - send_patch(client, (const PatchImpl*)block); + if (plugin->type() == Plugin::Graph) { + send_graph(client, (const GraphImpl*)block); } else { client->put(block->uri(), block->properties()); for (size_t j = 0; j < block->num_ports(); ++j) { @@ -98,30 +98,30 @@ send_block(Interface* client, const BlockImpl* block) } static void -send_patch(Interface* client, const PatchImpl* patch) +send_graph(Interface* client, const GraphImpl* graph) { - client->put(patch->uri(), - patch->properties(Resource::INTERNAL), + client->put(graph->uri(), + graph->properties(Resource::INTERNAL), Resource::INTERNAL); - client->put(patch->uri(), - patch->properties(Resource::EXTERNAL), + client->put(graph->uri(), + graph->properties(Resource::EXTERNAL), Resource::EXTERNAL); // Send blocks - for (PatchImpl::Blocks::const_iterator j = patch->blocks().begin(); - j != patch->blocks().end(); ++j) { + for (GraphImpl::Blocks::const_iterator j = graph->blocks().begin(); + j != graph->blocks().end(); ++j) { send_block(client, &*j); } // Send ports - for (uint32_t i = 0; i < patch->num_ports_non_rt(); ++i) { - send_port(client, patch->port_impl(i)); + for (uint32_t i = 0; i < graph->num_ports_non_rt(); ++i) { + send_port(client, graph->port_impl(i)); } // Send edges - for (PatchImpl::Edges::const_iterator j = patch->edges().begin(); - j != patch->edges().end(); ++j) { + for (GraphImpl::Edges::const_iterator j = graph->edges().begin(); + j != graph->edges().end(); ++j) { client->connect(j->second->tail_path(), j->second->head_path()); } } @@ -142,10 +142,10 @@ Get::post_process() } else if (_object) { _request_client->bundle_begin(); const BlockImpl* block = NULL; - const PatchImpl* patch = NULL; + const GraphImpl* graph = NULL; const PortImpl* port = NULL; - if ((patch = dynamic_cast(_object))) { - send_patch(_request_client.get(), patch); + if ((graph = dynamic_cast(_object))) { + send_graph(_request_client.get(), graph); } else if ((block = dynamic_cast(_object))) { send_block(_request_client.get(), block); } else if ((port = dynamic_cast(_object))) { diff --git a/src/server/events/Move.cpp b/src/server/events/Move.cpp index d5b4d116..58f47e13 100644 --- a/src/server/events/Move.cpp +++ b/src/server/events/Move.cpp @@ -24,7 +24,7 @@ #include "Driver.hpp" #include "Engine.hpp" #include "EnginePort.hpp" -#include "PatchImpl.hpp" +#include "GraphImpl.hpp" #include "events/Move.hpp" namespace Ingen { diff --git a/src/server/events/Move.hpp b/src/server/events/Move.hpp index 6c38347f..6e30cba6 100644 --- a/src/server/events/Move.hpp +++ b/src/server/events/Move.hpp @@ -25,7 +25,7 @@ namespace Ingen { namespace Server { -class PatchImpl; +class GraphImpl; class PortImpl; namespace Events { @@ -62,7 +62,7 @@ public: private: const Raul::Path _old_path; const Raul::Path _new_path; - PatchImpl* _parent_patch; + GraphImpl* _parent_graph; }; } // namespace Events diff --git a/src/server/ingen_lv2.cpp b/src/server/ingen_lv2.cpp index 5158e441..26f239da 100644 --- a/src/server/ingen_lv2.cpp +++ b/src/server/ingen_lv2.cpp @@ -49,7 +49,7 @@ #include "Engine.hpp" #include "EnginePort.hpp" #include "EventWriter.hpp" -#include "PatchImpl.hpp" +#include "GraphImpl.hpp" #include "PostProcessor.hpp" #include "ProcessContext.hpp" #include "ThreadManager.hpp" @@ -58,9 +58,9 @@ #define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#" #define NS_RDFS "http://www.w3.org/2000/01/rdf-schema#" -/** Record of a patch in this bundle. */ -struct LV2Patch { - LV2Patch(const std::string& u, const std::string& f); +/** Record of a graph in this bundle. */ +struct LV2Graph { + LV2Graph(const std::string& u, const std::string& f); const std::string uri; const std::string filename; @@ -72,9 +72,9 @@ class Lib { public: explicit Lib(const char* bundle_path); - typedef std::vector< SharedPtr > Patches; + typedef std::vector< SharedPtr > Graphes; - Patches patches; + Graphes graphes; }; namespace Ingen { @@ -101,7 +101,7 @@ public: *this) , _from_ui(block_length * sizeof(float)) // FIXME: size , _to_ui(block_length * sizeof(float)) // FIXME: size - , _root_patch(NULL) + , _root_graph(NULL) , _notify_capacity(0) , _block_length(block_length) , _sample_rate(sample_rate) @@ -111,28 +111,28 @@ public: {} void pre_process_port(ProcessContext& context, EnginePort* port) { - PortImpl* patch_port = port->patch_port(); + PortImpl* graph_port = port->graph_port(); void* buffer = port->buffer(); - if (!patch_port->is_input() || !buffer) { + if (!graph_port->is_input() || !buffer) { return; } - Buffer* const patch_buf = patch_port->buffer(0).get(); - if (patch_port->is_a(PortType::AUDIO) || - patch_port->is_a(PortType::CV)) { - memcpy(patch_buf->samples(), + Buffer* const graph_buf = graph_port->buffer(0).get(); + if (graph_port->is_a(PortType::AUDIO) || + graph_port->is_a(PortType::CV)) { + memcpy(graph_buf->samples(), buffer, context.nframes() * sizeof(float)); - } else if (patch_port->is_a(PortType::CONTROL)) { - patch_buf->samples()[0] = ((float*)buffer)[0]; + } else if (graph_port->is_a(PortType::CONTROL)) { + graph_buf->samples()[0] = ((float*)buffer)[0]; } else { LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)buffer; bool enqueued = false; - URIs& uris = patch_port->bufs().uris(); - patch_buf->prepare_write(context); + URIs& uris = graph_port->bufs().uris(); + graph_buf->prepare_write(context); LV2_ATOM_SEQUENCE_FOREACH(seq, ev) { - if (!patch_buf->append_event( + if (!graph_buf->append_event( ev->time.frames, ev->body.size, ev->body.type, (const uint8_t*)LV2_ATOM_BODY(&ev->body))) { _engine.log().warn("Failed to write to buffer, event lost!\n"); @@ -151,27 +151,27 @@ public: } void post_process_port(ProcessContext& context, EnginePort* port) { - PortImpl* patch_port = port->patch_port(); + PortImpl* graph_port = port->graph_port(); void* buffer = port->buffer(); - if (patch_port->is_input() || !buffer) { + if (graph_port->is_input() || !buffer) { return; } - Buffer* patch_buf = patch_port->buffer(0).get(); - if (patch_port->is_a(PortType::AUDIO) || - patch_port->is_a(PortType::CV)) { + Buffer* graph_buf = graph_port->buffer(0).get(); + if (graph_port->is_a(PortType::AUDIO) || + graph_port->is_a(PortType::CV)) { memcpy(buffer, - patch_buf->samples(), + graph_buf->samples(), context.nframes() * sizeof(float)); - } else if (patch_port->is_a(PortType::CONTROL)) { - ((float*)buffer)[0] = patch_buf->samples()[0]; - } else if (patch_port->index() != 1) { + } else if (graph_port->is_a(PortType::CONTROL)) { + ((float*)buffer)[0] = graph_buf->samples()[0]; + } else if (graph_port->index() != 1) { /* Copy Sequence output to LV2 buffer, except notify output which is written by flush_to_ui() (TODO: merge) */ memcpy(buffer, - patch_buf->atom(), - sizeof(LV2_Atom) + patch_buf->atom()->size); + graph_buf->atom(), + sizeof(LV2_Atom) + graph_buf->atom()->size); } } @@ -204,12 +204,12 @@ public: _main_sem.post(); } - virtual void set_root_patch(PatchImpl* patch) { _root_patch = patch; } - virtual PatchImpl* root_patch() { return _root_patch; } + virtual void set_root_graph(GraphImpl* graph) { _root_graph = graph; } + virtual GraphImpl* root_graph() { return _root_graph; } virtual EnginePort* get_port(const Raul::Path& path) { for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { - if ((*i)->patch_port()->path() == path) { + if ((*i)->graph_port()->path() == path) { return *i; } } @@ -221,7 +221,7 @@ public: * It is only called on initial load. */ virtual void add_port(ProcessContext& context, EnginePort* port) { - const uint32_t index = port->patch_port()->index(); + const uint32_t index = port->graph_port()->index(); if (_ports.size() <= index) { _ports.resize(index + 1); } @@ -241,8 +241,8 @@ public: virtual void rename_port(const Raul::Path& old_path, const Raul::Path& new_path) {} - virtual EnginePort* create_port(DuplexPort* patch_port) { - return new EnginePort(patch_port); + virtual EnginePort* create_port(DuplexPort* graph_port) { + return new EnginePort(graph_port); } /** Called in run thread for events received at control input port. */ @@ -359,7 +359,7 @@ private: AtomWriter _writer; Raul::RingBuffer _from_ui; Raul::RingBuffer _to_ui; - PatchImpl* _root_patch; + GraphImpl* _root_graph; uint32_t _notify_capacity; SampleCount _block_length; SampleCount _sample_rate; @@ -422,13 +422,13 @@ struct IngenPlugin { char** argv; }; -static Lib::Patches -find_patches(const Glib::ustring& manifest_uri) +static Lib::Graphes +find_graphes(const Glib::ustring& manifest_uri) { Sord::World world; const Sord::URI base(world, manifest_uri); const Sord::Node nil; - const Sord::URI ingen_Patch (world, NS_INGEN "Patch"); + const Sord::URI ingen_Graph (world, NS_INGEN "Graph"); const Sord::URI rdf_type (world, NS_RDF "type"); const Sord::URI rdfs_seeAlso(world, NS_RDFS "seeAlso"); @@ -436,22 +436,22 @@ find_patches(const Glib::ustring& manifest_uri) Sord::Model model(world, manifest_uri); model.load_file(env, SERD_TURTLE, manifest_uri); - Lib::Patches patches; - for (Sord::Iter i = model.find(nil, rdf_type, ingen_Patch); !i.end(); ++i) { - const Sord::Node patch = i.get_subject(); - Sord::Iter f = model.find(patch, rdfs_seeAlso, nil); - const std::string patch_uri = patch.to_c_string(); + Lib::Graphes graphes; + for (Sord::Iter i = model.find(nil, rdf_type, ingen_Graph); !i.end(); ++i) { + const Sord::Node graph = i.get_subject(); + Sord::Iter f = model.find(graph, rdfs_seeAlso, nil); + const std::string graph_uri = graph.to_c_string(); if (!f.end()) { const uint8_t* file_uri = f.get_object().to_u_string(); uint8_t* file_path = serd_file_uri_parse(file_uri, NULL); - patches.push_back(boost::shared_ptr( - new LV2Patch(patch_uri, (const char*)file_path))); + graphes.push_back(boost::shared_ptr( + new LV2Graph(graph_uri, (const char*)file_path))); free(file_path); } } serd_env_free(env); - return patches; + return graphes; } static LV2_Handle @@ -482,19 +482,19 @@ ingen_instantiate(const LV2_Descriptor* descriptor, } set_bundle_path(bundle_path); - Lib::Patches patches = find_patches( + Lib::Graphes graphes = find_graphes( Glib::filename_to_uri(Ingen::bundle_file_path("manifest.ttl"))); - const LV2Patch* patch = NULL; - for (Lib::Patches::iterator i = patches.begin(); i != patches.end(); ++i) { + const LV2Graph* graph = NULL; + for (Lib::Graphes::iterator i = graphes.begin(); i != graphes.end(); ++i) { if ((*i)->uri == descriptor->URI) { - patch = (*i).get(); + graph = (*i).get(); break; } } - if (!patch) { - const std::string msg((Raul::fmt("Could not find patch %1%\n") + if (!graph) { + const std::string msg((Raul::fmt("Could not find graph %1%\n") % descriptor->URI).str()); if (log) { log->vprintf(log->handle, @@ -560,14 +560,14 @@ ingen_instantiate(const LV2_Descriptor* descriptor, plugin->world->parser()->parse_file(plugin->world, plugin->world->interface().get(), - patch->filename); + graph->filename); while (engine->pending_events()) { engine->process_events(); engine->post_processor()->process(); } - /* Register client after loading patch so the to-ui ring does not overflow. + /* Register client after loading graph so the to-ui ring does not overflow. Since we are not yet rolling, it won't be drained, causing a deadlock. */ SharedPtr client(&driver->writer(), NullDeleter); interface->set_respondee(client); @@ -586,7 +586,7 @@ ingen_connect_port(LV2_Handle instance, uint32_t port, void* data) LV2Driver* driver = (LV2Driver*)engine->driver(); if (port < driver->ports().size()) { driver->ports().at(port)->set_buffer(data); - assert(driver->ports().at(port)->patch_port()->index() == port); + assert(driver->ports().at(port)->graph_port()->index() == port); assert(driver->ports().at(port)->buffer() == data); } else { engine->log().error(Raul::fmt("Connect to non-existent port %1%\n") @@ -668,7 +668,7 @@ ingen_save(LV2_Handle instance, LV2_URID atom_Path = plugin->map->map(plugin->map->handle, LV2_ATOM__Path); - char* real_path = make_path->path(make_path->handle, "patch.ttl"); + char* real_path = make_path->path(make_path->handle, "graph.ttl"); char* state_path = map_path->abstract_path(map_path->handle, real_path); Ingen::Store::iterator root = plugin->world->store()->find(Raul::Path("/")); @@ -736,7 +736,7 @@ ingen_extension_data(const char* uri) return NULL; } -LV2Patch::LV2Patch(const std::string& u, const std::string& f) +LV2Graph::LV2Graph(const std::string& u, const std::string& f) : uri(u) , filename(f) { @@ -753,7 +753,7 @@ LV2Patch::LV2Patch(const std::string& u, const std::string& f) Lib::Lib(const char* bundle_path) { Ingen::set_bundle_path(bundle_path); - patches = find_patches( + graphes = find_graphes( Glib::filename_to_uri(Ingen::bundle_file_path("manifest.ttl"))); } @@ -768,7 +768,7 @@ static const LV2_Descriptor* lib_get_plugin(LV2_Lib_Handle handle, uint32_t index) { Lib* lib = (Lib*)handle; - return index < lib->patches.size() ? &lib->patches[index]->descriptor : NULL; + return index < lib->graphes.size() ? &lib->graphes[index]->descriptor : NULL; } /** LV2 plugin library entry point */ diff --git a/src/server/internals/Controller.cpp b/src/server/internals/Controller.cpp index 0e8d125e..f38545d3 100644 --- a/src/server/internals/Controller.cpp +++ b/src/server/internals/Controller.cpp @@ -45,7 +45,7 @@ ControllerNode::ControllerNode(InternalPlugin* plugin, BufferFactory& bufs, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, SampleRate srate) : BlockImpl(plugin, symbol, false, parent, srate) , _learning(false) diff --git a/src/server/internals/Controller.hpp b/src/server/internals/Controller.hpp index 23401826..6cb78397 100644 --- a/src/server/internals/Controller.hpp +++ b/src/server/internals/Controller.hpp @@ -42,7 +42,7 @@ public: BufferFactory& bufs, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, SampleRate srate); void process(ProcessContext& context); diff --git a/src/server/internals/Delay.cpp b/src/server/internals/Delay.cpp index 1e7ed5a5..c528a068 100644 --- a/src/server/internals/Delay.cpp +++ b/src/server/internals/Delay.cpp @@ -25,10 +25,10 @@ #include "Buffer.hpp" #include "Driver.hpp" #include "Engine.hpp" +#include "GraphImpl.hpp" #include "InputPort.hpp" #include "InternalPlugin.hpp" #include "OutputPort.hpp" -#include "PatchImpl.hpp" #include "ProcessContext.hpp" #include "internals/Delay.hpp" #include "util.hpp" @@ -53,7 +53,7 @@ DelayNode::DelayNode(InternalPlugin* plugin, BufferFactory& bufs, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, SampleRate srate) : BlockImpl(plugin, symbol, polyphonic, parent, srate) , _buffer(0) diff --git a/src/server/internals/Delay.hpp b/src/server/internals/Delay.hpp index 8f4b758b..0dc5fb21 100644 --- a/src/server/internals/Delay.hpp +++ b/src/server/internals/Delay.hpp @@ -39,7 +39,7 @@ public: BufferFactory& bufs, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, SampleRate srate); ~DelayNode(); diff --git a/src/server/internals/Note.cpp b/src/server/internals/Note.cpp index 00ab0835..a373d4de 100644 --- a/src/server/internals/Note.cpp +++ b/src/server/internals/Note.cpp @@ -24,10 +24,10 @@ #include "Buffer.hpp" #include "Driver.hpp" +#include "GraphImpl.hpp" #include "InputPort.hpp" #include "InternalPlugin.hpp" #include "OutputPort.hpp" -#include "PatchImpl.hpp" #include "ProcessContext.hpp" #include "ingen_config.h" #include "internals/Note.hpp" @@ -50,7 +50,7 @@ NoteNode::NoteNode(InternalPlugin* plugin, BufferFactory& bufs, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, SampleRate srate) : BlockImpl(plugin, symbol, polyphonic, parent, srate) , _voices(new Raul::Array(_polyphony)) diff --git a/src/server/internals/Note.hpp b/src/server/internals/Note.hpp index 290908e8..dbdc59e7 100644 --- a/src/server/internals/Note.hpp +++ b/src/server/internals/Note.hpp @@ -42,7 +42,7 @@ public: BufferFactory& bufs, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, SampleRate srate); ~NoteNode(); diff --git a/src/server/internals/Trigger.cpp b/src/server/internals/Trigger.cpp index 31943425..2c353636 100644 --- a/src/server/internals/Trigger.cpp +++ b/src/server/internals/Trigger.cpp @@ -45,7 +45,7 @@ TriggerNode::TriggerNode(InternalPlugin* plugin, BufferFactory& bufs, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, SampleRate srate) : BlockImpl(plugin, symbol, false, parent, srate) , _learning(false) diff --git a/src/server/internals/Trigger.hpp b/src/server/internals/Trigger.hpp index 750cd287..b9ae4849 100644 --- a/src/server/internals/Trigger.hpp +++ b/src/server/internals/Trigger.hpp @@ -45,7 +45,7 @@ public: BufferFactory& bufs, const Raul::Symbol& symbol, bool polyphonic, - PatchImpl* parent, + GraphImpl* parent, SampleRate srate); void process(ProcessContext& context); diff --git a/src/server/wscript b/src/server/wscript index 9664545a..b6ec6e98 100644 --- a/src/server/wscript +++ b/src/server/wscript @@ -14,6 +14,7 @@ def build(bld): EdgeImpl.cpp Engine.cpp EventWriter.cpp + GraphImpl.cpp GraphObjectImpl.cpp InputPort.cpp InternalPlugin.cpp @@ -21,14 +22,13 @@ def build(bld): LV2Info.cpp LV2Plugin.cpp OutputPort.cpp - PatchImpl.cpp PortImpl.cpp PostProcessor.cpp PreProcessor.cpp Worker.cpp events/Connect.cpp events/CreateBlock.cpp - events/CreatePatch.cpp + events/CreateGraph.cpp events/CreatePort.cpp events/Delete.cpp events/Delta.cpp -- cgit v1.2.1