#include "pluginregistry.h" using namespace Xybrid::Config; #include #include #include #include #include "data/graph.h" using namespace Xybrid::Data; #include "gadgets/ioport.h" using Xybrid::Gadgets::IOPort; #include "util/strings.h" namespace { typedef std::list> 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> plugins; std::string priorityCategories[] { "Gadget", "Instrument", "Effect" }; } bool PluginRegistry::enqueueRegistration(std::function 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 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 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)> f, Graph* g) { std::map>> 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"%1​0-%1​F").arg(n)); auto* mos = mo->addMenu(QString(u8"%1​0-%1​F").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(createInstance("ioport")); n->setPort(Port::Input, dt, static_cast(i)); f(n); })->setEnabled(!g->port(Port::Input, dt, static_cast(i))); mos->addAction(nn, [f, dt, i] { auto n = std::static_pointer_cast(createInstance("ioport")); n->setPort(Port::Output, dt, static_cast(i)); f(n); })->setEnabled(!g->port(Port::Output, dt, static_cast(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); }); }