diff options
author | David Robillard <d@drobilla.net> | 2017-03-09 08:33:21 +0100 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2017-03-09 08:33:21 +0100 |
commit | 83d366452af8e93f0722658d730528d699f21e2b (patch) | |
tree | db66b0653d57ca2e2939a1352b3d45aeada4689e | |
parent | e360392489fe62dbae1f0c28b7f5fb839851f5f6 (diff) | |
download | ingen-83d366452af8e93f0722658d730528d699f21e2b.tar.gz ingen-83d366452af8e93f0722658d730528d699f21e2b.tar.bz2 ingen-83d366452af8e93f0722658d730528d699f21e2b.zip |
Preliminary port groups workgroups
-rw-r--r-- | ingen/Node.hpp | 3 | ||||
-rw-r--r-- | ingen/Resource.hpp | 3 | ||||
-rw-r--r-- | ingen/URIs.hpp | 8 | ||||
-rw-r--r-- | ingen/client/BlockModel.hpp | 5 | ||||
-rw-r--r-- | src/Resource.cpp | 13 | ||||
-rw-r--r-- | src/URIs.cpp | 9 | ||||
-rw-r--r-- | src/client/ClientStore.cpp | 10 | ||||
-rw-r--r-- | src/client/GraphModel.cpp | 10 | ||||
-rw-r--r-- | src/gui/GraphCanvas.cpp | 185 | ||||
-rw-r--r-- | src/gui/GraphCanvas.hpp | 10 | ||||
-rw-r--r-- | src/gui/GraphPortModule.cpp | 90 | ||||
-rw-r--r-- | src/gui/GraphPortModule.hpp | 26 | ||||
-rw-r--r-- | src/gui/ingen_gui.ui | 14 | ||||
-rw-r--r-- | src/server/events/Delta.cpp | 15 |
14 files changed, 327 insertions, 74 deletions
diff --git a/ingen/Node.hpp b/ingen/Node.hpp index a585d03a..066c5d17 100644 --- a/ingen/Node.hpp +++ b/ingen/Node.hpp @@ -53,7 +53,8 @@ public: enum class GraphType { GRAPH, BLOCK, - PORT + PORT, + GROUP }; typedef std::pair<const Node*, const Node*> ArcsKey; diff --git a/ingen/Resource.hpp b/ingen/Resource.hpp index 3eb1349f..1ffa571e 100644 --- a/ingen/Resource.hpp +++ b/ingen/Resource.hpp @@ -187,7 +187,8 @@ public: bool& graph, bool& block, bool& port, - bool& is_output); + bool& is_output, + bool& is_group); virtual void set_uri(const Raul::URI& uri) { _uri = uri; } diff --git a/ingen/URIs.hpp b/ingen/URIs.hpp index 44f1056e..8bd3eca4 100644 --- a/ingen/URIs.hpp +++ b/ingen/URIs.hpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2016 David Robillard <http://drobilla.net/> + Copyright 2007-2017 David Robillard <http://drobilla.net/> 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 @@ -194,6 +194,11 @@ public: const Quark patch_subject; const Quark patch_value; const Quark patch_wildcard; + const Quark pg_DiscreteGroup; + const Quark pg_InputGroup; + const Quark pg_OutputGroup; + const Quark pg_element; + const Quark pg_group; const Quark pprops_logarithmic; const Quark pset_Preset; const Quark pset_preset; @@ -201,6 +206,7 @@ public: const Quark rdfs_Class; const Quark rdfs_label; const Quark rdfs_seeAlso; + const Quark rdfs_subClassOf; const Quark rsz_minimumSize; const Quark state_loadDefaultState; const Quark state_state; diff --git a/ingen/client/BlockModel.hpp b/ingen/client/BlockModel.hpp index e689414c..bd8b336a 100644 --- a/ingen/client/BlockModel.hpp +++ b/ingen/client/BlockModel.hpp @@ -36,8 +36,9 @@ class URIs; namespace Client { -class PluginModel; class ClientStore; +class GroupModel; +class PluginModel; /** Block model class, used by the client to store engine's state. * @@ -81,6 +82,8 @@ public: // Signals INGEN_SIGNAL(new_port, void, SPtr<const PortModel>); INGEN_SIGNAL(removed_port, void, SPtr<const PortModel>); + INGEN_SIGNAL(new_group, void, SPtr<const GroupModel>); + INGEN_SIGNAL(removed_group, void, SPtr<const GroupModel>); protected: friend class ClientStore; diff --git a/src/Resource.cpp b/src/Resource.cpp index 623f601a..a9b9514a 100644 --- a/src/Resource.cpp +++ b/src/Resource.cpp @@ -152,12 +152,13 @@ Resource::type(const URIs& uris, bool& graph, bool& block, bool& port, - bool& is_output) + bool& is_output, + bool& group) { typedef Properties::const_iterator iterator; const std::pair<iterator, iterator> types_range = properties.equal_range(uris.rdf_type); - graph = block = port = is_output = false; + graph = block = port = is_output = group = false; for (iterator i = types_range.first; i != types_range.second; ++i) { const Atom& atom = i->second; if (atom.type() != uris.forge.URI && atom.type() != uris.forge.URID) { @@ -174,6 +175,12 @@ Resource::type(const URIs& uris, } else if (uris.lv2_OutputPort == atom) { port = true; is_output = true; + } else if (uris.pg_InputGroup == atom) { + group = true; + is_output = false; + } else if (uris.pg_OutputGroup == atom) { + group = true; + is_output = true; } } @@ -183,7 +190,7 @@ Resource::type(const URIs& uris, } else if (port && (graph || block)) { // nonsense port = false; return false; - } else if (graph || block || port) { // recognized type + } else if (graph || block || port || group) { // recognized type return true; } else { // unknown return false; diff --git a/src/URIs.cpp b/src/URIs.cpp index 1c0a6b23..28ca614a 100644 --- a/src/URIs.cpp +++ b/src/URIs.cpp @@ -1,6 +1,6 @@ /* This file is part of Ingen. - Copyright 2007-2016 David Robillard <http://drobilla.net/> + Copyright 2007-2017 David Robillard <http://drobilla.net/> 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 @@ -25,6 +25,7 @@ #include "lv2/lv2plug.in/ns/ext/options/options.h" #include "lv2/lv2plug.in/ns/ext/parameters/parameters.h" #include "lv2/lv2plug.in/ns/ext/patch/patch.h" +#include "lv2/lv2plug.in/ns/ext/port-groups/port-groups.h" #include "lv2/lv2plug.in/ns/ext/port-props/port-props.h" #include "lv2/lv2plug.in/ns/ext/presets/presets.h" #include "lv2/lv2plug.in/ns/ext/resize-port/resize-port.h" @@ -177,6 +178,11 @@ URIs::URIs(Forge& f, URIMap* map, LilvWorld* lworld) , patch_subject (forge, map, lworld, LV2_PATCH__subject) , patch_value (forge, map, lworld, LV2_PATCH__value) , patch_wildcard (forge, map, lworld, LV2_PATCH__wildcard) + , pg_DiscreteGroup (forge, map, lworld, LV2_PORT_GROUPS__DiscreteGroup) + , pg_InputGroup (forge, map, lworld, LV2_PORT_GROUPS__InputGroup) + , pg_OutputGroup (forge, map, lworld, LV2_PORT_GROUPS__OutputGroup) + , pg_element (forge, map, lworld, LV2_PORT_GROUPS__element) + , pg_group (forge, map, lworld, LV2_PORT_GROUPS__group) , pprops_logarithmic (forge, map, lworld, LV2_PORT_PROPS__logarithmic) , pset_Preset (forge, map, lworld, LV2_PRESETS__Preset) , pset_preset (forge, map, lworld, LV2_PRESETS__preset) @@ -184,6 +190,7 @@ URIs::URIs(Forge& f, URIMap* map, LilvWorld* lworld) , rdfs_Class (forge, map, lworld, NS_RDFS "Class") , rdfs_label (forge, map, lworld, NS_RDFS "label") , rdfs_seeAlso (forge, map, lworld, NS_RDFS "seeAlso") + , rdfs_subClassOf (forge, map, lworld, NS_RDFS "subClassOf") , rsz_minimumSize (forge, map, lworld, LV2_RESIZE_PORT__minimumSize) , state_loadDefaultState(forge, map, lworld, LV2_STATE__loadDefaultState) , state_state (forge, map, lworld, LV2_STATE__state) diff --git a/src/client/ClientStore.cpp b/src/client/ClientStore.cpp index eac853f7..92b6eab1 100644 --- a/src/client/ClientStore.cpp +++ b/src/client/ClientStore.cpp @@ -19,6 +19,7 @@ #include "ingen/client/BlockModel.hpp" #include "ingen/client/ClientStore.hpp" #include "ingen/client/GraphModel.hpp" +#include "ingen/client/GroupModel.hpp" #include "ingen/client/ObjectModel.hpp" #include "ingen/client/PluginModel.hpp" #include "ingen/client/PortModel.hpp" @@ -243,9 +244,9 @@ ClientStore::put(const Raul::URI& uri, { typedef Properties::const_iterator Iterator; - bool is_graph, is_block, is_port, is_output; + bool is_graph, is_block, is_port, is_output, is_group; Resource::type(uris(), properties, - is_graph, is_block, is_port, is_output); + is_graph, is_block, is_port, is_output, is_group); // Check for specially handled types const Iterator t = properties.find(_uris.rdf_type); @@ -334,6 +335,11 @@ ClientStore::put(const Raul::URI& uri, SPtr<PortModel> p(new PortModel(uris(), path, index, pdir)); p->set_properties(properties); add_object(p); + } else if (is_group) { + _log.warn(fmt("Group! %1%\n") % path.c_str()); + SPtr<GroupModel> g(new GroupModel(uris(), path)); + g->set_properties(properties); + add_object(g); } else { _log.warn(fmt("Ignoring %1% of unknown type\n") % path.c_str()); } diff --git a/src/client/GraphModel.cpp b/src/client/GraphModel.cpp index d02a3736..8cfd08e1 100644 --- a/src/client/GraphModel.cpp +++ b/src/client/GraphModel.cpp @@ -21,6 +21,7 @@ #include "ingen/client/BlockModel.hpp" #include "ingen/client/ClientStore.hpp" #include "ingen/client/GraphModel.hpp" +#include "ingen/client/GroupModel.hpp" using namespace std; @@ -38,6 +39,15 @@ GraphModel::add_child(SPtr<ObjectModel> c) return; } + SPtr<GroupModel> gm = dynamic_ptr_cast<GroupModel>(c); + if (gm) { + fprintf(stderr, "GROUP!!!!!!!!!!!\n"); + _signal_new_group.emit(gm); + // add_group(gm); + return; + } + + SPtr<BlockModel> bm = dynamic_ptr_cast<BlockModel>(c); if (bm) { _signal_new_block.emit(bm); diff --git a/src/gui/GraphCanvas.cpp b/src/gui/GraphCanvas.cpp index 6d22f407..1a07f0c6 100644 --- a/src/gui/GraphCanvas.cpp +++ b/src/gui/GraphCanvas.cpp @@ -16,6 +16,7 @@ #include <algorithm> #include <cassert> +#include <iterator> #include <map> #include <set> #include <string> @@ -34,6 +35,7 @@ #include "ingen/client/BlockModel.hpp" #include "ingen/client/ClientStore.hpp" #include "ingen/client/GraphModel.hpp" +#include "ingen/client/GroupModel.hpp" #include "ingen/client/PluginModel.hpp" #include "ingen/ingen.h" #include "lv2/lv2plug.in/ns/ext/atom/atom.h" @@ -93,6 +95,7 @@ GraphCanvas::GraphCanvas(App& app, Glib::RefPtr<Gtk::Builder> xml = WidgetFactory::create("canvas_menu"); xml->get_widget("canvas_menu", _menu); + xml->get_widget("canvas_menu_add_group_input", _add_input_group_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_cv_input", _menu_add_cv_input); @@ -109,7 +112,22 @@ GraphCanvas::GraphCanvas(App& app, const URIs& uris = _app.uris(); + LilvNodes* group_types = lilv_world_find_nodes( + app.world()->lilv_world(), NULL, uris.rdfs_subClassOf, uris.pg_DiscreteGroup); + LILV_FOREACH(nodes, t, group_types) { + const LilvNode* gtype = lilv_nodes_get(group_types, t); + _add_input_group_menu->items().push_back( + Gtk::Menu_Helpers::MenuElem(lilv_node_as_string(gtype))); + Gtk::MenuItem* menu_item = &(_add_input_group_menu->items().back()); + menu_item->signal_activate().connect( + sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_group), + "group", "Group", Raul::URI(lilv_node_as_string(gtype)), false)); + } + // Add port menu items + // _menu_add_audio_input->signal_activate().connect( + // sigc::bind(sigc::mem_fun(this, &GraphCanvas::menu_add_group), + // "stereo_in", "Stereo In", uris.pg_StereoGroup, false)); _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)); @@ -147,6 +165,10 @@ GraphCanvas::GraphCanvas(App& app, sigc::mem_fun(this, &GraphCanvas::add_block)); _graph->signal_removed_block().connect( sigc::mem_fun(this, &GraphCanvas::remove_block)); + _graph->signal_new_group().connect( + sigc::mem_fun(this, &GraphCanvas::add_group)); + _graph->signal_removed_group().connect( + sigc::mem_fun(this, &GraphCanvas::remove_group)); _graph->signal_new_port().connect( sigc::mem_fun(this, &GraphCanvas::add_port)); _graph->signal_removed_port().connect( @@ -357,7 +379,21 @@ GraphCanvas::remove_block(SPtr<const BlockModel> bm) void GraphCanvas::add_port(SPtr<const PortModel> pm) { - GraphPortModule* view = GraphPortModule::create(*this, pm); + const Atom& group = pm->get_property(_app.uris().pg_group); + if (group.is_valid()) { + // Port is on a group, add to group module + const Raul::URI group_uri(_app.forge().str(group, false)); + auto gm = _app.store()->object(uri_to_path(group_uri)); + auto g = _views.find(gm); + if (g != _views.end()) { + Port::create(_app, *g->second, pm, true); + return; + } + } + + // Port has no group, add it to anonymous module + GraphPortModule* view = GraphPortModule::create( + *this, SPtr<const GroupModel>(), pm); _views.insert(std::make_pair(pm, view)); view->show(); } @@ -380,6 +416,20 @@ GraphCanvas::remove_port(SPtr<const PortModel> pm) assert(_views.find(pm) == _views.end()); } +void +GraphCanvas::add_group(SPtr<const GroupModel> gm) +{ + GraphPortModule* view = GraphPortModule::create( + *this, gm, SPtr<const PortModel>()); + _views.insert(std::make_pair(gm, view)); + view->show(); +} + +void +GraphCanvas::remove_group(SPtr<const GroupModel> gm) +{ +} + Ganv::Port* GraphCanvas::get_port_view(SPtr<PortModel> port) { @@ -569,12 +619,13 @@ destroy_node(GanvNode* node, void* data) if (node_module) { app->interface()->del(node_module->block()->uri()); } else { - GraphPortModule* port_module = dynamic_cast<GraphPortModule*>(module); - if (port_module && - strcmp(port_module->port()->path().symbol(), "control") && - strcmp(port_module->port()->path().symbol(), "notify")) { - app->interface()->del(port_module->port()->uri()); - } + fprintf(stderr, "FIXME\n"); + // GraphPortModule* port_module = dynamic_cast<GraphPortModule*>(module); + // if (port_module && + // strcmp(port_module->port()->path().symbol(), "control") && + // strcmp(port_module->port()->path().symbol(), "notify")) { + // app->interface()->del(port_module->port()->uri()); + // } } } @@ -614,7 +665,13 @@ serialise_node(GanvNode* node, void* data) } else { GraphPortModule* port_module = dynamic_cast<GraphPortModule*>(module); if (port_module) { - serialiser->serialise(port_module->port()); + for (const auto& p : *port_module) { + if (Port* port = dynamic_cast<Port*>(p)) { + serialiser->serialise(port->model()); + } else { + fprintf(stderr, "ERR\n"); + } + } } } } @@ -786,33 +843,113 @@ GraphCanvas::generate_port_name( } void -GraphCanvas::menu_add_port(const string& sym_base, const string& name_base, - const Raul::URI& type, bool is_output) +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(); + const Raul::Path& path = _graph->path().child(Raul::Symbol(sym)); + const URIs& uris = _app.uris(); + Forge& forge = _app.forge(); + + // Basic port description + Properties props = { + {uris.rdf_type, forge.make_urid(type)}, + {uris.rdf_type, Property(is_output + ? uris.lv2_OutputPort + : uris.lv2_InputPort)}, + {uris.lv2_index, forge.make(int32_t(_graph->num_ports()))}, + {uris.lv2_name, forge.alloc(name.c_str())}}; - Properties props = get_initial_data(Resource::Graph::INTERNAL); - props.insert(make_pair(uris.rdf_type, _app.forge().make_urid(type))); + // Add atom:bufferType for sequence ports if (type == uris.atom_AtomPort) { - props.insert(make_pair(uris.atom_bufferType, - Property(uris.atom_Sequence))); + props.emplace(uris.atom_bufferType, + Property(uris.atom_Sequence)); } - props.insert(make_pair(uris.rdf_type, - Property(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()))); + + // Add initial data for canvas position etc + Properties init = get_initial_data(Resource::Graph::INTERNAL); + props.insert(std::make_move_iterator(init.begin()), + std::make_move_iterator(init.end())); + _app.interface()->put(path_to_uri(path), props); } void +GraphCanvas::menu_add_group(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(); + Forge& forge = _app.forge(); + World* world = _app.world(); + LilvWorld* lworld = world->lilv_world(); + + // Group description + Properties group_props = { + {uris.rdf_type, forge.make_urid(type)}, + {uris.rdf_type, Property(is_output + ? uris.pg_OutputGroup + : uris.pg_InputGroup)}, + {uris.lv2_name, forge.alloc(name.c_str())}}; + + // Add initial data for canvas position etc + Properties init = get_initial_data(Resource::Graph::INTERNAL); + group_props.insert(std::make_move_iterator(init.begin()), + std::make_move_iterator(init.end())); + + // Create a port for each element of this group type + std::map<uint32_t, std::pair<Raul::Path, Properties>> ports; + LilvNode* group = lilv_new_uri(lworld, type.c_str()); + LilvNodes* elements = lilv_world_find_nodes( + lworld, group, uris.pg_element, NULL); + LILV_FOREACH(nodes, e, elements) { + const LilvNode* element = lilv_nodes_get(elements, e); + const LilvNode* index_node = lilv_world_get(lworld, element, uris.lv2_index, NULL); + const LilvNode* designation = lilv_world_get(lworld, element, uris.lv2_designation, NULL); + const LilvNode* label = lilv_world_get(lworld, designation, uris.rdfs_label, NULL); + const char* label_str = lilv_node_as_string(label); + const uint32_t index = _graph->num_ports() + lilv_node_as_int(index_node); + + Properties port_props = { + {uris.rdf_type, forge.make_urid(uris.lv2_AudioPort)}, + {uris.rdf_type, Property(is_output + ? uris.lv2_OutputPort + : uris.lv2_InputPort)}, + {uris.pg_group, forge.make_urid(path_to_uri(path))}, + {uris.lv2_index, forge.make(int32_t(index))}, + {uris.lv2_name, forge.alloc(label_str)}}; + + const Raul::Symbol sym = Raul::Symbol::symbolify(label_str); + ports.insert( + std::make_pair( + index, + std::make_pair(_graph->path().child(sym), port_props))); + + // fprintf(stderr, "Element: %s %s %s %s\n", + // lilv_node_as_string(index), + // lilv_node_as_string(designation), + // lilv_node_as_string(label), + // Raul::Symbol::symbolify(lilv_node_as_string(label)).c_str()); + } + + _app.interface()->bundle_begin(); + _app.interface()->put(path_to_uri(path), group_props); + for (const auto& p : ports) { + _app.interface()->put(path_to_uri(p.second.first), p.second.second); + } + _app.interface()->bundle_end(); +} + +void GraphCanvas::load_plugin(WPtr<PluginModel> weak_plugin) { SPtr<PluginModel> plugin = weak_plugin.lock(); diff --git a/src/gui/GraphCanvas.hpp b/src/gui/GraphCanvas.hpp index c2212426..1865b846 100644 --- a/src/gui/GraphCanvas.hpp +++ b/src/gui/GraphCanvas.hpp @@ -34,7 +34,7 @@ namespace Ingen { -namespace Client { class GraphModel; } +namespace Client { class GraphModel; class GroupModel; } namespace GUI { @@ -68,6 +68,8 @@ public: void remove_block(SPtr<const Client::BlockModel> bm); void add_port(SPtr<const Client::PortModel> pm); void remove_port(SPtr<const Client::PortModel> pm); + void add_group(SPtr<const Client::GroupModel> gm); + void remove_group(SPtr<const Client::GroupModel> gm); void connection(SPtr<const Client::ArcModel> am); void disconnection(SPtr<const Client::ArcModel> am); @@ -93,6 +95,11 @@ private: const Raul::URI& type, bool is_output); + void menu_add_group(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(); @@ -134,6 +141,7 @@ private: Gtk::Menu* _menu; Gtk::Menu* _internal_menu; PluginMenu* _plugin_menu; + Gtk::Menu* _add_input_group_menu; Gtk::MenuItem* _menu_add_audio_input; Gtk::MenuItem* _menu_add_audio_output; Gtk::MenuItem* _menu_add_control_input; diff --git a/src/gui/GraphPortModule.cpp b/src/gui/GraphPortModule.cpp index 7a0ce102..40851b6d 100644 --- a/src/gui/GraphPortModule.cpp +++ b/src/gui/GraphPortModule.cpp @@ -22,6 +22,7 @@ #include "ingen/Interface.hpp" #include "ingen/client/BlockModel.hpp" #include "ingen/client/GraphModel.hpp" +#include "ingen/client/GroupModel.hpp" #include "App.hpp" #include "Style.hpp" @@ -42,46 +43,74 @@ using namespace Client; namespace GUI { -GraphPortModule::GraphPortModule(GraphCanvas& canvas, - SPtr<const Client::PortModel> model) +GraphPortModule::GraphPortModule(GraphCanvas& canvas, + SPtr<const Client::GroupModel> gm, + SPtr<const Client::PortModel> pm) : Ganv::Module(canvas, "", 0, 0, false) // FIXME: coords? - , _model(model) - , _port(NULL) + , _group(gm) { - assert(model); - - assert(dynamic_ptr_cast<const GraphModel>(model->parent())); - - set_stacked(model->polyphonic()); - if (model->is_input() && !model->is_numeric()) { - set_is_source(true); + if (pm) { + set_stacked(pm->polyphonic()); + if (pm->is_input() && !pm->is_numeric()) { + set_is_source(true); + } } - model->signal_property().connect( - sigc::mem_fun(this, &GraphPortModule::property_changed)); + if (gm) { + gm->signal_property().connect( + sigc::mem_fun(this, &GraphPortModule::property_changed)); + } else if (pm) { + pm->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, - SPtr<const PortModel> model) +GraphPortModule::create(GraphCanvas& canvas, + SPtr<const GroupModel> gm, + SPtr<const PortModel> pm) { - GraphPortModule* ret = new GraphPortModule(canvas, model); - Port* port = Port::create(canvas.app(), *ret, model, true); + GraphPortModule* ret = new GraphPortModule(canvas, gm, pm); + + if (pm) { + Port* port = Port::create(canvas.app(), *ret, pm, true); - ret->set_port(port); - if (model->is_numeric()) { - port->show_control(); + if (pm->is_numeric()) { + port->show_control(); + } } - for (const auto& p : model->properties()) + for (const auto& p : ret->model()->properties()) { ret->property_changed(p.first, p.second); + } return ret; } +SPtr<const ObjectModel> +GraphPortModule::model() +{ + if (_group) { + return _group; + } else if (Port* const port = get_port()) { + return port->model(); + } + return SPtr<const ObjectModel>(); +} + +Port* +GraphPortModule::get_port() +{ + if (begin() == end()) { + return nullptr; + } + + return dynamic_cast<Port*>(*begin()); +} + App& GraphPortModule::app() const { @@ -91,12 +120,18 @@ GraphPortModule::app() const bool GraphPortModule::show_menu(GdkEventButton* ev) { - return _port->show_menu(ev); + if (Port* const port = get_port()) { + return port->show_menu(ev); + } + fprintf(stderr, "ERR\n"); + return false; } void GraphPortModule::store_location(double ax, double ay) { + fprintf(stderr, "FIXME\n"); +#if 0 const URIs& uris = app().uris(); const Atom x(app().forge().make(static_cast<float>(ax))); @@ -110,24 +145,29 @@ GraphPortModule::store_location(double ax, double ay) {{uris.ingen_canvasX, Property(x, Property::Graph::INTERNAL)}, {uris.ingen_canvasY, Property(y, Property::Graph::INTERNAL)}}); } +#endif } void GraphPortModule::show_human_names(bool b) { const URIs& uris = app().uris(); - const Atom& name = _model->get_property(uris.lv2_name); + const Atom& name = model()->get_property(uris.lv2_name); if (b && name.type() == uris.forge.String) { set_name(name.ptr<char>()); } else { - set_name(_model->symbol().c_str()); + set_name(model()->symbol().c_str()); } } void GraphPortModule::set_name(const std::string& n) { - _port->set_label(n.c_str()); + if (_group) { + set_label(n.c_str()); + } else if (Port* port = get_port()) { + port->set_label(n.c_str()); + } } void diff --git a/src/gui/GraphPortModule.hpp b/src/gui/GraphPortModule.hpp index 9722e330..5a98df12 100644 --- a/src/gui/GraphPortModule.hpp +++ b/src/gui/GraphPortModule.hpp @@ -26,9 +26,13 @@ namespace Raul { class Atom; } -namespace Ingen { namespace Client { +namespace Ingen { +namespace Client { +class GroupModel; +class ObjectModel; class PortModel; -} } +} +} namespace Ingen { namespace GUI { @@ -47,8 +51,9 @@ class GraphPortModule : public Ganv::Module { public: static GraphPortModule* create( - GraphCanvas& canvas, - SPtr<const Client::PortModel> model); + GraphCanvas& canvas, + SPtr<const Client::GroupModel> gm, + SPtr<const Client::PortModel> pm); App& app() const; @@ -57,21 +62,20 @@ public: void set_name(const std::string& n); - SPtr<const Client::PortModel> port() const { return _model; } - protected: - GraphPortModule(GraphCanvas& canvas, - SPtr<const Client::PortModel> model); + GraphPortModule(GraphCanvas& canvas, + SPtr<const Client::GroupModel> gm, + SPtr<const Client::PortModel> pm); bool show_menu(GdkEventButton* ev); void set_selected(gboolean b); - void set_port(Port* port) { _port = port; } + SPtr<const Client::ObjectModel> model(); + Port* get_port(); void property_changed(const Raul::URI& predicate, const Atom& value); - SPtr<const Client::PortModel> _model; - Port* _port; + SPtr<const Client::GroupModel> _group; }; } // namespace GUI diff --git a/src/gui/ingen_gui.ui b/src/gui/ingen_gui.ui index 9e751064..1339fdec 100644 --- a/src/gui/ingen_gui.ui +++ b/src/gui/ingen_gui.ui @@ -64,6 +64,20 @@ See COPYING file included with this distribution, or http://www.gnu.org/licenses <object class="GtkMenu" id="input1_menu"> <property name="can_focus">False</property> <child> + <object class="GtkImageMenuItem" id="canvas_menu_add_group_input_menuitem"> + <property name="label">_Multi-Channel</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="use_underline">True</property> + <property name="use_stock">False</property> + <child type="submenu"> + <object class="GtkMenu" id="canvas_menu_add_group_input"> + <property name="can_focus">False</property> + </object> + </child> + </object> + </child> + <child> <object class="GtkMenuItem" id="canvas_menu_add_audio_input"> <property name="visible">True</property> <property name="can_focus">False</property> diff --git a/src/server/events/Delta.cpp b/src/server/events/Delta.cpp index 9f4c1da2..fb8b4c20 100644 --- a/src/server/events/Delta.cpp +++ b/src/server/events/Delta.cpp @@ -32,6 +32,7 @@ #include "Delta.hpp" #include "Engine.hpp" #include "GraphImpl.hpp" +#include "GroupImpl.hpp" #include "PluginImpl.hpp" #include "PortImpl.hpp" #include "PortType.hpp" @@ -190,8 +191,8 @@ Delta::pre_process(PreProcessContext& ctx) if (is_graph_object && !_object) { Raul::Path path(uri_to_path(_subject)); - 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); + bool is_graph = false, is_block = false, is_port = false, is_output = false, is_group = false; + Ingen::Resource::type(uris, _properties, is_graph, is_block, is_port, is_output, is_group); if (is_graph) { _create_event = new CreateGraph( @@ -203,14 +204,22 @@ Delta::pre_process(PreProcessContext& ctx) _create_event = new CreatePort( _engine, _request_client, _request_id, _time, path, _properties); + } else if (is_group) { + NodeImpl* const parent = dynamic_cast<NodeImpl*>( + _engine.store()->get(path.parent())); + if (!parent) { + return Event::pre_process_done(Status::PARENT_NOT_FOUND, path.parent()); + } + _object = new GroupImpl(uris, parent, Raul::Symbol(path.symbol())); } + if (_create_event) { if (_create_event->pre_process(ctx)) { _object = _engine.store()->get(path); // Get object for setting } else { return Event::pre_process_done(Status::CREATION_FAILED, _subject); } - } else { + } else if (!is_group) { return Event::pre_process_done(Status::BAD_OBJECT_TYPE, _subject); } } |