152 lines
4.8 KiB
C++
152 lines
4.8 KiB
C++
#include "pluginregistry.h"
|
||
using namespace Xybrid::Config;
|
||
|
||
#include <list>
|
||
#include <map>
|
||
#include <unordered_map>
|
||
|
||
#include <QMenu>
|
||
|
||
#include "data/graph.h"
|
||
using namespace Xybrid::Data;
|
||
|
||
#include "gadgets/ioport.h"
|
||
using Xybrid::Gadgets::IOPort;
|
||
|
||
#include "util/strings.h"
|
||
|
||
namespace {
|
||
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; }
|
||
|
||
std::unordered_map<std::string, std::shared_ptr<PluginInfo>> plugins;
|
||
|
||
std::string priorityCategories[] {
|
||
"Gadget", "Instrument", "Effect"
|
||
};
|
||
}
|
||
|
||
bool PluginRegistry::enqueueRegistration(std::function<void ()> f) {
|
||
auto& queue = regQueue();
|
||
queue.push_back(f);
|
||
if (initialized()) f();
|
||
return true;
|
||
}
|
||
|
||
void PluginRegistry::init() {
|
||
if (initialized()) return;
|
||
|
||
for (auto& f : regQueue()) f();
|
||
initialized() = true;
|
||
}
|
||
|
||
void PluginRegistry::registerPlugin(std::shared_ptr<PluginInfo> pi) {
|
||
if (pi->id.empty()) 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 std::string& id) {
|
||
auto f = plugins.find(id);
|
||
if (f == plugins.end()) return nullptr;
|
||
auto n = f->second->createInstance();
|
||
n->plugin = f->second;
|
||
n->init();
|
||
return n;
|
||
}
|
||
|
||
void PluginRegistry::populatePluginMenu(QMenu* m, std::function<void (std::shared_ptr<Node>)> f, Graph* g) {
|
||
std::map<std::string, std::map<std::string, std::shared_ptr<PluginInfo>>> cm; // category map
|
||
cm.try_emplace(""); // force empty category
|
||
for (auto& i : plugins) {
|
||
if (i.second->hidden) continue;
|
||
cm.try_emplace(i.second->category);
|
||
cm[i.second->category][i.second->displayName] = i.second;
|
||
}
|
||
|
||
// 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::Audio, Port::Command};
|
||
|
||
for (auto dt : d) {
|
||
auto* mi = mio->addMenu(QString("&%1 In").arg(Util::enumName(dt)));
|
||
auto* mo = mio->addMenu(QString("&%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(QString(u8"%10-%1F").arg(n));
|
||
auto* mos = mo->addMenu(QString(u8"%10-%1F").arg(n));
|
||
for (int il = 0; il < 16; il++) {
|
||
int i = ih*16+il;
|
||
QString nn = Util::hex(i);
|
||
mis->addAction(nn, [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, [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(QString::fromStdString(c->first));
|
||
for (auto& i : c->second) {
|
||
ccm->addAction(QString::fromStdString(i.second->displayName), [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.empty() || c.second.empty()) continue;
|
||
auto* ccm = m->addMenu(QString::fromStdString(c.first));
|
||
for (auto& i : c.second) {
|
||
ccm->addAction(QString::fromStdString(i.second->displayName), [f, pi = i.second] {
|
||
auto n = pi->createInstance();
|
||
n->plugin = pi;
|
||
n->init();
|
||
f(n);
|
||
});
|
||
}
|
||
}
|
||
|
||
m->addSeparator();
|
||
|
||
for (auto& i : cm[""]) m->addAction(QString::fromStdString(i.second->displayName), [f, pi = i.second] {
|
||
auto n = pi->createInstance();
|
||
n->plugin = pi;
|
||
n->init();
|
||
f(n);
|
||
});
|
||
|
||
}
|