aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2017-03-09 08:33:21 +0100
committerDavid Robillard <d@drobilla.net>2017-03-09 08:33:21 +0100
commit83d366452af8e93f0722658d730528d699f21e2b (patch)
treedb66b0653d57ca2e2939a1352b3d45aeada4689e
parente360392489fe62dbae1f0c28b7f5fb839851f5f6 (diff)
downloadingen-groups.tar.gz
ingen-groups.tar.bz2
ingen-groups.zip
Preliminary port groups workgroups
-rw-r--r--ingen/Node.hpp3
-rw-r--r--ingen/Resource.hpp3
-rw-r--r--ingen/URIs.hpp8
-rw-r--r--ingen/client/BlockModel.hpp5
-rw-r--r--src/Resource.cpp13
-rw-r--r--src/URIs.cpp9
-rw-r--r--src/client/ClientStore.cpp10
-rw-r--r--src/client/GraphModel.cpp10
-rw-r--r--src/gui/GraphCanvas.cpp185
-rw-r--r--src/gui/GraphCanvas.hpp10
-rw-r--r--src/gui/GraphPortModule.cpp90
-rw-r--r--src/gui/GraphPortModule.hpp26
-rw-r--r--src/gui/ingen_gui.ui14
-rw-r--r--src/server/events/Delta.cpp15
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);
}
}