| @@ -116,6 +116,9 @@ ifeq ($(ARCH), mac) | |||||
| mkdir -p $(BUNDLE)/Contents/Resources/plugins | mkdir -p $(BUNDLE)/Contents/Resources/plugins | ||||
| cp -R plugins/Fundamental/dist/Fundamental $(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 | endif | ||||
| ifeq ($(ARCH), win) | ifeq ($(ARCH), win) | ||||
| mkdir -p dist/Rack | mkdir -p dist/Rack | ||||
| @@ -135,6 +138,11 @@ ifeq ($(ARCH), win) | |||||
| cp dep/bin/portaudio_x64.dll dist/Rack/ | cp dep/bin/portaudio_x64.dll dist/Rack/ | ||||
| mkdir -p dist/Rack/plugins | mkdir -p dist/Rack/plugins | ||||
| cp -R plugins/Fundamental/dist/Fundamental 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 | endif | ||||
| ifeq ($(ARCH), lin) | ifeq ($(ARCH), lin) | ||||
| mkdir -p dist/Rack | mkdir -p dist/Rack | ||||
| @@ -149,16 +157,10 @@ ifeq ($(ARCH), lin) | |||||
| cp dep/lib/libportaudio.so.2 dist/Rack/ | cp dep/lib/libportaudio.so.2 dist/Rack/ | ||||
| cp dep/lib/librtmidi.so.4 dist/Rack/ | cp dep/lib/librtmidi.so.4 dist/Rack/ | ||||
| mkdir -p dist/Rack/plugins | mkdir -p dist/Rack/plugins | ||||
| # Make ZIP | |||||
| cp -R plugins/Fundamental/dist/Fundamental dist/Rack/plugins/ | cp -R plugins/Fundamental/dist/Fundamental dist/Rack/plugins/ | ||||
| endif | 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 | # Plugin helpers | ||||
| @@ -67,12 +67,12 @@ struct ModuleWidget : OpaqueWidget { | |||||
| void draw(NVGcontext *vg) override; | void draw(NVGcontext *vg) override; | ||||
| Vec dragPos; | 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; | struct ValueLight; | ||||
| @@ -144,9 +144,9 @@ struct RackWidget : OpaqueWidget { | |||||
| void step() override; | void step() override; | ||||
| void draw(NVGcontext *vg) 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 { | struct RackRail : TransparentWidget { | ||||
| @@ -184,8 +184,8 @@ struct ParamWidget : OpaqueWidget, QuantityWidget { | |||||
| json_t *toJson(); | json_t *toJson(); | ||||
| void fromJson(json_t *rootJ); | void fromJson(json_t *rootJ); | ||||
| virtual void randomize(); | 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 */ | /** Implements vertical dragging behavior for ParamWidgets */ | ||||
| @@ -193,11 +193,11 @@ struct Knob : ParamWidget { | |||||
| /** Snap to nearest integer while dragging */ | /** Snap to nearest integer while dragging */ | ||||
| bool snap = false; | bool snap = false; | ||||
| float dragValue; | 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 */ | /** Tell engine to smoothly vary this parameter */ | ||||
| void onChange() override; | |||||
| void onChange(EventChange &e) override; | |||||
| }; | }; | ||||
| struct SpriteKnob : virtual Knob, SpriteWidget { | struct SpriteKnob : virtual Knob, SpriteWidget { | ||||
| @@ -216,7 +216,7 @@ struct SVGKnob : virtual Knob, FramebufferWidget { | |||||
| SVGKnob(); | SVGKnob(); | ||||
| void setSVG(std::shared_ptr<SVG> svg); | void setSVG(std::shared_ptr<SVG> svg); | ||||
| void step() override; | void step() override; | ||||
| void onChange() override; | |||||
| void onChange(EventChange &e) override; | |||||
| }; | }; | ||||
| struct SVGSlider : Knob, FramebufferWidget { | struct SVGSlider : Knob, FramebufferWidget { | ||||
| @@ -228,7 +228,7 @@ struct SVGSlider : Knob, FramebufferWidget { | |||||
| SVGSlider(); | SVGSlider(); | ||||
| void step() override; | void step() override; | ||||
| void onChange() override; | |||||
| void onChange(EventChange &e) override; | |||||
| }; | }; | ||||
| struct Switch : ParamWidget { | struct Switch : ParamWidget { | ||||
| @@ -243,12 +243,12 @@ struct SVGSwitch : virtual Switch, FramebufferWidget { | |||||
| /** Adds an SVG file to represent the next switch position */ | /** Adds an SVG file to represent the next switch position */ | ||||
| void addFrame(std::shared_ptr<SVG> svg); | void addFrame(std::shared_ptr<SVG> svg); | ||||
| void step() override; | void step() override; | ||||
| void onChange() override; | |||||
| void onChange(EventChange &e) override; | |||||
| }; | }; | ||||
| /** A switch that cycles through each mechanical position */ | /** A switch that cycles through each mechanical position */ | ||||
| struct ToggleSwitch : virtual Switch { | struct ToggleSwitch : virtual Switch { | ||||
| void onDragStart() override { | |||||
| void onDragStart(EventDragStart &e) override { | |||||
| // Cycle through values | // Cycle through values | ||||
| // e.g. a range of [0.0, 3.0] would have modes 0, 1, 2, and 3. | // e.g. a range of [0.0, 3.0] would have modes 0, 1, 2, and 3. | ||||
| if (value >= maxValue) | if (value >= maxValue) | ||||
| @@ -262,10 +262,10 @@ struct ToggleSwitch : virtual Switch { | |||||
| struct MomentarySwitch : virtual Switch { | struct MomentarySwitch : virtual Switch { | ||||
| /** Don't randomize state */ | /** Don't randomize state */ | ||||
| void randomize() override {} | void randomize() override {} | ||||
| void onDragStart() override { | |||||
| void onDragStart(EventDragStart &e) override { | |||||
| setValue(maxValue); | setValue(maxValue); | ||||
| } | } | ||||
| void onDragEnd() override { | |||||
| void onDragEnd(EventDragEnd &e) override { | |||||
| setValue(minValue); | setValue(minValue); | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -286,12 +286,12 @@ struct Port : OpaqueWidget { | |||||
| ~Port(); | ~Port(); | ||||
| void draw(NVGcontext *vg) override; | 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 { | struct SVGPort : Port, FramebufferWidget { | ||||
| @@ -365,7 +365,8 @@ struct RackScene : Scene { | |||||
| RackScene(); | RackScene(); | ||||
| void step() override; | void step() override; | ||||
| void draw(NVGcontext *vg) override; | void draw(NVGcontext *vg) override; | ||||
| Widget *onHoverKey(Vec pos, int key) override; | |||||
| void onHoverKey(EventHoverKey &e) override; | |||||
| void onPathDrop(EventPathDrop &e) override; | |||||
| }; | }; | ||||
| //////////////////// | //////////////////// | ||||
| @@ -409,34 +409,39 @@ struct RedGreenBlueLight : ColorLightWidget { | |||||
| }; | }; | ||||
| /** Based on the size of 5mm LEDs */ | |||||
| template <typename BASE> | template <typename BASE> | ||||
| struct LargeLight : BASE { | struct LargeLight : BASE { | ||||
| LargeLight() { | LargeLight() { | ||||
| this->box.size = Vec(20, 20); | |||||
| this->box.size = mm2px(Vec(5.179, 5.179)); | |||||
| } | } | ||||
| }; | }; | ||||
| /** Based on the size of 3mm LEDs */ | |||||
| template <typename BASE> | template <typename BASE> | ||||
| struct MediumLight : BASE { | struct MediumLight : BASE { | ||||
| MediumLight() { | MediumLight() { | ||||
| this->box.size = Vec(12, 12); | |||||
| this->box.size = mm2px(Vec(3.176, 3.176)); | |||||
| } | } | ||||
| }; | }; | ||||
| /** Based on the size of 2mm LEDs */ | |||||
| template <typename BASE> | template <typename BASE> | ||||
| struct SmallLight : BASE { | struct SmallLight : BASE { | ||||
| SmallLight() { | SmallLight() { | ||||
| this->box.size = Vec(8, 8); | |||||
| this->box.size = mm2px(Vec(2.176, 2.176)); | |||||
| } | } | ||||
| }; | }; | ||||
| /** Based on the size of 1mm LEDs */ | |||||
| template <typename BASE> | template <typename BASE> | ||||
| struct TinyLight : BASE { | struct TinyLight : BASE { | ||||
| TinyLight() { | TinyLight() { | ||||
| this->box.size = Vec(5, 5); | |||||
| this->box.size = mm2px(Vec(1.088, 1.088)); | |||||
| } | } | ||||
| }; | }; | ||||
| //////////////////// | //////////////////// | ||||
| // Switches and Buttons | // 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 | // Misc | ||||
| @@ -63,15 +63,15 @@ struct Module { | |||||
| virtual void step() {} | virtual void step() {} | ||||
| virtual void onSampleRateChange() {} | 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 */ | /** Override these to implement spacial behavior when user clicks Initialize and Randomize */ | ||||
| virtual void reset() {} | virtual void reset() {} | ||||
| virtual void randomize() {} | virtual void randomize() {} | ||||
| /** Deprecated */ | /** Deprecated */ | ||||
| virtual void initialize() final {} | 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 { | struct Wire { | ||||
| @@ -0,0 +1,107 @@ | |||||
| #pragma once | |||||
| #include <list> | |||||
| #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<std::string> paths; | |||||
| }; | |||||
| struct EventAction : Event { | |||||
| }; | |||||
| struct EventChange : Event { | |||||
| }; | |||||
| struct EventZoom : Event { | |||||
| }; | |||||
| } // namespace rack | |||||
| @@ -8,6 +8,7 @@ | |||||
| #include "math.hpp" | #include "math.hpp" | ||||
| #include "util.hpp" | #include "util.hpp" | ||||
| #include "events.hpp" | |||||
| #define SVG_DPI 75.0 | #define SVG_DPI 75.0 | ||||
| @@ -122,35 +123,36 @@ struct Widget { | |||||
| Return `this` to accept the event. | Return `this` to accept the event. | ||||
| Return NULL to reject the event and pass it to the widget behind this one. | 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) */ | /** 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 */ | /** 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 */ | /** 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 */ | /** 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 */ | /** 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 */ | /** 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 */ | /** 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 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 { | struct TransformWidget : Widget { | ||||
| @@ -170,11 +172,11 @@ struct ZoomWidget : Widget { | |||||
| Rect getViewport(Rect r) override; | Rect getViewport(Rect r) override; | ||||
| void setZoom(float zoom); | void setZoom(float zoom); | ||||
| void draw(NVGcontext *vg) override; | 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; | |||||
| }; | }; | ||||
| //////////////////// | //////////////////// | ||||
| @@ -183,47 +185,36 @@ struct ZoomWidget : Widget { | |||||
| /** Widget that does not respond to events */ | /** Widget that does not respond to events */ | ||||
| struct TransparentWidget : virtual Widget { | 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 */ | /** Widget that automatically responds to all mouse events but gives a chance for children to respond instead */ | ||||
| struct OpaqueWidget : virtual Widget { | 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 { | struct SpriteWidget : virtual Widget { | ||||
| @@ -264,7 +255,7 @@ struct FramebufferWidget : virtual Widget { | |||||
| ~FramebufferWidget(); | ~FramebufferWidget(); | ||||
| void draw(NVGcontext *vg) override; | void draw(NVGcontext *vg) override; | ||||
| int getImageHandle(); | int getImageHandle(); | ||||
| void onZoom() override; | |||||
| void onZoom(EventZoom &e) override; | |||||
| }; | }; | ||||
| struct QuantityWidget : virtual Widget { | struct QuantityWidget : virtual Widget { | ||||
| @@ -302,9 +293,9 @@ struct Label : Widget { | |||||
| // Deletes itself from parent when clicked | // Deletes itself from parent when clicked | ||||
| struct MenuOverlay : OpaqueWidget { | 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; | struct MenuEntry; | ||||
| @@ -324,7 +315,7 @@ struct Menu : OpaqueWidget { | |||||
| void setChildMenu(Menu *menu); | void setChildMenu(Menu *menu); | ||||
| void step() override; | void step() override; | ||||
| void draw(NVGcontext *vg) override; | void draw(NVGcontext *vg) override; | ||||
| bool onScrollOpaque(Vec scrollRel) override; | |||||
| void onScroll(EventScroll &e) override; | |||||
| }; | }; | ||||
| struct MenuEntry : OpaqueWidget { | struct MenuEntry : OpaqueWidget { | ||||
| @@ -343,8 +334,8 @@ struct MenuLabel : MenuEntry { | |||||
| struct MenuItem : MenuEntry { | struct MenuItem : MenuEntry { | ||||
| void draw(NVGcontext *vg) override; | void draw(NVGcontext *vg) override; | ||||
| virtual Menu *createChildMenu() {return NULL;} | 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 { | struct Button : OpaqueWidget { | ||||
| @@ -355,11 +346,11 @@ struct Button : OpaqueWidget { | |||||
| box.size.y = BND_WIDGET_HEIGHT; | box.size.y = BND_WIDGET_HEIGHT; | ||||
| } | } | ||||
| void draw(NVGcontext *vg) override; | 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 { | struct ChoiceButton : Button { | ||||
| @@ -373,9 +364,9 @@ struct RadioButton : OpaqueWidget, QuantityWidget { | |||||
| box.size.y = BND_WIDGET_HEIGHT; | box.size.y = BND_WIDGET_HEIGHT; | ||||
| } | } | ||||
| void draw(NVGcontext *vg) override; | 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 { | struct Slider : OpaqueWidget, QuantityWidget { | ||||
| @@ -385,10 +376,10 @@ struct Slider : OpaqueWidget, QuantityWidget { | |||||
| box.size.y = BND_WIDGET_HEIGHT; | box.size.y = BND_WIDGET_HEIGHT; | ||||
| } | } | ||||
| void draw(NVGcontext *vg) override; | 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 */ | /** Parent must be a ScrollWidget */ | ||||
| @@ -400,9 +391,9 @@ struct ScrollBar : OpaqueWidget { | |||||
| box.size = Vec(BND_SCROLLBAR_WIDTH, BND_SCROLLBAR_HEIGHT); | box.size = Vec(BND_SCROLLBAR_WIDTH, BND_SCROLLBAR_HEIGHT); | ||||
| } | } | ||||
| void draw(NVGcontext *vg) override; | 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 */ | /** Handles a container with ScrollBar */ | ||||
| @@ -414,7 +405,7 @@ struct ScrollWidget : OpaqueWidget { | |||||
| ScrollWidget(); | ScrollWidget(); | ||||
| void step() override; | void step() override; | ||||
| bool onScrollOpaque(Vec scrollRel) override; | |||||
| void onScroll(EventScroll &e) override; | |||||
| }; | }; | ||||
| struct TextField : OpaqueWidget { | struct TextField : OpaqueWidget { | ||||
| @@ -428,10 +419,10 @@ struct TextField : OpaqueWidget { | |||||
| box.size.y = BND_WIDGET_HEIGHT; | box.size.y = BND_WIDGET_HEIGHT; | ||||
| } | } | ||||
| void draw(NVGcontext *vg) override; | 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); | void insertText(std::string newText); | ||||
| virtual void onTextChange() {} | virtual void onTextChange() {} | ||||
| }; | }; | ||||
| @@ -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 "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 | |||||
| ; 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 | |||||
| @@ -0,0 +1,71 @@ | |||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | |||||
| <svg | |||||
| xmlns:dc="http://purl.org/dc/elements/1.1/" | |||||
| xmlns:cc="http://creativecommons.org/ns#" | |||||
| xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||||
| xmlns:svg="http://www.w3.org/2000/svg" | |||||
| xmlns="http://www.w3.org/2000/svg" | |||||
| xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||||
| xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||||
| width="7.5001564mm" | |||||
| height="7.5000095mm" | |||||
| viewBox="0 0 7.5001564 7.5000095" | |||||
| version="1.1" | |||||
| id="svg64581" | |||||
| inkscape:version="0.92.2 5c3e80d, 2017-08-06" | |||||
| sodipodi:docname="LEDBezel.svg"> | |||||
| <defs | |||||
| id="defs64575" /> | |||||
| <sodipodi:namedview | |||||
| id="base" | |||||
| pagecolor="#ffffff" | |||||
| bordercolor="#666666" | |||||
| borderopacity="1.0" | |||||
| inkscape:pageopacity="0.0" | |||||
| inkscape:pageshadow="2" | |||||
| inkscape:zoom="1.979899" | |||||
| inkscape:cx="-100.74496" | |||||
| inkscape:cy="9.8683694" | |||||
| inkscape:document-units="mm" | |||||
| inkscape:current-layer="layer1" | |||||
| showgrid="false" | |||||
| fit-margin-top="0" | |||||
| fit-margin-left="0" | |||||
| fit-margin-right="0" | |||||
| fit-margin-bottom="0" | |||||
| inkscape:window-width="2560" | |||||
| inkscape:window-height="1422" | |||||
| inkscape:window-x="0" | |||||
| inkscape:window-y="18" | |||||
| inkscape:window-maximized="0" /> | |||||
| <metadata | |||||
| id="metadata64578"> | |||||
| <rdf:RDF> | |||||
| <cc:Work | |||||
| rdf:about=""> | |||||
| <dc:format>image/svg+xml</dc:format> | |||||
| <dc:type | |||||
| rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||||
| <dc:title></dc:title> | |||||
| </cc:Work> | |||||
| </rdf:RDF> | |||||
| </metadata> | |||||
| <g | |||||
| inkscape:label="Layer 1" | |||||
| inkscape:groupmode="layer" | |||||
| id="layer1" | |||||
| transform="translate(-94.523732,-120.89285)"> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path9729" | |||||
| d="m 94.750061,123.36034 c -0.706931,1.94578 0.297674,4.09829 2.240704,4.8066 1.947157,0.70556 4.098285,-0.29626 4.805225,-2.24208 0.70968,-1.94578 -0.29355,-4.09688 -2.239332,-4.80522 -1.945781,-0.70693 -4.096914,0.29355 -4.806597,2.2407" | |||||
| style="fill:#2b2b2b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| <path | |||||
| inkscape:connector-curvature="0" | |||||
| id="path64013" | |||||
| d="m 99.30033,121.82382 c -1.557161,-0.56497 -3.279704,0.23703 -3.846089,1.79285 -0.565009,1.55716 0.237031,3.27833 1.794192,3.84334 1.557197,0.56776 3.276987,-0.23428 3.844747,-1.79144 0.56498,-1.55582 -0.23565,-3.27837 -1.79285,-3.84475" | |||||
| style="clip-rule:nonzero;fill:#5a5a5a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||||
| </g> | |||||
| </svg> | |||||
| @@ -10,29 +10,30 @@ namespace rack { | |||||
| #define KNOB_SENSITIVITY 0.0015 | #define KNOB_SENSITIVITY 0.0015 | ||||
| void Knob::onDragStart() { | |||||
| void Knob::onDragStart(EventDragStart &e) { | |||||
| guiCursorLock(); | guiCursorLock(); | ||||
| dragValue = value; | dragValue = value; | ||||
| randomizable = false; | randomizable = false; | ||||
| } | } | ||||
| void Knob::onDragMove(Vec mouseRel) { | |||||
| void Knob::onDragMove(EventDragMove &e) { | |||||
| // Drag slower if Mod | // Drag slower if Mod | ||||
| float delta = KNOB_SENSITIVITY * (maxValue - minValue) * -e.mouseRel.y; | |||||
| if (guiIsModPressed()) | if (guiIsModPressed()) | ||||
| mouseRel = mouseRel.mult(1/16.0); | |||||
| dragValue += KNOB_SENSITIVITY * (maxValue - minValue) * -mouseRel.y; | |||||
| delta /= 16.0; | |||||
| dragValue += delta; | |||||
| if (snap) | if (snap) | ||||
| setValue(roundf(dragValue)); | setValue(roundf(dragValue)); | ||||
| else | else | ||||
| setValue(dragValue); | setValue(dragValue); | ||||
| } | } | ||||
| void Knob::onDragEnd() { | |||||
| void Knob::onDragEnd(EventDragEnd &e) { | |||||
| guiCursorUnlock(); | guiCursorUnlock(); | ||||
| randomizable = true; | randomizable = true; | ||||
| } | } | ||||
| void Knob::onChange() { | |||||
| void Knob::onChange(EventChange &e) { | |||||
| if (!module) | if (!module) | ||||
| return; | return; | ||||
| @@ -6,7 +6,7 @@ namespace rack { | |||||
| void LightWidget::draw(NVGcontext *vg) { | void LightWidget::draw(NVGcontext *vg) { | ||||
| float radius = box.size.x / 2.0; | 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.r = clampf(color.r, 0.0, 1.0); | ||||
| color.g = clampf(color.g, 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); | nvgRect(vg, radius - oradius, radius - oradius, 2*oradius, 2*oradius); | ||||
| NVGpaint paint; | NVGpaint paint; | ||||
| NVGcolor icol = color; | NVGcolor icol = color; | ||||
| icol.a *= 0.15; | |||||
| icol.a *= 0.10; | |||||
| NVGcolor ocol = color; | NVGcolor ocol = color; | ||||
| ocol.a = 0.0; | ocol.a = 0.0; | ||||
| paint = nvgRadialGradient(vg, radius, radius, radius, oradius, icol, ocol); | paint = nvgRadialGradient(vg, radius, radius, radius, oradius, icol, ocol); | ||||
| @@ -165,7 +165,22 @@ void ModuleWidget::draw(NVGcontext *vg) { | |||||
| nvgResetScissor(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) { | 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. | // 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) { | 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(); | this->finalizeEvents(); | ||||
| delete this; | delete this; | ||||
| // Kinda sketchy because events will be passed further down the tree | // 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: | case GLFW_KEY_I: | ||||
| if (guiIsModPressed() && !guiIsShiftPressed()) { | if (guiIsModPressed() && !guiIsShiftPressed()) { | ||||
| reset(); | reset(); | ||||
| return this; | |||||
| e.consumed = true; | |||||
| return; | |||||
| } | } | ||||
| break; | break; | ||||
| case GLFW_KEY_R: | case GLFW_KEY_R: | ||||
| if (guiIsModPressed() && !guiIsShiftPressed()) { | if (guiIsModPressed() && !guiIsShiftPressed()) { | ||||
| randomize(); | randomize(); | ||||
| return this; | |||||
| e.consumed = true; | |||||
| return; | |||||
| } | } | ||||
| break; | break; | ||||
| case GLFW_KEY_D: | case GLFW_KEY_D: | ||||
| if (guiIsModPressed() && !guiIsShiftPressed()) { | if (guiIsModPressed() && !guiIsShiftPressed()) { | ||||
| gRackWidget->cloneModule(this); | gRackWidget->cloneModule(this); | ||||
| return this; | |||||
| e.consumed = true; | |||||
| return; | |||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| return Widget::onHoverKey(pos, key); | |||||
| Widget::onHoverKey(e); | |||||
| } | } | ||||
| void ModuleWidget::onDragStart() { | |||||
| void ModuleWidget::onDragStart(EventDragStart &e) { | |||||
| dragPos = gRackWidget->lastMousePos.minus(box.pos); | dragPos = gRackWidget->lastMousePos.minus(box.pos); | ||||
| } | } | ||||
| void ModuleWidget::onDragMove(Vec mouseRel) { | |||||
| void ModuleWidget::onDragEnd(EventDragEnd &e) { | |||||
| } | |||||
| void ModuleWidget::onDragMove(EventDragMove &e) { | |||||
| Rect newBox = box; | Rect newBox = box; | ||||
| newBox.pos = gRackWidget->lastMousePos.minus(dragPos); | newBox.pos = gRackWidget->lastMousePos.minus(dragPos); | ||||
| gRackWidget->requestModuleBoxNearest(this, newBox); | gRackWidget->requestModuleBoxNearest(this, newBox); | ||||
| } | } | ||||
| void ModuleWidget::onDragEnd() { | |||||
| } | |||||
| struct DisconnectMenuItem : MenuItem { | struct DisconnectMenuItem : MenuItem { | ||||
| ModuleWidget *moduleWidget; | ModuleWidget *moduleWidget; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| moduleWidget->disconnect(); | moduleWidget->disconnect(); | ||||
| } | } | ||||
| }; | }; | ||||
| struct ResetMenuItem : MenuItem { | struct ResetMenuItem : MenuItem { | ||||
| ModuleWidget *moduleWidget; | ModuleWidget *moduleWidget; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| moduleWidget->reset(); | moduleWidget->reset(); | ||||
| } | } | ||||
| }; | }; | ||||
| struct RandomizeMenuItem : MenuItem { | struct RandomizeMenuItem : MenuItem { | ||||
| ModuleWidget *moduleWidget; | ModuleWidget *moduleWidget; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| moduleWidget->randomize(); | moduleWidget->randomize(); | ||||
| } | } | ||||
| }; | }; | ||||
| struct CloneMenuItem : MenuItem { | struct CloneMenuItem : MenuItem { | ||||
| ModuleWidget *moduleWidget; | ModuleWidget *moduleWidget; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| gRackWidget->cloneModule(moduleWidget); | gRackWidget->cloneModule(moduleWidget); | ||||
| } | } | ||||
| }; | }; | ||||
| struct DeleteMenuItem : MenuItem { | struct DeleteMenuItem : MenuItem { | ||||
| ModuleWidget *moduleWidget; | ModuleWidget *moduleWidget; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| gRackWidget->deleteModule(moduleWidget); | gRackWidget->deleteModule(moduleWidget); | ||||
| moduleWidget->finalizeEvents(); | moduleWidget->finalizeEvents(); | ||||
| delete moduleWidget; | delete moduleWidget; | ||||
| @@ -295,11 +313,5 @@ Menu *ModuleWidget::createContextMenu() { | |||||
| return menu; | return menu; | ||||
| } | } | ||||
| void ModuleWidget::onMouseDownOpaque(int button) { | |||||
| if (button == 1) { | |||||
| createContextMenu(); | |||||
| } | |||||
| } | |||||
| } // namespace rack | } // namespace rack | ||||
| @@ -19,13 +19,15 @@ void ParamWidget::randomize() { | |||||
| setValue(rescalef(randomf(), 0.0, 1.0, minValue, maxValue)); | 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); | setValue(defaultValue); | ||||
| } | } | ||||
| e.consumed = true; | |||||
| e.target = this; | |||||
| } | } | ||||
| void ParamWidget::onChange() { | |||||
| void ParamWidget::onChange(EventChange &e) { | |||||
| if (!module) | if (!module) | ||||
| return; | return; | ||||
| @@ -15,7 +15,7 @@ PluginManagerWidget::PluginManagerWidget() { | |||||
| Vec pos = Vec(0, 0); | Vec pos = Vec(0, 0); | ||||
| struct RegisterButton : Button { | struct RegisterButton : Button { | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| std::thread t(openBrowser, "https://vcvrack.com/"); | std::thread t(openBrowser, "https://vcvrack.com/"); | ||||
| t.detach(); | t.detach(); | ||||
| } | } | ||||
| @@ -46,7 +46,7 @@ PluginManagerWidget::PluginManagerWidget() { | |||||
| struct LogInButton : Button { | struct LogInButton : Button { | ||||
| TextField *emailField; | TextField *emailField; | ||||
| TextField *passwordField; | TextField *passwordField; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| std::thread t(pluginLogIn, emailField->text, passwordField->text); | std::thread t(pluginLogIn, emailField->text, passwordField->text); | ||||
| t.detach(); | t.detach(); | ||||
| passwordField->text = ""; | passwordField->text = ""; | ||||
| @@ -79,7 +79,7 @@ PluginManagerWidget::PluginManagerWidget() { | |||||
| Vec pos = Vec(0, 0); | Vec pos = Vec(0, 0); | ||||
| struct ManageButton : Button { | struct ManageButton : Button { | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| std::thread t(openBrowser, "https://vcvrack.com/"); | std::thread t(openBrowser, "https://vcvrack.com/"); | ||||
| t.detach(); | t.detach(); | ||||
| } | } | ||||
| @@ -92,7 +92,7 @@ PluginManagerWidget::PluginManagerWidget() { | |||||
| pos.x += manageButton->box.size.x; | pos.x += manageButton->box.size.x; | ||||
| struct RefreshButton : Button { | struct RefreshButton : Button { | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| std::thread t(pluginRefresh); | std::thread t(pluginRefresh); | ||||
| t.detach(); | t.detach(); | ||||
| } | } | ||||
| @@ -106,7 +106,7 @@ PluginManagerWidget::PluginManagerWidget() { | |||||
| pos.x += refreshButton->box.size.x; | pos.x += refreshButton->box.size.x; | ||||
| struct LogOutButton : Button { | struct LogOutButton : Button { | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| pluginLogOut(); | pluginLogOut(); | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -142,7 +142,7 @@ PluginManagerWidget::PluginManagerWidget() { | |||||
| pos.x += downloadProgress->box.size.x; | pos.x += downloadProgress->box.size.x; | ||||
| // struct CancelButton : Button { | // struct CancelButton : Button { | ||||
| // void onAction() override { | |||||
| // void onAction(EventAction &e) override { | |||||
| // pluginCancelDownload(); | // pluginCancelDownload(); | ||||
| // } | // } | ||||
| // }; | // }; | ||||
| @@ -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); | gRackWidget->wireContainer->removeTopWire(this); | ||||
| // HACK | // HACK | ||||
| // Update hovered*Port of active wire if applicable | // 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 | // Try to grab wire on top of stack | ||||
| WireWidget *wire = gRackWidget->wireContainer->getTopWire(this); | WireWidget *wire = gRackWidget->wireContainer->getTopWire(this); | ||||
| if (guiIsModPressed()) { | if (guiIsModPressed()) { | ||||
| @@ -62,10 +59,16 @@ void Port::onDragStart() { | |||||
| gRackWidget->wireContainer->setActiveWire(wire); | 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 | // Reject ports if this is an input port and something is already plugged into it | ||||
| if (type == INPUT) { | if (type == INPUT) { | ||||
| WireWidget *topWire = gRackWidget->wireContainer->getTopWire(this); | 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; | WireWidget *activeWire = gRackWidget->wireContainer->activeWire; | ||||
| if (activeWire) { | if (activeWire) { | ||||
| if (type == INPUT) | if (type == INPUT) | ||||
| @@ -82,39 +82,55 @@ void RackScene::draw(NVGcontext *vg) { | |||||
| Scene::draw(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: | case GLFW_KEY_N: | ||||
| if (guiIsModPressed() && !guiIsShiftPressed()) { | if (guiIsModPressed() && !guiIsShiftPressed()) { | ||||
| gRackWidget->reset(); | gRackWidget->reset(); | ||||
| return this; | |||||
| e.consumed = true; | |||||
| return; | |||||
| } | } | ||||
| break; | break; | ||||
| case GLFW_KEY_Q: | case GLFW_KEY_Q: | ||||
| if (guiIsModPressed() && !guiIsShiftPressed()) { | if (guiIsModPressed() && !guiIsShiftPressed()) { | ||||
| guiClose(); | guiClose(); | ||||
| return this; | |||||
| e.consumed = true; | |||||
| return; | |||||
| } | } | ||||
| break; | break; | ||||
| case GLFW_KEY_O: | case GLFW_KEY_O: | ||||
| if (guiIsModPressed() && !guiIsShiftPressed()) { | if (guiIsModPressed() && !guiIsShiftPressed()) { | ||||
| gRackWidget->openDialog(); | gRackWidget->openDialog(); | ||||
| return this; | |||||
| e.consumed = true; | |||||
| return; | |||||
| } | } | ||||
| break; | break; | ||||
| case GLFW_KEY_S: | case GLFW_KEY_S: | ||||
| if (guiIsModPressed() && !guiIsShiftPressed()) { | if (guiIsModPressed() && !guiIsShiftPressed()) { | ||||
| gRackWidget->saveDialog(); | gRackWidget->saveDialog(); | ||||
| return this; | |||||
| e.consumed = true; | |||||
| return; | |||||
| } | } | ||||
| if (guiIsModPressed() && guiIsShiftPressed()) { | if (guiIsModPressed() && guiIsShiftPressed()) { | ||||
| gRackWidget->saveAsDialog(); | gRackWidget->saveAsDialog(); | ||||
| return this; | |||||
| e.consumed = true; | |||||
| return; | |||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| return Widget::onHoverKey(pos, key); | |||||
| Widget::onHoverKey(e); | |||||
| } | |||||
| void RackScene::onPathDrop(EventPathDrop &e) { | |||||
| if (e.paths.size() >= 1) { | |||||
| const std::string& firstPath = e.paths.front(); | |||||
| if (extractExtension(firstPath) == "vcv") { | |||||
| gRackWidget->loadPatch(firstPath); | |||||
| e.consumed = true; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -375,7 +375,7 @@ void RackWidget::draw(NVGcontext *vg) { | |||||
| struct AddModuleMenuItem : MenuItem { | struct AddModuleMenuItem : MenuItem { | ||||
| Model *model; | Model *model; | ||||
| Vec modulePos; | Vec modulePos; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| ModuleWidget *moduleWidget = model->createModuleWidget(); | ModuleWidget *moduleWidget = model->createModuleWidget(); | ||||
| gRackWidget->moduleContainer->addChild(moduleWidget); | gRackWidget->moduleContainer->addChild(moduleWidget); | ||||
| // Move module nearest to the mouse position | // Move module nearest to the mouse position | ||||
| @@ -388,7 +388,7 @@ struct AddModuleMenuItem : MenuItem { | |||||
| struct UrlItem : MenuItem { | struct UrlItem : MenuItem { | ||||
| std::string url; | std::string url; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| std::thread t(openBrowser, url); | std::thread t(openBrowser, url); | ||||
| t.detach(); | 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 *menu = gScene->createMenu(); | ||||
| menu->pushChild(construct<MenuLabel>(&MenuLabel::text, "Add module")); | menu->pushChild(construct<MenuLabel>(&MenuLabel::text, "Add module")); | ||||
| @@ -519,15 +523,17 @@ void RackWidget::onMouseDownOpaque(int button) { | |||||
| AddManufacturerMenuItem *item = new AddManufacturerMenuItem(); | AddManufacturerMenuItem *item = new AddManufacturerMenuItem(); | ||||
| item->text = manufacturerName; | item->text = manufacturerName; | ||||
| item->manufacturerName = manufacturerName; | item->manufacturerName = manufacturerName; | ||||
| item->modulePos = lastMousePos; | |||||
| item->modulePos = e.pos; | |||||
| menu->pushChild(item); | menu->pushChild(item); | ||||
| } | } | ||||
| } | } | ||||
| e.consumed = true; | |||||
| e.target = this; | |||||
| } | } | ||||
| void RackWidget::onZoom() { | |||||
| void RackWidget::onZoom(EventZoom &e) { | |||||
| rails->box.size = Vec(); | rails->box.size = Vec(); | ||||
| Widget::onZoom(); | |||||
| Widget::onZoom(e); | |||||
| } | } | ||||
| @@ -35,9 +35,9 @@ void SVGKnob::step() { | |||||
| FramebufferWidget::step(); | FramebufferWidget::step(); | ||||
| } | } | ||||
| void SVGKnob::onChange() { | |||||
| void SVGKnob::onChange(EventChange &e) { | |||||
| dirty = true; | dirty = true; | ||||
| Knob::onChange(); | |||||
| Knob::onChange(e); | |||||
| } | } | ||||
| @@ -21,9 +21,9 @@ void SVGSlider::step() { | |||||
| FramebufferWidget::step(); | FramebufferWidget::step(); | ||||
| } | } | ||||
| void SVGSlider::onChange() { | |||||
| void SVGSlider::onChange(EventChange &e) { | |||||
| dirty = true; | dirty = true; | ||||
| ParamWidget::onChange(); | |||||
| ParamWidget::onChange(e); | |||||
| } | } | ||||
| @@ -22,12 +22,12 @@ void SVGSwitch::step() { | |||||
| FramebufferWidget::step(); | FramebufferWidget::step(); | ||||
| } | } | ||||
| void SVGSwitch::onChange() { | |||||
| void SVGSwitch::onChange(EventChange &e) { | |||||
| assert(frames.size() > 0); | assert(frames.size() > 0); | ||||
| int index = clampi((int) roundf(value), 0, frames.size() - 1); | int index = clampi((int) roundf(value), 0, frames.size() - 1); | ||||
| sw->setSVG(frames[index]); | sw->setSVG(frames[index]); | ||||
| dirty = true; | dirty = true; | ||||
| Switch::onChange(); | |||||
| Switch::onChange(e); | |||||
| } | } | ||||
| @@ -7,37 +7,37 @@ namespace rack { | |||||
| struct NewItem : MenuItem { | struct NewItem : MenuItem { | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| gRackWidget->reset(); | gRackWidget->reset(); | ||||
| } | } | ||||
| }; | }; | ||||
| struct OpenItem : MenuItem { | struct OpenItem : MenuItem { | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| gRackWidget->openDialog(); | gRackWidget->openDialog(); | ||||
| } | } | ||||
| }; | }; | ||||
| struct SaveItem : MenuItem { | struct SaveItem : MenuItem { | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| gRackWidget->saveDialog(); | gRackWidget->saveDialog(); | ||||
| } | } | ||||
| }; | }; | ||||
| struct SaveAsItem : MenuItem { | struct SaveAsItem : MenuItem { | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| gRackWidget->saveAsDialog(); | gRackWidget->saveAsDialog(); | ||||
| } | } | ||||
| }; | }; | ||||
| struct QuitItem : MenuItem { | struct QuitItem : MenuItem { | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| guiClose(); | guiClose(); | ||||
| } | } | ||||
| }; | }; | ||||
| struct FileChoice : ChoiceButton { | struct FileChoice : ChoiceButton { | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| Menu *menu = gScene->createMenu(); | Menu *menu = gScene->createMenu(); | ||||
| menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)); | menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)); | ||||
| menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
| @@ -54,21 +54,21 @@ struct FileChoice : ChoiceButton { | |||||
| struct PauseItem : MenuItem { | struct PauseItem : MenuItem { | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| gPaused = !gPaused; | gPaused = !gPaused; | ||||
| } | } | ||||
| }; | }; | ||||
| struct SampleRateItem : MenuItem { | struct SampleRateItem : MenuItem { | ||||
| float sampleRate; | float sampleRate; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| engineSetSampleRate(sampleRate); | engineSetSampleRate(sampleRate); | ||||
| gPaused = false; | gPaused = false; | ||||
| } | } | ||||
| }; | }; | ||||
| struct SampleRateChoice : ChoiceButton { | struct SampleRateChoice : ChoiceButton { | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| Menu *menu = gScene->createMenu(); | Menu *menu = gScene->createMenu(); | ||||
| menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)); | menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)); | ||||
| menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
| @@ -149,8 +149,8 @@ Toolbar::Toolbar() { | |||||
| xPos += margin; | xPos += margin; | ||||
| { | { | ||||
| struct ZoomSlider : Slider { | struct ZoomSlider : Slider { | ||||
| void onAction() override { | |||||
| Slider::onAction(); | |||||
| void onAction(EventAction &e) override { | |||||
| Slider::onAction(e); | |||||
| gRackScene->zoomWidget->setZoom(value / 100.0); | gRackScene->zoomWidget->setZoom(value / 100.0); | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -9,6 +9,11 @@ | |||||
| #include <pwd.h> | #include <pwd.h> | ||||
| #endif | #endif | ||||
| #if ARCH_WIN | |||||
| #include <Windows.h> | |||||
| #include <Shlobj.h> | |||||
| #endif | |||||
| namespace rack { | namespace rack { | ||||
| @@ -76,9 +81,14 @@ std::string assetLocal(std::string filename) { | |||||
| path += "/" + filename; | path += "/" + filename; | ||||
| #endif | #endif | ||||
| #if ARCH_WIN | #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 | #endif | ||||
| #if ARCH_LIN | #if ARCH_LIN | ||||
| // TODO | // TODO | ||||
| @@ -326,14 +326,14 @@ void AudioInterface::closeDevice() { | |||||
| struct AudioItem : MenuItem { | struct AudioItem : MenuItem { | ||||
| AudioInterface *audioInterface; | AudioInterface *audioInterface; | ||||
| int deviceId; | int deviceId; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| audioInterface->setDeviceId(deviceId); | audioInterface->setDeviceId(deviceId); | ||||
| } | } | ||||
| }; | }; | ||||
| struct AudioChoice : ChoiceButton { | struct AudioChoice : ChoiceButton { | ||||
| AudioInterface *audioInterface; | AudioInterface *audioInterface; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| Menu *menu = gScene->createMenu(); | Menu *menu = gScene->createMenu(); | ||||
| menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | ||||
| menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
| @@ -364,14 +364,14 @@ struct AudioChoice : ChoiceButton { | |||||
| struct SampleRateItem : MenuItem { | struct SampleRateItem : MenuItem { | ||||
| AudioInterface *audioInterface; | AudioInterface *audioInterface; | ||||
| float sampleRate; | float sampleRate; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| audioInterface->setSampleRate(sampleRate); | audioInterface->setSampleRate(sampleRate); | ||||
| } | } | ||||
| }; | }; | ||||
| struct SampleRateChoice : ChoiceButton { | struct SampleRateChoice : ChoiceButton { | ||||
| AudioInterface *audioInterface; | AudioInterface *audioInterface; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| Menu *menu = gScene->createMenu(); | Menu *menu = gScene->createMenu(); | ||||
| menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | ||||
| menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
| @@ -395,14 +395,14 @@ struct SampleRateChoice : ChoiceButton { | |||||
| struct BlockSizeItem : MenuItem { | struct BlockSizeItem : MenuItem { | ||||
| AudioInterface *audioInterface; | AudioInterface *audioInterface; | ||||
| int blockSize; | int blockSize; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| audioInterface->setBlockSize(blockSize); | audioInterface->setBlockSize(blockSize); | ||||
| } | } | ||||
| }; | }; | ||||
| struct BlockSizeChoice : ChoiceButton { | struct BlockSizeChoice : ChoiceButton { | ||||
| AudioInterface *audioInterface; | AudioInterface *audioInterface; | ||||
| void onAction() override { | |||||
| void onAction(EventAction &e) override { | |||||
| Menu *menu = gScene->createMenu(); | Menu *menu = gScene->createMenu(); | ||||
| menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | ||||
| menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
| @@ -10,20 +10,21 @@ struct ModuleResizeHandle : Widget { | |||||
| ModuleResizeHandle() { | ModuleResizeHandle() { | ||||
| box.size = Vec(RACK_GRID_WIDTH * 1, RACK_GRID_HEIGHT); | 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); | assert(parent); | ||||
| originalWidth = parent->box.size.x; | originalWidth = parent->box.size.x; | ||||
| totalX = 0.0; | totalX = 0.0; | ||||
| } | } | ||||
| void onDragMove(Vec mouseRel) override { | |||||
| void onDragMove(EventDragMove &e) override { | |||||
| ModuleWidget *m = dynamic_cast<ModuleWidget*>(parent); | ModuleWidget *m = dynamic_cast<ModuleWidget*>(parent); | ||||
| assert(m); | assert(m); | ||||
| totalX += mouseRel.x; | |||||
| totalX += e.mouseRel.x; | |||||
| float targetWidth = originalWidth; | float targetWidth = originalWidth; | ||||
| if (right) | if (right) | ||||
| targetWidth += totalX; | targetWidth += totalX; | ||||
| @@ -41,8 +41,8 @@ float Light::getBrightness() { | |||||
| void Light::setBrightnessSmooth(float brightness) { | void Light::setBrightnessSmooth(float brightness) { | ||||
| float v = brightness * brightness; | float v = brightness * brightness; | ||||
| if (v < value) { | 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 { | else { | ||||
| // Immediately illuminate light | // Immediately illuminate light | ||||
| @@ -54,25 +54,36 @@ void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { | |||||
| #endif | #endif | ||||
| if (action == GLFW_PRESS) { | if (action == GLFW_PRESS) { | ||||
| Widget *w = NULL; | |||||
| // onMouseDown | // 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 (button == GLFW_MOUSE_BUTTON_LEFT) { | ||||
| if (w) { | if (w) { | ||||
| // onDragStart | // onDragStart | ||||
| w->onDragStart(); | |||||
| EventDragStart e; | |||||
| w->onDragStart(e); | |||||
| } | } | ||||
| gDraggedWidget = w; | gDraggedWidget = w; | ||||
| if (w != gFocusedWidget) { | if (w != gFocusedWidget) { | ||||
| if (gFocusedWidget) { | if (gFocusedWidget) { | ||||
| // onDefocus | // onDefocus | ||||
| w->onDefocus(); | |||||
| EventDefocus e; | |||||
| w->onDefocus(e); | |||||
| } | } | ||||
| gFocusedWidget = NULL; | gFocusedWidget = NULL; | ||||
| if (w) { | if (w) { | ||||
| // onFocus | // onFocus | ||||
| if (w->onFocus()) { | |||||
| EventFocus e; | |||||
| w->onFocus(e); | |||||
| if (e.consumed) { | |||||
| gFocusedWidget = w; | gFocusedWidget = w; | ||||
| } | } | ||||
| } | } | ||||
| @@ -81,17 +92,27 @@ void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { | |||||
| } | } | ||||
| else if (action == GLFW_RELEASE) { | else if (action == GLFW_RELEASE) { | ||||
| // onMouseUp | // 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 (button == GLFW_MOUSE_BUTTON_LEFT) { | ||||
| if (gDraggedWidget) { | if (gDraggedWidget) { | ||||
| // onDragDrop | // 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 | // gDraggedWidget might have been set to null in the last event, recheck here | ||||
| if (gDraggedWidget) { | if (gDraggedWidget) { | ||||
| // onDragEnd | // onDragEnd | ||||
| gDraggedWidget->onDragEnd(); | |||||
| EventDragEnd e; | |||||
| gDraggedWidget->onDragEnd(e); | |||||
| } | } | ||||
| gDraggedWidget = NULL; | gDraggedWidget = NULL; | ||||
| gDragHoveredWidget = NULL; | gDragHoveredWidget = NULL; | ||||
| @@ -141,19 +162,32 @@ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { | |||||
| gMousePos = mousePos; | gMousePos = mousePos; | ||||
| Widget *hovered = NULL; | |||||
| // onMouseMove | // onMouseMove | ||||
| Widget *hovered = gScene->onMouseMove(gMousePos, mouseRel); | |||||
| { | |||||
| EventMouseMove e; | |||||
| e.pos = mousePos; | |||||
| e.mouseRel = mouseRel; | |||||
| gScene->onMouseMove(e); | |||||
| hovered = e.target; | |||||
| } | |||||
| if (gDraggedWidget) { | if (gDraggedWidget) { | ||||
| // onDragMove | // onDragMove | ||||
| gDraggedWidget->onDragMove(mouseRel); | |||||
| EventDragMove e; | |||||
| e.mouseRel = mouseRel; | |||||
| gDraggedWidget->onDragMove(e); | |||||
| if (hovered != gDragHoveredWidget) { | if (hovered != gDragHoveredWidget) { | ||||
| if (gDragHoveredWidget) { | if (gDragHoveredWidget) { | ||||
| gDragHoveredWidget->onDragLeave(gDraggedWidget); | |||||
| EventDragEnter e; | |||||
| e.origin = gDraggedWidget; | |||||
| gDragHoveredWidget->onDragLeave(e); | |||||
| } | } | ||||
| if (hovered) { | if (hovered) { | ||||
| hovered->onDragEnter(gDraggedWidget); | |||||
| EventDragEnter e; | |||||
| e.origin = gDraggedWidget; | |||||
| hovered->onDragEnter(e); | |||||
| } | } | ||||
| gDragHoveredWidget = hovered; | gDragHoveredWidget = hovered; | ||||
| } | } | ||||
| @@ -162,11 +196,13 @@ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { | |||||
| if (hovered != gHoveredWidget) { | if (hovered != gHoveredWidget) { | ||||
| if (gHoveredWidget) { | if (gHoveredWidget) { | ||||
| // onMouseLeave | // onMouseLeave | ||||
| gHoveredWidget->onMouseLeave(); | |||||
| EventMouseLeave e; | |||||
| gHoveredWidget->onMouseLeave(e); | |||||
| } | } | ||||
| if (hovered) { | if (hovered) { | ||||
| // onMouseEnter | |||||
| hovered->onMouseEnter(); | |||||
| // onMouseEnter | |||||
| EventMouseEnter e; | |||||
| hovered->onMouseEnter(e); | |||||
| } | } | ||||
| gHoveredWidget = hovered; | gHoveredWidget = hovered; | ||||
| } | } | ||||
| @@ -174,14 +210,19 @@ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { | |||||
| if (glfwGetMouseButton(gWindow, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS) { | if (glfwGetMouseButton(gWindow, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS) { | ||||
| // TODO | // TODO | ||||
| // Define a new global called gScrollWidget, which remembers the widget where middle-click was first pressed | // 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) { | void cursorEnterCallback(GLFWwindow* window, int entered) { | ||||
| if (!entered) { | if (!entered) { | ||||
| if (gHoveredWidget) { | if (gHoveredWidget) { | ||||
| gHoveredWidget->onMouseLeave(); | |||||
| // onMouseLeave | |||||
| EventMouseLeave e; | |||||
| gHoveredWidget->onMouseLeave(e); | |||||
| } | } | ||||
| gHoveredWidget = NULL; | gHoveredWidget = NULL; | ||||
| } | } | ||||
| @@ -194,23 +235,47 @@ void scrollCallback(GLFWwindow *window, double x, double y) { | |||||
| scrollRel = Vec(y, x); | scrollRel = Vec(y, x); | ||||
| #endif | #endif | ||||
| // onScroll | // 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) { | void charCallback(GLFWwindow *window, unsigned int codepoint) { | ||||
| if (gFocusedWidget) { | 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) { | |||||
| void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) { | |||||
| if (action == GLFW_PRESS || action == GLFW_REPEAT) { | 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 | // 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) { | |||||
| // onPathDrop | |||||
| EventPathDrop e; | |||||
| e.pos = gMousePos; | |||||
| for (int i = 0; i < count; i++) { | |||||
| e.paths.push_back(paths[i]); | |||||
| } | } | ||||
| gScene->onPathDrop(e); | |||||
| } | } | ||||
| void errorCallback(int error, const char *description) { | void errorCallback(int error, const char *description) { | ||||
| @@ -272,6 +337,7 @@ void guiInit() { | |||||
| glfwSetScrollCallback(gWindow, scrollCallback); | glfwSetScrollCallback(gWindow, scrollCallback); | ||||
| glfwSetCharCallback(gWindow, charCallback); | glfwSetCharCallback(gWindow, charCallback); | ||||
| glfwSetKeyCallback(gWindow, keyCallback); | glfwSetKeyCallback(gWindow, keyCallback); | ||||
| glfwSetDropCallback(gWindow, dropCallback); | |||||
| // Set up GLEW | // Set up GLEW | ||||
| glewExperimental = GL_TRUE; | glewExperimental = GL_TRUE; | ||||
| @@ -10,9 +10,15 @@ | |||||
| using namespace rack; | using namespace rack; | ||||
| int main(int argc, char* argv[]) { | 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(); | pluginInit(); | ||||
| engineInit(); | engineInit(); | ||||
| @@ -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()); | 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; | state = BND_HOVER; | ||||
| } | } | ||||
| void Button::onMouseLeave() { | |||||
| void Button::onMouseLeave(EventMouseLeave &e) { | |||||
| state = BND_DEFAULT; | state = BND_DEFAULT; | ||||
| } | } | ||||
| void Button::onDragStart() { | |||||
| void Button::onDragStart(EventDragStart &e) { | |||||
| state = BND_ACTIVE; | state = BND_ACTIVE; | ||||
| } | } | ||||
| void Button::onDragEnd() { | |||||
| void Button::onDragEnd(EventDragEnd &e) { | |||||
| state = BND_HOVER; | 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); | |||||
| } | } | ||||
| } | } | ||||
| @@ -117,7 +117,7 @@ int FramebufferWidget::getImageHandle() { | |||||
| return internal->fb->image; | return internal->fb->image; | ||||
| } | } | ||||
| void FramebufferWidget::onZoom() { | |||||
| void FramebufferWidget::onZoom(EventZoom &e) { | |||||
| dirty = true; | dirty = true; | ||||
| } | } | ||||
| @@ -52,12 +52,12 @@ void Menu::draw(NVGcontext *vg) { | |||||
| } | } | ||||
| bool Menu::onScrollOpaque(Vec scrollRel) { | |||||
| void Menu::onScroll(EventScroll &e) { | |||||
| if (!parent) | if (!parent) | ||||
| return true; | |||||
| return; | |||||
| if (!parent->box.contains(box)) | if (!parent->box.contains(box)) | ||||
| box.pos = box.pos.plus(scrollRel); | |||||
| return true; | |||||
| box.pos = box.pos.plus(e.scrollRel); | |||||
| e.consumed = true; | |||||
| } | } | ||||
| @@ -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); | 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<Menu*>(parent); | Menu *parentMenu = dynamic_cast<Menu*>(parent); | ||||
| if (!parentMenu) | if (!parentMenu) | ||||
| return; | return; | ||||
| @@ -38,11 +38,12 @@ void MenuItem::onMouseEnter() { | |||||
| parentMenu->setChildMenu(childMenu); | parentMenu->setChildMenu(childMenu); | ||||
| } | } | ||||
| void MenuItem::onDragDrop(Widget *origin) { | |||||
| if (origin != this) | |||||
| void MenuItem::onDragDrop(EventDragDrop &e) { | |||||
| if (e.origin != this) | |||||
| return; | return; | ||||
| onAction(); | |||||
| EventAction eAction; | |||||
| onAction(eAction); | |||||
| // deletes `this` | // deletes `this` | ||||
| gScene->setOverlay(NULL); | gScene->setOverlay(NULL); | ||||
| } | } | ||||
| @@ -3,18 +3,22 @@ | |||||
| namespace rack { | namespace rack { | ||||
| void MenuOverlay::onDragDrop(Widget *origin) { | |||||
| if (origin == this) { | |||||
| void MenuOverlay::onDragDrop(EventDragDrop &e) { | |||||
| if (e.origin == this) { | |||||
| // deletes `this` | // deletes `this` | ||||
| gScene->setOverlay(NULL); | 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; | |||||
| } | } | ||||
| @@ -4,12 +4,14 @@ | |||||
| namespace rack { | namespace rack { | ||||
| QuantityWidget::QuantityWidget() { | QuantityWidget::QuantityWidget() { | ||||
| onChange(); | |||||
| EventChange e; | |||||
| onChange(e); | |||||
| } | } | ||||
| void QuantityWidget::setValue(float value) { | void QuantityWidget::setValue(float value) { | ||||
| this->value = clampf(value, fminf(minValue, maxValue), fmaxf(minValue, maxValue)); | this->value = clampf(value, fminf(minValue, maxValue), fmaxf(minValue, maxValue)); | ||||
| onChange(); | |||||
| EventChange e; | |||||
| onChange(e); | |||||
| } | } | ||||
| void QuantityWidget::setLimits(float minValue, float maxValue) { | void QuantityWidget::setLimits(float minValue, float maxValue) { | ||||
| @@ -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()); | 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; | state = BND_HOVER; | ||||
| } | } | ||||
| void RadioButton::onMouseLeave() { | |||||
| void RadioButton::onMouseLeave(EventMouseLeave &e) { | |||||
| state = BND_DEFAULT; | state = BND_DEFAULT; | ||||
| } | } | ||||
| void RadioButton::onDragDrop(Widget *origin) { | |||||
| if (origin == this) { | |||||
| void RadioButton::onDragDrop(EventDragDrop &e) { | |||||
| if (e.origin == this) { | |||||
| if (value == 0.0) | if (value == 0.0) | ||||
| value = 1.0; | value = 1.0; | ||||
| else | else | ||||
| value = 0.0; | value = 0.0; | ||||
| onAction(); | |||||
| EventAction eAction; | |||||
| onAction(eAction); | |||||
| } | } | ||||
| } | } | ||||
| @@ -19,21 +19,21 @@ void ScrollBar::draw(NVGcontext *vg) { | |||||
| bndScrollBar(vg, 0.0, 0.0, box.size.x, box.size.y, state, offset, size); | 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; | state = BND_ACTIVE; | ||||
| guiCursorLock(); | guiCursorLock(); | ||||
| } | } | ||||
| void ScrollBar::onDragMove(Vec mouseRel) { | |||||
| void ScrollBar::onDragMove(EventDragMove &e) { | |||||
| ScrollWidget *scrollWidget = dynamic_cast<ScrollWidget*>(parent); | ScrollWidget *scrollWidget = dynamic_cast<ScrollWidget*>(parent); | ||||
| assert(scrollWidget); | assert(scrollWidget); | ||||
| if (orientation == HORIZONTAL) | if (orientation == HORIZONTAL) | ||||
| scrollWidget->offset.x += mouseRel.x; | |||||
| scrollWidget->offset.x += e.mouseRel.x; | |||||
| else | else | ||||
| scrollWidget->offset.y += mouseRel.y; | |||||
| scrollWidget->offset.y += e.mouseRel.y; | |||||
| } | } | ||||
| void ScrollBar::onDragEnd() { | |||||
| void ScrollBar::onDragEnd(EventDragEnd &e) { | |||||
| state = BND_DEFAULT; | state = BND_DEFAULT; | ||||
| guiCursorUnlock(); | guiCursorUnlock(); | ||||
| } | } | ||||
| @@ -58,9 +58,9 @@ void ScrollWidget::step() { | |||||
| Widget::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; | |||||
| } | } | ||||
| @@ -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); | 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; | state = BND_ACTIVE; | ||||
| guiCursorLock(); | 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; | state = BND_DEFAULT; | ||||
| guiCursorUnlock(); | 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); | setValue(defaultValue); | ||||
| onAction(); | |||||
| EventAction eAction; | |||||
| onAction(eAction); | |||||
| } | } | ||||
| e.consumed = true; | |||||
| e.target = this; | |||||
| } | } | ||||
| @@ -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); | 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: | case GLFW_KEY_BACKSPACE: | ||||
| if (begin < end) { | if (begin < end) { | ||||
| text.erase(begin, end - begin); | text.erase(begin, end - begin); | ||||
| @@ -107,20 +111,15 @@ bool TextField::onFocusKey(int key) { | |||||
| insertText("\n"); | insertText("\n"); | ||||
| } | } | ||||
| else { | else { | ||||
| onAction(); | |||||
| EventAction e; | |||||
| onAction(e); | |||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| begin = mini(maxi(begin, 0), text.size()); | begin = mini(maxi(begin, 0), text.size()); | ||||
| end = mini(maxi(end, 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) { | void TextField::insertText(std::string newText) { | ||||
| @@ -78,18 +78,21 @@ void Widget::clearChildren() { | |||||
| void Widget::finalizeEvents() { | void Widget::finalizeEvents() { | ||||
| // Stop dragging and hovering this widget | // Stop dragging and hovering this widget | ||||
| if (gHoveredWidget == this) { | if (gHoveredWidget == this) { | ||||
| gHoveredWidget->onMouseLeave(); | |||||
| EventMouseLeave e; | |||||
| gHoveredWidget->onMouseLeave(e); | |||||
| gHoveredWidget = NULL; | gHoveredWidget = NULL; | ||||
| } | } | ||||
| if (gDraggedWidget == this) { | if (gDraggedWidget == this) { | ||||
| gDraggedWidget->onDragEnd(); | |||||
| EventDragEnd e; | |||||
| gDraggedWidget->onDragEnd(e); | |||||
| gDraggedWidget = NULL; | gDraggedWidget = NULL; | ||||
| } | } | ||||
| if (gDragHoveredWidget == this) { | if (gDragHoveredWidget == this) { | ||||
| gDragHoveredWidget = NULL; | gDragHoveredWidget = NULL; | ||||
| } | } | ||||
| if (gFocusedWidget == this) { | if (gFocusedWidget == this) { | ||||
| gFocusedWidget->onDefocus(); | |||||
| EventDefocus e; | |||||
| gFocusedWidget->onDefocus(e); | |||||
| gFocusedWidget = NULL; | gFocusedWidget = NULL; | ||||
| } | } | ||||
| for (Widget *child : children) { | for (Widget *child : children) { | ||||
| @@ -114,80 +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); | |||||
| } | |||||
| 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++) { | for (auto it = children.rbegin(); it != children.rend(); it++) { | ||||
| Widget *child = *it; | Widget *child = *it; | ||||
| child->onZoom(); | |||||
| child->onZoom(e); | |||||
| } | } | ||||
| } | } | ||||
| @@ -18,8 +18,10 @@ Rect ZoomWidget::getViewport(Rect r) { | |||||
| } | } | ||||
| void ZoomWidget::setZoom(float zoom) { | void ZoomWidget::setZoom(float zoom) { | ||||
| if (zoom != this->zoom) | |||||
| onZoom(); | |||||
| if (zoom != this->zoom) { | |||||
| EventZoom e; | |||||
| onZoom(e); | |||||
| } | |||||
| this->zoom = zoom; | this->zoom = zoom; | ||||
| } | } | ||||
| @@ -28,24 +30,39 @@ void ZoomWidget::draw(NVGcontext *vg) { | |||||
| Widget::draw(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; | |||||
| } | } | ||||