153 lines
4.8 KiB
C++
153 lines
4.8 KiB
C++
#include "pluginregistry.h"
|
||
using namespace Xybrid::Config;
|
||
|
||
#include <list>
|
||
#include <map>
|
||
#include <unordered_map>
|
||
|
||
#include <QMenu>
|
||
#include <QHash>
|
||
|
||
#include "data/graph.h"
|
||
using namespace Xybrid::Data;
|
||
|
||
#include "nodes/gadget/ioport.h"
|
||
using Xybrid::Gadgets::IOPort;
|
||
|
||
#include "util/strings.h"
|
||
|
||
namespace { // clazy:excludeall=non-pod-global-static
|
||
typedef std::list<std::function<void()>> fqueue; // typedef so QtCreator's auto indent doesn't completely break :|
|
||
fqueue& regQueue() {
|
||
static fqueue q;
|
||
return q;
|
||
}
|
||
bool& initialized() { static bool b = false; return b; }
|
||
|
||
QHash<QString, std::shared_ptr<PluginInfo>> plugins;
|
||
|
||
QString priorityCategories[] {
|
||
"Gadget", "Effect", "Instrument", "Sampler"
|
||
};
|
||
}
|
||
|
||
std::shared_ptr<PluginInfo> PluginRegistry::enqueueRegistration(std::function<void ()> f) {
|
||
auto& queue = regQueue();
|
||
queue.push_back(f);
|
||
if (initialized()) f();
|
||
return nullptr;
|
||
}
|
||
|
||
void PluginRegistry::init() {
|
||
if (initialized()) return;
|
||
|
||
for (auto& f : regQueue()) f();
|
||
initialized() = true;
|
||
}
|
||
|
||
void PluginRegistry::registerPlugin(std::shared_ptr<PluginInfo> pi) {
|
||
if (pi->id.isEmpty()) return;
|
||
if (plugins.find(pi->id) != plugins.end()) return;
|
||
plugins[pi->id] = pi;
|
||
// there might be a better way to do this?
|
||
for (auto& id : pi->oldIds) plugins[id] = pi;
|
||
}
|
||
|
||
std::shared_ptr<Node> PluginRegistry::createInstance(const QString& id) {
|
||
auto f = plugins.find(id);
|
||
if (f == plugins.end()) return nullptr;
|
||
auto n = f.value()->createInstance();
|
||
n->plugin = f.value();
|
||
n->init();
|
||
return n;
|
||
}
|
||
|
||
void PluginRegistry::populatePluginMenu(QMenu* m, std::function<void (std::shared_ptr<Node>)> f, Graph* g) {
|
||
std::map<QString, std::map<QString, std::shared_ptr<PluginInfo>>> cm; // category map
|
||
cm.try_emplace(""); // force empty category
|
||
for (auto& i : qAsConst(plugins)) {
|
||
if (i->hidden) continue;
|
||
cm.try_emplace(i->category);
|
||
cm[i->category][i->displayName] = i;
|
||
}
|
||
|
||
// I/O ports
|
||
if (g) {
|
||
auto* mio = m->addMenu("I/O Port");
|
||
//auto* mi = mio->addMenu("Input");
|
||
//auto* mo = mio->addMenu("Output");
|
||
Port::DataType d[] {Port::Command, Port::Audio};
|
||
|
||
for (auto dt : d) {
|
||
auto* mi = mio->addMenu(qs("&%1 In").arg(Util::enumName(dt)));
|
||
auto* mo = mio->addMenu(qs("&%1 Out").arg(Util::enumName(dt)));
|
||
//mi->setStyleSheet("QMenu { menu-scrollable: 1; }");
|
||
//mi->setFixedHeight(256);
|
||
|
||
for (int ih = 0; ih < 16; ih++) {
|
||
QString n = QString::number(ih, 16).toUpper();
|
||
auto* mis = mi->addMenu(qs("%10-%1F").arg(n));
|
||
auto* mos = mo->addMenu(qs("%10-%1F").arg(n));
|
||
for (int il = 0; il < 16; il++) {
|
||
int i = ih*16+il;
|
||
QString nn = Util::hex(i);
|
||
mis->addAction(nn, m, [f, dt, i] {
|
||
auto n = std::static_pointer_cast<IOPort>(createInstance("ioport"));
|
||
n->setPort(Port::Input, dt, static_cast<uint8_t>(i));
|
||
f(n);
|
||
})->setEnabled(!g->port(Port::Input, dt, static_cast<uint8_t>(i)));
|
||
mos->addAction(nn, m, [f, dt, i] {
|
||
auto n = std::static_pointer_cast<IOPort>(createInstance("ioport"));
|
||
n->setPort(Port::Output, dt, static_cast<uint8_t>(i));
|
||
f(n);
|
||
})->setEnabled(!g->port(Port::Output, dt, static_cast<uint8_t>(i)));
|
||
}
|
||
|
||
}
|
||
//
|
||
}
|
||
|
||
m->addSeparator();
|
||
}
|
||
|
||
// populate priorities into menu
|
||
for (auto& pc : priorityCategories) {
|
||
if (auto c = cm.find(pc); c != cm.end()) {
|
||
auto* ccm = m->addMenu(c->first);
|
||
for (auto& i : c->second) {
|
||
ccm->addAction(i.second->displayName, m, [f, pi = i.second] {
|
||
auto n = pi->createInstance();
|
||
n->plugin = pi;
|
||
n->init();
|
||
f(n);
|
||
});
|
||
}
|
||
cm.erase(pc);
|
||
}
|
||
}
|
||
|
||
// then any other category
|
||
for (auto& c : cm) {
|
||
if (c.first.isEmpty() || c.second.empty()) continue;
|
||
auto* ccm = m->addMenu(c.first);
|
||
for (auto& i : c.second) {
|
||
ccm->addAction(i.second->displayName, m, [f, pi = i.second] {
|
||
auto n = pi->createInstance();
|
||
n->plugin = pi;
|
||
n->init();
|
||
f(n);
|
||
});
|
||
}
|
||
}
|
||
|
||
m->addSeparator();
|
||
|
||
for (auto& i : cm[""]) m->addAction(i.second->displayName, m, [f, pi = i.second] {
|
||
auto n = pi->createInstance();
|
||
n->plugin = pi;
|
||
n->init();
|
||
f(n);
|
||
});
|
||
|
||
}
|