Browse Source

Merge branch 'master' of https://github.com/VCVRack/Rack

tags/v0.5.0
Andrew Belt 7 years ago
parent
commit
205c04d4fe
41 changed files with 800 additions and 403 deletions
  1. +9
    -7
      Makefile
  2. +1
    -1
      ext/osdialog
  3. +29
    -28
      include/app.hpp
  4. +15
    -4
      include/components.hpp
  5. +4
    -4
      include/engine.hpp
  6. +107
    -0
      include/events.hpp
  7. +77
    -86
      include/widgets.hpp
  8. BIN
      installer-banner.bmp
  9. +88
    -0
      installer.nsi
  10. +71
    -0
      res/ComponentLibrary/LEDBezel.svg
  11. +7
    -6
      src/app/Knob.cpp
  12. +2
    -2
      src/app/LightWidget.cpp
  13. +36
    -24
      src/app/ModuleWidget.cpp
  14. +5
    -3
      src/app/ParamWidget.cpp
  15. +6
    -6
      src/app/PluginManagerWidget.cpp
  16. +16
    -13
      src/app/Port.cpp
  17. +24
    -8
      src/app/RackScene.cpp
  18. +16
    -10
      src/app/RackWidget.cpp
  19. +2
    -2
      src/app/SVGKnob.cpp
  20. +2
    -2
      src/app/SVGSlider.cpp
  21. +2
    -2
      src/app/SVGSwitch.cpp
  22. +11
    -11
      src/app/Toolbar.cpp
  23. +13
    -3
      src/asset.cpp
  24. +6
    -6
      src/core/AudioInterface.cpp
  25. +8
    -7
      src/core/Blank.cpp
  26. +2
    -2
      src/engine.cpp
  27. +89
    -23
      src/gui.cpp
  28. +9
    -3
      src/main.cpp
  29. +8
    -7
      src/widgets/Button.cpp
  30. +1
    -1
      src/widgets/FramebufferWidget.cpp
  31. +4
    -4
      src/widgets/Menu.cpp
  32. +5
    -4
      src/widgets/MenuItem.cpp
  33. +11
    -7
      src/widgets/MenuOverlay.cpp
  34. +4
    -2
      src/widgets/QuantityWidget.cpp
  35. +6
    -5
      src/widgets/RadioButton.cpp
  36. +5
    -5
      src/widgets/ScrollBar.cpp
  37. +3
    -3
      src/widgets/ScrollWidget.cpp
  38. +12
    -8
      src/widgets/Slider.cpp
  39. +16
    -17
      src/widgets/TextField.cpp
  40. +39
    -65
      src/widgets/Widget.cpp
  41. +29
    -12
      src/widgets/ZoomWidget.cpp

+ 9
- 7
Makefile View File

@@ -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




+ 1
- 1
ext/osdialog

@@ -1 +1 @@
Subproject commit 4dd22f56d6b733c8de13d6e8b12f13390aa5782e
Subproject commit 015d020615e8169d2f227ad385c5f2aa1e091fd1

+ 29
- 28
include/app.hpp View File

@@ -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;
}; };


//////////////////// ////////////////////


+ 15
- 4
include/components.hpp View File

@@ -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


+ 4
- 4
include/engine.hpp View File

@@ -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 {


+ 107
- 0
include/events.hpp View File

@@ -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

+ 77
- 86
include/widgets.hpp View File

@@ -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() {}
}; };


BIN
installer-banner.bmp View File

Before After

+ 88
- 0
installer.nsi View File

@@ -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

+ 71
- 0
res/ComponentLibrary/LEDBezel.svg View File

@@ -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>

+ 7
- 6
src/app/Knob.cpp View File

@@ -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;




+ 2
- 2
src/app/LightWidget.cpp View File

@@ -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);


+ 36
- 24
src/app/ModuleWidget.cpp View File

@@ -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

+ 5
- 3
src/app/ParamWidget.cpp View File

@@ -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;




+ 6
- 6
src/app/PluginManagerWidget.cpp View File

@@ -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();
// } // }
// }; // };


+ 16
- 13
src/app/Port.cpp View File

@@ -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)


+ 24
- 8
src/app/RackScene.cpp View File

@@ -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;
}
}
} }






+ 16
- 10
src/app/RackWidget.cpp View File

@@ -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);
} }






+ 2
- 2
src/app/SVGKnob.cpp View File

@@ -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);
} }






+ 2
- 2
src/app/SVGSlider.cpp View File

@@ -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);
} }






+ 2
- 2
src/app/SVGSwitch.cpp View File

@@ -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);
} }






+ 11
- 11
src/app/Toolbar.cpp View File

@@ -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);
} }
}; };


+ 13
- 3
src/asset.cpp View File

@@ -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


+ 6
- 6
src/core/AudioInterface.cpp View File

@@ -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;


+ 8
- 7
src/core/Blank.cpp View File

@@ -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;


+ 2
- 2
src/engine.cpp View File

@@ -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


+ 89
- 23
src/gui.cpp View File

@@ -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;


+ 9
- 3
src/main.cpp View File

@@ -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();


+ 8
- 7
src/widgets/Button.cpp View File

@@ -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);
} }
} }




+ 1
- 1
src/widgets/FramebufferWidget.cpp View File

@@ -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;
} }




+ 4
- 4
src/widgets/Menu.cpp View File

@@ -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;
} }






+ 5
- 4
src/widgets/MenuItem.cpp View File

@@ -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);
} }


+ 11
- 7
src/widgets/MenuOverlay.cpp View File

@@ -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
- 2
src/widgets/QuantityWidget.cpp View File

@@ -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) {


+ 6
- 5
src/widgets/RadioButton.cpp View File

@@ -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);
} }
} }




+ 5
- 5
src/widgets/ScrollBar.cpp View File

@@ -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();
} }


+ 3
- 3
src/widgets/ScrollWidget.cpp View File

@@ -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;
} }






+ 12
- 8
src/widgets/Slider.cpp View File

@@ -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;
} }






+ 16
- 17
src/widgets/TextField.cpp View File

@@ -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) {


+ 39
- 65
src/widgets/Widget.cpp View File

@@ -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);
} }
} }




+ 29
- 12
src/widgets/ZoomWidget.cpp View File

@@ -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;
} }






Loading…
Cancel
Save