diff --git a/include/WidgetState.hpp b/include/WidgetState.hpp index e6fa971e..7b458b46 100644 --- a/include/WidgetState.hpp +++ b/include/WidgetState.hpp @@ -1,11 +1,13 @@ #pragma once -#include "event.hpp" -#include "widgets/Widget.hpp" +#include "math.hpp" +#include namespace rack { +struct Widget; + struct WidgetState { Widget *rootWidget = NULL; diff --git a/include/app.hpp b/include/app.hpp index c7748bf6..69c4be07 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -1,441 +1,38 @@ #pragma once -#include -#include -#include "widgets.hpp" -#include "ui.hpp" -#include "WidgetState.hpp" - - -static const float SVG_DPI = 75.0; -static const float MM_PER_IN = 25.4; - - -namespace rack { - - -inline float in2px(float inches) { - return inches * SVG_DPI; -} - -inline math::Vec in2px(math::Vec inches) { - return inches.mult(SVG_DPI); -} - -inline float mm2px(float millimeters) { - return millimeters * (SVG_DPI / MM_PER_IN); -} - -inline math::Vec mm2px(math::Vec millimeters) { - return millimeters.mult(SVG_DPI / MM_PER_IN); -} - - -struct Model; -struct Module; -struct Wire; - -struct RackWidget; -struct ParamWidget; -struct Port; -struct SVGPanel; - -//////////////////// -// module -//////////////////// - -// A 1HPx3U module should be 15x380 pixels. Thus the width of a module should be a factor of 15. -static const float RACK_GRID_WIDTH = 15; -static const float RACK_GRID_HEIGHT = 380; -static const math::Vec RACK_GRID_SIZE = math::Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT); -static const std::string PRESET_FILTERS = "VCV Rack module preset (.vcvm):vcvm"; -static const std::string PATCH_FILTERS = "VCV Rack patch (.vcv):vcv"; - -} // namespace rack - - +#include "app/AudioWidget.hpp" +#include "app/CircularShadow.hpp" +#include "app/common.hpp" +#include "app/Component.hpp" +#include "app/Knob.hpp" +#include "app/LedDisplay.hpp" +#include "app/LightWidget.hpp" +#include "app/MidiWidget.hpp" +#include "app/ModuleLightWidget.hpp" #include "app/ModuleWidget.hpp" +#include "app/MomentarySwitch.hpp" +#include "app/MultiLightWidget.hpp" +#include "app/ParamWidget.hpp" +#include "app/PluginManagerWidget.hpp" +#include "app/Port.hpp" +#include "app/RackRail.hpp" +#include "app/RackScene.hpp" +#include "app/RackScrollWidget.hpp" +#include "app/RackWidget.hpp" +#include "app/SVGButton.hpp" +#include "app/SVGKnob.hpp" +#include "app/SVGPanel.hpp" +#include "app/SVGPort.hpp" +#include "app/SVGScrew.hpp" +#include "app/SVGSlider.hpp" +#include "app/SVGSwitch.hpp" +#include "app/ToggleSwitch.hpp" +#include "app/Toolbar.hpp" +#include "app/WireContainer.hpp" +#include "app/WireWidget.hpp" namespace rack { - -struct WireWidget : OpaqueWidget { - Port *outputPort = NULL; - Port *inputPort = NULL; - Port *hoveredOutputPort = NULL; - Port *hoveredInputPort = NULL; - Wire *wire = NULL; - NVGcolor color; - - WireWidget(); - ~WireWidget(); - /** Synchronizes the plugged state of the widget to the owned wire */ - void updateWire(); - math::Vec getOutputPos(); - math::Vec getInputPos(); - json_t *toJson(); - void fromJson(json_t *rootJ); - void draw(NVGcontext *vg) override; - void drawPlugs(NVGcontext *vg); -}; - -struct WireContainer : TransparentWidget { - WireWidget *activeWire = NULL; - /** Takes ownership of `w` and adds it as a child if it isn't already */ - void setActiveWire(WireWidget *w); - /** "Drops" the wire onto the port, making an engine connection if successful */ - void commitActiveWire(); - void removeTopWire(Port *port); - void removeAllWires(Port *port); - /** Returns the most recently added wire connected to the given Port, i.e. the top of the stack */ - WireWidget *getTopWire(Port *port); - void draw(NVGcontext *vg) override; -}; - -struct RackWidget : OpaqueWidget { - FramebufferWidget *rails; - // Only put ModuleWidgets in here - Widget *moduleContainer; - // Only put WireWidgets in here - WireContainer *wireContainer; - std::string lastPath; - math::Vec lastMousePos; - bool lockModules = false; - - RackWidget(); - ~RackWidget(); - - /** Completely clear the rack's modules and wires */ - void clear(); - /** Clears the rack and loads the template patch */ - void reset(); - void loadDialog(); - void saveDialog(); - void saveAsDialog(); - /** If `lastPath` is defined, ask the user to reload it */ - void revert(); - /** Disconnects all wires */ - void disconnect(); - void save(std::string filename); - void load(std::string filename); - json_t *toJson(); - void fromJson(json_t *rootJ); - /** Creates a module and adds it to the rack */ - ModuleWidget *moduleFromJson(json_t *moduleJ); - void pastePresetClipboard(); - - void addModule(ModuleWidget *m); - /** Removes the module and transfers ownership to the caller */ - void deleteModule(ModuleWidget *m); - void cloneModule(ModuleWidget *m); - /** Sets a module's box if non-colliding. Returns true if set */ - bool requestModuleBox(ModuleWidget *m, math::Rect box); - /** Moves a module to the closest non-colliding position */ - bool requestModuleBoxNearest(ModuleWidget *m, math::Rect box); - - void step() override; - void draw(NVGcontext *vg) override; - - void onHover(event::Hover &e) override; - void onButton(event::Button &e) override; - void onZoom(event::Zoom &e) override; -}; - -struct RackRail : TransparentWidget { - void draw(NVGcontext *vg) override; -}; - -//////////////////// -// ParamWidgets and other components -//////////////////// - -/** A Widget that exists on a Panel and interacts with a Module */ -struct Component : OpaqueWidget { - Module *module = NULL; -}; - -struct CircularShadow : TransparentWidget { - float blurRadius; - float opacity; - CircularShadow(); - void draw(NVGcontext *vg) override; -}; - -/** A Component which has control over a Param (defined in engine.hpp) */ -struct ParamWidget : Component, QuantityWidget { - int paramId; - /** Used to momentarily disable value randomization - To permanently disable or change randomization behavior, override the randomize() method instead of changing this. - */ - bool randomizable = true; - /** Apply per-sample smoothing in the engine */ - bool smooth = false; - - json_t *toJson(); - void fromJson(json_t *rootJ); - virtual void reset(); - virtual void randomize(); - void onButton(event::Button &e) override; - void onChange(event::Change &e) override; -}; - -/** Implements vertical dragging behavior for ParamWidgets */ -struct Knob : ParamWidget { - /** Snap to nearest integer while dragging */ - bool snap = false; - /** Multiplier for mouse movement to adjust knob value */ - float speed = 1.0; - float dragValue; - Knob(); - void onDragStart(event::DragStart &e) override; - void onDragMove(event::DragMove &e) override; - void onDragEnd(event::DragEnd &e) override; -}; - -/** A knob which rotates an SVG and caches it in a framebuffer */ -struct SVGKnob : Knob, FramebufferWidget { - TransformWidget *tw; - SVGWidget *sw; - CircularShadow *shadow; - /** Angles in radians */ - float minAngle, maxAngle; - - SVGKnob(); - void setSVG(std::shared_ptr svg); - void step() override; - void onChange(event::Change &e) override; -}; - -/** Behaves like a knob but linearly moves an SVGWidget between two points. -Can be used for horizontal or vertical linear faders. -*/ -struct SVGSlider : Knob, FramebufferWidget { - SVGWidget *background; - SVGWidget *handle; - /** Intermediate positions will be interpolated between these positions */ - math::Vec minHandlePos, maxHandlePos; - - SVGSlider(); - void setSVGs(std::shared_ptr backgroundSVG, std::shared_ptr handleSVG); - void step() override; - void onChange(event::Change &e) override; -}; - -/** A ParamWidget with multiple frames corresponding to its value */ -struct SVGSwitch : virtual ParamWidget, FramebufferWidget { - std::vector> frames; - SVGWidget *sw; - SVGSwitch(); - /** Adds an SVG file to represent the next switch position */ - void addFrame(std::shared_ptr svg); - void onChange(event::Change &e) override; -}; - -/** A switch that cycles through each mechanical position */ -struct ToggleSwitch : virtual ParamWidget { - void onDragStart(event::DragStart &e) override; -}; - -/** A switch that is turned on when held and turned off when released. -Consider using SVGButton if the switch simply changes the state of your Module when clicked. -*/ -struct MomentarySwitch : virtual ParamWidget { - /** Don't randomize state */ - void randomize() override {} - void onDragStart(event::DragStart &e) override; - void onDragEnd(event::DragEnd &e) override; -}; - -/** A Component with a default (up) and active (down) state when clicked. -Does not modify a Param, simply calls onAction() of a subclass. -*/ -struct SVGButton : Component, FramebufferWidget { - Module *module = NULL; - std::shared_ptr defaultSVG; - std::shared_ptr activeSVG; - SVGWidget *sw; - SVGButton(); - /** If `activeSVG` is NULL, `defaultSVG` is used as the active state instead. */ - void setSVGs(std::shared_ptr defaultSVG, std::shared_ptr activeSVG); - void onDragStart(event::DragStart &e) override; - void onDragEnd(event::DragEnd &e) override; -}; - -//////////////////// -// IO widgets -//////////////////// - -struct LedDisplay : virtual Widget { - void draw(NVGcontext *vg) override; -}; - -struct LedDisplaySeparator : TransparentWidget { - LedDisplaySeparator(); - void draw(NVGcontext *vg) override; -}; - -struct LedDisplayChoice : TransparentWidget { - std::string text; - std::shared_ptr font; - math::Vec textOffset; - NVGcolor color; - LedDisplayChoice(); - void draw(NVGcontext *vg) override; - void onButton(event::Button &e) override; -}; - -struct LedDisplayTextField : TextField { - std::shared_ptr font; - math::Vec textOffset; - NVGcolor color; - LedDisplayTextField(); - void draw(NVGcontext *vg) override; - int getTextPosition(math::Vec mousePos) override; -}; - - -struct AudioIO; -struct MidiIO; - -struct AudioWidget : LedDisplay { - /** Not owned */ - AudioIO *audioIO = NULL; - LedDisplayChoice *driverChoice; - LedDisplaySeparator *driverSeparator; - LedDisplayChoice *deviceChoice; - LedDisplaySeparator *deviceSeparator; - LedDisplayChoice *sampleRateChoice; - LedDisplaySeparator *sampleRateSeparator; - LedDisplayChoice *bufferSizeChoice; - AudioWidget(); - void step() override; -}; - -struct MidiWidget : LedDisplay { - /** Not owned */ - MidiIO *midiIO = NULL; - LedDisplayChoice *driverChoice; - LedDisplaySeparator *driverSeparator; - LedDisplayChoice *deviceChoice; - LedDisplaySeparator *deviceSeparator; - LedDisplayChoice *channelChoice; - MidiWidget(); - void step() override; -}; - -//////////////////// -// lights -//////////////////// - -struct LightWidget : TransparentWidget { - NVGcolor bgColor = nvgRGBA(0, 0, 0, 0); - NVGcolor color = nvgRGBA(0, 0, 0, 0); - NVGcolor borderColor = nvgRGBA(0, 0, 0, 0); - void draw(NVGcontext *vg) override; - virtual void drawLight(NVGcontext *vg); - virtual void drawHalo(NVGcontext *vg); -}; - -/** Mixes a list of colors based on a list of brightness values */ -struct MultiLightWidget : LightWidget { - /** Colors of each value state */ - std::vector baseColors; - void addBaseColor(NVGcolor baseColor); - /** Sets the color to a linear combination of the baseColors with the given weights */ - void setValues(const std::vector &values); -}; - -/** A MultiLightWidget that points to a module's Light or a range of lights -Will access firstLightId, firstLightId + 1, etc. for each added color -*/ -struct ModuleLightWidget : MultiLightWidget { - Module *module = NULL; - int firstLightId; - void step() override; -}; - -//////////////////// -// ports -//////////////////// - -struct Port : Component { - enum PortType { - INPUT, - OUTPUT - }; - PortType type = INPUT; - int portId; - MultiLightWidget *plugLight; - - Port(); - ~Port(); - void step() override; - void draw(NVGcontext *vg) override; - void onButton(event::Button &e) override; - void onDragStart(event::DragStart &e) override; - void onDragEnd(event::DragEnd &e) override; - void onDragDrop(event::DragDrop &e) override; - void onDragEnter(event::DragEnter &e) override; - void onDragLeave(event::DragLeave &e) override; -}; - -struct SVGPort : Port, FramebufferWidget { - SVGWidget *background; - CircularShadow *shadow; - - SVGPort(); - void setSVG(std::shared_ptr svg); - void draw(NVGcontext *vg) override; -}; - -/** If you don't add these to your ModuleWidget, they will fall out of the rack... */ -struct SVGScrew : FramebufferWidget { - SVGWidget *sw; - - SVGScrew(); -}; - -//////////////////// -// scene -//////////////////// - -struct Toolbar : OpaqueWidget { - Slider *wireOpacitySlider; - Slider *wireTensionSlider; - Slider *zoomSlider; - RadioButton *cpuUsageButton; - - Toolbar(); - void draw(NVGcontext *vg) override; -}; - -struct PluginManagerWidget : virtual Widget { - Widget *loginWidget; - Widget *manageWidget; - Widget *downloadWidget; - PluginManagerWidget(); - void step() override; -}; - -struct RackScrollWidget : ScrollWidget { - void step() override; -}; - -struct RackScene : Scene { - ScrollWidget *scrollWidget; - ZoomWidget *zoomWidget; - - RackScene(); - void step() override; - void draw(NVGcontext *vg) override; - void onHoverKey(event::HoverKey &e) override; - void onPathDrop(event::PathDrop &e) override; -}; - -//////////////////// -// globals -//////////////////// - extern std::string gApplicationName; extern std::string gApplicationVersion; extern std::string gApiHost; @@ -453,11 +50,4 @@ void appModuleBrowserCreate(); json_t *appModuleBrowserToJson(); void appModuleBrowserFromJson(json_t *rootJ); - -/** Deprecated. Will be removed in v1 */ -json_t *colorToJson(NVGcolor color); -/** Deprecated. Will be removed in v1 */ -NVGcolor jsonToColor(json_t *colorJ); - - } // namespace rack diff --git a/include/app/AudioWidget.hpp b/include/app/AudioWidget.hpp new file mode 100644 index 00000000..142793a5 --- /dev/null +++ b/include/app/AudioWidget.hpp @@ -0,0 +1,27 @@ +#pragma once +#include "common.hpp" +#include "LedDisplay.hpp" + + +namespace rack { + + +struct AudioIO; + + +struct AudioWidget : LedDisplay { + /** Not owned */ + AudioIO *audioIO = NULL; + LedDisplayChoice *driverChoice; + LedDisplaySeparator *driverSeparator; + LedDisplayChoice *deviceChoice; + LedDisplaySeparator *deviceSeparator; + LedDisplayChoice *sampleRateChoice; + LedDisplaySeparator *sampleRateSeparator; + LedDisplayChoice *bufferSizeChoice; + AudioWidget(); + void step() override; +}; + + +} // namespace rack diff --git a/include/app/CircularShadow.hpp b/include/app/CircularShadow.hpp new file mode 100644 index 00000000..68971f39 --- /dev/null +++ b/include/app/CircularShadow.hpp @@ -0,0 +1,16 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +struct CircularShadow : TransparentWidget { + float blurRadius; + float opacity; + CircularShadow(); + void draw(NVGcontext *vg) override; +}; + + +} // namespace rack diff --git a/include/app/Component.hpp b/include/app/Component.hpp new file mode 100644 index 00000000..ad9ed176 --- /dev/null +++ b/include/app/Component.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +struct Module; + + +/** A Widget that exists on a Panel and interacts with a Module */ +struct Component : OpaqueWidget { + Module *module = NULL; +}; + + +} // namespace rack diff --git a/include/app/Knob.hpp b/include/app/Knob.hpp new file mode 100644 index 00000000..54c12862 --- /dev/null +++ b/include/app/Knob.hpp @@ -0,0 +1,23 @@ +#pragma once +#include "common.hpp" +#include "ParamWidget.hpp" + + +namespace rack { + + +/** Implements vertical dragging behavior for ParamWidgets */ +struct Knob : ParamWidget { + /** Snap to nearest integer while dragging */ + bool snap = false; + /** Multiplier for mouse movement to adjust knob value */ + float speed = 1.0; + float dragValue; + Knob(); + void onDragStart(event::DragStart &e) override; + void onDragMove(event::DragMove &e) override; + void onDragEnd(event::DragEnd &e) override; +}; + + +} // namespace rack diff --git a/include/app/LedDisplay.hpp b/include/app/LedDisplay.hpp new file mode 100644 index 00000000..71a6d85c --- /dev/null +++ b/include/app/LedDisplay.hpp @@ -0,0 +1,37 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +struct LedDisplay : virtual Widget { + void draw(NVGcontext *vg) override; +}; + +struct LedDisplaySeparator : TransparentWidget { + LedDisplaySeparator(); + void draw(NVGcontext *vg) override; +}; + +struct LedDisplayChoice : TransparentWidget { + std::string text; + std::shared_ptr font; + math::Vec textOffset; + NVGcolor color; + LedDisplayChoice(); + void draw(NVGcontext *vg) override; + void onButton(event::Button &e) override; +}; + +struct LedDisplayTextField : TextField { + std::shared_ptr font; + math::Vec textOffset; + NVGcolor color; + LedDisplayTextField(); + void draw(NVGcontext *vg) override; + int getTextPosition(math::Vec mousePos) override; +}; + + +} // namespace rack diff --git a/include/app/LightWidget.hpp b/include/app/LightWidget.hpp new file mode 100644 index 00000000..1aadc31c --- /dev/null +++ b/include/app/LightWidget.hpp @@ -0,0 +1,18 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +struct LightWidget : TransparentWidget { + NVGcolor bgColor = nvgRGBA(0, 0, 0, 0); + NVGcolor color = nvgRGBA(0, 0, 0, 0); + NVGcolor borderColor = nvgRGBA(0, 0, 0, 0); + void draw(NVGcontext *vg) override; + virtual void drawLight(NVGcontext *vg); + virtual void drawHalo(NVGcontext *vg); +}; + + +} // namespace rack diff --git a/include/app/MidiWidget.hpp b/include/app/MidiWidget.hpp new file mode 100644 index 00000000..57aab5f7 --- /dev/null +++ b/include/app/MidiWidget.hpp @@ -0,0 +1,25 @@ +#pragma once +#include "common.hpp" +#include "LedDisplay.hpp" + + +namespace rack { + + +struct MidiIO; + + +struct MidiWidget : LedDisplay { + /** Not owned */ + MidiIO *midiIO = NULL; + LedDisplayChoice *driverChoice; + LedDisplaySeparator *driverSeparator; + LedDisplayChoice *deviceChoice; + LedDisplaySeparator *deviceSeparator; + LedDisplayChoice *channelChoice; + MidiWidget(); + void step() override; +}; + + +} // namespace rack diff --git a/include/app/ModuleLightWidget.hpp b/include/app/ModuleLightWidget.hpp new file mode 100644 index 00000000..d6b53599 --- /dev/null +++ b/include/app/ModuleLightWidget.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "common.hpp" +#include "MultiLightWidget.hpp" + + +namespace rack { + + +/** A MultiLightWidget that points to a module's Light or a range of lights +Will access firstLightId, firstLightId + 1, etc. for each added color +*/ +struct ModuleLightWidget : MultiLightWidget { + Module *module = NULL; + int firstLightId; + void step() override; +}; + + +} // namespace rack diff --git a/include/app/ModuleWidget.hpp b/include/app/ModuleWidget.hpp index 0ef82532..80187274 100644 --- a/include/app/ModuleWidget.hpp +++ b/include/app/ModuleWidget.hpp @@ -1,6 +1,5 @@ #pragma once -#include "widgets/OpaqueWidget.hpp" -#include "app/SVGPanel.hpp" +#include "common.hpp" #include "plugin.hpp" #include "engine.hpp" @@ -8,6 +7,10 @@ namespace rack { +struct SVGPanel; +struct Port; + + struct ModuleWidget : OpaqueWidget { Model *model = NULL; /** Owns the module pointer */ diff --git a/include/app/MomentarySwitch.hpp b/include/app/MomentarySwitch.hpp new file mode 100644 index 00000000..205ebdcf --- /dev/null +++ b/include/app/MomentarySwitch.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +/** A switch that is turned on when held and turned off when released. +Consider using SVGButton if the switch simply changes the state of your Module when clicked. +*/ +struct MomentarySwitch : virtual ParamWidget { + /** Don't randomize state */ + void randomize() override {} + void onDragStart(event::DragStart &e) override; + void onDragEnd(event::DragEnd &e) override; +}; + + +} // namespace rack diff --git a/include/app/MultiLightWidget.hpp b/include/app/MultiLightWidget.hpp new file mode 100644 index 00000000..16f2536f --- /dev/null +++ b/include/app/MultiLightWidget.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "common.hpp" +#include "LightWidget.hpp" + + +namespace rack { + + +/** Mixes a list of colors based on a list of brightness values */ +struct MultiLightWidget : LightWidget { + /** Colors of each value state */ + std::vector baseColors; + void addBaseColor(NVGcolor baseColor); + /** Sets the color to a linear combination of the baseColors with the given weights */ + void setValues(const std::vector &values); +}; + + +} // namespace rack diff --git a/include/app/ParamWidget.hpp b/include/app/ParamWidget.hpp new file mode 100644 index 00000000..02452301 --- /dev/null +++ b/include/app/ParamWidget.hpp @@ -0,0 +1,28 @@ +#pragma once +#include "common.hpp" +#include "engine.hpp" + + +namespace rack { + + +/** A Component which has control over a Param */ +struct ParamWidget : Component, QuantityWidget { + int paramId; + /** Used to momentarily disable value randomization + To permanently disable or change randomization behavior, override the randomize() method instead of changing this. + */ + bool randomizable = true; + /** Apply per-sample smoothing in the engine */ + bool smooth = false; + + json_t *toJson(); + void fromJson(json_t *rootJ); + virtual void reset(); + virtual void randomize(); + void onButton(event::Button &e) override; + void onChange(event::Change &e) override; +}; + + +} // namespace rack diff --git a/include/app/PluginManagerWidget.hpp b/include/app/PluginManagerWidget.hpp new file mode 100644 index 00000000..e6cb2614 --- /dev/null +++ b/include/app/PluginManagerWidget.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +struct PluginManagerWidget : virtual Widget { + Widget *loginWidget; + Widget *manageWidget; + Widget *downloadWidget; + PluginManagerWidget(); + void step() override; +}; + + +} // namespace rack diff --git a/include/app/Port.hpp b/include/app/Port.hpp new file mode 100644 index 00000000..7e1b10e0 --- /dev/null +++ b/include/app/Port.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +struct Port : Component { + enum PortType { + INPUT, + OUTPUT + }; + PortType type = INPUT; + int portId; + MultiLightWidget *plugLight; + + Port(); + ~Port(); + void step() override; + void draw(NVGcontext *vg) override; + void onButton(event::Button &e) override; + void onDragStart(event::DragStart &e) override; + void onDragEnd(event::DragEnd &e) override; + void onDragDrop(event::DragDrop &e) override; + void onDragEnter(event::DragEnter &e) override; + void onDragLeave(event::DragLeave &e) override; +}; + + +} // namespace rack diff --git a/include/app/RackRail.hpp b/include/app/RackRail.hpp new file mode 100644 index 00000000..b072a3ec --- /dev/null +++ b/include/app/RackRail.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +struct RackRail : TransparentWidget { + void draw(NVGcontext *vg) override; +}; + + +} // namespace rack diff --git a/include/app/RackScene.hpp b/include/app/RackScene.hpp new file mode 100644 index 00000000..97930322 --- /dev/null +++ b/include/app/RackScene.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +struct RackScene : Scene { + ScrollWidget *scrollWidget; + ZoomWidget *zoomWidget; + + RackScene(); + void step() override; + void draw(NVGcontext *vg) override; + void onHoverKey(event::HoverKey &e) override; + void onPathDrop(event::PathDrop &e) override; +}; + + +} // namespace rack diff --git a/include/app/RackScrollWidget.hpp b/include/app/RackScrollWidget.hpp new file mode 100644 index 00000000..5c01b095 --- /dev/null +++ b/include/app/RackScrollWidget.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +struct RackScrollWidget : ScrollWidget { + void step() override; +}; + + +} // namespace rack diff --git a/include/app/RackWidget.hpp b/include/app/RackWidget.hpp new file mode 100644 index 00000000..c0faf7d0 --- /dev/null +++ b/include/app/RackWidget.hpp @@ -0,0 +1,61 @@ +#pragma once +#include "common.hpp" +#include "WireWidget.hpp" +#include "WireContainer.hpp" +#include "engine.hpp" + + +namespace rack { + + +struct RackWidget : OpaqueWidget { + FramebufferWidget *rails; + // Only put ModuleWidgets in here + Widget *moduleContainer; + // Only put WireWidgets in here + WireContainer *wireContainer; + std::string lastPath; + math::Vec lastMousePos; + bool lockModules = false; + + RackWidget(); + ~RackWidget(); + + /** Completely clear the rack's modules and wires */ + void clear(); + /** Clears the rack and loads the template patch */ + void reset(); + void loadDialog(); + void saveDialog(); + void saveAsDialog(); + /** If `lastPath` is defined, ask the user to reload it */ + void revert(); + /** Disconnects all wires */ + void disconnect(); + void save(std::string filename); + void load(std::string filename); + json_t *toJson(); + void fromJson(json_t *rootJ); + /** Creates a module and adds it to the rack */ + ModuleWidget *moduleFromJson(json_t *moduleJ); + void pastePresetClipboard(); + + void addModule(ModuleWidget *m); + /** Removes the module and transfers ownership to the caller */ + void deleteModule(ModuleWidget *m); + void cloneModule(ModuleWidget *m); + /** Sets a module's box if non-colliding. Returns true if set */ + bool requestModuleBox(ModuleWidget *m, math::Rect box); + /** Moves a module to the closest non-colliding position */ + bool requestModuleBoxNearest(ModuleWidget *m, math::Rect box); + + void step() override; + void draw(NVGcontext *vg) override; + + void onHover(event::Hover &e) override; + void onButton(event::Button &e) override; + void onZoom(event::Zoom &e) override; +}; + + +} // namespace rack diff --git a/include/app/SVGButton.hpp b/include/app/SVGButton.hpp new file mode 100644 index 00000000..63b3633f --- /dev/null +++ b/include/app/SVGButton.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "common.hpp" +#include "engine.hpp" + + +namespace rack { + + +/** A Component with a default (up) and active (down) state when clicked. +Does not modify a Param, simply calls onAction() of a subclass. +*/ +struct SVGButton : Component, FramebufferWidget { + std::shared_ptr defaultSVG; + std::shared_ptr activeSVG; + SVGWidget *sw; + SVGButton(); + /** If `activeSVG` is NULL, `defaultSVG` is used as the active state instead. */ + void setSVGs(std::shared_ptr defaultSVG, std::shared_ptr activeSVG); + void onDragStart(event::DragStart &e) override; + void onDragEnd(event::DragEnd &e) override; +}; + + +} // namespace rack diff --git a/include/app/SVGKnob.hpp b/include/app/SVGKnob.hpp new file mode 100644 index 00000000..7afe32e1 --- /dev/null +++ b/include/app/SVGKnob.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "common.hpp" +#include "CircularShadow.hpp" + + +namespace rack { + + +/** A knob which rotates an SVG and caches it in a framebuffer */ +struct SVGKnob : Knob, FramebufferWidget { + TransformWidget *tw; + SVGWidget *sw; + CircularShadow *shadow; + /** Angles in radians */ + float minAngle, maxAngle; + + SVGKnob(); + void setSVG(std::shared_ptr svg); + void step() override; + void onChange(event::Change &e) override; +}; + + +} // namespace rack diff --git a/include/app/SVGPanel.hpp b/include/app/SVGPanel.hpp index d6bb61ef..51d5e33b 100644 --- a/include/app/SVGPanel.hpp +++ b/include/app/SVGPanel.hpp @@ -1,7 +1,5 @@ #pragma once -#include "app.hpp" -#include "widgets/FramebufferWidget.hpp" -#include "widgets/SVGWidget.hpp" +#include "common.hpp" namespace rack { diff --git a/include/app/SVGPort.hpp b/include/app/SVGPort.hpp new file mode 100644 index 00000000..fd4d41c6 --- /dev/null +++ b/include/app/SVGPort.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "common.hpp" +#include "Port.hpp" + + +namespace rack { + + +struct SVGPort : Port, FramebufferWidget { + SVGWidget *background; + CircularShadow *shadow; + + SVGPort(); + void setSVG(std::shared_ptr svg); + void draw(NVGcontext *vg) override; +}; + + +} // namespace rack diff --git a/include/app/SVGScrew.hpp b/include/app/SVGScrew.hpp new file mode 100644 index 00000000..cdbe8ddf --- /dev/null +++ b/include/app/SVGScrew.hpp @@ -0,0 +1,17 @@ +#pragma once +#include "common.hpp" +#include "Port.hpp" + + +namespace rack { + + +/** If you don't add these to your ModuleWidget, they will fall out of the rack... */ +struct SVGScrew : FramebufferWidget { + SVGWidget *sw; + + SVGScrew(); +}; + + +} // namespace rack diff --git a/include/app/SVGSlider.hpp b/include/app/SVGSlider.hpp new file mode 100644 index 00000000..4de27504 --- /dev/null +++ b/include/app/SVGSlider.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +/** Behaves like a knob but linearly moves an SVGWidget between two points. +Can be used for horizontal or vertical linear faders. +*/ +struct SVGSlider : Knob, FramebufferWidget { + SVGWidget *background; + SVGWidget *handle; + /** Intermediate positions will be interpolated between these positions */ + math::Vec minHandlePos, maxHandlePos; + + SVGSlider(); + void setSVGs(std::shared_ptr backgroundSVG, std::shared_ptr handleSVG); + void step() override; + void onChange(event::Change &e) override; +}; + + +} // namespace rack diff --git a/include/app/SVGSwitch.hpp b/include/app/SVGSwitch.hpp new file mode 100644 index 00000000..2052d459 --- /dev/null +++ b/include/app/SVGSwitch.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +/** A ParamWidget with multiple frames corresponding to its value */ +struct SVGSwitch : virtual ParamWidget, FramebufferWidget { + std::vector> frames; + SVGWidget *sw; + + SVGSwitch(); + /** Adds an SVG file to represent the next switch position */ + void addFrame(std::shared_ptr svg); + void onChange(event::Change &e) override; +}; + + +} // namespace rack diff --git a/include/app/ToggleSwitch.hpp b/include/app/ToggleSwitch.hpp new file mode 100644 index 00000000..ba37f31b --- /dev/null +++ b/include/app/ToggleSwitch.hpp @@ -0,0 +1,14 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +/** A switch that cycles through each mechanical position */ +struct ToggleSwitch : virtual ParamWidget { + void onDragStart(event::DragStart &e) override; +}; + + +} // namespace rack diff --git a/include/app/Toolbar.hpp b/include/app/Toolbar.hpp new file mode 100644 index 00000000..9e6f914b --- /dev/null +++ b/include/app/Toolbar.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +struct Toolbar : OpaqueWidget { + Slider *wireOpacitySlider; + Slider *wireTensionSlider; + Slider *zoomSlider; + RadioButton *cpuUsageButton; + + Toolbar(); + void draw(NVGcontext *vg) override; +}; + + +} // namespace rack diff --git a/include/app/WireContainer.hpp b/include/app/WireContainer.hpp new file mode 100644 index 00000000..4cb59323 --- /dev/null +++ b/include/app/WireContainer.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "common.hpp" +#include "WireWidget.hpp" +#include "engine.hpp" + + +namespace rack { + + +struct WireContainer : TransparentWidget { + WireWidget *activeWire = NULL; + /** Takes ownership of `w` and adds it as a child if it isn't already */ + void setActiveWire(WireWidget *w); + /** "Drops" the wire onto the port, making an engine connection if successful */ + void commitActiveWire(); + void removeTopWire(Port *port); + void removeAllWires(Port *port); + /** Returns the most recently added wire connected to the given Port, i.e. the top of the stack */ + WireWidget *getTopWire(Port *port); + void draw(NVGcontext *vg) override; +}; + + +} // namespace rack diff --git a/include/app/WireWidget.hpp b/include/app/WireWidget.hpp new file mode 100644 index 00000000..fa2649ab --- /dev/null +++ b/include/app/WireWidget.hpp @@ -0,0 +1,32 @@ +#pragma once +#include "common.hpp" + + +namespace rack { + + +struct Port; + + +struct WireWidget : OpaqueWidget { + Port *outputPort = NULL; + Port *inputPort = NULL; + Port *hoveredOutputPort = NULL; + Port *hoveredInputPort = NULL; + Wire *wire = NULL; + NVGcolor color; + + WireWidget(); + ~WireWidget(); + /** Synchronizes the plugged state of the widget to the owned wire */ + void updateWire(); + math::Vec getOutputPos(); + math::Vec getInputPos(); + json_t *toJson(); + void fromJson(json_t *rootJ); + void draw(NVGcontext *vg) override; + void drawPlugs(NVGcontext *vg); +}; + + +} // namespace rack diff --git a/include/app/common.hpp b/include/app/common.hpp new file mode 100644 index 00000000..fe8233b2 --- /dev/null +++ b/include/app/common.hpp @@ -0,0 +1,47 @@ +#pragma once +#include "ui.hpp" +#include + + +namespace rack { + + +static const float SVG_DPI = 75.0; +static const float MM_PER_IN = 25.4; + + +/** Converts inch measurements to pixels */ +inline float in2px(float in) { + return in * SVG_DPI; +} + +inline math::Vec in2px(math::Vec in) { + return in.mult(SVG_DPI); +} + +/** Converts millimeter measurements to pixels */ +inline float mm2px(float mm) { + return mm * (SVG_DPI / MM_PER_IN); +} + +inline math::Vec mm2px(math::Vec mm) { + return mm.mult(SVG_DPI / MM_PER_IN); +} + + +// A 1HPx3U module should be 15x380 pixels. Thus the width of a module should be a factor of 15. +static const float RACK_GRID_WIDTH = 15; +static const float RACK_GRID_HEIGHT = 380; +static const math::Vec RACK_GRID_SIZE = math::Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT); +static const std::string PRESET_FILTERS = "VCV Rack module preset (.vcvm):vcvm"; +static const std::string PATCH_FILTERS = "VCV Rack patch (.vcv):vcv"; + + + +/** Deprecated. Will be removed in v1 */ +json_t *colorToJson(NVGcolor color); +/** Deprecated. Will be removed in v1 */ +NVGcolor jsonToColor(json_t *colorJ); + + +} // namespace rack diff --git a/include/event.hpp b/include/event.hpp index 647b7b70..f1337873 100644 --- a/include/event.hpp +++ b/include/event.hpp @@ -12,8 +12,10 @@ struct Widget; namespace event { +/** Base event class */ struct Event { - /** Set this to the Widget that consumes (responds to) the event. + /** The Widget that consumes the event. + Set to `this` in your event handler method if consumed. This stops propagation of the event if applicable. */ Widget *target = NULL; @@ -46,7 +48,7 @@ struct Text { /** Occurs every frame when the mouse is hovering over a Widget. Recurses until consumed. -If target is set, other events may occur on that Widget. +If `target` is set, other events may occur on that Widget. */ struct Hover : Event, Position { /** Change in mouse position since the last frame. Can be zero. */ @@ -56,7 +58,7 @@ struct Hover : Event, Position { /** Occurs each mouse button press or release. Recurses until consumed. -If target is set, other events may occur on that Widget. +If `target` is set, other events may occur on that Widget. */ struct Button : Event, Position { /** GLFW_MOUSE_BUTTON_LEFT, GLFW_MOUSE_BUTTON_RIGHT, GLFW_MOUSE_BUTTON_MIDDLE, etc. */ @@ -116,6 +118,7 @@ struct Deselect : Event { /** Occurs when a key is pressed while a Widget is selected. +If consumed, a HoverKey event will not be triggered. */ struct SelectKey : Event, Key { }; @@ -140,14 +143,22 @@ struct DragEnd : Event { }; -/** Occurs when a dragged Widget is moved. -Called once per frame, even when mouseDelta is zero. +/** Occurs every frame on the dragged Widget. +`mouseDelta` may be zero. */ struct DragMove : Event { math::Vec mouseDelta; }; +/** Occurs every frame when the mouse is hovering over a Widget while dragging. +Must consume to allow DragEnter, DragLeave, and DragDrop to occur. +*/ +struct DragHover : Event, Position { + /** Change in mouse position since the last frame. Can be zero. */ + math::Vec mouseDelta; +}; + /** Occurs when the mouse enters a Widget while dragging. */ struct DragEnter : Event { diff --git a/include/ui.hpp b/include/ui.hpp index 05f8386f..2c3cb936 100644 --- a/include/ui.hpp +++ b/include/ui.hpp @@ -1,4 +1,5 @@ #pragma once +#include "ui/common.hpp" #include "ui/SequentialLayout.hpp" #include "ui/Label.hpp" #include "ui/List.hpp" diff --git a/include/ui/Button.hpp b/include/ui/Button.hpp index 63ff0c8d..a6a3721c 100644 --- a/include/ui/Button.hpp +++ b/include/ui/Button.hpp @@ -1,7 +1,5 @@ #pragma once - -#include "widgets.hpp" -#include "blendish.h" +#include "common.hpp" namespace rack { diff --git a/include/ui/ChoiceButton.hpp b/include/ui/ChoiceButton.hpp index a35e993e..1be9533f 100644 --- a/include/ui/ChoiceButton.hpp +++ b/include/ui/ChoiceButton.hpp @@ -1,6 +1,5 @@ #pragma once - -#include "ui/Button.hpp" +#include "Button.hpp" namespace rack { diff --git a/include/ui/IconButton.hpp b/include/ui/IconButton.hpp index 4be6dc4b..360e65f5 100644 --- a/include/ui/IconButton.hpp +++ b/include/ui/IconButton.hpp @@ -1,6 +1,5 @@ #pragma once - -#include "ui/Button.hpp" +#include "common.hpp" namespace rack { diff --git a/include/ui/Label.hpp b/include/ui/Label.hpp index fe9296fe..1bd39455 100644 --- a/include/ui/Label.hpp +++ b/include/ui/Label.hpp @@ -1,7 +1,5 @@ #pragma once - -#include "widgets.hpp" -#include "blendish.h" +#include "common.hpp" namespace rack { diff --git a/include/ui/List.hpp b/include/ui/List.hpp index 84d2f220..9516605c 100644 --- a/include/ui/List.hpp +++ b/include/ui/List.hpp @@ -1,6 +1,5 @@ #pragma once - -#include "widgets.hpp" +#include "common.hpp" namespace rack { diff --git a/include/ui/Menu.hpp b/include/ui/Menu.hpp index 0f607271..d0c1d583 100644 --- a/include/ui/Menu.hpp +++ b/include/ui/Menu.hpp @@ -1,7 +1,5 @@ #pragma once - #include "MenuEntry.hpp" -#include "blendish.h" namespace rack { diff --git a/include/ui/MenuEntry.hpp b/include/ui/MenuEntry.hpp index 30c03486..1636efda 100644 --- a/include/ui/MenuEntry.hpp +++ b/include/ui/MenuEntry.hpp @@ -1,6 +1,5 @@ #pragma once - -#include "widgets.hpp" +#include "common.hpp" namespace rack { diff --git a/include/ui/MenuItem.hpp b/include/ui/MenuItem.hpp index cca9d138..1fa26de1 100644 --- a/include/ui/MenuItem.hpp +++ b/include/ui/MenuItem.hpp @@ -1,8 +1,6 @@ #pragma once - -#include "widgets.hpp" -#include "blendish.h" -#include "ui/MenuOverlay.hpp" +#include "common.hpp" +#include "MenuOverlay.hpp" namespace rack { diff --git a/include/ui/MenuLabel.hpp b/include/ui/MenuLabel.hpp index b74e8e56..ee6b79a7 100644 --- a/include/ui/MenuLabel.hpp +++ b/include/ui/MenuLabel.hpp @@ -1,7 +1,5 @@ #pragma once - -#include "widgets.hpp" -#include "blendish.h" +#include "common.hpp" namespace rack { diff --git a/include/ui/MenuOverlay.hpp b/include/ui/MenuOverlay.hpp index 69672b71..b66a83f5 100644 --- a/include/ui/MenuOverlay.hpp +++ b/include/ui/MenuOverlay.hpp @@ -1,6 +1,5 @@ #pragma once - -#include "widgets.hpp" +#include "common.hpp" namespace rack { diff --git a/include/ui/MenuSeparator.hpp b/include/ui/MenuSeparator.hpp index e075febe..8c46d5e4 100644 --- a/include/ui/MenuSeparator.hpp +++ b/include/ui/MenuSeparator.hpp @@ -1,7 +1,5 @@ #pragma once - -#include "widgets.hpp" -#include "blendish.h" +#include "common.hpp" namespace rack { diff --git a/include/ui/PasswordField.hpp b/include/ui/PasswordField.hpp index f0760bd7..9e1243a9 100644 --- a/include/ui/PasswordField.hpp +++ b/include/ui/PasswordField.hpp @@ -1,6 +1,6 @@ #pragma once - -#include "ui/TextField.hpp" +#include "common.hpp" +#include "TextField.hpp" namespace rack { diff --git a/include/ui/ProgressBar.hpp b/include/ui/ProgressBar.hpp index a3ba8069..c2382014 100644 --- a/include/ui/ProgressBar.hpp +++ b/include/ui/ProgressBar.hpp @@ -1,7 +1,5 @@ #pragma once - -#include "widgets.hpp" -#include "blendish.h" +#include "common.hpp" namespace rack { diff --git a/include/ui/RadioButton.hpp b/include/ui/RadioButton.hpp index 1ef00f25..c4cb4d42 100644 --- a/include/ui/RadioButton.hpp +++ b/include/ui/RadioButton.hpp @@ -1,7 +1,5 @@ #pragma once - -#include "widgets.hpp" -#include "blendish.h" +#include "common.hpp" namespace rack { diff --git a/include/ui/Scene.hpp b/include/ui/Scene.hpp index fdcc180b..d25e27e8 100644 --- a/include/ui/Scene.hpp +++ b/include/ui/Scene.hpp @@ -1,7 +1,5 @@ #pragma once - -#include "widgets.hpp" -#include "logger.hpp" +#include "common.hpp" namespace rack { diff --git a/include/ui/ScrollWidget.hpp b/include/ui/ScrollWidget.hpp index 2a6951d6..3f63681c 100644 --- a/include/ui/ScrollWidget.hpp +++ b/include/ui/ScrollWidget.hpp @@ -1,6 +1,5 @@ #pragma once - -#include "widgets.hpp" +#include "common.hpp" #include "WidgetState.hpp" diff --git a/include/ui/SequentialLayout.hpp b/include/ui/SequentialLayout.hpp index f074d532..f7391fc5 100644 --- a/include/ui/SequentialLayout.hpp +++ b/include/ui/SequentialLayout.hpp @@ -1,6 +1,5 @@ #pragma once - -#include "widgets.hpp" +#include "common.hpp" namespace rack { diff --git a/include/ui/Slider.hpp b/include/ui/Slider.hpp index b8b150f1..08100c8b 100644 --- a/include/ui/Slider.hpp +++ b/include/ui/Slider.hpp @@ -1,7 +1,5 @@ #pragma once - -#include "widgets.hpp" -#include "blendish.h" +#include "common.hpp" namespace rack { diff --git a/include/ui/TextField.hpp b/include/ui/TextField.hpp index 3b0f9250..9661e9d7 100644 --- a/include/ui/TextField.hpp +++ b/include/ui/TextField.hpp @@ -1,8 +1,6 @@ #pragma once - -#include "widgets.hpp" +#include "common.hpp" #include "WidgetState.hpp" -#include "blendish.h" namespace rack { diff --git a/include/ui/Tooltip.hpp b/include/ui/Tooltip.hpp index a10b5eae..d04c8412 100644 --- a/include/ui/Tooltip.hpp +++ b/include/ui/Tooltip.hpp @@ -1,7 +1,5 @@ #pragma once - -#include "widgets.hpp" -#include "blendish.h" +#include "common.hpp" namespace rack { diff --git a/include/ui/TooltipOverlay.hpp b/include/ui/TooltipOverlay.hpp index d6e5242a..9835f9d2 100644 --- a/include/ui/TooltipOverlay.hpp +++ b/include/ui/TooltipOverlay.hpp @@ -1,6 +1,5 @@ #pragma once - -#include "widgets.hpp" +#include "common.hpp" namespace rack { diff --git a/include/ui/WindowOverlay.hpp b/include/ui/WindowOverlay.hpp index b937c3c4..eb763904 100644 --- a/include/ui/WindowOverlay.hpp +++ b/include/ui/WindowOverlay.hpp @@ -1,6 +1,5 @@ #pragma once - -#include "widgets.hpp" +#include "common.hpp" namespace rack { diff --git a/include/ui/WindowWidget.hpp b/include/ui/WindowWidget.hpp index 9af9fcff..14ca61fb 100644 --- a/include/ui/WindowWidget.hpp +++ b/include/ui/WindowWidget.hpp @@ -1,7 +1,5 @@ #pragma once - -#include "widgets.hpp" -#include "blendish.h" +#include "common.hpp" namespace rack { diff --git a/include/ui/common.hpp b/include/ui/common.hpp new file mode 100644 index 00000000..18a3691a --- /dev/null +++ b/include/ui/common.hpp @@ -0,0 +1,6 @@ +#pragma once +#include "widgets.hpp" +#include "blendish.h" + +#define CHECKMARK_STRING "✔" +#define CHECKMARK(_cond) ((_cond) ? CHECKMARK_STRING : "") diff --git a/include/widgets.hpp b/include/widgets.hpp index c3d4acd6..920f89fc 100644 --- a/include/widgets.hpp +++ b/include/widgets.hpp @@ -1,5 +1,4 @@ #pragma once - #include "widgets/Widget.hpp" #include "widgets/TransparentWidget.hpp" #include "widgets/OpaqueWidget.hpp" @@ -8,7 +7,3 @@ #include "widgets/SVGWidget.hpp" #include "widgets/FramebufferWidget.hpp" #include "widgets/QuantityWidget.hpp" - - -#define CHECKMARK_STRING "✔" -#define CHECKMARK(_cond) ((_cond) ? CHECKMARK_STRING : "") diff --git a/include/widgets/OpaqueWidget.hpp b/include/widgets/OpaqueWidget.hpp index 7b27eeae..c5e2783d 100644 --- a/include/widgets/OpaqueWidget.hpp +++ b/include/widgets/OpaqueWidget.hpp @@ -15,31 +15,31 @@ struct OpaqueWidget : virtual Widget { if (!e.target) e.target = this; } - void onButton(event::Button &e) override { Widget::onButton(e); if (!e.target) e.target = this; } - void onHoverKey(event::HoverKey &e) override { Widget::onHoverKey(e); if (!e.target) e.target = this; } - void onHoverText(event::HoverText &e) override { Widget::onHoverText(e); if (!e.target) e.target = this; } - - // void onHoverScroll(event::HoverScroll &e) override { - // Widget::onHoverScroll(e); - // if (!e.target) - // e.target = this; - // } - + void onHoverScroll(event::HoverScroll &e) override { + Widget::onHoverScroll(e); + if (!e.target) + e.target = this; + } + void onDragHover(event::DragHover &e) override { + Widget::onDragHover(e); + if (!e.target) + e.target = this; + } void onPathDrop(event::PathDrop &e) override { Widget::onPathDrop(e); if (!e.target) diff --git a/include/widgets/Widget.hpp b/include/widgets/Widget.hpp index d3759c5f..1c6f8918 100644 --- a/include/widgets/Widget.hpp +++ b/include/widgets/Widget.hpp @@ -121,6 +121,7 @@ struct Widget { virtual void onDragStart(event::DragStart &e) {} virtual void onDragEnd(event::DragEnd &e) {} virtual void onDragMove(event::DragMove &e) {} + virtual void onDragHover(event::DragHover &e) {recursePositionEvent(&Widget::onDragHover, e);} virtual void onDragEnter(event::DragEnter &e) {} virtual void onDragLeave(event::DragLeave &e) {} virtual void onDragDrop(event::DragDrop &e) {} diff --git a/src/WidgetState.cpp b/src/WidgetState.cpp index 528fcba5..8252a747 100644 --- a/src/WidgetState.cpp +++ b/src/WidgetState.cpp @@ -1,11 +1,14 @@ #include "WidgetState.hpp" +#include "event.hpp" +#include "widgets.hpp" #include "logger.hpp" + namespace rack { void WidgetState::handleButton(math::Vec pos, int button, int action, int mods) { - // Button event + // event::Button event::Button eButton; eButton.pos = pos; eButton.button = button; @@ -15,28 +18,37 @@ void WidgetState::handleButton(math::Vec pos, int button, int action, int mods) Widget *clickedWidget = eButton.target; if (button == GLFW_MOUSE_BUTTON_LEFT) { - // Drag events if (action == GLFW_PRESS && !draggedWidget && clickedWidget) { + // event::DragStart event::DragStart eDragStart; clickedWidget->onDragStart(eDragStart); draggedWidget = clickedWidget; } if (action == GLFW_RELEASE && draggedWidget) { + if (dragHoveredWidget) { + // event::DragLeave + event::DragLeave eDragLeave; + dragHoveredWidget->onDragLeave(eDragLeave); + } + if (clickedWidget) { + // event::DragDrop event::DragDrop eDragDrop; eDragDrop.origin = draggedWidget; clickedWidget->onDragDrop(eDragDrop); } + // event::DragEnd event::DragEnd eDragEnd; draggedWidget->onDragEnd(eDragEnd); draggedWidget = NULL; + dragHoveredWidget = NULL; } - // Select events if (action == GLFW_PRESS && clickedWidget != selectedWidget) { if (selectedWidget) { + // event::Deselect event::Deselect eDeselect; selectedWidget->onDeselect(eDeselect); } @@ -44,6 +56,7 @@ void WidgetState::handleButton(math::Vec pos, int button, int action, int mods) selectedWidget = clickedWidget; if (selectedWidget) { + // event::Select event::Select eSelect; selectedWidget->onSelect(eSelect); } @@ -62,22 +75,47 @@ void WidgetState::handleButton(math::Vec pos, int button, int action, int mods) void WidgetState::handleHover(math::Vec pos, math::Vec mouseDelta) { - // Drag events if (draggedWidget) { + // event::DragMove event::DragMove eDragMove; eDragMove.mouseDelta = mouseDelta; draggedWidget->onDragMove(eDragMove); + + // event::DragHover + event::DragHover eDragHover; + eDragHover.pos = pos; + eDragHover.mouseDelta = mouseDelta; + rootWidget->onDragHover(eDragHover); + Widget *newDragHoveredWidget = eDragHover.target; + + if (newDragHoveredWidget != dragHoveredWidget) { + if (dragHoveredWidget) { + // event::DragLeave + event::DragLeave eDragLeave; + dragHoveredWidget->onDragLeave(eDragLeave); + } + + dragHoveredWidget = newDragHoveredWidget; + + if (dragHoveredWidget) { + // event::DragEnter + event::DragEnter eDragEnter; + dragHoveredWidget->onDragEnter(eDragEnter); + } + } + return; } // if (scrollWidget) { + // event::HoverScroll // event::HoverScroll eHoverScroll; // eHoverScroll.pos = pos; // eHoverScroll.scrollDelta = scrollDelta; // rootWidget->onHoverScroll(eHoverScroll); // } - // Hover event + // event::Hover event::Hover eHover; eHover.pos = pos; eHover.mouseDelta = mouseDelta; @@ -86,6 +124,7 @@ void WidgetState::handleHover(math::Vec pos, math::Vec mouseDelta) { if (newHoveredWidget != hoveredWidget) { if (hoveredWidget) { + // event::Leave event::Leave eLeave; hoveredWidget->onLeave(eLeave); } @@ -93,6 +132,7 @@ void WidgetState::handleHover(math::Vec pos, math::Vec mouseDelta) { hoveredWidget = newHoveredWidget; if (hoveredWidget) { + // event::Enter event::Enter eEnter; hoveredWidget->onEnter(eEnter); } @@ -101,7 +141,7 @@ void WidgetState::handleHover(math::Vec pos, math::Vec mouseDelta) { void WidgetState::handleLeave() { if (hoveredWidget) { - // Leave event + // event::Leave event::Leave eLeave; hoveredWidget->onLeave(eLeave); } @@ -109,7 +149,7 @@ void WidgetState::handleLeave() { } void WidgetState::handleScroll(math::Vec pos, math::Vec scrollDelta) { - // HoverScroll event + // event::HoverScroll event::HoverScroll eHoverScroll; eHoverScroll.pos = pos; eHoverScroll.scrollDelta = scrollDelta; @@ -117,7 +157,7 @@ void WidgetState::handleScroll(math::Vec pos, math::Vec scrollDelta) { } void WidgetState::handleDrop(math::Vec pos, std::vector paths) { - // PathDrop event + // event::PathDrop event::PathDrop ePathDrop; ePathDrop.pos = pos; ePathDrop.paths = paths; @@ -126,7 +166,7 @@ void WidgetState::handleDrop(math::Vec pos, std::vector paths) { void WidgetState::handleText(math::Vec pos, int codepoint) { if (selectedWidget) { - // SelectText event + // event::SelectText event::SelectText eSelectText; eSelectText.codepoint = codepoint; selectedWidget->onSelectText(eSelectText); @@ -134,7 +174,7 @@ void WidgetState::handleText(math::Vec pos, int codepoint) { return; } - // HoverText event + // event::HoverText event::HoverText eHoverText; eHoverText.pos = pos; eHoverText.codepoint = codepoint; @@ -143,6 +183,7 @@ void WidgetState::handleText(math::Vec pos, int codepoint) { void WidgetState::handleKey(math::Vec pos, int key, int scancode, int action, int mods) { if (selectedWidget) { + // event::SelectKey event::SelectKey eSelectKey; eSelectKey.key = key; eSelectKey.scancode = scancode; @@ -153,6 +194,7 @@ void WidgetState::handleKey(math::Vec pos, int key, int scancode, int action, in return; } + // event::HoverKey event::HoverKey eHoverKey; eHoverKey.pos = pos; eHoverKey.key = key; @@ -171,6 +213,7 @@ void WidgetState::finalizeWidget(Widget *w) { } void WidgetState::handleZoom() { + // event::Zoom event::Zoom eZoom; rootWidget->onZoom(eZoom); }