summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2014-01-07 04:53:47 +0000
committerDavid Robillard <d@drobilla.net>2014-01-07 04:53:47 +0000
commit2aa1cf33b26c76b024913d1994066c627075bbbd (patch)
tree3b9f05646e069345792ff214bf91ef57eab4927b
parentd30907023903bc7b4a2de16d3fe5d7674861e394 (diff)
downloadingen-2aa1cf33b26c76b024913d1994066c627075bbbd.tar.gz
ingen-2aa1cf33b26c76b024913d1994066c627075bbbd.tar.bz2
ingen-2aa1cf33b26c76b024913d1994066c627075bbbd.zip
Factor out plugin menu code into a separate class.
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@5297 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--src/gui/GraphCanvas.cpp166
-rw-r--r--src/gui/GraphCanvas.hpp32
-rw-r--r--src/gui/PluginMenu.cpp163
-rw-r--r--src/gui/PluginMenu.hpp79
-rw-r--r--src/gui/wscript1
5 files changed, 265 insertions, 176 deletions
diff --git a/src/gui/GraphCanvas.cpp b/src/gui/GraphCanvas.cpp
index 2ecbec80..bb7c968c 100644
--- a/src/gui/GraphCanvas.cpp
+++ b/src/gui/GraphCanvas.cpp
@@ -44,6 +44,7 @@
#include "LoadPluginWindow.hpp"
#include "NewSubgraphWindow.hpp"
#include "NodeModule.hpp"
+#include "PluginMenu.hpp"
#include "Port.hpp"
#include "SubgraphModule.hpp"
#include "ThreadedLoader.hpp"
@@ -71,7 +72,6 @@ GraphCanvas::GraphCanvas(App& app,
, _paste_count(0)
, _menu(NULL)
, _internal_menu(NULL)
- , _classless_menu(NULL)
, _plugin_menu(NULL)
, _human_names(true)
, _show_port_names(true)
@@ -191,111 +191,24 @@ GraphCanvas::build_menus()
}
// 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
- SPtr<const ClientStore::Plugins> plugins = _app.store()->plugins();
- for (const auto& p : *plugins.get())
- add_plugin(p.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<const char*>& 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<LV2Children::const_iterator, LV2Children::const_iterator> 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(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(
- std::string("_") + 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 {
+ if (!_plugin_menu) {
+ _plugin_menu = Gtk::manage(new PluginMenu(*_app.world()));
_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);
+ _plugin_menu->signal_load_plugin.connect(
+ sigc::mem_fun(this, &GraphCanvas::load_plugin));
}
- 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));
+ // Add known plugins to menu heirarchy
+ SPtr<const ClientStore::Plugins> plugins = _app.store()->plugins();
+ for (const auto& p : *plugins.get()) {
+ add_plugin(p.second);
}
- std::set<const char*> ancestors;
- build_plugin_class_menu(_plugin_menu, lv2_plugin, classes, children, ancestors);
}
void
@@ -351,61 +264,15 @@ GraphCanvas::show_port_names(bool b)
}
void
-GraphCanvas::add_plugin_to_menu(Gtk::Menu* menu, SPtr<PluginModel> p)
-{
- bool is_graph = false;
- if (p->lilv_plugin()) {
- const URIs& uris = _app.uris();
- LilvWorld* lworld = _app.world()->lilv_world();
- LilvNode* ingen_Graph = lilv_new_uri(lworld, uris.ingen_Graph.c_str());
- LilvNode* rdf_type = lilv_new_uri(lworld, uris.rdf_type.c_str());
-
- is_graph = lilv_world_ask(_app.world()->lilv_world(),
- lilv_plugin_get_uri(p->lilv_plugin()),
- rdf_type,
- ingen_Graph);
-
- lilv_node_free(rdf_type);
- lilv_node_free(ingen_Graph);
- }
-
- menu->items().push_back(
- Gtk::Menu_Helpers::MenuElem(
- std::string("_") + p->human_name() + (is_graph ? " ⚙" : ""),
- sigc::bind(sigc::mem_fun(this, &GraphCanvas::load_plugin), p)));
-
- if (!menu->is_visible()) {
- menu->show();
- }
-}
-
-void
GraphCanvas::add_plugin(SPtr<PluginModel> p)
{
- typedef ClassMenus::iterator iterator;
if (_internal_menu && p->type() == Plugin::Internal) {
- add_plugin_to_menu(_internal_menu, 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);
-
- pair<iterator, iterator> range = _class_menus.equal_range(class_uri_str);
- if (range.first == _class_menus.end() || range.first == range.second
- || range.first->second.menu == _plugin_menu) {
- // Add to uncategorized plugin menu
- add_plugin_to_menu(_classless_menu, p);
- } else {
- // For each menu that represents plugin's class (possibly several)
- for (iterator i = range.first; i != range.second ; ++i) {
- add_plugin_to_menu(i->second.menu, p);
- }
- }
+ _internal_menu->items().push_back(
+ Gtk::Menu_Helpers::MenuElem(
+ std::string("_") + p->human_name(),
+ sigc::bind(sigc::mem_fun(this, &GraphCanvas::load_plugin), p)));
+ } else if (_plugin_menu) {
+ _plugin_menu->add_plugin(p);
}
}
@@ -898,8 +765,7 @@ GraphCanvas::get_initial_data(Resource::Graph ctx)
void
GraphCanvas::menu_load_plugin()
{
- _app.window_factory()->present_load_plugin(
- _graph, get_initial_data());
+ _app.window_factory()->present_load_plugin(_graph, get_initial_data());
}
void
diff --git a/src/gui/GraphCanvas.hpp b/src/gui/GraphCanvas.hpp
index 6592106b..47d267d2 100644
--- a/src/gui/GraphCanvas.hpp
+++ b/src/gui/GraphCanvas.hpp
@@ -39,6 +39,7 @@ namespace Client { class GraphModel; }
namespace GUI {
class NodeModule;
+class PluginMenu;
/** Graph canvas widget.
*
@@ -86,9 +87,10 @@ private:
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_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();
@@ -98,21 +100,10 @@ private:
void build_menus();
- void build_internal_menu();
- void build_classless_menu();
- void add_plugin_to_menu(Gtk::Menu* menu, SPtr<Client::PluginModel> p);
-
void auto_menu_position(int& x, int& y, bool& push_in);
typedef std::multimap<const std::string, const LilvPluginClass*> 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<const char*>& ancestors);
-
Node::Properties get_initial_data(Resource::Graph ctx=Resource::Graph::DEFAULT);
Ganv::Port* get_port_view(SPtr<Client::PortModel> port);
@@ -139,20 +130,9 @@ private:
// Track pasted objects so they can be selected when they arrive
std::set<Raul::Path> _pastees;
- struct MenuRecord {
- MenuRecord(Gtk::MenuItem* i, Gtk::Menu* m) : item(i), menu(m) {}
- Gtk::MenuItem* item;
- Gtk::Menu* menu;
- };
-
- typedef std::multimap<const std::string, MenuRecord> ClassMenus;
-
- ClassMenus _class_menus;
-
Gtk::Menu* _menu;
Gtk::Menu* _internal_menu;
- Gtk::Menu* _classless_menu;
- Gtk::Menu* _plugin_menu;
+ PluginMenu* _plugin_menu;
Gtk::MenuItem* _menu_add_audio_input;
Gtk::MenuItem* _menu_add_audio_output;
Gtk::MenuItem* _menu_add_control_input;
diff --git a/src/gui/PluginMenu.cpp b/src/gui/PluginMenu.cpp
new file mode 100644
index 00000000..65dac0a1
--- /dev/null
+++ b/src/gui/PluginMenu.cpp
@@ -0,0 +1,163 @@
+/*
+ This file is part of Ingen.
+ Copyright 2014 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
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "PluginMenu.hpp"
+#include "ingen/Log.hpp"
+#include "ingen/client/PluginModel.hpp"
+
+namespace Ingen {
+namespace GUI {
+
+PluginMenu::PluginMenu(Ingen::World& world)
+ : _world(world)
+ , _classless_menu(NULL, NULL)
+{
+ const LilvWorld* lworld = _world.lilv_world();
+ const LilvPluginClass* lv2_plugin = lilv_world_get_plugin_class(lworld);
+ const LilvPluginClasses* classes = lilv_world_get_plugin_classes(lworld);
+
+ 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(std::make_pair(lilv_node_as_string(p), c));
+ }
+
+ std::set<const char*> ancestors;
+ build_plugin_class_menu(this, lv2_plugin, classes, children, ancestors);
+
+ items().push_back(Gtk::Menu_Helpers::MenuElem("_Uncategorized"));
+ _classless_menu.item = &(items().back());
+ _classless_menu.menu = new Gtk::Menu();
+ _classless_menu.item->set_submenu(*_classless_menu.menu);
+ _classless_menu.item->hide();
+}
+
+void
+PluginMenu::add_plugin(SPtr<Client::PluginModel> p)
+{
+ typedef ClassMenus::iterator iterator;
+
+ if (!p->lilv_plugin() || lilv_plugin_is_replaced(p->lilv_plugin())) {
+ 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);
+
+ std::pair<iterator, iterator> range = _class_menus.equal_range(class_uri_str);
+ if (range.first == _class_menus.end() || range.first == range.second
+ || range.first->second.menu == this) {
+ // Add to uncategorized plugin menu
+ add_plugin_to_menu(_classless_menu, p);
+ } else {
+ // For each menu that represents plugin's class (possibly several)
+ for (iterator i = range.first; i != range.second ; ++i) {
+ add_plugin_to_menu(i->second, p);
+ }
+ }
+}
+
+size_t
+PluginMenu::build_plugin_class_menu(Gtk::Menu* menu,
+ const LilvPluginClass* plugin_class,
+ const LilvPluginClasses* classes,
+ const LV2Children& children,
+ std::set<const char*>& 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<LV2Children::const_iterator, LV2Children::const_iterator> 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()) {
+ _world.log().warn(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(
+ std::string("_") + sub_label_str);
+ menu->items().push_back(menu_elem);
+ Gtk::MenuItem* menu_item = &(menu->items().back());
+
+ Gtk::Menu* submenu = 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(std::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
+PluginMenu::add_plugin_to_menu(MenuRecord& menu, SPtr<Client::PluginModel> p)
+{
+ const URIs& uris = _world.uris();
+ LilvWorld* lworld = _world.lilv_world();
+ LilvNode* ingen_Graph = lilv_new_uri(lworld, uris.ingen_Graph.c_str());
+ LilvNode* rdf_type = lilv_new_uri(lworld, uris.rdf_type.c_str());
+
+ bool is_graph = lilv_world_ask(lworld,
+ lilv_plugin_get_uri(p->lilv_plugin()),
+ rdf_type,
+ ingen_Graph);
+
+ menu.menu->items().push_back(
+ Gtk::Menu_Helpers::MenuElem(
+ std::string("_") + p->human_name() + (is_graph ? " ⚙" : ""),
+ sigc::bind(sigc::mem_fun(this, &PluginMenu::load_plugin), p)));
+
+ if (!menu.item->is_visible()) {
+ menu.item->show();
+ }
+
+ lilv_node_free(rdf_type);
+ lilv_node_free(ingen_Graph);
+}
+
+void
+PluginMenu::load_plugin(WPtr<Client::PluginModel> weak_plugin)
+{
+ signal_load_plugin.emit(weak_plugin);
+}
+
+} // namespace GUI
+} // namespace Ingen
diff --git a/src/gui/PluginMenu.hpp b/src/gui/PluginMenu.hpp
new file mode 100644
index 00000000..54624104
--- /dev/null
+++ b/src/gui/PluginMenu.hpp
@@ -0,0 +1,79 @@
+/*
+ This file is part of Ingen.
+ Copyright 2014 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
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_GUI_PLUGINMENU_HPP
+#define INGEN_GUI_PLUGINMENU_HPP
+
+#include <map>
+#include <set>
+#include <string>
+
+#include <gtkmm/menu.h>
+
+#include "ingen/World.hpp"
+#include "ingen/types.hpp"
+#include "lilv/lilv.h"
+
+namespace Ingen {
+
+namespace Client { class PluginModel; }
+
+namespace GUI {
+
+/**
+ Type-hierarchical plugin menu.
+
+ @ingroup GUI
+*/
+class PluginMenu : public Gtk::Menu
+{
+public:
+ PluginMenu(Ingen::World& world);
+
+ void add_plugin(SPtr<Client::PluginModel> p);
+
+ sigc::signal< void, WPtr<Client::PluginModel> > signal_load_plugin;
+
+private:
+ struct MenuRecord {
+ MenuRecord(Gtk::MenuItem* i, Gtk::Menu* m) : item(i), menu(m) {}
+ Gtk::MenuItem* item;
+ Gtk::Menu* menu;
+ };
+
+ typedef std::multimap<const std::string, const LilvPluginClass*> LV2Children;
+ typedef std::multimap<const std::string, MenuRecord> ClassMenus;
+
+ /// Recursively add hierarchy rooted at @a plugin_class to @a menu.
+ size_t build_plugin_class_menu(Gtk::Menu* menu,
+ const LilvPluginClass* plugin_class,
+ const LilvPluginClasses* classes,
+ const LV2Children& children,
+ std::set<const char*>& ancestors);
+
+ void add_plugin_to_menu(MenuRecord& menu, SPtr<Client::PluginModel> p);
+
+ void load_plugin(WPtr<Client::PluginModel> weak_plugin);
+
+ Ingen::World& _world;
+ MenuRecord _classless_menu;
+ ClassMenus _class_menus;
+};
+
+} // namespace GUI
+} // namespace Ingen
+
+#endif // INGEN_GUI_PLUGINMENU_HPP
diff --git a/src/gui/wscript b/src/gui/wscript
index 982c93d8..62731abe 100644
--- a/src/gui/wscript
+++ b/src/gui/wscript
@@ -44,6 +44,7 @@ def build(bld):
NodeMenu.cpp
NodeModule.cpp
ObjectMenu.cpp
+ PluginMenu.cpp
Port.cpp
PortMenu.cpp
PortPropertiesWindow.cpp