From 0c386dd52629a5f53d483e93f51b3e8b64f612a6 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Tue, 31 Oct 2017 14:40:08 -0400 Subject: [PATCH 01/11] Fade out Light more slowly --- src/engine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine.cpp b/src/engine.cpp index 6663e2bf..2e8f984e 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -41,8 +41,8 @@ float Light::getBrightness() { void Light::setBrightnessSmooth(float brightness) { float v = brightness * brightness; if (v < value) { - // Fade out light with lambda = 3 * framerate - value += (v - value) * sampleTime * (60.0 * 3.0); + // Fade out light with lambda = 2 * framerate + value += (v - value) * sampleTime * (60.0 * 2.0); } else { // Immediately illuminate light From 093fa99474f75990ce2b6c2af86971a8526876dc Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Wed, 1 Nov 2017 03:40:51 -0400 Subject: [PATCH 02/11] Add Widget::onPathDrop() event, added dragging patches to window to load them --- include/app.hpp | 1 + include/widgets.hpp | 1 + src/app/RackScene.cpp | 12 ++++++++++++ src/gui.cpp | 11 ++++++++++- src/widgets/Widget.cpp | 13 +++++++++++++ 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/include/app.hpp b/include/app.hpp index 0f6e5bba..e5aec153 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -366,6 +366,7 @@ struct RackScene : Scene { void step() override; void draw(NVGcontext *vg) override; Widget *onHoverKey(Vec pos, int key) override; + bool onPathDrop(Vec pos, const std::list& paths) override; }; //////////////////// diff --git a/include/widgets.hpp b/include/widgets.hpp index 18d7321d..6f61bc76 100644 --- a/include/widgets.hpp +++ b/include/widgets.hpp @@ -147,6 +147,7 @@ struct Widget { virtual void onDragEnter(Widget *origin) {} virtual void onDragLeave(Widget *origin) {} virtual void onDragDrop(Widget *origin) {} + virtual bool onPathDrop(Vec pos, const std::list& paths); virtual void onAction() {} virtual void onChange() {} diff --git a/src/app/RackScene.cpp b/src/app/RackScene.cpp index e55ab507..7b9481a7 100644 --- a/src/app/RackScene.cpp +++ b/src/app/RackScene.cpp @@ -118,5 +118,17 @@ Widget *RackScene::onHoverKey(Vec pos, int key) { } +bool RackScene::onPathDrop(Vec pos, const std::list& paths) { + if (paths.size() >= 1) { + const std::string& firstPath = paths.front(); + if (extractExtension(firstPath) == "vcv") { + gRackWidget->loadPatch(firstPath); + return true; + } + } + return false; +} + + } // namespace rack diff --git a/src/gui.cpp b/src/gui.cpp index 01de9ab1..ee4f8238 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -203,7 +203,7 @@ void charCallback(GLFWwindow *window, unsigned int codepoint) { } } -void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { +void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) { if (action == GLFW_PRESS || action == GLFW_REPEAT) { // onFocusKey if (gFocusedWidget && gFocusedWidget->onFocusKey(key)) @@ -213,6 +213,14 @@ void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods } } +void dropCallback(GLFWwindow *window, int count, const char **paths) { + std::list pathsList; + for (int i = 0; i < count; i++) { + pathsList.push_back(paths[i]); + } + gScene->onPathDrop(gMousePos, pathsList); +} + void errorCallback(int error, const char *description) { fprintf(stderr, "GLFW error %d: %s\n", error, description); } @@ -272,6 +280,7 @@ void guiInit() { glfwSetScrollCallback(gWindow, scrollCallback); glfwSetCharCallback(gWindow, charCallback); glfwSetKeyCallback(gWindow, keyCallback); + glfwSetDropCallback(gWindow, dropCallback); // Set up GLEW glewExperimental = GL_TRUE; diff --git a/src/widgets/Widget.cpp b/src/widgets/Widget.cpp index 65af2567..6d955a16 100644 --- a/src/widgets/Widget.cpp +++ b/src/widgets/Widget.cpp @@ -184,6 +184,19 @@ Widget *Widget::onScroll(Vec pos, Vec scrollRel) { return NULL; } +bool Widget::onPathDrop(Vec pos, const std::list& paths) { + for (auto it = children.rbegin(); it != children.rend(); it++) { + Widget *child = *it; + if (!child->visible) + continue; + if (child->box.contains(pos)) { + if (child->onPathDrop(pos.minus(child->box.pos), paths)); + return true; + } + } + return false; +} + void Widget::onZoom() { for (auto it = children.rbegin(); it != children.rend(); it++) { Widget *child = *it; From 8e251c0ddbfc1f4a2e03a6123d8eda42218b76fe Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Wed, 1 Nov 2017 08:27:59 -0400 Subject: [PATCH 03/11] Refactor event framework. Everything uses Event* structs instead of messy function arguments, removed on*Opaque() --- include/app.hpp | 58 +++++------ include/events.hpp | 107 +++++++++++++++++++ include/widgets.hpp | 164 ++++++++++++++---------------- src/app/Knob.cpp | 13 +-- src/app/ModuleWidget.cpp | 60 ++++++----- src/app/ParamWidget.cpp | 8 +- src/app/PluginManagerWidget.cpp | 12 +-- src/app/Port.cpp | 29 +++--- src/app/RackScene.cpp | 30 +++--- src/app/RackWidget.cpp | 26 +++-- src/app/SVGKnob.cpp | 4 +- src/app/SVGSlider.cpp | 4 +- src/app/SVGSwitch.cpp | 4 +- src/app/Toolbar.cpp | 22 ++-- src/core/AudioInterface.cpp | 12 +-- src/core/Blank.cpp | 15 +-- src/gui.cpp | 107 ++++++++++++++----- src/widgets/Button.cpp | 15 +-- src/widgets/FramebufferWidget.cpp | 2 +- src/widgets/Menu.cpp | 8 +- src/widgets/MenuItem.cpp | 9 +- src/widgets/MenuOverlay.cpp | 18 ++-- src/widgets/QuantityWidget.cpp | 6 +- src/widgets/RadioButton.cpp | 11 +- src/widgets/ScrollBar.cpp | 10 +- src/widgets/ScrollWidget.cpp | 6 +- src/widgets/Slider.cpp | 20 ++-- src/widgets/TextField.cpp | 33 +++--- src/widgets/Widget.cpp | 113 +++++++------------- src/widgets/ZoomWidget.cpp | 41 +++++--- 30 files changed, 570 insertions(+), 397 deletions(-) create mode 100644 include/events.hpp diff --git a/include/app.hpp b/include/app.hpp index e5aec153..b0bcb4b4 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -67,12 +67,12 @@ struct ModuleWidget : OpaqueWidget { void draw(NVGcontext *vg) override; Vec dragPos; - Widget *onMouseMove(Vec pos, Vec mouseRel) override; - Widget *onHoverKey(Vec pos, int key) override; - void onDragStart() override; - void onDragMove(Vec mouseRel) override; - void onDragEnd() override; - void onMouseDownOpaque(int button) override; + void onMouseDown(EventMouseDown &e) override; + void onMouseMove(EventMouseMove &e) override; + void onHoverKey(EventHoverKey &e) override; + void onDragStart(EventDragStart &e) override; + void onDragEnd(EventDragEnd &e) override; + void onDragMove(EventDragMove &e) override; }; struct ValueLight; @@ -144,9 +144,9 @@ struct RackWidget : OpaqueWidget { void step() override; void draw(NVGcontext *vg) override; - Widget *onMouseMove(Vec pos, Vec mouseRel) override; - void onMouseDownOpaque(int button) override; - void onZoom() override; + void onMouseMove(EventMouseMove &e) override; + void onMouseDown(EventMouseDown &e) override; + void onZoom(EventZoom &e) override; }; struct RackRail : TransparentWidget { @@ -184,8 +184,8 @@ struct ParamWidget : OpaqueWidget, QuantityWidget { json_t *toJson(); void fromJson(json_t *rootJ); virtual void randomize(); - void onMouseDownOpaque(int button) override; - void onChange() override; + void onMouseDown(EventMouseDown &e) override; + void onChange(EventChange &e) override; }; /** Implements vertical dragging behavior for ParamWidgets */ @@ -193,11 +193,11 @@ struct Knob : ParamWidget { /** Snap to nearest integer while dragging */ bool snap = false; float dragValue; - void onDragStart() override; - void onDragMove(Vec mouseRel) override; - void onDragEnd() override; + void onDragStart(EventDragStart &e) override; + void onDragMove(EventDragMove &e) override; + void onDragEnd(EventDragEnd &e) override; /** Tell engine to smoothly vary this parameter */ - void onChange() override; + void onChange(EventChange &e) override; }; struct SpriteKnob : virtual Knob, SpriteWidget { @@ -216,7 +216,7 @@ struct SVGKnob : virtual Knob, FramebufferWidget { SVGKnob(); void setSVG(std::shared_ptr svg); void step() override; - void onChange() override; + void onChange(EventChange &e) override; }; struct SVGSlider : Knob, FramebufferWidget { @@ -228,7 +228,7 @@ struct SVGSlider : Knob, FramebufferWidget { SVGSlider(); void step() override; - void onChange() override; + void onChange(EventChange &e) override; }; struct Switch : ParamWidget { @@ -243,12 +243,12 @@ struct SVGSwitch : virtual Switch, FramebufferWidget { /** Adds an SVG file to represent the next switch position */ void addFrame(std::shared_ptr svg); void step() override; - void onChange() override; + void onChange(EventChange &e) override; }; /** A switch that cycles through each mechanical position */ struct ToggleSwitch : virtual Switch { - void onDragStart() override { + void onDragStart(EventDragStart &e) override { // Cycle through values // e.g. a range of [0.0, 3.0] would have modes 0, 1, 2, and 3. if (value >= maxValue) @@ -262,10 +262,10 @@ struct ToggleSwitch : virtual Switch { struct MomentarySwitch : virtual Switch { /** Don't randomize state */ void randomize() override {} - void onDragStart() override { + void onDragStart(EventDragStart &e) override { setValue(maxValue); } - void onDragEnd() override { + void onDragEnd(EventDragEnd &e) override { setValue(minValue); } }; @@ -286,12 +286,12 @@ struct Port : OpaqueWidget { ~Port(); void draw(NVGcontext *vg) override; - void onMouseDownOpaque(int button) override; - void onDragEnd() override; - void onDragStart() override; - void onDragDrop(Widget *origin) override; - void onDragEnter(Widget *origin) override; - void onDragLeave(Widget *origin) override; + void onMouseDown(EventMouseDown &e) override; + void onDragStart(EventDragStart &e) override; + void onDragEnd(EventDragEnd &e) override; + void onDragDrop(EventDragDrop &e) override; + void onDragEnter(EventDragEnter &e) override; + void onDragLeave(EventDragEnter &e) override; }; struct SVGPort : Port, FramebufferWidget { @@ -365,8 +365,8 @@ struct RackScene : Scene { RackScene(); void step() override; void draw(NVGcontext *vg) override; - Widget *onHoverKey(Vec pos, int key) override; - bool onPathDrop(Vec pos, const std::list& paths) override; + void onHoverKey(EventHoverKey &e) override; + void onPathDrop(EventPathDrop &e) override; }; //////////////////// diff --git a/include/events.hpp b/include/events.hpp new file mode 100644 index 00000000..12d95b04 --- /dev/null +++ b/include/events.hpp @@ -0,0 +1,107 @@ +#pragma once +#include + +#include "math.hpp" + + +namespace rack { + + +struct Widget; + + +struct Event { + /** Set this to true to signal that no other widgets should receive the event */ + bool consumed = false; +}; + +struct EventPosition : Event { + Vec pos; +}; + +/////////// + +struct EventMouseDown : EventPosition { + int button; + /** The widget which responded to the click. Set it to `this` if consumed. */ + Widget *target = NULL; +}; + +struct EventMouseUp : EventPosition { + int button; + Widget *target = NULL; +}; + +struct EventMouseMove : EventPosition { + Vec mouseRel; + Widget *target = NULL; +}; + +struct EventHoverKey : EventPosition { + int key; + Widget *target = NULL; +}; + +struct EventMouseEnter : Event { +}; + +struct EventMouseLeave : Event { +}; + +struct EventFocus : Event { +}; + +struct EventDefocus : Event { +}; + +struct EventText : Event { + int codepoint; +}; + +struct EventKey : Event { + int key; +}; + +struct EventScroll : EventPosition { + Vec scrollRel; +}; + +///////////// + +struct EventDragStart : Event { +}; + +struct EventDragEnd : Event { +}; + +struct EventDragMove : Event { + Vec mouseRel; +}; + +struct EventDragEnter : Event { + Widget *origin = NULL; +}; + +struct EventDragLeave : Event { + Widget *origin = NULL; +}; + +struct EventDragDrop : Event { + Widget *origin = NULL; +}; + +struct EventPathDrop : EventPosition { + std::list paths; +}; + +struct EventAction : Event { +}; + +struct EventChange : Event { +}; + +struct EventZoom : Event { +}; + + +} // namespace rack diff --git a/include/widgets.hpp b/include/widgets.hpp index 6f61bc76..13c1df0e 100644 --- a/include/widgets.hpp +++ b/include/widgets.hpp @@ -8,6 +8,7 @@ #include "math.hpp" #include "util.hpp" +#include "events.hpp" #define SVG_DPI 75.0 @@ -122,36 +123,36 @@ struct Widget { Return `this` to accept the event. Return NULL to reject the event and pass it to the widget behind this one. */ - virtual Widget *onMouseDown(Vec pos, int button); - virtual Widget *onMouseUp(Vec pos, int button); + virtual void onMouseDown(EventMouseDown &e); + virtual void onMouseUp(EventMouseUp &e); /** Called on every frame, even if mouseRel = Vec(0, 0) */ - virtual Widget *onMouseMove(Vec pos, Vec mouseRel); - virtual Widget *onHoverKey(Vec pos, int key); + virtual void onMouseMove(EventMouseMove &e); + virtual void onHoverKey(EventHoverKey &e); /** Called when this widget begins responding to `onMouseMove` events */ - virtual void onMouseEnter() {} + virtual void onMouseEnter(EventMouseEnter &e) {} /** Called when another widget begins responding to `onMouseMove` events */ - virtual void onMouseLeave() {} - virtual bool onFocus() {return false;} - virtual void onDefocus() {} - virtual bool onFocusText(int codepoint) {return false;} - virtual bool onFocusKey(int key) {return false;} - virtual Widget *onScroll(Vec pos, Vec scrollRel); + virtual void onMouseLeave(EventMouseLeave &e) {} + virtual void onFocus(EventFocus &e) {} + virtual void onDefocus(EventDefocus &e) {} + virtual void onText(EventText &e) {} + virtual void onKey(EventKey &e) {} + virtual void onScroll(EventScroll &e); /** Called when a widget responds to `onMouseDown` for a left button press */ - virtual void onDragStart() {} + virtual void onDragStart(EventDragStart &e) {} /** Called when the left button is released and this widget is being dragged */ - virtual void onDragEnd() {} + virtual void onDragEnd(EventDragEnd &e) {} /** Called when a widget responds to `onMouseMove` and is being dragged */ - virtual void onDragMove(Vec mouseRel) {} + virtual void onDragMove(EventDragMove &e) {} /** Called when a widget responds to `onMouseUp` for a left button release and a widget is being dragged */ - virtual void onDragEnter(Widget *origin) {} - virtual void onDragLeave(Widget *origin) {} - virtual void onDragDrop(Widget *origin) {} - virtual bool onPathDrop(Vec pos, const std::list& paths); - - virtual void onAction() {} - virtual void onChange() {} - virtual void onZoom(); + virtual void onDragEnter(EventDragEnter &e) {} + virtual void onDragLeave(EventDragEnter &e) {} + virtual void onDragDrop(EventDragDrop &e) {} + virtual void onPathDrop(EventPathDrop &e); + + virtual void onAction(EventAction &e) {} + virtual void onChange(EventChange &e) {} + virtual void onZoom(EventZoom &e); }; struct TransformWidget : Widget { @@ -171,11 +172,11 @@ struct ZoomWidget : Widget { Rect getViewport(Rect r) override; void setZoom(float zoom); void draw(NVGcontext *vg) override; - Widget *onMouseDown(Vec pos, int button) override; - Widget *onMouseUp(Vec pos, int button) override; - Widget *onMouseMove(Vec pos, Vec mouseRel) override; - Widget *onHoverKey(Vec pos, int key) override; - Widget *onScroll(Vec pos, Vec scrollRel) override; + void onMouseDown(EventMouseDown &e) override; + void onMouseUp(EventMouseUp &e) override; + void onMouseMove(EventMouseMove &e) override; + void onHoverKey(EventHoverKey &e) override; + void onScroll(EventScroll &e) override; }; //////////////////// @@ -184,47 +185,36 @@ struct ZoomWidget : Widget { /** Widget that does not respond to events */ struct TransparentWidget : virtual Widget { - Widget *onMouseDown(Vec pos, int button) override {return NULL;} - Widget *onMouseUp(Vec pos, int button) override {return NULL;} - Widget *onMouseMove(Vec pos, Vec mouseRel) override {return NULL;} - Widget *onScroll(Vec pos, Vec scrollRel) override {return NULL;} + void onMouseDown(EventMouseDown &e) override {} + void onMouseUp(EventMouseUp &e) override {} + void onMouseMove(EventMouseMove &e) override {} + void onScroll(EventScroll &e) override {} }; /** Widget that automatically responds to all mouse events but gives a chance for children to respond instead */ struct OpaqueWidget : virtual Widget { - Widget *onMouseDown(Vec pos, int button) override { - Widget *w = Widget::onMouseDown(pos, button); - if (w) return w; - onMouseDownOpaque(button); - return this; + void onMouseDown(EventMouseDown &e) override { + Widget::onMouseDown(e); + if (!e.target) + e.target = this; + e.consumed = true; } - Widget *onMouseUp(Vec pos, int button) override { - Widget *w = Widget::onMouseUp(pos, button); - if (w) return w; - onMouseUpOpaque(button); - return this; + void onMouseUp(EventMouseUp &e) override { + Widget::onMouseUp(e); + if (!e.target) + e.target = this; + e.consumed = true; } - Widget *onMouseMove(Vec pos, Vec mouseRel) override { - Widget *w = Widget::onMouseMove(pos, mouseRel); - if (w) return w; - onMouseMoveOpaque(mouseRel); - return this; + void onMouseMove(EventMouseMove &e) override { + Widget::onMouseMove(e); + if (!e.target) + e.target = this; + e.consumed = true; } - Widget *onScroll(Vec pos, Vec scrollRel) override { - Widget *w = Widget::onScroll(pos, scrollRel); - if (w) return w; - if (onScrollOpaque(scrollRel)) - return this; - return NULL; + void onScroll(EventScroll &e) override { + Widget::onScroll(e); + e.consumed = true; } - - /** "High level" events called by the above lower level events. - Use these if you don't care about the clicked position. - */ - virtual void onMouseDownOpaque(int button) {} - virtual void onMouseUpOpaque(int button) {} - virtual void onMouseMoveOpaque(Vec mouseRel) {} - virtual bool onScrollOpaque(Vec scrollRel) {return false;} }; struct SpriteWidget : virtual Widget { @@ -265,7 +255,7 @@ struct FramebufferWidget : virtual Widget { ~FramebufferWidget(); void draw(NVGcontext *vg) override; int getImageHandle(); - void onZoom() override; + void onZoom(EventZoom &e) override; }; struct QuantityWidget : virtual Widget { @@ -303,9 +293,9 @@ struct Label : Widget { // Deletes itself from parent when clicked struct MenuOverlay : OpaqueWidget { - void onDragDrop(Widget *origin) override; - bool onScrollOpaque(Vec scrollRel) override {return true;} - Widget *onHoverKey(Vec pos, int key) override; + void onDragDrop(EventDragDrop &e) override; + void onScroll(EventScroll &e) override; + void onHoverKey(EventHoverKey &e) override; }; struct MenuEntry; @@ -325,7 +315,7 @@ struct Menu : OpaqueWidget { void setChildMenu(Menu *menu); void step() override; void draw(NVGcontext *vg) override; - bool onScrollOpaque(Vec scrollRel) override; + void onScroll(EventScroll &e) override; }; struct MenuEntry : OpaqueWidget { @@ -344,8 +334,8 @@ struct MenuLabel : MenuEntry { struct MenuItem : MenuEntry { void draw(NVGcontext *vg) override; virtual Menu *createChildMenu() {return NULL;} - void onMouseEnter() override; - void onDragDrop(Widget *origin) override; + void onMouseEnter(EventMouseEnter &e) override; + void onDragDrop(EventDragDrop &e) override; }; struct Button : OpaqueWidget { @@ -356,11 +346,11 @@ struct Button : OpaqueWidget { box.size.y = BND_WIDGET_HEIGHT; } void draw(NVGcontext *vg) override; - void onMouseEnter() override; - void onMouseLeave() override; - void onDragStart() override; - void onDragEnd() override; - void onDragDrop(Widget *origin) override; + void onMouseEnter(EventMouseEnter &e) override; + void onMouseLeave(EventMouseLeave &e) override; + void onDragStart(EventDragStart &e) override; + void onDragEnd(EventDragEnd &e) override; + void onDragDrop(EventDragDrop &e) override; }; struct ChoiceButton : Button { @@ -374,9 +364,9 @@ struct RadioButton : OpaqueWidget, QuantityWidget { box.size.y = BND_WIDGET_HEIGHT; } void draw(NVGcontext *vg) override; - void onMouseEnter() override; - void onMouseLeave() override; - void onDragDrop(Widget *origin) override; + void onMouseEnter(EventMouseEnter &e) override; + void onMouseLeave(EventMouseLeave &e) override; + void onDragDrop(EventDragDrop &e) override; }; struct Slider : OpaqueWidget, QuantityWidget { @@ -386,10 +376,10 @@ struct Slider : OpaqueWidget, QuantityWidget { box.size.y = BND_WIDGET_HEIGHT; } void draw(NVGcontext *vg) override; - void onDragStart() override; - void onDragMove(Vec mouseRel) override; - void onDragEnd() override; - void onMouseDownOpaque(int button) override; + void onDragStart(EventDragStart &e) override; + void onDragMove(EventDragMove &e) override; + void onDragEnd(EventDragEnd &e) override; + void onMouseDown(EventMouseDown &e) override; }; /** Parent must be a ScrollWidget */ @@ -401,9 +391,9 @@ struct ScrollBar : OpaqueWidget { box.size = Vec(BND_SCROLLBAR_WIDTH, BND_SCROLLBAR_HEIGHT); } void draw(NVGcontext *vg) override; - void onDragStart() override; - void onDragMove(Vec mouseRel) override; - void onDragEnd() override; + void onDragStart(EventDragStart &e) override; + void onDragMove(EventDragMove &e) override; + void onDragEnd(EventDragEnd &e) override; }; /** Handles a container with ScrollBar */ @@ -415,7 +405,7 @@ struct ScrollWidget : OpaqueWidget { ScrollWidget(); void step() override; - bool onScrollOpaque(Vec scrollRel) override; + void onScroll(EventScroll &e) override; }; struct TextField : OpaqueWidget { @@ -429,10 +419,10 @@ struct TextField : OpaqueWidget { box.size.y = BND_WIDGET_HEIGHT; } void draw(NVGcontext *vg) override; - Widget *onMouseDown(Vec pos, int button) override; - bool onFocusText(int codepoint) override; - bool onFocusKey(int key) override; - bool onFocus() override; + void onMouseDown(EventMouseDown &e) override; + void onFocus(EventFocus &e) override; + void onText(EventText &e) override; + void onKey(EventKey &e) override; void insertText(std::string newText); virtual void onTextChange() {} }; diff --git a/src/app/Knob.cpp b/src/app/Knob.cpp index 01061ef6..4495b98e 100644 --- a/src/app/Knob.cpp +++ b/src/app/Knob.cpp @@ -10,29 +10,30 @@ namespace rack { #define KNOB_SENSITIVITY 0.0015 -void Knob::onDragStart() { +void Knob::onDragStart(EventDragStart &e) { guiCursorLock(); dragValue = value; randomizable = false; } -void Knob::onDragMove(Vec mouseRel) { +void Knob::onDragMove(EventDragMove &e) { // Drag slower if Mod + float delta = KNOB_SENSITIVITY * (maxValue - minValue) * -e.mouseRel.y; if (guiIsModPressed()) - mouseRel = mouseRel.mult(1/16.0); - dragValue += KNOB_SENSITIVITY * (maxValue - minValue) * -mouseRel.y; + delta /= 16.0; + dragValue += delta; if (snap) setValue(roundf(dragValue)); else setValue(dragValue); } -void Knob::onDragEnd() { +void Knob::onDragEnd(EventDragEnd &e) { guiCursorUnlock(); randomizable = true; } -void Knob::onChange() { +void Knob::onChange(EventChange &e) { if (!module) return; diff --git a/src/app/ModuleWidget.cpp b/src/app/ModuleWidget.cpp index 695fe0e9..548bdc06 100644 --- a/src/app/ModuleWidget.cpp +++ b/src/app/ModuleWidget.cpp @@ -165,7 +165,22 @@ void ModuleWidget::draw(NVGcontext *vg) { nvgResetScissor(vg); } -Widget *ModuleWidget::onMouseMove(Vec pos, Vec mouseRel) { +void ModuleWidget::onMouseDown(EventMouseDown &e) { + Widget::onMouseDown(e); + if (e.consumed) + return; + + if (e.button == 1) { + createContextMenu(); + } + e.consumed = true; + e.target = this; +} + +void ModuleWidget::onMouseMove(EventMouseMove &e) { + OpaqueWidget::onMouseMove(e); + + // Don't delete the ModuleWidget if a TextField is focused if (!gFocusedWidget) { // Instead of checking key-down events, delete the module even if key-repeat hasn't fired yet and the cursor is hovering over the widget. if (glfwGetKey(gWindow, GLFW_KEY_DELETE) == GLFW_PRESS || glfwGetKey(gWindow, GLFW_KEY_BACKSPACE) == GLFW_PRESS) { @@ -174,82 +189,85 @@ Widget *ModuleWidget::onMouseMove(Vec pos, Vec mouseRel) { this->finalizeEvents(); delete this; // Kinda sketchy because events will be passed further down the tree - return NULL; + return; } } } - return OpaqueWidget::onMouseMove(pos, mouseRel); } -Widget *ModuleWidget::onHoverKey(Vec pos, int key) { - switch (key) { +void ModuleWidget::onHoverKey(EventHoverKey &e) { + switch (e.key) { case GLFW_KEY_I: if (guiIsModPressed() && !guiIsShiftPressed()) { reset(); - return this; + e.consumed = true; + return; } break; case GLFW_KEY_R: if (guiIsModPressed() && !guiIsShiftPressed()) { randomize(); - return this; + e.consumed = true; + return; } break; case GLFW_KEY_D: if (guiIsModPressed() && !guiIsShiftPressed()) { gRackWidget->cloneModule(this); - return this; + e.consumed = true; + return; } break; } - return Widget::onHoverKey(pos, key); + Widget::onHoverKey(e); } -void ModuleWidget::onDragStart() { +void ModuleWidget::onDragStart(EventDragStart &e) { dragPos = gRackWidget->lastMousePos.minus(box.pos); } -void ModuleWidget::onDragMove(Vec mouseRel) { +void ModuleWidget::onDragEnd(EventDragEnd &e) { +} + +void ModuleWidget::onDragMove(EventDragMove &e) { Rect newBox = box; newBox.pos = gRackWidget->lastMousePos.minus(dragPos); gRackWidget->requestModuleBoxNearest(this, newBox); } -void ModuleWidget::onDragEnd() { -} struct DisconnectMenuItem : MenuItem { ModuleWidget *moduleWidget; - void onAction() override { + void onAction(EventAction &e) override { moduleWidget->disconnect(); } }; struct ResetMenuItem : MenuItem { ModuleWidget *moduleWidget; - void onAction() override { + void onAction(EventAction &e) override { moduleWidget->reset(); } }; struct RandomizeMenuItem : MenuItem { ModuleWidget *moduleWidget; - void onAction() override { + void onAction(EventAction &e) override { moduleWidget->randomize(); } }; struct CloneMenuItem : MenuItem { ModuleWidget *moduleWidget; - void onAction() override { + void onAction(EventAction &e) override { gRackWidget->cloneModule(moduleWidget); } }; struct DeleteMenuItem : MenuItem { ModuleWidget *moduleWidget; - void onAction() override { + void onAction(EventAction &e) override { gRackWidget->deleteModule(moduleWidget); moduleWidget->finalizeEvents(); delete moduleWidget; @@ -295,11 +313,5 @@ Menu *ModuleWidget::createContextMenu() { return menu; } -void ModuleWidget::onMouseDownOpaque(int button) { - if (button == 1) { - createContextMenu(); - } -} - } // namespace rack \ No newline at end of file diff --git a/src/app/ParamWidget.cpp b/src/app/ParamWidget.cpp index 5ebe765b..dcfde25f 100644 --- a/src/app/ParamWidget.cpp +++ b/src/app/ParamWidget.cpp @@ -19,13 +19,15 @@ void ParamWidget::randomize() { setValue(rescalef(randomf(), 0.0, 1.0, minValue, maxValue)); } -void ParamWidget::onMouseDownOpaque(int button) { - if (button == 1) { +void ParamWidget::onMouseDown(EventMouseDown &e) { + if (e.button == 1) { setValue(defaultValue); } + e.consumed = true; + e.target = this; } -void ParamWidget::onChange() { +void ParamWidget::onChange(EventChange &e) { if (!module) return; diff --git a/src/app/PluginManagerWidget.cpp b/src/app/PluginManagerWidget.cpp index 8e4b6023..c246c325 100644 --- a/src/app/PluginManagerWidget.cpp +++ b/src/app/PluginManagerWidget.cpp @@ -15,7 +15,7 @@ PluginManagerWidget::PluginManagerWidget() { Vec pos = Vec(0, 0); struct RegisterButton : Button { - void onAction() override { + void onAction(EventAction &e) override { std::thread t(openBrowser, "https://vcvrack.com/"); t.detach(); } @@ -46,7 +46,7 @@ PluginManagerWidget::PluginManagerWidget() { struct LogInButton : Button { TextField *emailField; TextField *passwordField; - void onAction() override { + void onAction(EventAction &e) override { std::thread t(pluginLogIn, emailField->text, passwordField->text); t.detach(); passwordField->text = ""; @@ -79,7 +79,7 @@ PluginManagerWidget::PluginManagerWidget() { Vec pos = Vec(0, 0); struct ManageButton : Button { - void onAction() override { + void onAction(EventAction &e) override { std::thread t(openBrowser, "https://vcvrack.com/"); t.detach(); } @@ -92,7 +92,7 @@ PluginManagerWidget::PluginManagerWidget() { pos.x += manageButton->box.size.x; struct RefreshButton : Button { - void onAction() override { + void onAction(EventAction &e) override { std::thread t(pluginRefresh); t.detach(); } @@ -106,7 +106,7 @@ PluginManagerWidget::PluginManagerWidget() { pos.x += refreshButton->box.size.x; struct LogOutButton : Button { - void onAction() override { + void onAction(EventAction &e) override { pluginLogOut(); } }; @@ -142,7 +142,7 @@ PluginManagerWidget::PluginManagerWidget() { pos.x += downloadProgress->box.size.x; // struct CancelButton : Button { - // void onAction() override { + // void onAction(EventAction &e) override { // pluginCancelDownload(); // } // }; diff --git a/src/app/Port.cpp b/src/app/Port.cpp index 881583d9..0f1e5ae0 100644 --- a/src/app/Port.cpp +++ b/src/app/Port.cpp @@ -17,23 +17,20 @@ void Port::draw(NVGcontext *vg) { } } -void Port::onMouseDownOpaque(int button) { - if (button == 1) { +void Port::onMouseDown(EventMouseDown &e) { + if (e.button == 1) { gRackWidget->wireContainer->removeTopWire(this); // HACK // Update hovered*Port of active wire if applicable - onDragEnter(NULL); + EventDragEnter e; + onDragEnter(e); } + e.consumed = true; + e.target = this; } -void Port::onDragEnd() { - // FIXME - // If the source Port is deleted, this will be called, removing the cable - gRackWidget->wireContainer->commitActiveWire(); -} - -void Port::onDragStart() { +void Port::onDragStart(EventDragStart &e) { // Try to grab wire on top of stack WireWidget *wire = gRackWidget->wireContainer->getTopWire(this); if (guiIsModPressed()) { @@ -62,10 +59,16 @@ void Port::onDragStart() { gRackWidget->wireContainer->setActiveWire(wire); } -void Port::onDragDrop(Widget *origin) { +void Port::onDragEnd(EventDragEnd &e) { + // FIXME + // If the source Port is deleted, this will be called, removing the cable + gRackWidget->wireContainer->commitActiveWire(); +} + +void Port::onDragDrop(EventDragDrop &e) { } -void Port::onDragEnter(Widget *origin) { +void Port::onDragEnter(EventDragEnter &e) { // Reject ports if this is an input port and something is already plugged into it if (type == INPUT) { WireWidget *topWire = gRackWidget->wireContainer->getTopWire(this); @@ -82,7 +85,7 @@ void Port::onDragEnter(Widget *origin) { } } -void Port::onDragLeave(Widget *origin) { +void Port::onDragLeave(EventDragEnter &e) { WireWidget *activeWire = gRackWidget->wireContainer->activeWire; if (activeWire) { if (type == INPUT) diff --git a/src/app/RackScene.cpp b/src/app/RackScene.cpp index 7b9481a7..7c6cf7c8 100644 --- a/src/app/RackScene.cpp +++ b/src/app/RackScene.cpp @@ -82,51 +82,55 @@ void RackScene::draw(NVGcontext *vg) { Scene::draw(vg); } -Widget *RackScene::onHoverKey(Vec pos, int key) { - switch (key) { +void RackScene::onHoverKey(EventHoverKey &e) { + switch (e.key) { case GLFW_KEY_N: if (guiIsModPressed() && !guiIsShiftPressed()) { gRackWidget->reset(); - return this; + e.consumed = true; + return; } break; case GLFW_KEY_Q: if (guiIsModPressed() && !guiIsShiftPressed()) { guiClose(); - return this; + e.consumed = true; + return; } break; case GLFW_KEY_O: if (guiIsModPressed() && !guiIsShiftPressed()) { gRackWidget->openDialog(); - return this; + e.consumed = true; + return; } break; case GLFW_KEY_S: if (guiIsModPressed() && !guiIsShiftPressed()) { gRackWidget->saveDialog(); - return this; + e.consumed = true; + return; } if (guiIsModPressed() && guiIsShiftPressed()) { gRackWidget->saveAsDialog(); - return this; + e.consumed = true; + return; } break; } - return Widget::onHoverKey(pos, key); + Widget::onHoverKey(e); } -bool RackScene::onPathDrop(Vec pos, const std::list& paths) { - if (paths.size() >= 1) { - const std::string& firstPath = paths.front(); +void RackScene::onPathDrop(EventPathDrop &e) { + if (e.paths.size() >= 1) { + const std::string& firstPath = e.paths.front(); if (extractExtension(firstPath) == "vcv") { gRackWidget->loadPatch(firstPath); - return true; + e.consumed = true; } } - return false; } diff --git a/src/app/RackWidget.cpp b/src/app/RackWidget.cpp index 3177567c..2d368c95 100644 --- a/src/app/RackWidget.cpp +++ b/src/app/RackWidget.cpp @@ -375,7 +375,7 @@ void RackWidget::draw(NVGcontext *vg) { struct AddModuleMenuItem : MenuItem { Model *model; Vec modulePos; - void onAction() override { + void onAction(EventAction &e) override { ModuleWidget *moduleWidget = model->createModuleWidget(); gRackWidget->moduleContainer->addChild(moduleWidget); // Move module nearest to the mouse position @@ -388,7 +388,7 @@ struct AddModuleMenuItem : MenuItem { struct UrlItem : MenuItem { std::string url; - void onAction() override { + void onAction(EventAction &e) override { std::thread t(openBrowser, url); t.detach(); } @@ -487,13 +487,17 @@ struct SearchModuleField : TextField { } }; -Widget *RackWidget::onMouseMove(Vec pos, Vec mouseRel) { - lastMousePos = pos; - return OpaqueWidget::onMouseMove(pos, mouseRel); +void RackWidget::onMouseMove(EventMouseMove &e) { + OpaqueWidget::onMouseMove(e); + lastMousePos = e.pos; } -void RackWidget::onMouseDownOpaque(int button) { - if (button == 1) { +void RackWidget::onMouseDown(EventMouseDown &e) { + Widget::onMouseDown(e); + if (e.consumed) + return; + + if (e.button == 1) { Menu *menu = gScene->createMenu(); menu->pushChild(construct(&MenuLabel::text, "Add module")); @@ -519,15 +523,17 @@ void RackWidget::onMouseDownOpaque(int button) { AddManufacturerMenuItem *item = new AddManufacturerMenuItem(); item->text = manufacturerName; item->manufacturerName = manufacturerName; - item->modulePos = lastMousePos; + item->modulePos = e.pos; menu->pushChild(item); } } + e.consumed = true; + e.target = this; } -void RackWidget::onZoom() { +void RackWidget::onZoom(EventZoom &e) { rails->box.size = Vec(); - Widget::onZoom(); + Widget::onZoom(e); } diff --git a/src/app/SVGKnob.cpp b/src/app/SVGKnob.cpp index 256e6917..0db5e415 100644 --- a/src/app/SVGKnob.cpp +++ b/src/app/SVGKnob.cpp @@ -35,9 +35,9 @@ void SVGKnob::step() { FramebufferWidget::step(); } -void SVGKnob::onChange() { +void SVGKnob::onChange(EventChange &e) { dirty = true; - Knob::onChange(); + Knob::onChange(e); } diff --git a/src/app/SVGSlider.cpp b/src/app/SVGSlider.cpp index 2bd40e8e..5d0beb60 100644 --- a/src/app/SVGSlider.cpp +++ b/src/app/SVGSlider.cpp @@ -21,9 +21,9 @@ void SVGSlider::step() { FramebufferWidget::step(); } -void SVGSlider::onChange() { +void SVGSlider::onChange(EventChange &e) { dirty = true; - ParamWidget::onChange(); + ParamWidget::onChange(e); } diff --git a/src/app/SVGSwitch.cpp b/src/app/SVGSwitch.cpp index 3b48819d..5b66518d 100644 --- a/src/app/SVGSwitch.cpp +++ b/src/app/SVGSwitch.cpp @@ -22,12 +22,12 @@ void SVGSwitch::step() { FramebufferWidget::step(); } -void SVGSwitch::onChange() { +void SVGSwitch::onChange(EventChange &e) { assert(frames.size() > 0); int index = clampi((int) roundf(value), 0, frames.size() - 1); sw->setSVG(frames[index]); dirty = true; - Switch::onChange(); + Switch::onChange(e); } diff --git a/src/app/Toolbar.cpp b/src/app/Toolbar.cpp index 5a04460a..df95947b 100644 --- a/src/app/Toolbar.cpp +++ b/src/app/Toolbar.cpp @@ -7,37 +7,37 @@ namespace rack { struct NewItem : MenuItem { - void onAction() override { + void onAction(EventAction &e) override { gRackWidget->reset(); } }; struct OpenItem : MenuItem { - void onAction() override { + void onAction(EventAction &e) override { gRackWidget->openDialog(); } }; struct SaveItem : MenuItem { - void onAction() override { + void onAction(EventAction &e) override { gRackWidget->saveDialog(); } }; struct SaveAsItem : MenuItem { - void onAction() override { + void onAction(EventAction &e) override { gRackWidget->saveAsDialog(); } }; struct QuitItem : MenuItem { - void onAction() override { + void onAction(EventAction &e) override { guiClose(); } }; struct FileChoice : ChoiceButton { - void onAction() override { + void onAction(EventAction &e) override { Menu *menu = gScene->createMenu(); menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)); menu->box.size.x = box.size.x; @@ -54,21 +54,21 @@ struct FileChoice : ChoiceButton { struct PauseItem : MenuItem { - void onAction() override { + void onAction(EventAction &e) override { gPaused = !gPaused; } }; struct SampleRateItem : MenuItem { float sampleRate; - void onAction() override { + void onAction(EventAction &e) override { engineSetSampleRate(sampleRate); gPaused = false; } }; struct SampleRateChoice : ChoiceButton { - void onAction() override { + void onAction(EventAction &e) override { Menu *menu = gScene->createMenu(); menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)); menu->box.size.x = box.size.x; @@ -149,8 +149,8 @@ Toolbar::Toolbar() { xPos += margin; { struct ZoomSlider : Slider { - void onAction() override { - Slider::onAction(); + void onAction(EventAction &e) override { + Slider::onAction(e); gRackScene->zoomWidget->setZoom(value / 100.0); } }; diff --git a/src/core/AudioInterface.cpp b/src/core/AudioInterface.cpp index 0da52dc0..21e5c16e 100644 --- a/src/core/AudioInterface.cpp +++ b/src/core/AudioInterface.cpp @@ -326,14 +326,14 @@ void AudioInterface::closeDevice() { struct AudioItem : MenuItem { AudioInterface *audioInterface; int deviceId; - void onAction() override { + void onAction(EventAction &e) override { audioInterface->setDeviceId(deviceId); } }; struct AudioChoice : ChoiceButton { AudioInterface *audioInterface; - void onAction() override { + void onAction(EventAction &e) override { Menu *menu = gScene->createMenu(); menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); menu->box.size.x = box.size.x; @@ -364,14 +364,14 @@ struct AudioChoice : ChoiceButton { struct SampleRateItem : MenuItem { AudioInterface *audioInterface; float sampleRate; - void onAction() override { + void onAction(EventAction &e) override { audioInterface->setSampleRate(sampleRate); } }; struct SampleRateChoice : ChoiceButton { AudioInterface *audioInterface; - void onAction() override { + void onAction(EventAction &e) override { Menu *menu = gScene->createMenu(); menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); menu->box.size.x = box.size.x; @@ -395,14 +395,14 @@ struct SampleRateChoice : ChoiceButton { struct BlockSizeItem : MenuItem { AudioInterface *audioInterface; int blockSize; - void onAction() override { + void onAction(EventAction &e) override { audioInterface->setBlockSize(blockSize); } }; struct BlockSizeChoice : ChoiceButton { AudioInterface *audioInterface; - void onAction() override { + void onAction(EventAction &e) override { Menu *menu = gScene->createMenu(); menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); menu->box.size.x = box.size.x; diff --git a/src/core/Blank.cpp b/src/core/Blank.cpp index ca1db935..07f4c691 100644 --- a/src/core/Blank.cpp +++ b/src/core/Blank.cpp @@ -10,20 +10,21 @@ struct ModuleResizeHandle : Widget { ModuleResizeHandle() { box.size = Vec(RACK_GRID_WIDTH * 1, RACK_GRID_HEIGHT); } - Widget *onMouseDown(Vec pos, int button) override { - if (button == 0) - return this; - return NULL; + void onMouseDown(EventMouseDown &e) override { + if (e.button == 0) { + e.consumed = true; + e.target = this; + } } - void onDragStart() override { + void onDragStart(EventDragStart &e) override { assert(parent); originalWidth = parent->box.size.x; totalX = 0.0; } - void onDragMove(Vec mouseRel) override { + void onDragMove(EventDragMove &e) override { ModuleWidget *m = dynamic_cast(parent); assert(m); - totalX += mouseRel.x; + totalX += e.mouseRel.x; float targetWidth = originalWidth; if (right) targetWidth += totalX; diff --git a/src/gui.cpp b/src/gui.cpp index ee4f8238..00ffd0f6 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -54,25 +54,36 @@ void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { #endif if (action == GLFW_PRESS) { + Widget *w = NULL; // onMouseDown - Widget *w = gScene->onMouseDown(gMousePos, button); + { + EventMouseDown e; + e.pos = gMousePos; + e.button = button; + gScene->onMouseDown(e); + w = e.target; + } if (button == GLFW_MOUSE_BUTTON_LEFT) { if (w) { // onDragStart - w->onDragStart(); + EventDragStart e; + w->onDragStart(e); } gDraggedWidget = w; if (w != gFocusedWidget) { if (gFocusedWidget) { // onDefocus - w->onDefocus(); + EventDefocus e; + w->onDefocus(e); } gFocusedWidget = NULL; if (w) { // onFocus - if (w->onFocus()) { + EventFocus e; + w->onFocus(e); + if (e.consumed) { gFocusedWidget = w; } } @@ -81,17 +92,27 @@ void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { } else if (action == GLFW_RELEASE) { // onMouseUp - Widget *w = gScene->onMouseUp(gMousePos, button); + Widget *w = NULL; + { + EventMouseUp e; + e.pos = gMousePos; + e.button = button; + gScene->onMouseUp(e); + w = e.target; + } if (button == GLFW_MOUSE_BUTTON_LEFT) { if (gDraggedWidget) { // onDragDrop - w->onDragDrop(gDraggedWidget); + EventDragDrop e; + e.origin = gDraggedWidget; + w->onDragDrop(e); } // gDraggedWidget might have been set to null in the last event, recheck here if (gDraggedWidget) { // onDragEnd - gDraggedWidget->onDragEnd(); + EventDragEnd e; + gDraggedWidget->onDragEnd(e); } gDraggedWidget = NULL; gDragHoveredWidget = NULL; @@ -141,19 +162,32 @@ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { gMousePos = mousePos; + Widget *hovered = NULL; // onMouseMove - Widget *hovered = gScene->onMouseMove(gMousePos, mouseRel); + { + EventMouseMove e; + e.pos = mousePos; + e.mouseRel = mouseRel; + gScene->onMouseMove(e); + hovered = e.target; + } if (gDraggedWidget) { // onDragMove - gDraggedWidget->onDragMove(mouseRel); + EventDragMove e; + e.mouseRel = mouseRel; + gDraggedWidget->onDragMove(e); if (hovered != gDragHoveredWidget) { if (gDragHoveredWidget) { - gDragHoveredWidget->onDragLeave(gDraggedWidget); + EventDragEnter e; + e.origin = gDraggedWidget; + gDragHoveredWidget->onDragLeave(e); } if (hovered) { - hovered->onDragEnter(gDraggedWidget); + EventDragEnter e; + e.origin = gDraggedWidget; + hovered->onDragEnter(e); } gDragHoveredWidget = hovered; } @@ -162,11 +196,13 @@ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { if (hovered != gHoveredWidget) { if (gHoveredWidget) { // onMouseLeave - gHoveredWidget->onMouseLeave(); + EventMouseLeave e; + gHoveredWidget->onMouseLeave(e); } if (hovered) { - // onMouseEnter - hovered->onMouseEnter(); + // onMouseEnter + EventMouseEnter e; + hovered->onMouseEnter(e); } gHoveredWidget = hovered; } @@ -174,14 +210,19 @@ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { if (glfwGetMouseButton(gWindow, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS) { // TODO // Define a new global called gScrollWidget, which remembers the widget where middle-click was first pressed - gScene->onScroll(mousePos, mouseRel); + EventScroll e; + e.pos = mousePos; + e.scrollRel = mouseRel; + gScene->onScroll(e); } } void cursorEnterCallback(GLFWwindow* window, int entered) { if (!entered) { if (gHoveredWidget) { - gHoveredWidget->onMouseLeave(); + // onMouseLeave + EventMouseLeave e; + gHoveredWidget->onMouseLeave(e); } gHoveredWidget = NULL; } @@ -194,31 +235,47 @@ void scrollCallback(GLFWwindow *window, double x, double y) { scrollRel = Vec(y, x); #endif // onScroll - gScene->onScroll(gMousePos, scrollRel.mult(50.0)); + EventScroll e; + e.pos = gMousePos; + e.scrollRel = scrollRel.mult(50.0); + gScene->onScroll(e); } void charCallback(GLFWwindow *window, unsigned int codepoint) { if (gFocusedWidget) { - gFocusedWidget->onFocusText(codepoint); + // onText + EventText e; + e.codepoint = codepoint; + gFocusedWidget->onText(e); } } void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) { if (action == GLFW_PRESS || action == GLFW_REPEAT) { - // onFocusKey - if (gFocusedWidget && gFocusedWidget->onFocusKey(key)) - return; + if (gFocusedWidget) { + // onKey + EventKey e; + e.key = key; + gFocusedWidget->onKey(e); + if (e.consumed) + return; + } // onHoverKey - gScene->onHoverKey(gMousePos, key); + EventHoverKey e; + e.pos = gMousePos; + e.key = key; + gScene->onHoverKey(e); } } void dropCallback(GLFWwindow *window, int count, const char **paths) { - std::list pathsList; + // onPathDrop + EventPathDrop e; + e.pos = gMousePos; for (int i = 0; i < count; i++) { - pathsList.push_back(paths[i]); + e.paths.push_back(paths[i]); } - gScene->onPathDrop(gMousePos, pathsList); + gScene->onPathDrop(e); } void errorCallback(int error, const char *description) { diff --git a/src/widgets/Button.cpp b/src/widgets/Button.cpp index 42c01873..d2fa4f2a 100644 --- a/src/widgets/Button.cpp +++ b/src/widgets/Button.cpp @@ -7,25 +7,26 @@ void Button::draw(NVGcontext *vg) { bndToolButton(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str()); } -void Button::onMouseEnter() { +void Button::onMouseEnter(EventMouseEnter &e) { state = BND_HOVER; } -void Button::onMouseLeave() { +void Button::onMouseLeave(EventMouseLeave &e) { state = BND_DEFAULT; } -void Button::onDragStart() { +void Button::onDragStart(EventDragStart &e) { state = BND_ACTIVE; } -void Button::onDragEnd() { +void Button::onDragEnd(EventDragEnd &e) { state = BND_HOVER; } -void Button::onDragDrop(Widget *origin) { - if (origin == this) { - onAction(); +void Button::onDragDrop(EventDragDrop &e) { + if (e.origin == this) { + EventAction eAction; + onAction(eAction); } } diff --git a/src/widgets/FramebufferWidget.cpp b/src/widgets/FramebufferWidget.cpp index 9d4a633d..030cc2ce 100644 --- a/src/widgets/FramebufferWidget.cpp +++ b/src/widgets/FramebufferWidget.cpp @@ -117,7 +117,7 @@ int FramebufferWidget::getImageHandle() { return internal->fb->image; } -void FramebufferWidget::onZoom() { +void FramebufferWidget::onZoom(EventZoom &e) { dirty = true; } diff --git a/src/widgets/Menu.cpp b/src/widgets/Menu.cpp index a2987f9c..a5009a68 100644 --- a/src/widgets/Menu.cpp +++ b/src/widgets/Menu.cpp @@ -52,12 +52,12 @@ void Menu::draw(NVGcontext *vg) { } -bool Menu::onScrollOpaque(Vec scrollRel) { +void Menu::onScroll(EventScroll &e) { if (!parent) - return true; + return; if (!parent->box.contains(box)) - box.pos = box.pos.plus(scrollRel); - return true; + box.pos = box.pos.plus(e.scrollRel); + e.consumed = true; } diff --git a/src/widgets/MenuItem.cpp b/src/widgets/MenuItem.cpp index 8bc8c03e..f1907767 100644 --- a/src/widgets/MenuItem.cpp +++ b/src/widgets/MenuItem.cpp @@ -22,7 +22,7 @@ void MenuItem::draw(NVGcontext *vg) { bndIconLabelValue(vg, x, 0.0, box.size.x, box.size.y, -1, rightColor, BND_LEFT, BND_LABEL_FONT_SIZE, rightText.c_str(), NULL); } -void MenuItem::onMouseEnter() { +void MenuItem::onMouseEnter(EventMouseEnter &e) { Menu *parentMenu = dynamic_cast(parent); if (!parentMenu) return; @@ -38,11 +38,12 @@ void MenuItem::onMouseEnter() { parentMenu->setChildMenu(childMenu); } -void MenuItem::onDragDrop(Widget *origin) { - if (origin != this) +void MenuItem::onDragDrop(EventDragDrop &e) { + if (e.origin != this) return; - onAction(); + EventAction eAction; + onAction(eAction); // deletes `this` gScene->setOverlay(NULL); } diff --git a/src/widgets/MenuOverlay.cpp b/src/widgets/MenuOverlay.cpp index e887c274..e7bde39b 100644 --- a/src/widgets/MenuOverlay.cpp +++ b/src/widgets/MenuOverlay.cpp @@ -3,18 +3,22 @@ namespace rack { -void MenuOverlay::onDragDrop(Widget *origin) { - if (origin == this) { +void MenuOverlay::onDragDrop(EventDragDrop &e) { + if (e.origin == this) { // deletes `this` gScene->setOverlay(NULL); } } -Widget *MenuOverlay::onHoverKey(Vec pos, int key) { - Widget *w = Widget::onHoverKey(pos, key); - if (w) return w; - // Steal all keys - return this; +void MenuOverlay::onScroll(EventScroll &e) { + // Don't recurse children, consume the event + e.consumed = true; +} + +void MenuOverlay::onHoverKey(EventHoverKey &e) { + // Recurse children but consume the event + Widget::onHoverKey(e); + e.consumed = true; } diff --git a/src/widgets/QuantityWidget.cpp b/src/widgets/QuantityWidget.cpp index b083ff02..268e4e99 100644 --- a/src/widgets/QuantityWidget.cpp +++ b/src/widgets/QuantityWidget.cpp @@ -4,12 +4,14 @@ namespace rack { QuantityWidget::QuantityWidget() { - onChange(); + EventChange e; + onChange(e); } void QuantityWidget::setValue(float value) { this->value = clampf(value, fminf(minValue, maxValue), fmaxf(minValue, maxValue)); - onChange(); + EventChange e; + onChange(e); } void QuantityWidget::setLimits(float minValue, float maxValue) { diff --git a/src/widgets/RadioButton.cpp b/src/widgets/RadioButton.cpp index e1a75641..fb7192a6 100644 --- a/src/widgets/RadioButton.cpp +++ b/src/widgets/RadioButton.cpp @@ -7,22 +7,23 @@ void RadioButton::draw(NVGcontext *vg) { bndRadioButton(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, value == 0.0 ? state : BND_ACTIVE, -1, label.c_str()); } -void RadioButton::onMouseEnter() { +void RadioButton::onMouseEnter(EventMouseEnter &e) { state = BND_HOVER; } -void RadioButton::onMouseLeave() { +void RadioButton::onMouseLeave(EventMouseLeave &e) { state = BND_DEFAULT; } -void RadioButton::onDragDrop(Widget *origin) { - if (origin == this) { +void RadioButton::onDragDrop(EventDragDrop &e) { + if (e.origin == this) { if (value == 0.0) value = 1.0; else value = 0.0; - onAction(); + EventAction eAction; + onAction(eAction); } } diff --git a/src/widgets/ScrollBar.cpp b/src/widgets/ScrollBar.cpp index db912ece..803071e5 100644 --- a/src/widgets/ScrollBar.cpp +++ b/src/widgets/ScrollBar.cpp @@ -19,21 +19,21 @@ void ScrollBar::draw(NVGcontext *vg) { bndScrollBar(vg, 0.0, 0.0, box.size.x, box.size.y, state, offset, size); } -void ScrollBar::onDragStart() { +void ScrollBar::onDragStart(EventDragStart &e) { state = BND_ACTIVE; guiCursorLock(); } -void ScrollBar::onDragMove(Vec mouseRel) { +void ScrollBar::onDragMove(EventDragMove &e) { ScrollWidget *scrollWidget = dynamic_cast(parent); assert(scrollWidget); if (orientation == HORIZONTAL) - scrollWidget->offset.x += mouseRel.x; + scrollWidget->offset.x += e.mouseRel.x; else - scrollWidget->offset.y += mouseRel.y; + scrollWidget->offset.y += e.mouseRel.y; } -void ScrollBar::onDragEnd() { +void ScrollBar::onDragEnd(EventDragEnd &e) { state = BND_DEFAULT; guiCursorUnlock(); } diff --git a/src/widgets/ScrollWidget.cpp b/src/widgets/ScrollWidget.cpp index 42fa4bff..c4faabf0 100644 --- a/src/widgets/ScrollWidget.cpp +++ b/src/widgets/ScrollWidget.cpp @@ -58,9 +58,9 @@ void ScrollWidget::step() { Widget::step(); } -bool ScrollWidget::onScrollOpaque(Vec scrollRel) { - offset = offset.minus(scrollRel); - return true; +void ScrollWidget::onScroll(EventScroll &e) { + offset = offset.minus(e.scrollRel); + e.consumed = true; } diff --git a/src/widgets/Slider.cpp b/src/widgets/Slider.cpp index a0e2c3aa..de3e22cb 100644 --- a/src/widgets/Slider.cpp +++ b/src/widgets/Slider.cpp @@ -11,26 +11,30 @@ void Slider::draw(NVGcontext *vg) { bndSlider(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, progress, getText().c_str(), NULL); } -void Slider::onDragStart() { +void Slider::onDragStart(EventDragStart &e) { state = BND_ACTIVE; guiCursorLock(); } -void Slider::onDragMove(Vec mouseRel) { - setValue(value + SLIDER_SENSITIVITY * (maxValue - minValue) * mouseRel.x); +void Slider::onDragMove(EventDragMove &e) { + setValue(value + SLIDER_SENSITIVITY * (maxValue - minValue) * e.mouseRel.x); } -void Slider::onDragEnd() { +void Slider::onDragEnd(EventDragEnd &e) { state = BND_DEFAULT; guiCursorUnlock(); - onAction(); + EventAction eAction; + onAction(eAction); } -void Slider::onMouseDownOpaque(int button) { - if (button == 1) { +void Slider::onMouseDown(EventMouseDown &e) { + if (e.button == 1) { setValue(defaultValue); - onAction(); + EventAction eAction; + onAction(eAction); } + e.consumed = true; + e.target = this; } diff --git a/src/widgets/TextField.cpp b/src/widgets/TextField.cpp index f3703f36..8bea1bf5 100644 --- a/src/widgets/TextField.cpp +++ b/src/widgets/TextField.cpp @@ -24,21 +24,25 @@ void TextField::draw(NVGcontext *vg) { } } -Widget *TextField::onMouseDown(Vec pos, int button) { - end = begin = bndTextFieldTextPosition(gVg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str(), pos.x, pos.y); - return OpaqueWidget::onMouseDown(pos, button); +void TextField::onMouseDown(EventMouseDown &e) { + end = begin = bndTextFieldTextPosition(gVg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str(), e.pos.x, e.pos.y); + OpaqueWidget::onMouseDown(e); } +void TextField::onFocus(EventFocus &e) { + begin = 0; + end = text.size(); + e.consumed = true; +} -bool TextField::onFocusText(int codepoint) { - char c = codepoint; - std::string newText(1, c); +void TextField::onText(EventText &e) { + std::string newText(1, (char) e.codepoint); insertText(newText); - return true; + e.consumed = true; } -bool TextField::onFocusKey(int key) { - switch (key) { +void TextField::onKey(EventKey &e) { + switch (e.key) { case GLFW_KEY_BACKSPACE: if (begin < end) { text.erase(begin, end - begin); @@ -107,20 +111,15 @@ bool TextField::onFocusKey(int key) { insertText("\n"); } else { - onAction(); + EventAction e; + onAction(e); } break; } begin = mini(maxi(begin, 0), text.size()); end = mini(maxi(end, 0), text.size()); - return true; -} - -bool TextField::onFocus() { - begin = 0; - end = text.size(); - return true; + e.consumed = true; } void TextField::insertText(std::string newText) { diff --git a/src/widgets/Widget.cpp b/src/widgets/Widget.cpp index 6d955a16..d6c6c0fc 100644 --- a/src/widgets/Widget.cpp +++ b/src/widgets/Widget.cpp @@ -78,18 +78,21 @@ void Widget::clearChildren() { void Widget::finalizeEvents() { // Stop dragging and hovering this widget if (gHoveredWidget == this) { - gHoveredWidget->onMouseLeave(); + EventMouseLeave e; + gHoveredWidget->onMouseLeave(e); gHoveredWidget = NULL; } if (gDraggedWidget == this) { - gDraggedWidget->onDragEnd(); + EventDragEnd e; + gDraggedWidget->onDragEnd(e); gDraggedWidget = NULL; } if (gDragHoveredWidget == this) { gDragHoveredWidget = NULL; } if (gFocusedWidget == this) { - gFocusedWidget->onDefocus(); + EventDefocus e; + gFocusedWidget->onDefocus(e); gFocusedWidget = NULL; } for (Widget *child : children) { @@ -114,93 +117,51 @@ void Widget::draw(NVGcontext *vg) { } } -Widget *Widget::onMouseDown(Vec pos, int button) { - for (auto it = children.rbegin(); it != children.rend(); it++) { - Widget *child = *it; - if (!child->visible) - continue; - if (child->box.contains(pos)) { - Widget *w = child->onMouseDown(pos.minus(child->box.pos), button); - if (w) - return w; - } - } - return NULL; +#define RECURSE_EVENT_POSITION(_method) { \ + Vec pos = e.pos; \ + for (auto it = children.rbegin(); it != children.rend(); it++) { \ + Widget *child = *it; \ + if (!child->visible) \ + continue; \ + if (child->box.contains(pos)) { \ + e.pos = pos.minus(child->box.pos); \ + child->_method(e); \ + if (e.consumed) \ + break; \ + } \ + } \ + e.pos = pos; \ } -Widget *Widget::onMouseUp(Vec pos, int button) { - for (auto it = children.rbegin(); it != children.rend(); it++) { - Widget *child = *it; - if (!child->visible) - continue; - if (child->box.contains(pos)) { - Widget *w = child->onMouseUp(pos.minus(child->box.pos), button); - if (w) - return w; - } - } - return NULL; + +void Widget::onMouseDown(EventMouseDown &e) { + RECURSE_EVENT_POSITION(onMouseDown); } -Widget *Widget::onMouseMove(Vec pos, Vec mouseRel) { - for (auto it = children.rbegin(); it != children.rend(); it++) { - Widget *child = *it; - if (!child->visible) - continue; - if (child->box.contains(pos)) { - Widget *w = child->onMouseMove(pos.minus(child->box.pos), mouseRel); - if (w) - return w; - } - } - return NULL; +void Widget::onMouseUp(EventMouseUp &e) { + RECURSE_EVENT_POSITION(onMouseUp); } -Widget *Widget::onHoverKey(Vec pos, int key) { - for (auto it = children.rbegin(); it != children.rend(); it++) { - Widget *child = *it; - if (!child->visible) - continue; - if (child->box.contains(pos)) { - Widget *w = child->onHoverKey(pos.minus(child->box.pos), key); - if (w) - return w; - } - } - return NULL; +void Widget::onMouseMove(EventMouseMove &e) { + RECURSE_EVENT_POSITION(onMouseMove); } -Widget *Widget::onScroll(Vec pos, Vec scrollRel) { - for (auto it = children.rbegin(); it != children.rend(); it++) { - Widget *child = *it; - if (!child->visible) - continue; - if (child->box.contains(pos)) { - Widget *w = child->onScroll(pos.minus(child->box.pos), scrollRel); - if (w) - return w; - } - } - return NULL; +void Widget::onHoverKey(EventHoverKey &e) { + RECURSE_EVENT_POSITION(onHoverKey); } -bool Widget::onPathDrop(Vec pos, const std::list& paths) { - for (auto it = children.rbegin(); it != children.rend(); it++) { - Widget *child = *it; - if (!child->visible) - continue; - if (child->box.contains(pos)) { - if (child->onPathDrop(pos.minus(child->box.pos), paths)); - return true; - } - } - return false; +void Widget::onScroll(EventScroll &e) { + RECURSE_EVENT_POSITION(onScroll); +} + +void Widget::onPathDrop(EventPathDrop &e) { + RECURSE_EVENT_POSITION(onPathDrop); } -void Widget::onZoom() { +void Widget::onZoom(EventZoom &e) { for (auto it = children.rbegin(); it != children.rend(); it++) { Widget *child = *it; - child->onZoom(); + child->onZoom(e); } } diff --git a/src/widgets/ZoomWidget.cpp b/src/widgets/ZoomWidget.cpp index a0bb4b0c..c6d6cb5d 100644 --- a/src/widgets/ZoomWidget.cpp +++ b/src/widgets/ZoomWidget.cpp @@ -18,8 +18,10 @@ Rect ZoomWidget::getViewport(Rect r) { } void ZoomWidget::setZoom(float zoom) { - if (zoom != this->zoom) - onZoom(); + if (zoom != this->zoom) { + EventZoom e; + onZoom(e); + } this->zoom = zoom; } @@ -28,24 +30,39 @@ void ZoomWidget::draw(NVGcontext *vg) { Widget::draw(vg); } -Widget *ZoomWidget::onMouseDown(Vec pos, int button) { - return Widget::onMouseDown(pos.div(zoom), button); +void ZoomWidget::onMouseDown(EventMouseDown &e) { + Vec pos = e.pos; + e.pos = e.pos.div(zoom); + Widget::onMouseDown(e); + e.pos = pos; } -Widget *ZoomWidget::onMouseUp(Vec pos, int button) { - return Widget::onMouseUp(pos.div(zoom), button); +void ZoomWidget::onMouseUp(EventMouseUp &e) { + Vec pos = e.pos; + e.pos = e.pos.div(zoom); + Widget::onMouseUp(e); + e.pos = pos; } -Widget *ZoomWidget::onMouseMove(Vec pos, Vec mouseRel) { - return Widget::onMouseMove(pos.div(zoom), mouseRel); +void ZoomWidget::onMouseMove(EventMouseMove &e) { + Vec pos = e.pos; + e.pos = e.pos.div(zoom); + Widget::onMouseMove(e); + e.pos = pos; } -Widget *ZoomWidget::onHoverKey(Vec pos, int key) { - return Widget::onHoverKey(pos.div(zoom), key); +void ZoomWidget::onHoverKey(EventHoverKey &e) { + Vec pos = e.pos; + e.pos = e.pos.div(zoom); + Widget::onHoverKey(e); + e.pos = pos; } -Widget *ZoomWidget::onScroll(Vec pos, Vec scrollRel) { - return Widget::onScroll(pos.div(zoom), scrollRel); +void ZoomWidget::onScroll(EventScroll &e) { + Vec pos = e.pos; + e.pos = e.pos.div(zoom); + Widget::onScroll(e); + e.pos = pos; } From 55088c0183699a73d1fd3cb0cc3406ac93f5e243 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 2 Nov 2017 05:48:42 -0400 Subject: [PATCH 04/11] Use My Documents/Rack for local directory on Windows --- src/asset.cpp | 16 +++++++++++++--- src/main.cpp | 12 +++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/asset.cpp b/src/asset.cpp index 8fc4d13c..f01e31c1 100644 --- a/src/asset.cpp +++ b/src/asset.cpp @@ -9,6 +9,11 @@ #include #endif +#if ARCH_WIN + #include + #include +#endif + namespace rack { @@ -76,9 +81,14 @@ std::string assetLocal(std::string filename) { path += "/" + filename; #endif #if ARCH_WIN - // TODO - // Use ~/My Documents/Rack or something - path = "./" + filename; + // Get My Documents folder + char buf[MAX_PATH]; + HRESULT result = SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, buf); + assert(result == S_OK); + path = buf; + path += "/Rack"; + CreateDirectory(path.c_str(), NULL); + path += "/" + filename; #endif #if ARCH_LIN // TODO diff --git a/src/main.cpp b/src/main.cpp index 4fae38f7..3278c84a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,9 +10,15 @@ using namespace rack; int main(int argc, char* argv[]) { - char *cwd = getcwd(NULL, 0); - printf("Current working directory is %s\n", cwd); - free(cwd); + { + char *cwd = getcwd(NULL, 0); + printf("Current working directory: %s\n", cwd); + free(cwd); + std::string globalDir = assetGlobal(""); + std::string localDir = assetLocal(""); + printf("Global directory: %s\n", globalDir.c_str()); + printf("Local directory: %s\n", localDir.c_str()); + } pluginInit(); engineInit(); From c91e0f127bd8745aac49caf2741856d3d03acd96 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 2 Nov 2017 05:50:03 -0400 Subject: [PATCH 05/11] Add NSIS installer --- installer.nsi | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 installer.nsi diff --git a/installer.nsi b/installer.nsi new file mode 100644 index 00000000..c6fc468a --- /dev/null +++ b/installer.nsi @@ -0,0 +1,88 @@ + +!include "MUI2.nsh" + +Name "VCV Rack" +OutFile "Rack-setup.exe" +SetCompressor "bzip2" +CRCCheck On + +;Default installation folder +InstallDir "$PROGRAMFILES\VCV" + +;Get installation folder from registry if available +InstallDirRegKey HKCU "Software\VCV Rack" "" + +;Request application privileges for Windows Vista +RequestExecutionLevel admin + + + +!define MUI_ICON "icon.ico" + +!define MUI_HEADERIMAGE +!define MUI_HEADERIMAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Header\nsis.bmp" ; 150x57 +!define MUI_WELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\win.bmp" ; 164x314 +!define MUI_UNWELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\win.bmp" ; 164x314 +!define MUI_COMPONENTSPAGE_NODESC + + +; Pages + +; !insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_COMPONENTS +!insertmacro MUI_PAGE_DIRECTORY + +;second directory selection +; Var DbInstDir +; !define MUI_PAGE_HEADER_SUBTEXT "Choose the folder in which to install the database." +; !define MUI_DIRECTORYPAGE_TEXT_TOP "The installer will install the database(s) in the following folder. To install in a differenct folder, click Browse and select another folder. Click Next to continue." +; !define MUI_DIRECTORYPAGE_VARIABLE $DbInstDir ; <= the other directory will be stored into that variable +; !insertmacro MUI_PAGE_DIRECTORY + +!insertmacro MUI_PAGE_INSTFILES + +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES + +!insertmacro MUI_LANGUAGE "English" + + + +Section "!VCV Rack" VCVRACK + SetOutPath "$INSTDIR" + + File /r "dist\Rack" + + ;Store installation folder + WriteRegStr HKCU "Software\VCV Rack" "" $INSTDIR + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VCV Rack" "DisplayName" "VCV Rack" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VCV Rack" "UninstallString" "$\"$INSTDIR\UninstallRack.exe$\"" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VCV Rack" "QuietUninstallString" "$\"$INSTDIR\UninstallRack.exe$\" /S" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VCV Rack" "InstallLocation" "$\"$INSTDIR$\"" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VCV Rack" "Publisher" "VCV" + + ;Create uninstaller + WriteUninstaller "$INSTDIR\UninstallRack.exe" + + ;Create shortcuts + CreateDirectory "$SMPROGRAMS" + ; Set working directory of shortcut + SetOutPath "$INSTDIR\Rack" + CreateShortcut "$SMPROGRAMS\VCV Rack.lnk" "$INSTDIR\Rack\Rack.exe" +SectionEnd + + +; Section "VST Plugin" VST +; SectionEnd + + +Section "Uninstall" + RMDir /r "$INSTDIR\Rack" + Delete "$INSTDIR\UninstallRack.exe" + RMDir "$INSTDIR" + + Delete "$SMPROGRAMS\VCV Rack.lnk" + + DeleteRegKey /ifempty HKCU "Software\VCV Rack" + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VCV Rack" +SectionEnd From 3fea2f9674e77ce9675a02d7c8f16cb7c7e8af7a Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 2 Nov 2017 08:23:42 -0400 Subject: [PATCH 06/11] Added Windows installer banner --- installer-banner.bmp | Bin 0 -> 34338 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 installer-banner.bmp diff --git a/installer-banner.bmp b/installer-banner.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8b1c03b5f69f46a6c8e81a70b28678efb5d1bec8 GIT binary patch literal 34338 zcmcJY2b@+#vi8TgYgk=(*Q{ii8JHR35QdC^Bm+n=Vn8JbDnSJU83hzXKqQC+iIQ{9 zIp-`i++(yZX4R zn7giu$r5voyZ7xB6Z6lTQZM&v{}dAw`7fs2gEg94Mn>;fM-|l9Uw?hswRrJjO`JGU zd-v}3*T#(-{e9oQeVR6Hn&!`+e_8qH`f0sGYuo0{>OOpw`psRaIjdG{-|pSo?Jn{* zY}laDqepAUjvaqUd;9k78vWHMecW!k>Xx3WSyNVP&z?P=&boE$^wn2iY3I(Je@G|f zbML;rnmu{F9?koeK5jE!UoBm#q(NiUbKYX@cm1a9`0?YlY}vBk(cQXrtLL3N<+#%) zcAU#_R0ep=5w^Nf}(S)y&*ws|`H9j*EkrmJwD!CJg# zt>b6!73oCNz0!N9PM!3`6HoXtWqjd#)22q6_>Z@<0l z0#~C(jnc7W$8_}QQ9nl9j~_p-apT5m?%cVTm5;8U*8A5^#_?ZHRI&cU^rn+hp3yT@ zefW4CIC#*vK_7+<8|HDAR{bz-`;INDUSxnie0!EooIIw3j>h4`hdmv}4m!v(tdr5_ zS+iy;rSYfAIbf2fiM;4L^+${t;c*pB3mgp}KHTGgvW(54Lx=o$fvGla+ISwL>qWnB zcJq!l)~;Qv3Kc47=+L3QZD_7ou|oZae5rp8o2;=*SNxy)7Tq52$gW?%e!jhh3m5t^ zr_bbp5pclVPpfX2wtxSA&oARhI@k&Gc|LOFh?fh`^a=f7vi;_pZ@j#t>yX~Od2^L1 zQ$`bRqM($W56^?DT@Jx#~l7(kCcT03C4 zTeog{f#t`8-~Ojp~*%Qb1}I@QcSRV!Dnj_?Flpwqc?XTA5{dwTN8C-v4_Z;8H# zyrX-oR;}t~fqo<3_yPYNJ9hN?tAGFg`t;LJMZd_W??#6{wP?{oAAR(ZpU*ZX`&@dB ziL=#c+B}^&dbvJ;2AH6aFTVJquaEw>w$r=QFLZ0;#*OvKC!a*-WXKP7Pn|lYwr$(` zdGgw8uce~)kaarW$4Pxs83Gup6rrykBdNh=orhI86rt}tH4540tAhiLxFRS`XHe9W7@L{)NP z6OW|Jo0UcG4?g&y_mBR}cv}7FyV>9d4H|fCh55*;_ktx#ar*v58a5{^`)8ifGw4YC zyl}4m85-+0tkvu7YJ1&DAHs{d0xiQ8V{qe*H|qWO-&dEeUEInc#{2Nx-+A{PuRs6# z*S~uIuVBG~s`p%7)ok{LV(K=~8_k-jK!F0PRJoG3+L^x?t6>Wk z>)_s0zlgb$IddkbYdh=B7Oj=_s&}<^)fP2qP+yN$e^i5q3|9U6_4V{qPwCJehmCdX zRlIRi#XQ?kF)cgl@2xuO{x@1Hv1MD8YTZe#rp?vEoxADw>UC6i@JMBP`Bi1=(o;9I zY^T3;AFcv}#w#XYK9zndMOA8*)s5HPs6EbpZ`-z2YnJcQ!|~HJe$*l@UA#J?`_WnS zwL!xMdiAwel_yUgHFJG6-;Vxm+wL&#XwXj^n}GudDmgh>4?p~{$2atNs}h&DJR?M)29o+i@t<(cwXw(HU$eNt7C_zYSyBulJnoKer;pbzsmz! zw{U%0(*YzVy-{FdR{uRA6afah3wGU0| zw^7{HJ(Ta5qlOKgtheY{$M4cbi}c>O3A(Cb3*FeIx3V?QtkSJ&>zOf= zb^W^^>4q-NbW_{PYB=CMjhQe)2lnq(@2-=T?do@w@9!UJ)ylPgzF`L*dgvj4WzL*g z6)RTs^TyUf$Z*2M30_{vl`$pns;jQ@^O8A=l{)Qg>gYvF6w|4jd~;_ln=M;5<<6a3^B2tbX(7E8D^_aM;CEE7a*WzMAEVCAa=5kR zI-NXq&Xqmx{dn4=pC5JmNW+E?(>2#z<84TYt9kS1c{yayo?TO?P4yT%c#+lef&JC=P>i`&=F3@3{?3M6Vh!S)}r|<{J7#LHEPsI#fumB^1@eVEo!*h;&9xwSyTPx zFMshd24pjMaB4qqzx{U4)4%@pFM$E*u)c>+)@SvdUS`fAf3CUn<|-~O&gVC8(cF(Q zxMJLvY;^J~T2e9DW7S~#0v&U@BqO+5yKb$g*QHAr?bx})w_~_Mo?m?Nh5q@^f9mgl z|GTD4o$@w-P#4Cp_=_W`@oqeln+c#_0ERU6xloZXLJzHf;mC~!7yXdVsi&XXTC%nwSe5dz2 z`Tn+eqlKzhuO7kGx6UsbxoD}HIa{^N$;f0`s8B(D_})}?e{ZIW7fVsC2{Uz9ryi=< zsmaJW;W>d!Mp1!>lUw?wr@pH7z*%;cx4(839S1nt$ zbnSki=U;eP?K^hSuHE}we(HLHv0J@*wRY~>>1B=2^0&YJP50b$j~`RkhUd?p_x?H9 zLe|W`oH=uP{{~qwPWXeY)tWYK>g^BdhO4ig{%<;UuIi4Rs`ak#jOicYiu$xg%nV(M zO*A}^&NFtUckkZbx8s?#@M6B!tW{HE2EDHSy_zaVj_eT|4G-8h)=aFK8#;SYvSdjg z7lppH53X*y=_Y^OaKjB=CZ>OwW5|m8oH=v+*xhy4UAon!U4Q-cYSN^MA7d~G{?Q5O z62`{-4xVQ?TaK>*@3i}`f83^`B}?d*himDt?YgP&;uU)FnWvS{jU_q)tYR0b%Z2U0 z#xTFGzwUbP`w)+WFL;M<{2{Opzqh$^w>y17zV+qin{U>A_uc1p3>et5WsA<7JfqHI z-_e~ND=B;b(Q3b7sn%`U?ADjZl;p5jw%GluR`LcltoaXT3lcQg&EZk~>TAiIAwH&f z=$q8o8vVle!k=M{j()|bW$i#b;@x-ORjXF5{F;o|6=jiwjU}?dw?ape2Cf)CpYM1* z>hdU`QCv}$crdcFHmGa3A|K4zyOps!vD^6gc$FwwN`(p~>)w0sy$o0AJIY??<}Egg zxg8fD=j{%(p$o3?+tJ00XE+x4po|x3_*aDr6;jcnMSVN?9mGY@9bm1L(`7kw(&98Be;SGWCA|nd%}bX-j+eLQl(0|_S$PbU2ugA;IHe14^*vB1&vs| zRJRYCrnaAVQTJE>s)tJdOR>3fdY*dq>gDJ8!2^3WX~=8p-|7}k9`mu&H@{!U+W4e* zxAh?TV2U^%d=fV$&2R4Gg zvVsnJlsPbd@-n@DK&YXp3(^tfn4m-c4y7Zv4 z0oEV*1xL{2PCqQp0RHiLtqtDM-^*8|wo4v-&?e6d7B28Mg+3rVcwV?@q3;iUrA@;X z?VLDvT5Tt`QH#EfG@xy6wU{(fIR=l{oaL+hdJGzrL;rC9=9?qhuyLJck87{N9TT*6 zO{!n^^2;yl?z`{yIK&@k4iRU?hiCnTzl?oFme7F@?yS-2tBteaihS&(*(ziN&M1$J z;D>sYW1R8ZS({NFpYBSyqRy2rc;vEiw6gGU?93@0J9Sd0zCW+cE}p$|>qedV>4Mg6 z*sj4nm#O)4qt*JADH=I&xjuYnmO3__<#c(f?BI99#tj}*wqB);^&8gvaYFYY6Z*&c z0}Rra!$%HBa77HOuiGO$v_E*n>9Knwn?4s=djJf{;E&T7-%oyzyf14^n@LCqQs)Pq^3YW#>5 z-VVZ3>&6px_jQlxhHLKCm;DwyI>&t;wknNZpJzl9MHy} z!4>_)$3V7R@NRQCf~$*XwPMQ#CDpB@f<-=8kB&h$8fc8_bw&6vjZ{BTI-D| zvwi<)557l^9H~JrPPTnV>fQ}?kZbEUt;Jdky2z3-`+CpUTD5wWA0uoVwjnIfxb54& z&zEJ7mwn7BQ>OTJFLFTFu_sB)3A`AtjynH*@q)>E{!1yLOhjN4KW_p z8sLsTQ3oAWt5&VZ_K=3gHNL^WaDMx=I!P!o1E>~pl^@8#0UgE62llqb*h8+E`QY2?us7resDZWpWP zopR_0`a-(3g}#C=dFz~=+U)j%D1YYUSv4H|qNXgK;`Wvteb;~H(`jeltBjweCX;5m z^sgf_h9336_Q6BPG_ZYwmM@v(^vWiIarkGx;3t3=c!dw@u;+?DcJK~=#v6XP7fUH7 z;+6O=$j~nIlC=wO_RO9Edx+3EdfZ*kNB`i>`TFdm#X9xf*;GuqH2P(@B2LBJWRBwt zP#1Zjhp;jB&NySkIgf)Kga-PTy4XVO67Pm9WP`6m%#fJA*=fd}^0dd?qb=%v`Q?{> zp5qsQ1H+ZI0S&_tbyhjNvhKk)QwCblgbwx+S-~Uw4U;EN_WM(eHFeEz=b85KeR$^D zv1f>-Af2z13fg9k>E>ti>2t?!;IQxjC@eVQSyuLn>OPgc9;4di*^5?6W%W z%Fl8!)?IE7AvP(u%S-Zk=zqqKi}8j}JGX;xvB|}*!#U zmpQ>$n|w**f-Y(BMH#~tZO|UN8~tMZkRS4l%#082;Fq%S16}wq{TSlP`UDRbFJ9Cy zKmVdJ%fHfFLtA*AWtgF@TJ}shq;Fmeg7~Fo_)f&{fjLx3_(Z_LH zz1_;|8T^XG#Kedlgf4cAIYw+eI?g~I_M3cUa`N0+ZFTFf(?5Ube4F)pv-R8hplcVu z-+t=+S-_}3w$iT-%Yu1eDD&m94 zo_y$Z?fRjfDmvfAckcIo*sU&ZNx#wA)(&m(jt}zRxR?vjWc(Og8}~nZH(Y>CboGCO zH)zmTctcLe&}51{*sH&X;j@PJe$v^VTfWoQwPP&G%=tY0pk=+xgqMBO7n{r(JYC?OET#J7t;U zZQQv<@Q!}6eDca9HrJ|!hg{6CfbSQ5<3c{rHhpDv{#$qC#`T}lGkx`+(n+g+sISQ9 z47SO~?$>6zT6MpCBGM1T6*8YZWwJUuncp{Jie{}?<;Q_~wjL~8q`1cSspRz4o8D(& ztwa2TJt^iL@;3~DAAD|N29}0hM{i))@kJK9J>=sKS34Z8cK_hkUH|igzB%pU^!UTh zuK`!{*DTlS^G9^z*YEW0xl=x-Lp$^jx~8wvl1E0?T6?KUHvfn}MoqZrX#}~HCnt@n8YiahoI5S3?l?ic$E`Q*G2Ygx1)ZmvPGb;-p z=wr^05H~MTB6TfBel)Hq%N)bsVC~CZq{ViO9(T%NXQ2g6?31lMtXzmI_+kIW@I;*1 zo=dbZ;`CAK8pUvh4&|9Pb~>G$GIENB&tIe#ZtaJ@!`}rfJGZ($oM*36j-0vF=#@r3 zwnALX^p)|7+|4&34Shu#{XlPV@qE&)!?y0-rBluhp8D~kP7z1C6x+f^&Rw=hXMg!# zCx38fFkRj;7ca8@LNBAZqAk`B_^IHU{$56BEB;}sobele_~D1hI8Zm#SKxYylRNb|>%cx7XS_}Rj0?O|#&8AAaEz=hy4`3pcS+}bt>t6S=}U+!+Qr6Frf%K3 zk+S%f(LMt0Q;v9*(ZnwfnG`_pMKUazx?9YZRk7dBLnJk&cVlS zT%3(G!xed)vF7{|cAL23rfpkv!r^O|i~Du`=tCc;LQcnB+-T<9InGv|)@ElLJALrJ z-&eNz^k;Ad50s~Wp$@Qg zuF&5`C%l78>cmZ`fckj!xeg$^JylV!_NPW8#7C--8l*{g?!1IJZYjndhIs7T)(ku z*RJi)sIzV*pK*KPg%=|2g8gtkh>vf)`1PQhFT@#;FMG0xjUf9y}7tZS+|M*8F zkN6nvz)ME;mB}%!J9MB&9zG>8IqVj`7=4Py6?5MBB%Wf=b?VgdWvva$g>el#%f@*l z(;J2>`~#!I_@f801H?p)9`P0{!`U!#gA}w101^JtV$He3pGuV#X$Ce5okI0(+e#VqC(BU_M&?KF5#=FgzP+#Hm^IHrX z54#hS3fqJy_QovV?!Wy`=Qle@+nkB8GTa&G&<;YIGd5uv^dadXu6V}}Gdx*&{NRv3 zduHxi8SY@(^0-IiiZpa0wwoA^Va4j?`yjV=Z@;u2bT)}IZO~og&bYEqL=24gzqvTm zU%L&^J$VvcJZ-O+=~rE|`@A;wZcu}!_4Mu8)Hn|^$4BIxh{ZVE*cB+_~4!-Fj@VU(*ce-BJVIjM1R(52*T^4R!4M zvk`eAH~K+b5qZ-dyps-3#7%8~kTl~7U5fsuZ^(%}i!l*P0k7y@j61xs|ALH-hY(lvgSkf;{6BP1 zxQ9a>F7Qqnd{*Me^o#u!_9~!38N(I2g*^Je{HLG9iIAVsqfeaofEE{HV`CoT3fioB zvF+GqY$?ysH(GXwZ+t0!s|-z^=@08GD?=Of1^t(IeNdV7qEMXgEQzhcf(AA0bH zj^Ld&H&~|cL*_0}e)pT2)6A=1f6~vAi)KoD4j=G!sE0hj2l8W#j6dW;8nQ-@pc_rT z+-+ZoSU?!#B@Ya;HbPFeZx!MS-r4WxTu6vj>kI9n=S>&k%b-Ka4{>F@hIiTzaTVtM zr_Y9~|CCOMtN)Z%bbZ5abo!Ov7p_~VLYcnY(c5uYV5toe%^MzO$@jT>v(#`L8 zdiBvYkH4UX^%W~B;tJltJ$`4P}SE=R98Z8r4<1PHnL!X5aeY-h)d1 zFt0mDI>*HiCVRh#^&tFEA3vFkcr12%45}C>}j{2t6N7e zJokjZ8aJxv@AaO4(x;R6yt}Ln_h+A}?caTwOV6Z-WuAXF^*y9xW$Hd%Gva^Ie{84O z&uH0TN6~@UXmk(bV7eZ;qB|K&eh)&-$6^A=0C`61EAV7z+|hxYUr!4M=+0`@szvl9 zK6f}ShAZl_ZVuOG_&xeVvLAq^Nw^qKeIa zw`xCD&DAfbhpLqGb#r97<1$>C9HQ^YWPv-M!kA!3InTlR-_``=^P5uU4Er*yRruWu zeK)@;#1%Tn&PUjIa7UhD+tB6rF<}{=t5m5H!Jy#^97LDnJ&ax8mykyMm9?>zryn7% zms7f$iXR7PsMXK?68|~P?N67`_RIG5K ziWW}rSBaE-k!MRQRU)4ruUOST8!?{5$3+vZb8i3jg0|+C1i+ zJqx23?w^FXX74}56=Q9275KAQ9P428w$bCxe6n_l``9zK%*vS^WG}c^?_S==H(a6P zInTiFGWZ=J{w;de^jV#OH8g78$cSw~mh1=OU$LLXIaqvf>^e51^M_qEe(D7E8#!2$ zH@f|uotvHBxktHU?^hmoaW7IRw{qvY&%aw*=@N;W+P8=Xbt|l#+1;M4D_1aIY@}Xl zxlH=(!{U18u{gD9nqP6bQt1^<&U0D0>>1QoCLeqVe09bE{cY(X7LXHr$k=*|A4TJe zaWfr|KY#wnSa6<;vPPFX`v!~^XP^y(VcgMhgW|Trn5$ zhr=>Fhj=!c{6^2p5fip&;&xWX>>#|N8|^$a`N)xY40|kmZ>V6Qg8myuhO1@km#JL$ z658dyHDa=XKV-Et!;Ebhi#+qLib5v|&|R&fqjdEzofE{`j4b}0=E zd0h1_tRdYCD_8bZynrh!!#%gVKJApE=W4~fdtntXoYm)ptFT;-tiRboc&6XxGnq{6 zj*j8?d?q(LlTUt#E8g+Z@FlEnG_EMmx)xf*ER3eDFRdPT<|g^<&zkPX_Lz(fSKyi0 z9A#~MiKB+=0c-{FQfrSp=c^f;5LdKIy>JhSve=oBH=dbmHaBd~k+?JbSXt9oyxVzJ z%QIYI%lO6~`+E2ThO4tD&Z>C(!WuqtnES2TZ?Ox$PX$ltbL=DhVk?NJ^V_qQ@4l^A zcYb*D*3B8l)ij5zkv)rC5m&w16w}L3=GK6&$*T8QtnPoocY&HGoGCgB`NACC; z;dtyT=(G;x$Gq8dsEsCt_jjE3i%uu@cgy9oD|+8}xNa58wFpwtiZ?VzF*{_6A*(H%8sYclG*>yl^atPygi3Hozx7B>SSo+n#*tNw+rM z;OtpW6)qSbxyqJKR&s&3$UD!KD;Cj$fn_!Qi*m}B6zB6x7SA6kL;YlTeb%9zS~X18 z=ssms|M3E9P_M8`6)$vIxx5M4yk5o^MZd7_Vm`BPfX%jx`C$EE-^KQl*t=l9Asci} z^kvve3s=aMba27kjP{33?xZtrl!Hfb!L#LuxFQc;NTY4utz3A=M*>HoevHPIwL#lp z0Uo1$D`*-&(>?SJQp zQKzrkJHKj~kH0b==6j-7iLI~}2Uj_==kT#v_GLC~Snt z`;|S*?H*Ui0KV{X*+0SuuzAJYVx4DLqCf0=^IP$>;_c!1*>hUBLiVhenPcoNG9Fgm z?u<410v{OO&{xE@(KTkTp<@_;25VM)JJ#!#ZuGd*SN0HziSrvRcq2W;6=~=)XrTMR zDCfRIU)*R?hIvPu@Q1!Z?_jH~jOiC5NZE3Ux)+o<6u=w3AeKX9{hl%qh=;N{7 z{I|3y4<_0FwK0Jn^BX%&3=G<&rTzwHgB$A%_*caf9j*#%VZWjdmudS~_)zaRDWvud z5;Wz*WYw>cOQ#Oj)chH>)bEob%9|&%o~|9|aP^yig$&?_^VH#7Bb~nB+nTR!y32Gm zbCEa%HXdJtI7%D$JIlQJ@_HFiKa4Y&ywL@rO|W#*plNMWpLh5|reU2BSCogQ)irv& zhjmDg?qi56Yd5@y&(ZYYFPc7S)Zs#|@J*b7eQegfJX3}XEMY@Ae}SArTt(VFk~$8Q zXMYdeVVjBBajq5r0DR*IfPZW&Yew=OuIRo$75fK%JGlC!uvQKzs;pUlTMvf*IM46C zRcW{M_7VR?PGyTU_ z@NW8wd}PNN8RW=2d|*$|ambhXOd43l2F#c_!~1#kebJI-n%2FjUVOf^s=L@zjfdUZ z^XU}Ttei*H%EhZv8RvVKjMWQ|R@I`8{2)vi~_v>RCg*+SGKuRO&a4;g^0#&tuZL zzzk!EjNm`qgGXlQfBX+{$C+BzZ?osj_Hqhw1s%qMaWvZ8X*c?86nc^G?jScS3lGR2 zI;33*SFFoSx7r>1k(Qqn;tJYE-`WMEeE-$x*c~6o#@otzB6J&%P#7Dq?15kyt>nWEa13zEU0+U#}Qn zT~*_ra^JHlqm}*2Xz`~-G`vSC)vA$OwI3~@ys>erS-7eS<;$c3iJ8^DVIlQwo}{5| z^6TR!i4IRMx~sXnUe?*8PpWN$qU!KkIc?vT`rFC$`e*6PGjs|54)I0%JqP)rz9Mb_ z<~S3^cd(-MmH85^32f}Z2H*U#v5LN9Bdi^CJL@IZl8jYaxMD7cG0fw-1);8F?H^6Y-s!W=M=;Bt47LinKs&@0`$pKPux*}ck24g8Kf@LJi{AtyA9NP| zj*i2T$C{Zl_W13bBj#-EOE16V-q$H-wp9NrKF-BQY=#pb-vVKG+u+&87l#aDLq?(_arw`PUat9f31(k!ofHBGvN ztJgJQOl3X)bdpLH$?E;~ZBGA2_c6V9YTgC%{6sAatb zzqTVT3a%cAuj+A?lsmINd%LK|RqGcM)T61x*9R#olafa{vby-a^S`*VXJtK@>R(xZ z(z}BVFoK=}L&(9(h8QD_bNzdWUtRJCLR>MPtYe5VGnUAicoK5r_cX|Y-w=djM|>0g zLRrq_QVzQd4{6~Fofy_cGO32(O2@&jhy-93^i*h{7`u0JALe(ecIlo4(pJjb}uKW zLzBE-e}T#9xM<<5MYUsV>iNI0PiZ|fR#*C-4BuwpJ03^f?}LsUci&m#J3;RGC~1Md zVqMAi^6*tG{>u8BbrSnC?CnMC8gPUjVLZBa?drd^11{3T73qu_?XbtpH}#^|ve7XE z!xdNnyI_MoM`QuL%UV9a~$0s0L4K%bT^TdF+qnUps%d*mu!G_R6e?9$SBu2!z3 zmh>*KrG1O5^zpYy0tVuC6s)o|ac%;M@~*YrN+RIWrW6-Y{@mza=QDa8`> zVB#aHocNeZBo( ztljNT=<@h$)Lf5{9X{}cUHM`IT?vxJy@!+rgkf%2|Wty)t8do zp0e|=^5yV8SjG59oxZx)+qg0*@h%dtb5NY{5R~N?GGXo@Ev|n zhIKIOVJ@5h^xwW4%X9cWnbhy~ozUrv=hb>pPc`V?M(4i2sADG`-rRgM|H{tmVmFvu z$O<{xexb?O?&t}0JZ0d6-#&957F>eIwCo@>(S`W0M#t`)i2yIqvvJ~XxMF<3E^!m) znw0?~_Wfa_Wq0h7(F3oh~Texrar-{j6vWCT|gOC@V;_cH4Gc0nIAFA|%qC-S|jqH)P88~|x@|VN3DF@qY{hHip~{S3Db!rcbRL>qPVrv0r#(pJdhA)&AQne9z$cY4?3a=L3L= zFqRSG3R>`NznkKmA~MBa1k=`*;R<_#uSOZp^m%cU9)@4L*h|DOq6~A?+dFsv=7{^g&;j?I zkz-DNN8C3j$aD1#S4K0vJAM>?#sznsx%iz<|M;`c|IfeO^*`?UCpUJfzOdC#4_B5C zUYQsC_5<3M9(@mS6`dEp(^sQ+_I&EMFHik+QRjaBQ73=A;J+_t>lLdPjVsd8P3#e2 zt600)+R^G5uJ9XJ`(oR`7gJiovE zU`drJS;+4zmo8Dzo%c&niDLQOm0tyu5>?!-?aDgcRnndPOD+)a$`(|Wq7{@M8U?@V79dt&~~2kTpSN1pTt-+}lw<+&(B z9v8Ct)Wx^HbnCl*1Nyta&5-&noQ&cMT%!|Me@}7eQiqQluhYN$strH?tZhI2taA=u zCof!#v`gE6ge>a~MCL*ip0&vOZ=6SMWx8Vnx&3S>xIB=V{x1x4-@CMGZK*T4&w& zpiX{w{<3diP(CeOS-a`o4Oirweh%k5aSUR-#6Qsg$ey?;c*FkPbn{KA`-9F7qML{r zaIaFSw91w);%wc$dZb!;RerFP!$d*VdaSAvb7%2qi%U6-a8c&bhbs6p$f;P%@5@xU zbOxC;{3*^SbAGv6m9m~zuIzV3>`8k4%SbwyvU2G1WA5T^xXUQ6_znSf7$0n)^PNXc zoTO7OE;HxnU$g+d_3ul#3fj98uHcJU68kRLczm+Z_8QOJGlDDT74b&mwERYF$nas> z=)SkN@0YV`b$GT;{p!B2;=TusPZ`pV#uYph-^A~R4*iYhE5sFc0iTWjAWQPNqr1?- z*aB=m-xp<_ivHqU8MvcgGp0{*Yul;*K5g1$O?Q`1Bi&z9-I@F;sn@0aunf;!GiOYT z(3m-MdW4RzJI&R1*No|omMaTSp$yV{rXS3C)>)iQ3;P}7Dy{k%#T9hGBeskAch;Sw zIOFuyMHkh*@Nc>AcK@OiXD*MEUkO+60-f+mi$BtkfArW!m!%&@3m#87fA7?H=bTRc zPT&3e7hw(TSSK^Pd8S$^c2xH5IZa?ZUcI4zKH+J9q>$r=f%TF6{H(*2Tc?El@thW}%&)gKaWrosuA=GT zb5S46&_6DCi!R5z?J1^}msT1y=^y-I9r&bJ6-4 zT{nEk=0b=5kiO&B5h`Z%f literal 0 HcmV?d00001 From 233518e689b40d9c7aa1ef433ef2c8c417fc9d0b Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 2 Nov 2017 08:29:04 -0400 Subject: [PATCH 07/11] Fade out installer banner --- installer-banner.bmp | Bin 34338 -> 34338 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/installer-banner.bmp b/installer-banner.bmp index 8b1c03b5f69f46a6c8e81a70b28678efb5d1bec8..d3f732ee984e32b386d81cbdc355b9847539bf79 100644 GIT binary patch delta 7924 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 UH~-X&gsc>YqB12?RZ^P#AGKKf!2kdN delta 6346 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 From e6e9feeff7a4a325a70ba176d0ba44986b1e40b8 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 2 Nov 2017 08:54:29 -0400 Subject: [PATCH 08/11] Finished Windows installer --- Makefile | 16 +++++++++------- installer-banner.bmp | Bin 34338 -> 34254 bytes installer.nsi | 6 +++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 70ffcf23..7f8b9cc1 100644 --- a/Makefile +++ b/Makefile @@ -116,6 +116,9 @@ ifeq ($(ARCH), mac) mkdir -p $(BUNDLE)/Contents/Resources/plugins cp -R plugins/Fundamental/dist/Fundamental $(BUNDLE)/Contents/Resources/plugins + # Make DMG image + cd dist && ln -s /Applications Applications + cd dist && hdiutil create -srcfolder . -volname Rack -ov -format UDZO Rack-$(VERSION)-$(ARCH).dmg endif ifeq ($(ARCH), win) mkdir -p dist/Rack @@ -135,6 +138,11 @@ ifeq ($(ARCH), win) cp dep/bin/portaudio_x64.dll dist/Rack/ mkdir -p dist/Rack/plugins cp -R plugins/Fundamental/dist/Fundamental dist/Rack/plugins/ + # Make ZIP + cd dist && zip -5 -r Rack-$(VERSION)-$(ARCH).zip Rack + # Make NSIS installer + makensis installer.nsi + mv Rack-setup.exe dist/Rack-$(VERSION)-$(ARCH).exe endif ifeq ($(ARCH), lin) mkdir -p dist/Rack @@ -149,16 +157,10 @@ ifeq ($(ARCH), lin) cp dep/lib/libportaudio.so.2 dist/Rack/ cp dep/lib/librtmidi.so.4 dist/Rack/ mkdir -p dist/Rack/plugins + # Make ZIP cp -R plugins/Fundamental/dist/Fundamental dist/Rack/plugins/ endif -ifeq ($(ARCH), mac) - cd dist && ln -s /Applications Applications - cd dist && hdiutil create -srcfolder . -volname Rack -ov -format UDZO Rack-$(VERSION)-$(ARCH).dmg -else - cd dist && zip -5 -r Rack-$(VERSION)-$(ARCH).zip Rack -endif - # Plugin helpers diff --git a/installer-banner.bmp b/installer-banner.bmp index d3f732ee984e32b386d81cbdc355b9847539bf79..616104b3eee8387d9c5f8285174a63a33b7a765d 100644 GIT binary patch literal 34254 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 literal 34338 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 diff --git a/installer.nsi b/installer.nsi index c6fc468a..d347c4b8 100644 --- a/installer.nsi +++ b/installer.nsi @@ -20,9 +20,9 @@ RequestExecutionLevel admin !define MUI_ICON "icon.ico" !define MUI_HEADERIMAGE -!define MUI_HEADERIMAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Header\nsis.bmp" ; 150x57 -!define MUI_WELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\win.bmp" ; 164x314 -!define MUI_UNWELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\win.bmp" ; 164x314 +!define MUI_HEADERIMAGE_BITMAP "installer-banner.bmp" ; 150x57 +; !define MUI_WELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\win.bmp" ; 164x314 +; !define MUI_UNWELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\win.bmp" ; 164x314 !define MUI_COMPONENTSPAGE_NODESC From 887fcc47ca7e5d5772f332bb424e395674323272 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Thu, 2 Nov 2017 10:24:25 -0400 Subject: [PATCH 09/11] Update odsialog --- ext/osdialog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/osdialog b/ext/osdialog index 4dd22f56..015d0206 160000 --- a/ext/osdialog +++ b/ext/osdialog @@ -1 +1 @@ -Subproject commit 4dd22f56d6b733c8de13d6e8b12f13390aa5782e +Subproject commit 015d020615e8169d2f227ad385c5f2aa1e091fd1 From e46448150db970c874b66682ed27f51c231e1372 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Fri, 3 Nov 2017 05:57:30 -0400 Subject: [PATCH 10/11] Reduce Light radius and magnitude --- src/app/LightWidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/LightWidget.cpp b/src/app/LightWidget.cpp index 02acac06..a75bf23c 100644 --- a/src/app/LightWidget.cpp +++ b/src/app/LightWidget.cpp @@ -6,7 +6,7 @@ namespace rack { void LightWidget::draw(NVGcontext *vg) { float radius = box.size.x / 2.0; - float oradius = radius + 20.0; + float oradius = radius + 15.0; color.r = clampf(color.r, 0.0, 1.0); color.g = clampf(color.g, 0.0, 1.0); @@ -36,7 +36,7 @@ void LightWidget::draw(NVGcontext *vg) { nvgRect(vg, radius - oradius, radius - oradius, 2*oradius, 2*oradius); NVGpaint paint; NVGcolor icol = color; - icol.a *= 0.15; + icol.a *= 0.10; NVGcolor ocol = color; ocol.a = 0.0; paint = nvgRadialGradient(vg, radius, radius, radius, oradius, icol, ocol); From e7a305a1dc03c780f6b7212eb27ae378c55887f4 Mon Sep 17 00:00:00 2001 From: Andrew Belt Date: Fri, 3 Nov 2017 12:09:14 -0400 Subject: [PATCH 11/11] Add LEDBezel, change sizes of LEDs --- include/components.hpp | 19 +++++++-- include/engine.hpp | 8 ++-- res/ComponentLibrary/LEDBezel.svg | 71 +++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 res/ComponentLibrary/LEDBezel.svg diff --git a/include/components.hpp b/include/components.hpp index 640618f9..40849dff 100644 --- a/include/components.hpp +++ b/include/components.hpp @@ -409,34 +409,39 @@ struct RedGreenBlueLight : ColorLightWidget { }; +/** Based on the size of 5mm LEDs */ template struct LargeLight : BASE { LargeLight() { - this->box.size = Vec(20, 20); + this->box.size = mm2px(Vec(5.179, 5.179)); } }; +/** Based on the size of 3mm LEDs */ template struct MediumLight : BASE { MediumLight() { - this->box.size = Vec(12, 12); + this->box.size = mm2px(Vec(3.176, 3.176)); } }; +/** Based on the size of 2mm LEDs */ template struct SmallLight : BASE { SmallLight() { - this->box.size = Vec(8, 8); + this->box.size = mm2px(Vec(2.176, 2.176)); } }; +/** Based on the size of 1mm LEDs */ template struct TinyLight : BASE { TinyLight() { - this->box.size = Vec(5, 5); + this->box.size = mm2px(Vec(1.088, 1.088)); } }; + //////////////////// // Switches and Buttons //////////////////// @@ -497,6 +502,12 @@ struct PB61303 : SVGSwitch, MomentarySwitch { } }; +struct LEDBezel : SVGSwitch, MomentarySwitch { + LEDBezel() { + addFrame(SVG::load(assetGlobal("res/ComponentLibrary/LEDBezel.svg"))); + } +}; + //////////////////// // Misc diff --git a/include/engine.hpp b/include/engine.hpp index 1496f0d6..2f0bc546 100644 --- a/include/engine.hpp +++ b/include/engine.hpp @@ -63,15 +63,15 @@ struct Module { virtual void step() {} virtual void onSampleRateChange() {} - /** Override these to store extra internal data in the "data" property */ - virtual json_t *toJson() { return NULL; } - virtual void fromJson(json_t *root) {} - /** Override these to implement spacial behavior when user clicks Initialize and Randomize */ virtual void reset() {} virtual void randomize() {} /** Deprecated */ virtual void initialize() final {} + + /** Override these to store extra internal data in the "data" property */ + virtual json_t *toJson() { return NULL; } + virtual void fromJson(json_t *root) {} }; struct Wire { diff --git a/res/ComponentLibrary/LEDBezel.svg b/res/ComponentLibrary/LEDBezel.svg new file mode 100644 index 00000000..c4302dc4 --- /dev/null +++ b/res/ComponentLibrary/LEDBezel.svg @@ -0,0 +1,71 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + +