diff --git a/include/plugin.hpp b/include/plugin.hpp index d2ca606c..b9d428cd 100644 --- a/include/plugin.hpp +++ b/include/plugin.hpp @@ -68,11 +68,18 @@ struct Plugin { /** Used when syncing plugins with the API */ std::string slug; + + // Optional plugin metadata + /** The version of your plugin Plugins should follow the versioning scheme described at https://github.com/VCVRack/Rack/issues/266 Do not include the "v" in "v1.0" for example. */ std::string version; + /** URL for plugin homepage */ + std::string website; + /** URL for plugin manual */ + std::string manual; virtual ~Plugin(); void addModel(Model *model); diff --git a/include/util.hpp b/include/util.hpp index 1992c5f5..40e01df5 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -30,6 +30,9 @@ will expand to #define LENGTHOF(arr) (sizeof(arr) / sizeof((arr)[0])) +/** Deprecation notice for GCC */ +#define DEPRECATED __attribute__ ((deprecated)) + namespace rack { diff --git a/include/widgets.hpp b/include/widgets.hpp index ecf99b5c..e0e76df4 100644 --- a/include/widgets.hpp +++ b/include/widgets.hpp @@ -312,7 +312,9 @@ struct Menu : OpaqueWidget { } ~Menu(); // Resizes menu and calls addChild() - void pushChild(Widget *child); + void pushChild(Widget *child) DEPRECATED { + addChild(child); + } void setChildMenu(Menu *menu); void step() override; void draw(NVGcontext *vg) override; diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index 231033b7..02da93a3 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -247,8 +247,8 @@ void RackWidget::fromJson(json_t *rootJ) { int outputModuleId, outputId; int inputModuleId, inputId; int err = json_unpack(wireJ, "{s:i, s:i, s:i, s:i}", - "outputModuleId", &outputModuleId, "outputId", &outputId, - "inputModuleId", &inputModuleId, "inputId", &inputId); + "outputModuleId", &outputModuleId, "outputId", &outputId, + "inputModuleId", &inputModuleId, "inputId", &inputId); if (err) continue; // Get ports ModuleWidget *outputModuleWidget = moduleWidgets[outputModuleId]; @@ -354,7 +354,7 @@ void RackWidget::step() { } // Autosave every 15 seconds - if (gGuiFrame % (60*15) == 0) { + if (gGuiFrame % (60 * 15) == 0) { savePatch(assetLocal("autosave.vcv")); settingsSave(assetLocal("settings.json")); } @@ -366,6 +366,16 @@ void RackWidget::draw(NVGcontext *vg) { Widget::draw(vg); } + +struct UrlItem : MenuItem { + std::string url; + void onAction(EventAction &e) override { + std::thread t(openBrowser, url); + t.detach(); + } +}; + + struct AddModuleMenuItem : MenuItem { Model *model; Vec modulePos; @@ -378,19 +388,47 @@ struct AddModuleMenuItem : MenuItem { box.pos = modulePos.minus(box.getCenter()); gRackWidget->requestModuleBoxNearest(moduleWidget, box); } -}; -struct UrlItem : MenuItem { - std::string url; - void onAction(EventAction &e) override { - std::thread t(openBrowser, url); - t.detach(); + Menu *createChildMenu() override { + Menu *menu = new Menu(); + + // Tag list + if (!model->tags.empty()) { + for (ModelTag tag : model->tags) { + menu->addChild(construct(&MenuEntry::text, gTagNames[tag])); + } + menu->addChild(construct()); + } + + // Plugin name + std::string pluginName = model->plugin->slug; + if (!model->plugin->version.empty()) { + pluginName += " v"; + pluginName += model->plugin->version; + } + menu->addChild(construct(&MenuEntry::text, pluginName)); + + // Plugin metadata + if (!model->plugin->website.empty()) { + menu->addChild(construct(&MenuEntry::text, "Website", &UrlItem::url, model->plugin->path)); + } + if (!model->plugin->manual.empty()) { + menu->addChild(construct(&MenuEntry::text, "Manual", &UrlItem::url, model->plugin->manual)); + } + if (!model->plugin->path.empty()) { + menu->addChild(construct(&MenuEntry::text, "Browse directory", &UrlItem::url, model->plugin->path)); + } + + return menu; } }; struct AddManufacturerMenuItem : MenuItem { std::string manufacturerName; Vec modulePos; + void onAction(EventAction &e) override { + e.consumed = false; + } Menu *createChildMenu() override { Menu *menu = new Menu(); @@ -405,51 +443,11 @@ struct AddManufacturerMenuItem : MenuItem { // item->rightText += " v" + model->plugin->version; item->model = model; item->modulePos = modulePos; - menu->pushChild(item); + menu->addChild(item); } } } - // Metadata items - /* - { - MenuLabel *label = new MenuLabel(); - menu->pushChild(label); - } - { - MenuLabel *label = new MenuLabel(); - label->text = plugin->name; - menu->pushChild(label); - } - - if (!plugin->homepageUrl.empty()) { - UrlItem *item = new UrlItem(); - item->text = "Homepage"; - item->url = plugin->homepageUrl; - menu->pushChild(item); - } - - if (!plugin->manualUrl.empty()) { - UrlItem *item = new UrlItem(); - item->text = "Manual"; - item->url = plugin->manualUrl; - menu->pushChild(item); - } - - if (!plugin->path.empty()) { - UrlItem *item = new UrlItem(); - item->text = "Browse directory"; - item->url = plugin->path; - menu->pushChild(item); - } - - if (!plugin->version.empty()) { - MenuLabel *item = new MenuLabel(); - item->text = "Version: v" + plugin->version; - menu->pushChild(item); - } - */ - return menu; } }; @@ -486,16 +484,11 @@ void RackWidget::onMouseDown(EventMouseDown &e) { if (e.button == 1) { Menu *menu = gScene->createMenu(); - menu->pushChild(construct(&MenuLabel::text, "Add module")); - - /* - // TODO make functional TextField *searchField = construct(); searchField->box.size.x = 100.0; - menu->pushChild(searchField); + menu->addChild(searchField); // Focus search field gFocusedWidget = searchField; - */ // Collect manufacturer names std::set manufacturerNames; @@ -510,7 +503,7 @@ void RackWidget::onMouseDown(EventMouseDown &e) { item->text = manufacturerName; item->manufacturerName = manufacturerName; item->modulePos = e.pos; - menu->pushChild(item); + menu->addChild(item); } } e.consumed = true; diff --git a/src/core/core.cpp b/src/core/core.cpp index 8dcefa14..a7587071 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -3,6 +3,10 @@ void init(rack::Plugin *p) { p->slug = "Core"; +#ifdef VERSION + p->version = TOSTRING(VERSION); +#endif + p->addModel(createModel("Core", "Core", "AudioInterface", "Audio Interface", EXTERNAL_TAG)); p->addModel(createModel("Core", "Core", "MIDIToCVInterface", "MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); diff --git a/src/widgets/Menu.cpp b/src/widgets/Menu.cpp index a5009a68..6a4042d2 100644 --- a/src/widgets/Menu.cpp +++ b/src/widgets/Menu.cpp @@ -7,12 +7,6 @@ Menu::~Menu() { setChildMenu(NULL); } -void Menu::pushChild(Widget *child) { - child->box.pos = Vec(0, box.size.y); - addChild(child); - box.size.y += child->box.size.y; -} - void Menu::setChildMenu(Menu *menu) { if (childMenu) { if (childMenu->parent) @@ -28,22 +22,30 @@ void Menu::setChildMenu(Menu *menu) { } void Menu::step() { - // Try to fit into the parent's box - if (parent) - box = box.nudge(Rect(Vec(0, 0), parent->box.size)); - Widget::step(); - // Resize the width to the widest child + // Set positions of children + box.size = Vec(0, 0); for (Widget *child : children) { + if (!child->visible) + continue; + // Increase height, set position of child + child->box.pos = Vec(0, box.size.y); + box.size.y += child->box.size.y; + // Increase width based on maximum width of child if (child->box.size.x > box.size.x) { box.size.x = child->box.size.x; } } + // Resize widths of children for (Widget *child : children) { child->box.size.x = box.size.x; } + + // Try to fit into the parent's box + if (parent) + box = box.nudge(Rect(Vec(0, 0), parent->box.size)); } void Menu::draw(NVGcontext *vg) {