|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- #pragma once
- #include <plugin/Model.hpp>
- #include <ui/MenuOverlay.hpp>
- #include <ui/MenuItem.hpp>
- #include <ui/MenuLabel.hpp>
- #include <ui/Menu.hpp>
- #include <app/PortWidget.hpp>
- #include <app/ParamWidget.hpp>
- #include <app/ModuleLightWidget.hpp>
- #include <app/Scene.hpp>
- #include <app/SvgPanel.hpp>
- #include <engine/Module.hpp>
- #include <engine/ParamQuantity.hpp>
- #include <context.hpp>
-
- #include <functional>
-
-
- namespace rack {
-
-
- /** Returns a Model that constructs a Module and ModuleWidget subclass. */
- template <class TModule, class TModuleWidget>
- plugin::Model* createModel(std::string slug) {
- struct TModel : plugin::Model {
- engine::Module* createModule() override {
- engine::Module* m = new TModule;
- m->model = this;
- return m;
- }
- app::ModuleWidget* createModuleWidget(engine::Module* m) override {
- TModule* tm = NULL;
- if (m) {
- assert(m->model == this);
- tm = dynamic_cast<TModule*>(m);
- }
- app::ModuleWidget* mw = new TModuleWidget(tm);
- mw->setModel(this);
- return mw;
- }
- };
-
- plugin::Model* o = new TModel;
- o->slug = slug;
- return o;
- }
-
-
- /** Creates a Widget subclass with its top-left at a position. */
- template <class TWidget>
- TWidget* createWidget(math::Vec pos) {
- TWidget* o = new TWidget;
- o->box.pos = pos;
- return o;
- }
-
-
- /** Creates a Widget subclass with its center at a position. */
- template <class TWidget>
- TWidget* createWidgetCentered(math::Vec pos) {
- TWidget* o = createWidget<TWidget>(pos);
- o->box.pos = o->box.pos.minus(o->box.size.div(2));
- return o;
- }
-
-
- inline app::SvgPanel* createPanel(std::string svgPath) {
- app::SvgPanel* panel = new app::SvgPanel;
- std::shared_ptr<Svg> svg = Svg::load(svgPath);
- panel->setBackground(svg);
- return panel;
- }
-
-
- template <class TParamWidget>
- TParamWidget* createParam(math::Vec pos, engine::Module* module, int paramId) {
- TParamWidget* o = new TParamWidget;
- o->box.pos = pos;
- o->app::ParamWidget::module = module;
- o->app::ParamWidget::paramId = paramId;
- o->initParamQuantity();
- return o;
- }
-
-
- template <class TParamWidget>
- TParamWidget* createParamCentered(math::Vec pos, engine::Module* module, int paramId) {
- TParamWidget* o = createParam<TParamWidget>(pos, module, paramId);
- o->box.pos = o->box.pos.minus(o->box.size.div(2));
- return o;
- }
-
-
- template <class TPortWidget>
- TPortWidget* createInput(math::Vec pos, engine::Module* module, int inputId) {
- TPortWidget* o = new TPortWidget;
- o->box.pos = pos;
- o->app::PortWidget::module = module;
- o->app::PortWidget::type = engine::Port::INPUT;
- o->app::PortWidget::portId = inputId;
- return o;
- }
-
-
- template <class TPortWidget>
- TPortWidget* createInputCentered(math::Vec pos, engine::Module* module, int inputId) {
- TPortWidget* o = createInput<TPortWidget>(pos, module, inputId);
- o->box.pos = o->box.pos.minus(o->box.size.div(2));
- return o;
- }
-
-
- template <class TPortWidget>
- TPortWidget* createOutput(math::Vec pos, engine::Module* module, int outputId) {
- TPortWidget* o = new TPortWidget;
- o->box.pos = pos;
- o->app::PortWidget::module = module;
- o->app::PortWidget::type = engine::Port::OUTPUT;
- o->app::PortWidget::portId = outputId;
- return o;
- }
-
-
- template <class TPortWidget>
- TPortWidget* createOutputCentered(math::Vec pos, engine::Module* module, int outputId) {
- TPortWidget* o = createOutput<TPortWidget>(pos, module, outputId);
- o->box.pos = o->box.pos.minus(o->box.size.div(2));
- return o;
- }
-
-
- template <class TModuleLightWidget>
- TModuleLightWidget* createLight(math::Vec pos, engine::Module* module, int firstLightId) {
- TModuleLightWidget* o = new TModuleLightWidget;
- o->box.pos = pos;
- o->app::ModuleLightWidget::module = module;
- o->app::ModuleLightWidget::firstLightId = firstLightId;
- return o;
- }
-
-
- template <class TModuleLightWidget>
- TModuleLightWidget* createLightCentered(math::Vec pos, engine::Module* module, int firstLightId) {
- TModuleLightWidget* o = createLight<TModuleLightWidget>(pos, module, firstLightId);
- o->box.pos = o->box.pos.minus(o->box.size.div(2));
- return o;
- }
-
-
- /** Creates a param with a light and calls setFirstLightId() on it.
- Requires ParamWidget to have a `light` member.
- */
- template <class TParamWidget>
- TParamWidget* createLightParam(math::Vec pos, engine::Module* module, int paramId, int firstLightId) {
- TParamWidget* o = createParam<TParamWidget>(pos, module, paramId);
- o->light->module = module;
- o->light->firstLightId = firstLightId;
- return o;
- }
-
-
- template <class TParamWidget>
- TParamWidget* createLightParamCentered(math::Vec pos, engine::Module* module, int paramId, int firstLightId) {
- TParamWidget* o = createLightParam<TParamWidget>(pos, module, paramId, firstLightId);
- o->box.pos = o->box.pos.minus(o->box.size.div(2));
- return o;
- }
-
-
- template <class TMenu = ui::Menu>
- TMenu* createMenu() {
- TMenu* o = new TMenu;
- o->box.pos = APP->scene->mousePos;
-
- ui::MenuOverlay* menuOverlay = new ui::MenuOverlay;
- menuOverlay->addChild(o);
-
- APP->scene->addChild(menuOverlay);
- return o;
- }
-
-
- template <class TMenuLabel = ui::MenuLabel>
- TMenuLabel* createMenuLabel(std::string text) {
- TMenuLabel* o = new TMenuLabel;
- o->text = text;
- return o;
- }
-
-
- template <class TMenuItem = ui::MenuItem>
- TMenuItem* createMenuItem(std::string text, std::string rightText = "") {
- TMenuItem* o = new TMenuItem;
- o->text = text;
- o->rightText = rightText;
- return o;
- }
-
-
- /** Creates a MenuItem with an action that calls a lambda function.
- Example:
-
- menu->addChild(createMenuItem("Load sample", "kick.wav",
- [=]() {
- module->loadSample();
- }
- ));
- */
- template <class TMenuItem = ui::MenuItem>
- TMenuItem* createMenuItem(std::string text, std::string rightText, std::function<void()> action, bool disabled = false, bool alwaysConsume = false) {
- struct Item : TMenuItem {
- std::function<void()> action;
- bool alwaysConsume;
-
- void onAction(const event::Action& e) override {
- action();
- if (alwaysConsume)
- e.consume(this);
- }
- };
-
- Item* item = createMenuItem<Item>(text, rightText);
- item->action = action;
- item->disabled = disabled;
- item->alwaysConsume = alwaysConsume;
- return item;
- }
-
-
- /** Creates a MenuItem with a check mark set by a lambda function.
- Example:
-
- menu->addChild(createCheckMenuItem("Loop",
- [=]() {
- return module->isLoop();
- },
- [=]() {
- module->toggleLoop();
- }
- ));
- */
- template <class TMenuItem = ui::MenuItem>
- ui::MenuItem* createCheckMenuItem(std::string text, std::function<bool()> checked, std::function<void()> action, bool disabled = false, bool alwaysConsume = false) {
- struct Item : TMenuItem {
- std::function<bool()> checked;
- std::function<void()> action;
- bool alwaysConsume;
-
- void step() override {
- this->rightText = CHECKMARK(checked());
- TMenuItem::step();
- }
- void onAction(const event::Action& e) override {
- action();
- if (alwaysConsume)
- e.consume(this);
- }
- };
-
- Item* item = createMenuItem<Item>(text);
- item->checked = checked;
- item->action = action;
- item->disabled = disabled;
- item->alwaysConsume = alwaysConsume;
- return item;
- }
-
-
- /** Creates a MenuItem that controls a boolean value with a check mark.
- Example:
-
- menu->addChild(createBoolMenuItem("Loop",
- [=]() {
- return module->isLoop();
- },
- [=](bool loop) {
- module->setLoop(loop);
- }
- ));
- */
- template <class TMenuItem = ui::MenuItem>
- ui::MenuItem* createBoolMenuItem(std::string text, std::function<bool()> getter, std::function<void(bool state)> setter, bool disabled = false, bool alwaysConsume = false) {
- struct Item : TMenuItem {
- std::function<bool()> getter;
- std::function<void(size_t)> setter;
- bool alwaysConsume;
-
- void step() override {
- this->rightText = CHECKMARK(getter());
- TMenuItem::step();
- }
- void onAction(const event::Action& e) override {
- setter(!getter());
- if (alwaysConsume)
- e.consume(this);
- }
- };
-
- Item* item = createMenuItem<Item>(text);
- item->getter = getter;
- item->setter = setter;
- item->disabled = disabled;
- item->alwaysConsume = alwaysConsume;
- return item;
- }
-
-
- /** Easy wrapper for createBoolMenuItem() to modify a bool pointer.
- Example:
-
- menu->addChild(createBoolPtrMenuItem("Loop", &module->loop));
- */
- template <typename T>
- ui::MenuItem* createBoolPtrMenuItem(std::string text, T* ptr) {
- return createBoolMenuItem(text,
- [=]() {return *ptr;},
- [=](T val) {*ptr = val;}
- );
- }
-
-
- /** Creates a MenuItem that opens a submenu.
- Example:
-
- menu->addChild(createSubmenuItem("Edit", "",
- [=](Menu* menu) {
- menu->addChild(createMenuItem("Copy", "", [=]() {copy();}));
- menu->addChild(createMenuItem("Paste", "", [=]() {paste();}));
- }
- ));
- */
- template <class TMenuItem = ui::MenuItem>
- ui::MenuItem* createSubmenuItem(std::string text, std::string rightText, std::function<void(ui::Menu* menu)> createMenu, bool disabled = false) {
- struct Item : TMenuItem {
- std::function<void(ui::Menu* menu)> createMenu;
-
- ui::Menu* createChildMenu() override {
- ui::Menu* menu = new ui::Menu;
- createMenu(menu);
- return menu;
- }
- };
-
- Item* item = createMenuItem<Item>(text, rightText + (rightText.empty() ? "" : " ") + RIGHT_ARROW);
- item->createMenu = createMenu;
- item->disabled = disabled;
- return item;
- }
-
-
- /** Creates a MenuItem that when hovered, opens a submenu with several MenuItems indexed by an integer.
- Example:
-
- menu->addChild(createIndexSubmenuItem("Mode",
- {"Hi-fi", "Mid-fi", "Lo-fi"},
- [=]() {
- return module->getMode();
- },
- [=](int mode) {
- module->setMode(mode);
- }
- ));
- */
- template <class TMenuItem = ui::MenuItem>
- ui::MenuItem* createIndexSubmenuItem(std::string text, std::vector<std::string> labels, std::function<size_t()> getter, std::function<void(size_t val)> setter, bool disabled = false, bool alwaysConsume = false) {
- struct IndexItem : ui::MenuItem {
- std::function<size_t()> getter;
- std::function<void(size_t)> setter;
- size_t index;
- bool alwaysConsume;
-
- void step() override {
- size_t currIndex = getter();
- this->rightText = CHECKMARK(currIndex == index);
- MenuItem::step();
- }
- void onAction(const event::Action& e) override {
- setter(index);
- if (alwaysConsume)
- e.consume(this);
- }
- };
-
- struct Item : TMenuItem {
- std::function<size_t()> getter;
- std::function<void(size_t)> setter;
- std::vector<std::string> labels;
- bool alwaysConsume;
-
- void step() override {
- size_t currIndex = getter();
- std::string label = (currIndex < labels.size()) ? labels[currIndex] : "";
- this->rightText = label + " " + RIGHT_ARROW;
- TMenuItem::step();
- }
- ui::Menu* createChildMenu() override {
- ui::Menu* menu = new ui::Menu;
- for (size_t i = 0; i < labels.size(); i++) {
- IndexItem* item = createMenuItem<IndexItem>(labels[i]);
- item->getter = getter;
- item->setter = setter;
- item->index = i;
- item->alwaysConsume = alwaysConsume;
- menu->addChild(item);
- }
- return menu;
- }
- };
-
- Item* item = createMenuItem<Item>(text);
- item->getter = getter;
- item->setter = setter;
- item->labels = labels;
- item->disabled = disabled;
- item->alwaysConsume = alwaysConsume;
- return item;
- }
-
-
- /** Easy wrapper for createIndexSubmenuItem() that controls an integer index at a pointer address.
- Example:
-
- menu->addChild(createIndexPtrSubmenuItem("Mode",
- {"Hi-fi", "Mid-fi", "Lo-fi"},
- &module->mode
- ));
- */
- template <typename T>
- ui::MenuItem* createIndexPtrSubmenuItem(std::string text, std::vector<std::string> labels, T* ptr) {
- return createIndexSubmenuItem(text, labels,
- [=]() {return *ptr;},
- [=](size_t index) {*ptr = T(index);}
- );
- }
-
-
- } // namespace rack
|