@@ -116,6 +116,9 @@ ifeq ($(ARCH), mac) | |||
mkdir -p $(BUNDLE)/Contents/Resources/plugins | |||
cp -R plugins/Fundamental/dist/Fundamental $(BUNDLE)/Contents/Resources/plugins | |||
# Make DMG image | |||
cd dist && ln -s /Applications Applications | |||
cd dist && hdiutil create -srcfolder . -volname Rack -ov -format UDZO Rack-$(VERSION)-$(ARCH).dmg | |||
endif | |||
ifeq ($(ARCH), win) | |||
mkdir -p dist/Rack | |||
@@ -135,6 +138,11 @@ ifeq ($(ARCH), win) | |||
cp dep/bin/portaudio_x64.dll dist/Rack/ | |||
mkdir -p dist/Rack/plugins | |||
cp -R plugins/Fundamental/dist/Fundamental dist/Rack/plugins/ | |||
# Make ZIP | |||
cd dist && zip -5 -r Rack-$(VERSION)-$(ARCH).zip Rack | |||
# Make NSIS installer | |||
makensis installer.nsi | |||
mv Rack-setup.exe dist/Rack-$(VERSION)-$(ARCH).exe | |||
endif | |||
ifeq ($(ARCH), lin) | |||
mkdir -p dist/Rack | |||
@@ -149,16 +157,10 @@ ifeq ($(ARCH), lin) | |||
cp dep/lib/libportaudio.so.2 dist/Rack/ | |||
cp dep/lib/librtmidi.so.4 dist/Rack/ | |||
mkdir -p dist/Rack/plugins | |||
# Make ZIP | |||
cp -R plugins/Fundamental/dist/Fundamental dist/Rack/plugins/ | |||
endif | |||
ifeq ($(ARCH), mac) | |||
cd dist && ln -s /Applications Applications | |||
cd dist && hdiutil create -srcfolder . -volname Rack -ov -format UDZO Rack-$(VERSION)-$(ARCH).dmg | |||
else | |||
cd dist && zip -5 -r Rack-$(VERSION)-$(ARCH).zip Rack | |||
endif | |||
# Plugin helpers | |||
@@ -1 +1 @@ | |||
Subproject commit 4dd22f56d6b733c8de13d6e8b12f13390aa5782e | |||
Subproject commit 015d020615e8169d2f227ad385c5f2aa1e091fd1 |
@@ -67,12 +67,12 @@ struct ModuleWidget : OpaqueWidget { | |||
void draw(NVGcontext *vg) override; | |||
Vec dragPos; | |||
Widget *onMouseMove(Vec pos, Vec mouseRel) override; | |||
Widget *onHoverKey(Vec pos, int key) override; | |||
void onDragStart() override; | |||
void onDragMove(Vec mouseRel) override; | |||
void onDragEnd() override; | |||
void onMouseDownOpaque(int button) override; | |||
void onMouseDown(EventMouseDown &e) override; | |||
void onMouseMove(EventMouseMove &e) override; | |||
void onHoverKey(EventHoverKey &e) override; | |||
void onDragStart(EventDragStart &e) override; | |||
void onDragEnd(EventDragEnd &e) override; | |||
void onDragMove(EventDragMove &e) override; | |||
}; | |||
struct ValueLight; | |||
@@ -144,9 +144,9 @@ struct RackWidget : OpaqueWidget { | |||
void step() override; | |||
void draw(NVGcontext *vg) override; | |||
Widget *onMouseMove(Vec pos, Vec mouseRel) override; | |||
void onMouseDownOpaque(int button) override; | |||
void onZoom() override; | |||
void onMouseMove(EventMouseMove &e) override; | |||
void onMouseDown(EventMouseDown &e) override; | |||
void onZoom(EventZoom &e) override; | |||
}; | |||
struct RackRail : TransparentWidget { | |||
@@ -184,8 +184,8 @@ struct ParamWidget : OpaqueWidget, QuantityWidget { | |||
json_t *toJson(); | |||
void fromJson(json_t *rootJ); | |||
virtual void randomize(); | |||
void onMouseDownOpaque(int button) override; | |||
void onChange() override; | |||
void onMouseDown(EventMouseDown &e) override; | |||
void onChange(EventChange &e) override; | |||
}; | |||
/** Implements vertical dragging behavior for ParamWidgets */ | |||
@@ -193,11 +193,11 @@ struct Knob : ParamWidget { | |||
/** Snap to nearest integer while dragging */ | |||
bool snap = false; | |||
float dragValue; | |||
void onDragStart() override; | |||
void onDragMove(Vec mouseRel) override; | |||
void onDragEnd() override; | |||
void onDragStart(EventDragStart &e) override; | |||
void onDragMove(EventDragMove &e) override; | |||
void onDragEnd(EventDragEnd &e) override; | |||
/** Tell engine to smoothly vary this parameter */ | |||
void onChange() override; | |||
void onChange(EventChange &e) override; | |||
}; | |||
struct SpriteKnob : virtual Knob, SpriteWidget { | |||
@@ -216,7 +216,7 @@ struct SVGKnob : virtual Knob, FramebufferWidget { | |||
SVGKnob(); | |||
void setSVG(std::shared_ptr<SVG> svg); | |||
void step() override; | |||
void onChange() override; | |||
void onChange(EventChange &e) override; | |||
}; | |||
struct SVGSlider : Knob, FramebufferWidget { | |||
@@ -228,7 +228,7 @@ struct SVGSlider : Knob, FramebufferWidget { | |||
SVGSlider(); | |||
void step() override; | |||
void onChange() override; | |||
void onChange(EventChange &e) override; | |||
}; | |||
struct Switch : ParamWidget { | |||
@@ -243,12 +243,12 @@ struct SVGSwitch : virtual Switch, FramebufferWidget { | |||
/** Adds an SVG file to represent the next switch position */ | |||
void addFrame(std::shared_ptr<SVG> svg); | |||
void step() override; | |||
void onChange() override; | |||
void onChange(EventChange &e) override; | |||
}; | |||
/** A switch that cycles through each mechanical position */ | |||
struct ToggleSwitch : virtual Switch { | |||
void onDragStart() override { | |||
void onDragStart(EventDragStart &e) override { | |||
// Cycle through values | |||
// e.g. a range of [0.0, 3.0] would have modes 0, 1, 2, and 3. | |||
if (value >= maxValue) | |||
@@ -262,10 +262,10 @@ struct ToggleSwitch : virtual Switch { | |||
struct MomentarySwitch : virtual Switch { | |||
/** Don't randomize state */ | |||
void randomize() override {} | |||
void onDragStart() override { | |||
void onDragStart(EventDragStart &e) override { | |||
setValue(maxValue); | |||
} | |||
void onDragEnd() override { | |||
void onDragEnd(EventDragEnd &e) override { | |||
setValue(minValue); | |||
} | |||
}; | |||
@@ -286,12 +286,12 @@ struct Port : OpaqueWidget { | |||
~Port(); | |||
void draw(NVGcontext *vg) override; | |||
void onMouseDownOpaque(int button) override; | |||
void onDragEnd() override; | |||
void onDragStart() override; | |||
void onDragDrop(Widget *origin) override; | |||
void onDragEnter(Widget *origin) override; | |||
void onDragLeave(Widget *origin) override; | |||
void onMouseDown(EventMouseDown &e) override; | |||
void onDragStart(EventDragStart &e) override; | |||
void onDragEnd(EventDragEnd &e) override; | |||
void onDragDrop(EventDragDrop &e) override; | |||
void onDragEnter(EventDragEnter &e) override; | |||
void onDragLeave(EventDragEnter &e) override; | |||
}; | |||
struct SVGPort : Port, FramebufferWidget { | |||
@@ -365,7 +365,8 @@ struct RackScene : Scene { | |||
RackScene(); | |||
void step() override; | |||
void draw(NVGcontext *vg) override; | |||
Widget *onHoverKey(Vec pos, int key) override; | |||
void onHoverKey(EventHoverKey &e) override; | |||
void onPathDrop(EventPathDrop &e) override; | |||
}; | |||
//////////////////// | |||
@@ -409,34 +409,39 @@ struct RedGreenBlueLight : ColorLightWidget { | |||
}; | |||
/** Based on the size of 5mm LEDs */ | |||
template <typename BASE> | |||
struct LargeLight : BASE { | |||
LargeLight() { | |||
this->box.size = Vec(20, 20); | |||
this->box.size = mm2px(Vec(5.179, 5.179)); | |||
} | |||
}; | |||
/** Based on the size of 3mm LEDs */ | |||
template <typename BASE> | |||
struct MediumLight : BASE { | |||
MediumLight() { | |||
this->box.size = Vec(12, 12); | |||
this->box.size = mm2px(Vec(3.176, 3.176)); | |||
} | |||
}; | |||
/** Based on the size of 2mm LEDs */ | |||
template <typename BASE> | |||
struct SmallLight : BASE { | |||
SmallLight() { | |||
this->box.size = Vec(8, 8); | |||
this->box.size = mm2px(Vec(2.176, 2.176)); | |||
} | |||
}; | |||
/** Based on the size of 1mm LEDs */ | |||
template <typename BASE> | |||
struct TinyLight : BASE { | |||
TinyLight() { | |||
this->box.size = Vec(5, 5); | |||
this->box.size = mm2px(Vec(1.088, 1.088)); | |||
} | |||
}; | |||
//////////////////// | |||
// Switches and Buttons | |||
//////////////////// | |||
@@ -497,6 +502,12 @@ struct PB61303 : SVGSwitch, MomentarySwitch { | |||
} | |||
}; | |||
struct LEDBezel : SVGSwitch, MomentarySwitch { | |||
LEDBezel() { | |||
addFrame(SVG::load(assetGlobal("res/ComponentLibrary/LEDBezel.svg"))); | |||
} | |||
}; | |||
//////////////////// | |||
// Misc | |||
@@ -63,15 +63,15 @@ struct Module { | |||
virtual void step() {} | |||
virtual void onSampleRateChange() {} | |||
/** Override these to store extra internal data in the "data" property */ | |||
virtual json_t *toJson() { return NULL; } | |||
virtual void fromJson(json_t *root) {} | |||
/** Override these to implement spacial behavior when user clicks Initialize and Randomize */ | |||
virtual void reset() {} | |||
virtual void randomize() {} | |||
/** Deprecated */ | |||
virtual void initialize() final {} | |||
/** Override these to store extra internal data in the "data" property */ | |||
virtual json_t *toJson() { return NULL; } | |||
virtual void fromJson(json_t *root) {} | |||
}; | |||
struct Wire { | |||
@@ -0,0 +1,107 @@ | |||
#pragma once | |||
#include <list> | |||
#include "math.hpp" | |||
namespace rack { | |||
struct Widget; | |||
struct Event { | |||
/** Set this to true to signal that no other widgets should receive the event */ | |||
bool consumed = false; | |||
}; | |||
struct EventPosition : Event { | |||
Vec pos; | |||
}; | |||
/////////// | |||
struct EventMouseDown : EventPosition { | |||
int button; | |||
/** The widget which responded to the click. Set it to `this` if consumed. */ | |||
Widget *target = NULL; | |||
}; | |||
struct EventMouseUp : EventPosition { | |||
int button; | |||
Widget *target = NULL; | |||
}; | |||
struct EventMouseMove : EventPosition { | |||
Vec mouseRel; | |||
Widget *target = NULL; | |||
}; | |||
struct EventHoverKey : EventPosition { | |||
int key; | |||
Widget *target = NULL; | |||
}; | |||
struct EventMouseEnter : Event { | |||
}; | |||
struct EventMouseLeave : Event { | |||
}; | |||
struct EventFocus : Event { | |||
}; | |||
struct EventDefocus : Event { | |||
}; | |||
struct EventText : Event { | |||
int codepoint; | |||
}; | |||
struct EventKey : Event { | |||
int key; | |||
}; | |||
struct EventScroll : EventPosition { | |||
Vec scrollRel; | |||
}; | |||
///////////// | |||
struct EventDragStart : Event { | |||
}; | |||
struct EventDragEnd : Event { | |||
}; | |||
struct EventDragMove : Event { | |||
Vec mouseRel; | |||
}; | |||
struct EventDragEnter : Event { | |||
Widget *origin = NULL; | |||
}; | |||
struct EventDragLeave : Event { | |||
Widget *origin = NULL; | |||
}; | |||
struct EventDragDrop : Event { | |||
Widget *origin = NULL; | |||
}; | |||
struct EventPathDrop : EventPosition { | |||
std::list<std::string> paths; | |||
}; | |||
struct EventAction : Event { | |||
}; | |||
struct EventChange : Event { | |||
}; | |||
struct EventZoom : Event { | |||
}; | |||
} // namespace rack |
@@ -8,6 +8,7 @@ | |||
#include "math.hpp" | |||
#include "util.hpp" | |||
#include "events.hpp" | |||
#define SVG_DPI 75.0 | |||
@@ -122,35 +123,36 @@ struct Widget { | |||
Return `this` to accept the event. | |||
Return NULL to reject the event and pass it to the widget behind this one. | |||
*/ | |||
virtual Widget *onMouseDown(Vec pos, int button); | |||
virtual Widget *onMouseUp(Vec pos, int button); | |||
virtual void onMouseDown(EventMouseDown &e); | |||
virtual void onMouseUp(EventMouseUp &e); | |||
/** Called on every frame, even if mouseRel = Vec(0, 0) */ | |||
virtual Widget *onMouseMove(Vec pos, Vec mouseRel); | |||
virtual Widget *onHoverKey(Vec pos, int key); | |||
virtual void onMouseMove(EventMouseMove &e); | |||
virtual void onHoverKey(EventHoverKey &e); | |||
/** Called when this widget begins responding to `onMouseMove` events */ | |||
virtual void onMouseEnter() {} | |||
virtual void onMouseEnter(EventMouseEnter &e) {} | |||
/** Called when another widget begins responding to `onMouseMove` events */ | |||
virtual void onMouseLeave() {} | |||
virtual bool onFocus() {return false;} | |||
virtual void onDefocus() {} | |||
virtual bool onFocusText(int codepoint) {return false;} | |||
virtual bool onFocusKey(int key) {return false;} | |||
virtual Widget *onScroll(Vec pos, Vec scrollRel); | |||
virtual void onMouseLeave(EventMouseLeave &e) {} | |||
virtual void onFocus(EventFocus &e) {} | |||
virtual void onDefocus(EventDefocus &e) {} | |||
virtual void onText(EventText &e) {} | |||
virtual void onKey(EventKey &e) {} | |||
virtual void onScroll(EventScroll &e); | |||
/** Called when a widget responds to `onMouseDown` for a left button press */ | |||
virtual void onDragStart() {} | |||
virtual void onDragStart(EventDragStart &e) {} | |||
/** Called when the left button is released and this widget is being dragged */ | |||
virtual void onDragEnd() {} | |||
virtual void onDragEnd(EventDragEnd &e) {} | |||
/** Called when a widget responds to `onMouseMove` and is being dragged */ | |||
virtual void onDragMove(Vec mouseRel) {} | |||
virtual void onDragMove(EventDragMove &e) {} | |||
/** Called when a widget responds to `onMouseUp` for a left button release and a widget is being dragged */ | |||
virtual void onDragEnter(Widget *origin) {} | |||
virtual void onDragLeave(Widget *origin) {} | |||
virtual void onDragDrop(Widget *origin) {} | |||
virtual 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 { | |||
@@ -170,11 +172,11 @@ struct ZoomWidget : Widget { | |||
Rect getViewport(Rect r) override; | |||
void setZoom(float zoom); | |||
void draw(NVGcontext *vg) override; | |||
Widget *onMouseDown(Vec pos, int button) override; | |||
Widget *onMouseUp(Vec pos, int button) override; | |||
Widget *onMouseMove(Vec pos, Vec mouseRel) override; | |||
Widget *onHoverKey(Vec pos, int key) override; | |||
Widget *onScroll(Vec pos, Vec scrollRel) override; | |||
void onMouseDown(EventMouseDown &e) override; | |||
void onMouseUp(EventMouseUp &e) override; | |||
void onMouseMove(EventMouseMove &e) override; | |||
void onHoverKey(EventHoverKey &e) override; | |||
void onScroll(EventScroll &e) override; | |||
}; | |||
//////////////////// | |||
@@ -183,47 +185,36 @@ struct ZoomWidget : Widget { | |||
/** Widget that does not respond to events */ | |||
struct TransparentWidget : virtual Widget { | |||
Widget *onMouseDown(Vec pos, int button) override {return NULL;} | |||
Widget *onMouseUp(Vec pos, int button) override {return NULL;} | |||
Widget *onMouseMove(Vec pos, Vec mouseRel) override {return NULL;} | |||
Widget *onScroll(Vec pos, Vec scrollRel) override {return NULL;} | |||
void onMouseDown(EventMouseDown &e) override {} | |||
void onMouseUp(EventMouseUp &e) override {} | |||
void onMouseMove(EventMouseMove &e) override {} | |||
void onScroll(EventScroll &e) override {} | |||
}; | |||
/** Widget that automatically responds to all mouse events but gives a chance for children to respond instead */ | |||
struct OpaqueWidget : virtual Widget { | |||
Widget *onMouseDown(Vec pos, int button) override { | |||
Widget *w = Widget::onMouseDown(pos, button); | |||
if (w) return w; | |||
onMouseDownOpaque(button); | |||
return this; | |||
void onMouseDown(EventMouseDown &e) override { | |||
Widget::onMouseDown(e); | |||
if (!e.target) | |||
e.target = this; | |||
e.consumed = true; | |||
} | |||
Widget *onMouseUp(Vec pos, int button) override { | |||
Widget *w = Widget::onMouseUp(pos, button); | |||
if (w) return w; | |||
onMouseUpOpaque(button); | |||
return this; | |||
void onMouseUp(EventMouseUp &e) override { | |||
Widget::onMouseUp(e); | |||
if (!e.target) | |||
e.target = this; | |||
e.consumed = true; | |||
} | |||
Widget *onMouseMove(Vec pos, Vec mouseRel) override { | |||
Widget *w = Widget::onMouseMove(pos, mouseRel); | |||
if (w) return w; | |||
onMouseMoveOpaque(mouseRel); | |||
return this; | |||
void onMouseMove(EventMouseMove &e) override { | |||
Widget::onMouseMove(e); | |||
if (!e.target) | |||
e.target = this; | |||
e.consumed = true; | |||
} | |||
Widget *onScroll(Vec pos, Vec scrollRel) override { | |||
Widget *w = Widget::onScroll(pos, scrollRel); | |||
if (w) return w; | |||
if (onScrollOpaque(scrollRel)) | |||
return this; | |||
return NULL; | |||
void onScroll(EventScroll &e) override { | |||
Widget::onScroll(e); | |||
e.consumed = true; | |||
} | |||
/** "High level" events called by the above lower level events. | |||
Use these if you don't care about the clicked position. | |||
*/ | |||
virtual void onMouseDownOpaque(int button) {} | |||
virtual void onMouseUpOpaque(int button) {} | |||
virtual void onMouseMoveOpaque(Vec mouseRel) {} | |||
virtual bool onScrollOpaque(Vec scrollRel) {return false;} | |||
}; | |||
struct SpriteWidget : virtual Widget { | |||
@@ -264,7 +255,7 @@ struct FramebufferWidget : virtual Widget { | |||
~FramebufferWidget(); | |||
void draw(NVGcontext *vg) override; | |||
int getImageHandle(); | |||
void onZoom() override; | |||
void onZoom(EventZoom &e) override; | |||
}; | |||
struct QuantityWidget : virtual Widget { | |||
@@ -302,9 +293,9 @@ struct Label : Widget { | |||
// Deletes itself from parent when clicked | |||
struct MenuOverlay : OpaqueWidget { | |||
void onDragDrop(Widget *origin) override; | |||
bool onScrollOpaque(Vec scrollRel) override {return true;} | |||
Widget *onHoverKey(Vec pos, int key) override; | |||
void onDragDrop(EventDragDrop &e) override; | |||
void onScroll(EventScroll &e) override; | |||
void onHoverKey(EventHoverKey &e) override; | |||
}; | |||
struct MenuEntry; | |||
@@ -324,7 +315,7 @@ struct Menu : OpaqueWidget { | |||
void setChildMenu(Menu *menu); | |||
void step() override; | |||
void draw(NVGcontext *vg) override; | |||
bool onScrollOpaque(Vec scrollRel) override; | |||
void onScroll(EventScroll &e) override; | |||
}; | |||
struct MenuEntry : OpaqueWidget { | |||
@@ -343,8 +334,8 @@ struct MenuLabel : MenuEntry { | |||
struct MenuItem : MenuEntry { | |||
void draw(NVGcontext *vg) override; | |||
virtual Menu *createChildMenu() {return NULL;} | |||
void onMouseEnter() override; | |||
void onDragDrop(Widget *origin) override; | |||
void onMouseEnter(EventMouseEnter &e) override; | |||
void onDragDrop(EventDragDrop &e) override; | |||
}; | |||
struct Button : OpaqueWidget { | |||
@@ -355,11 +346,11 @@ struct Button : OpaqueWidget { | |||
box.size.y = BND_WIDGET_HEIGHT; | |||
} | |||
void draw(NVGcontext *vg) override; | |||
void onMouseEnter() override; | |||
void onMouseLeave() override; | |||
void onDragStart() override; | |||
void onDragEnd() override; | |||
void onDragDrop(Widget *origin) override; | |||
void onMouseEnter(EventMouseEnter &e) override; | |||
void onMouseLeave(EventMouseLeave &e) override; | |||
void onDragStart(EventDragStart &e) override; | |||
void onDragEnd(EventDragEnd &e) override; | |||
void onDragDrop(EventDragDrop &e) override; | |||
}; | |||
struct ChoiceButton : Button { | |||
@@ -373,9 +364,9 @@ struct RadioButton : OpaqueWidget, QuantityWidget { | |||
box.size.y = BND_WIDGET_HEIGHT; | |||
} | |||
void draw(NVGcontext *vg) override; | |||
void onMouseEnter() override; | |||
void onMouseLeave() override; | |||
void onDragDrop(Widget *origin) override; | |||
void onMouseEnter(EventMouseEnter &e) override; | |||
void onMouseLeave(EventMouseLeave &e) override; | |||
void onDragDrop(EventDragDrop &e) override; | |||
}; | |||
struct Slider : OpaqueWidget, QuantityWidget { | |||
@@ -385,10 +376,10 @@ struct Slider : OpaqueWidget, QuantityWidget { | |||
box.size.y = BND_WIDGET_HEIGHT; | |||
} | |||
void draw(NVGcontext *vg) override; | |||
void onDragStart() override; | |||
void onDragMove(Vec mouseRel) override; | |||
void onDragEnd() override; | |||
void onMouseDownOpaque(int button) override; | |||
void onDragStart(EventDragStart &e) override; | |||
void onDragMove(EventDragMove &e) override; | |||
void onDragEnd(EventDragEnd &e) override; | |||
void onMouseDown(EventMouseDown &e) override; | |||
}; | |||
/** Parent must be a ScrollWidget */ | |||
@@ -400,9 +391,9 @@ struct ScrollBar : OpaqueWidget { | |||
box.size = Vec(BND_SCROLLBAR_WIDTH, BND_SCROLLBAR_HEIGHT); | |||
} | |||
void draw(NVGcontext *vg) override; | |||
void onDragStart() override; | |||
void onDragMove(Vec mouseRel) override; | |||
void onDragEnd() override; | |||
void onDragStart(EventDragStart &e) override; | |||
void onDragMove(EventDragMove &e) override; | |||
void onDragEnd(EventDragEnd &e) override; | |||
}; | |||
/** Handles a container with ScrollBar */ | |||
@@ -414,7 +405,7 @@ struct ScrollWidget : OpaqueWidget { | |||
ScrollWidget(); | |||
void step() override; | |||
bool onScrollOpaque(Vec scrollRel) override; | |||
void onScroll(EventScroll &e) override; | |||
}; | |||
struct TextField : OpaqueWidget { | |||
@@ -428,10 +419,10 @@ struct TextField : OpaqueWidget { | |||
box.size.y = BND_WIDGET_HEIGHT; | |||
} | |||
void draw(NVGcontext *vg) override; | |||
Widget *onMouseDown(Vec pos, int button) override; | |||
bool onFocusText(int codepoint) override; | |||
bool onFocusKey(int key) override; | |||
bool onFocus() override; | |||
void onMouseDown(EventMouseDown &e) override; | |||
void onFocus(EventFocus &e) override; | |||
void onText(EventText &e) override; | |||
void onKey(EventKey &e) override; | |||
void insertText(std::string newText); | |||
virtual void onTextChange() {} | |||
}; | |||
@@ -0,0 +1,88 @@ | |||
!include "MUI2.nsh" | |||
Name "VCV Rack" | |||
OutFile "Rack-setup.exe" | |||
SetCompressor "bzip2" | |||
CRCCheck On | |||
;Default installation folder | |||
InstallDir "$PROGRAMFILES\VCV" | |||
;Get installation folder from registry if available | |||
InstallDirRegKey HKCU "Software\VCV Rack" "" | |||
;Request application privileges for Windows Vista | |||
RequestExecutionLevel admin | |||
!define MUI_ICON "icon.ico" | |||
!define MUI_HEADERIMAGE | |||
!define MUI_HEADERIMAGE_BITMAP "installer-banner.bmp" ; 150x57 | |||
; !define MUI_WELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\win.bmp" ; 164x314 | |||
; !define MUI_UNWELCOMEFINISHPAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Wizard\win.bmp" ; 164x314 | |||
!define MUI_COMPONENTSPAGE_NODESC | |||
; Pages | |||
; !insertmacro MUI_PAGE_WELCOME | |||
!insertmacro MUI_PAGE_COMPONENTS | |||
!insertmacro MUI_PAGE_DIRECTORY | |||
;second directory selection | |||
; Var DbInstDir | |||
; !define MUI_PAGE_HEADER_SUBTEXT "Choose the folder in which to install the database." | |||
; !define MUI_DIRECTORYPAGE_TEXT_TOP "The installer will install the database(s) in the following folder. To install in a differenct folder, click Browse and select another folder. Click Next to continue." | |||
; !define MUI_DIRECTORYPAGE_VARIABLE $DbInstDir ; <= the other directory will be stored into that variable | |||
; !insertmacro MUI_PAGE_DIRECTORY | |||
!insertmacro MUI_PAGE_INSTFILES | |||
!insertmacro MUI_UNPAGE_CONFIRM | |||
!insertmacro MUI_UNPAGE_INSTFILES | |||
!insertmacro MUI_LANGUAGE "English" | |||
Section "!VCV Rack" VCVRACK | |||
SetOutPath "$INSTDIR" | |||
File /r "dist\Rack" | |||
;Store installation folder | |||
WriteRegStr HKCU "Software\VCV Rack" "" $INSTDIR | |||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VCV Rack" "DisplayName" "VCV Rack" | |||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VCV Rack" "UninstallString" "$\"$INSTDIR\UninstallRack.exe$\"" | |||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VCV Rack" "QuietUninstallString" "$\"$INSTDIR\UninstallRack.exe$\" /S" | |||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VCV Rack" "InstallLocation" "$\"$INSTDIR$\"" | |||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VCV Rack" "Publisher" "VCV" | |||
;Create uninstaller | |||
WriteUninstaller "$INSTDIR\UninstallRack.exe" | |||
;Create shortcuts | |||
CreateDirectory "$SMPROGRAMS" | |||
; Set working directory of shortcut | |||
SetOutPath "$INSTDIR\Rack" | |||
CreateShortcut "$SMPROGRAMS\VCV Rack.lnk" "$INSTDIR\Rack\Rack.exe" | |||
SectionEnd | |||
; Section "VST Plugin" VST | |||
; SectionEnd | |||
Section "Uninstall" | |||
RMDir /r "$INSTDIR\Rack" | |||
Delete "$INSTDIR\UninstallRack.exe" | |||
RMDir "$INSTDIR" | |||
Delete "$SMPROGRAMS\VCV Rack.lnk" | |||
DeleteRegKey /ifempty HKCU "Software\VCV Rack" | |||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VCV Rack" | |||
SectionEnd |
@@ -0,0 +1,71 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||
<!-- Created with Inkscape (http://www.inkscape.org/) --> | |||
<svg | |||
xmlns:dc="http://purl.org/dc/elements/1.1/" | |||
xmlns:cc="http://creativecommons.org/ns#" | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns:svg="http://www.w3.org/2000/svg" | |||
xmlns="http://www.w3.org/2000/svg" | |||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |||
width="7.5001564mm" | |||
height="7.5000095mm" | |||
viewBox="0 0 7.5001564 7.5000095" | |||
version="1.1" | |||
id="svg64581" | |||
inkscape:version="0.92.2 5c3e80d, 2017-08-06" | |||
sodipodi:docname="LEDBezel.svg"> | |||
<defs | |||
id="defs64575" /> | |||
<sodipodi:namedview | |||
id="base" | |||
pagecolor="#ffffff" | |||
bordercolor="#666666" | |||
borderopacity="1.0" | |||
inkscape:pageopacity="0.0" | |||
inkscape:pageshadow="2" | |||
inkscape:zoom="1.979899" | |||
inkscape:cx="-100.74496" | |||
inkscape:cy="9.8683694" | |||
inkscape:document-units="mm" | |||
inkscape:current-layer="layer1" | |||
showgrid="false" | |||
fit-margin-top="0" | |||
fit-margin-left="0" | |||
fit-margin-right="0" | |||
fit-margin-bottom="0" | |||
inkscape:window-width="2560" | |||
inkscape:window-height="1422" | |||
inkscape:window-x="0" | |||
inkscape:window-y="18" | |||
inkscape:window-maximized="0" /> | |||
<metadata | |||
id="metadata64578"> | |||
<rdf:RDF> | |||
<cc:Work | |||
rdf:about=""> | |||
<dc:format>image/svg+xml</dc:format> | |||
<dc:type | |||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | |||
<dc:title></dc:title> | |||
</cc:Work> | |||
</rdf:RDF> | |||
</metadata> | |||
<g | |||
inkscape:label="Layer 1" | |||
inkscape:groupmode="layer" | |||
id="layer1" | |||
transform="translate(-94.523732,-120.89285)"> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path9729" | |||
d="m 94.750061,123.36034 c -0.706931,1.94578 0.297674,4.09829 2.240704,4.8066 1.947157,0.70556 4.098285,-0.29626 4.805225,-2.24208 0.70968,-1.94578 -0.29355,-4.09688 -2.239332,-4.80522 -1.945781,-0.70693 -4.096914,0.29355 -4.806597,2.2407" | |||
style="fill:#2b2b2b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
<path | |||
inkscape:connector-curvature="0" | |||
id="path64013" | |||
d="m 99.30033,121.82382 c -1.557161,-0.56497 -3.279704,0.23703 -3.846089,1.79285 -0.565009,1.55716 0.237031,3.27833 1.794192,3.84334 1.557197,0.56776 3.276987,-0.23428 3.844747,-1.79144 0.56498,-1.55582 -0.23565,-3.27837 -1.79285,-3.84475" | |||
style="clip-rule:nonzero;fill:#5a5a5a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.35277775" /> | |||
</g> | |||
</svg> |
@@ -10,29 +10,30 @@ namespace rack { | |||
#define KNOB_SENSITIVITY 0.0015 | |||
void Knob::onDragStart() { | |||
void Knob::onDragStart(EventDragStart &e) { | |||
guiCursorLock(); | |||
dragValue = value; | |||
randomizable = false; | |||
} | |||
void Knob::onDragMove(Vec mouseRel) { | |||
void Knob::onDragMove(EventDragMove &e) { | |||
// Drag slower if Mod | |||
float delta = KNOB_SENSITIVITY * (maxValue - minValue) * -e.mouseRel.y; | |||
if (guiIsModPressed()) | |||
mouseRel = mouseRel.mult(1/16.0); | |||
dragValue += KNOB_SENSITIVITY * (maxValue - minValue) * -mouseRel.y; | |||
delta /= 16.0; | |||
dragValue += delta; | |||
if (snap) | |||
setValue(roundf(dragValue)); | |||
else | |||
setValue(dragValue); | |||
} | |||
void Knob::onDragEnd() { | |||
void Knob::onDragEnd(EventDragEnd &e) { | |||
guiCursorUnlock(); | |||
randomizable = true; | |||
} | |||
void Knob::onChange() { | |||
void Knob::onChange(EventChange &e) { | |||
if (!module) | |||
return; | |||
@@ -6,7 +6,7 @@ namespace rack { | |||
void LightWidget::draw(NVGcontext *vg) { | |||
float radius = box.size.x / 2.0; | |||
float oradius = radius + 20.0; | |||
float oradius = radius + 15.0; | |||
color.r = clampf(color.r, 0.0, 1.0); | |||
color.g = clampf(color.g, 0.0, 1.0); | |||
@@ -36,7 +36,7 @@ void LightWidget::draw(NVGcontext *vg) { | |||
nvgRect(vg, radius - oradius, radius - oradius, 2*oradius, 2*oradius); | |||
NVGpaint paint; | |||
NVGcolor icol = color; | |||
icol.a *= 0.15; | |||
icol.a *= 0.10; | |||
NVGcolor ocol = color; | |||
ocol.a = 0.0; | |||
paint = nvgRadialGradient(vg, radius, radius, radius, oradius, icol, ocol); | |||
@@ -165,7 +165,22 @@ void ModuleWidget::draw(NVGcontext *vg) { | |||
nvgResetScissor(vg); | |||
} | |||
Widget *ModuleWidget::onMouseMove(Vec pos, Vec mouseRel) { | |||
void ModuleWidget::onMouseDown(EventMouseDown &e) { | |||
Widget::onMouseDown(e); | |||
if (e.consumed) | |||
return; | |||
if (e.button == 1) { | |||
createContextMenu(); | |||
} | |||
e.consumed = true; | |||
e.target = this; | |||
} | |||
void ModuleWidget::onMouseMove(EventMouseMove &e) { | |||
OpaqueWidget::onMouseMove(e); | |||
// Don't delete the ModuleWidget if a TextField is focused | |||
if (!gFocusedWidget) { | |||
// Instead of checking key-down events, delete the module even if key-repeat hasn't fired yet and the cursor is hovering over the widget. | |||
if (glfwGetKey(gWindow, GLFW_KEY_DELETE) == GLFW_PRESS || glfwGetKey(gWindow, GLFW_KEY_BACKSPACE) == GLFW_PRESS) { | |||
@@ -174,82 +189,85 @@ Widget *ModuleWidget::onMouseMove(Vec pos, Vec mouseRel) { | |||
this->finalizeEvents(); | |||
delete this; | |||
// Kinda sketchy because events will be passed further down the tree | |||
return NULL; | |||
return; | |||
} | |||
} | |||
} | |||
return OpaqueWidget::onMouseMove(pos, mouseRel); | |||
} | |||
Widget *ModuleWidget::onHoverKey(Vec pos, int key) { | |||
switch (key) { | |||
void ModuleWidget::onHoverKey(EventHoverKey &e) { | |||
switch (e.key) { | |||
case GLFW_KEY_I: | |||
if (guiIsModPressed() && !guiIsShiftPressed()) { | |||
reset(); | |||
return this; | |||
e.consumed = true; | |||
return; | |||
} | |||
break; | |||
case GLFW_KEY_R: | |||
if (guiIsModPressed() && !guiIsShiftPressed()) { | |||
randomize(); | |||
return this; | |||
e.consumed = true; | |||
return; | |||
} | |||
break; | |||
case GLFW_KEY_D: | |||
if (guiIsModPressed() && !guiIsShiftPressed()) { | |||
gRackWidget->cloneModule(this); | |||
return this; | |||
e.consumed = true; | |||
return; | |||
} | |||
break; | |||
} | |||
return Widget::onHoverKey(pos, key); | |||
Widget::onHoverKey(e); | |||
} | |||
void ModuleWidget::onDragStart() { | |||
void ModuleWidget::onDragStart(EventDragStart &e) { | |||
dragPos = gRackWidget->lastMousePos.minus(box.pos); | |||
} | |||
void ModuleWidget::onDragMove(Vec mouseRel) { | |||
void ModuleWidget::onDragEnd(EventDragEnd &e) { | |||
} | |||
void ModuleWidget::onDragMove(EventDragMove &e) { | |||
Rect newBox = box; | |||
newBox.pos = gRackWidget->lastMousePos.minus(dragPos); | |||
gRackWidget->requestModuleBoxNearest(this, newBox); | |||
} | |||
void ModuleWidget::onDragEnd() { | |||
} | |||
struct DisconnectMenuItem : MenuItem { | |||
ModuleWidget *moduleWidget; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
moduleWidget->disconnect(); | |||
} | |||
}; | |||
struct ResetMenuItem : MenuItem { | |||
ModuleWidget *moduleWidget; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
moduleWidget->reset(); | |||
} | |||
}; | |||
struct RandomizeMenuItem : MenuItem { | |||
ModuleWidget *moduleWidget; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
moduleWidget->randomize(); | |||
} | |||
}; | |||
struct CloneMenuItem : MenuItem { | |||
ModuleWidget *moduleWidget; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
gRackWidget->cloneModule(moduleWidget); | |||
} | |||
}; | |||
struct DeleteMenuItem : MenuItem { | |||
ModuleWidget *moduleWidget; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
gRackWidget->deleteModule(moduleWidget); | |||
moduleWidget->finalizeEvents(); | |||
delete moduleWidget; | |||
@@ -295,11 +313,5 @@ Menu *ModuleWidget::createContextMenu() { | |||
return menu; | |||
} | |||
void ModuleWidget::onMouseDownOpaque(int button) { | |||
if (button == 1) { | |||
createContextMenu(); | |||
} | |||
} | |||
} // namespace rack |
@@ -19,13 +19,15 @@ void ParamWidget::randomize() { | |||
setValue(rescalef(randomf(), 0.0, 1.0, minValue, maxValue)); | |||
} | |||
void ParamWidget::onMouseDownOpaque(int button) { | |||
if (button == 1) { | |||
void ParamWidget::onMouseDown(EventMouseDown &e) { | |||
if (e.button == 1) { | |||
setValue(defaultValue); | |||
} | |||
e.consumed = true; | |||
e.target = this; | |||
} | |||
void ParamWidget::onChange() { | |||
void ParamWidget::onChange(EventChange &e) { | |||
if (!module) | |||
return; | |||
@@ -15,7 +15,7 @@ PluginManagerWidget::PluginManagerWidget() { | |||
Vec pos = Vec(0, 0); | |||
struct RegisterButton : Button { | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
std::thread t(openBrowser, "https://vcvrack.com/"); | |||
t.detach(); | |||
} | |||
@@ -46,7 +46,7 @@ PluginManagerWidget::PluginManagerWidget() { | |||
struct LogInButton : Button { | |||
TextField *emailField; | |||
TextField *passwordField; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
std::thread t(pluginLogIn, emailField->text, passwordField->text); | |||
t.detach(); | |||
passwordField->text = ""; | |||
@@ -79,7 +79,7 @@ PluginManagerWidget::PluginManagerWidget() { | |||
Vec pos = Vec(0, 0); | |||
struct ManageButton : Button { | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
std::thread t(openBrowser, "https://vcvrack.com/"); | |||
t.detach(); | |||
} | |||
@@ -92,7 +92,7 @@ PluginManagerWidget::PluginManagerWidget() { | |||
pos.x += manageButton->box.size.x; | |||
struct RefreshButton : Button { | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
std::thread t(pluginRefresh); | |||
t.detach(); | |||
} | |||
@@ -106,7 +106,7 @@ PluginManagerWidget::PluginManagerWidget() { | |||
pos.x += refreshButton->box.size.x; | |||
struct LogOutButton : Button { | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
pluginLogOut(); | |||
} | |||
}; | |||
@@ -142,7 +142,7 @@ PluginManagerWidget::PluginManagerWidget() { | |||
pos.x += downloadProgress->box.size.x; | |||
// struct CancelButton : Button { | |||
// void onAction() override { | |||
// void onAction(EventAction &e) override { | |||
// pluginCancelDownload(); | |||
// } | |||
// }; | |||
@@ -17,23 +17,20 @@ void Port::draw(NVGcontext *vg) { | |||
} | |||
} | |||
void Port::onMouseDownOpaque(int button) { | |||
if (button == 1) { | |||
void Port::onMouseDown(EventMouseDown &e) { | |||
if (e.button == 1) { | |||
gRackWidget->wireContainer->removeTopWire(this); | |||
// HACK | |||
// Update hovered*Port of active wire if applicable | |||
onDragEnter(NULL); | |||
EventDragEnter e; | |||
onDragEnter(e); | |||
} | |||
e.consumed = true; | |||
e.target = this; | |||
} | |||
void Port::onDragEnd() { | |||
// FIXME | |||
// If the source Port is deleted, this will be called, removing the cable | |||
gRackWidget->wireContainer->commitActiveWire(); | |||
} | |||
void Port::onDragStart() { | |||
void Port::onDragStart(EventDragStart &e) { | |||
// Try to grab wire on top of stack | |||
WireWidget *wire = gRackWidget->wireContainer->getTopWire(this); | |||
if (guiIsModPressed()) { | |||
@@ -62,10 +59,16 @@ void Port::onDragStart() { | |||
gRackWidget->wireContainer->setActiveWire(wire); | |||
} | |||
void Port::onDragDrop(Widget *origin) { | |||
void Port::onDragEnd(EventDragEnd &e) { | |||
// FIXME | |||
// If the source Port is deleted, this will be called, removing the cable | |||
gRackWidget->wireContainer->commitActiveWire(); | |||
} | |||
void Port::onDragDrop(EventDragDrop &e) { | |||
} | |||
void Port::onDragEnter(Widget *origin) { | |||
void Port::onDragEnter(EventDragEnter &e) { | |||
// Reject ports if this is an input port and something is already plugged into it | |||
if (type == INPUT) { | |||
WireWidget *topWire = gRackWidget->wireContainer->getTopWire(this); | |||
@@ -82,7 +85,7 @@ void Port::onDragEnter(Widget *origin) { | |||
} | |||
} | |||
void Port::onDragLeave(Widget *origin) { | |||
void Port::onDragLeave(EventDragEnter &e) { | |||
WireWidget *activeWire = gRackWidget->wireContainer->activeWire; | |||
if (activeWire) { | |||
if (type == INPUT) | |||
@@ -82,39 +82,55 @@ void RackScene::draw(NVGcontext *vg) { | |||
Scene::draw(vg); | |||
} | |||
Widget *RackScene::onHoverKey(Vec pos, int key) { | |||
switch (key) { | |||
void RackScene::onHoverKey(EventHoverKey &e) { | |||
switch (e.key) { | |||
case GLFW_KEY_N: | |||
if (guiIsModPressed() && !guiIsShiftPressed()) { | |||
gRackWidget->reset(); | |||
return this; | |||
e.consumed = true; | |||
return; | |||
} | |||
break; | |||
case GLFW_KEY_Q: | |||
if (guiIsModPressed() && !guiIsShiftPressed()) { | |||
guiClose(); | |||
return this; | |||
e.consumed = true; | |||
return; | |||
} | |||
break; | |||
case GLFW_KEY_O: | |||
if (guiIsModPressed() && !guiIsShiftPressed()) { | |||
gRackWidget->openDialog(); | |||
return this; | |||
e.consumed = true; | |||
return; | |||
} | |||
break; | |||
case GLFW_KEY_S: | |||
if (guiIsModPressed() && !guiIsShiftPressed()) { | |||
gRackWidget->saveDialog(); | |||
return this; | |||
e.consumed = true; | |||
return; | |||
} | |||
if (guiIsModPressed() && guiIsShiftPressed()) { | |||
gRackWidget->saveAsDialog(); | |||
return this; | |||
e.consumed = true; | |||
return; | |||
} | |||
break; | |||
} | |||
return Widget::onHoverKey(pos, key); | |||
Widget::onHoverKey(e); | |||
} | |||
void RackScene::onPathDrop(EventPathDrop &e) { | |||
if (e.paths.size() >= 1) { | |||
const std::string& firstPath = e.paths.front(); | |||
if (extractExtension(firstPath) == "vcv") { | |||
gRackWidget->loadPatch(firstPath); | |||
e.consumed = true; | |||
} | |||
} | |||
} | |||
@@ -375,7 +375,7 @@ void RackWidget::draw(NVGcontext *vg) { | |||
struct AddModuleMenuItem : MenuItem { | |||
Model *model; | |||
Vec modulePos; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
ModuleWidget *moduleWidget = model->createModuleWidget(); | |||
gRackWidget->moduleContainer->addChild(moduleWidget); | |||
// Move module nearest to the mouse position | |||
@@ -388,7 +388,7 @@ struct AddModuleMenuItem : MenuItem { | |||
struct UrlItem : MenuItem { | |||
std::string url; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
std::thread t(openBrowser, url); | |||
t.detach(); | |||
} | |||
@@ -487,13 +487,17 @@ struct SearchModuleField : TextField { | |||
} | |||
}; | |||
Widget *RackWidget::onMouseMove(Vec pos, Vec mouseRel) { | |||
lastMousePos = pos; | |||
return OpaqueWidget::onMouseMove(pos, mouseRel); | |||
void RackWidget::onMouseMove(EventMouseMove &e) { | |||
OpaqueWidget::onMouseMove(e); | |||
lastMousePos = e.pos; | |||
} | |||
void RackWidget::onMouseDownOpaque(int button) { | |||
if (button == 1) { | |||
void RackWidget::onMouseDown(EventMouseDown &e) { | |||
Widget::onMouseDown(e); | |||
if (e.consumed) | |||
return; | |||
if (e.button == 1) { | |||
Menu *menu = gScene->createMenu(); | |||
menu->pushChild(construct<MenuLabel>(&MenuLabel::text, "Add module")); | |||
@@ -519,15 +523,17 @@ void RackWidget::onMouseDownOpaque(int button) { | |||
AddManufacturerMenuItem *item = new AddManufacturerMenuItem(); | |||
item->text = manufacturerName; | |||
item->manufacturerName = manufacturerName; | |||
item->modulePos = lastMousePos; | |||
item->modulePos = e.pos; | |||
menu->pushChild(item); | |||
} | |||
} | |||
e.consumed = true; | |||
e.target = this; | |||
} | |||
void RackWidget::onZoom() { | |||
void RackWidget::onZoom(EventZoom &e) { | |||
rails->box.size = Vec(); | |||
Widget::onZoom(); | |||
Widget::onZoom(e); | |||
} | |||
@@ -35,9 +35,9 @@ void SVGKnob::step() { | |||
FramebufferWidget::step(); | |||
} | |||
void SVGKnob::onChange() { | |||
void SVGKnob::onChange(EventChange &e) { | |||
dirty = true; | |||
Knob::onChange(); | |||
Knob::onChange(e); | |||
} | |||
@@ -21,9 +21,9 @@ void SVGSlider::step() { | |||
FramebufferWidget::step(); | |||
} | |||
void SVGSlider::onChange() { | |||
void SVGSlider::onChange(EventChange &e) { | |||
dirty = true; | |||
ParamWidget::onChange(); | |||
ParamWidget::onChange(e); | |||
} | |||
@@ -22,12 +22,12 @@ void SVGSwitch::step() { | |||
FramebufferWidget::step(); | |||
} | |||
void SVGSwitch::onChange() { | |||
void SVGSwitch::onChange(EventChange &e) { | |||
assert(frames.size() > 0); | |||
int index = clampi((int) roundf(value), 0, frames.size() - 1); | |||
sw->setSVG(frames[index]); | |||
dirty = true; | |||
Switch::onChange(); | |||
Switch::onChange(e); | |||
} | |||
@@ -7,37 +7,37 @@ namespace rack { | |||
struct NewItem : MenuItem { | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
gRackWidget->reset(); | |||
} | |||
}; | |||
struct OpenItem : MenuItem { | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
gRackWidget->openDialog(); | |||
} | |||
}; | |||
struct SaveItem : MenuItem { | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
gRackWidget->saveDialog(); | |||
} | |||
}; | |||
struct SaveAsItem : MenuItem { | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
gRackWidget->saveAsDialog(); | |||
} | |||
}; | |||
struct QuitItem : MenuItem { | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
guiClose(); | |||
} | |||
}; | |||
struct FileChoice : ChoiceButton { | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
Menu *menu = gScene->createMenu(); | |||
menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)); | |||
menu->box.size.x = box.size.x; | |||
@@ -54,21 +54,21 @@ struct FileChoice : ChoiceButton { | |||
struct PauseItem : MenuItem { | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
gPaused = !gPaused; | |||
} | |||
}; | |||
struct SampleRateItem : MenuItem { | |||
float sampleRate; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
engineSetSampleRate(sampleRate); | |||
gPaused = false; | |||
} | |||
}; | |||
struct SampleRateChoice : ChoiceButton { | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
Menu *menu = gScene->createMenu(); | |||
menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)); | |||
menu->box.size.x = box.size.x; | |||
@@ -149,8 +149,8 @@ Toolbar::Toolbar() { | |||
xPos += margin; | |||
{ | |||
struct ZoomSlider : Slider { | |||
void onAction() override { | |||
Slider::onAction(); | |||
void onAction(EventAction &e) override { | |||
Slider::onAction(e); | |||
gRackScene->zoomWidget->setZoom(value / 100.0); | |||
} | |||
}; | |||
@@ -9,6 +9,11 @@ | |||
#include <pwd.h> | |||
#endif | |||
#if ARCH_WIN | |||
#include <Windows.h> | |||
#include <Shlobj.h> | |||
#endif | |||
namespace rack { | |||
@@ -76,9 +81,14 @@ std::string assetLocal(std::string filename) { | |||
path += "/" + filename; | |||
#endif | |||
#if ARCH_WIN | |||
// TODO | |||
// Use ~/My Documents/Rack or something | |||
path = "./" + filename; | |||
// Get My Documents folder | |||
char buf[MAX_PATH]; | |||
HRESULT result = SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, buf); | |||
assert(result == S_OK); | |||
path = buf; | |||
path += "/Rack"; | |||
CreateDirectory(path.c_str(), NULL); | |||
path += "/" + filename; | |||
#endif | |||
#if ARCH_LIN | |||
// TODO | |||
@@ -326,14 +326,14 @@ void AudioInterface::closeDevice() { | |||
struct AudioItem : MenuItem { | |||
AudioInterface *audioInterface; | |||
int deviceId; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
audioInterface->setDeviceId(deviceId); | |||
} | |||
}; | |||
struct AudioChoice : ChoiceButton { | |||
AudioInterface *audioInterface; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
Menu *menu = gScene->createMenu(); | |||
menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | |||
menu->box.size.x = box.size.x; | |||
@@ -364,14 +364,14 @@ struct AudioChoice : ChoiceButton { | |||
struct SampleRateItem : MenuItem { | |||
AudioInterface *audioInterface; | |||
float sampleRate; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
audioInterface->setSampleRate(sampleRate); | |||
} | |||
}; | |||
struct SampleRateChoice : ChoiceButton { | |||
AudioInterface *audioInterface; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
Menu *menu = gScene->createMenu(); | |||
menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | |||
menu->box.size.x = box.size.x; | |||
@@ -395,14 +395,14 @@ struct SampleRateChoice : ChoiceButton { | |||
struct BlockSizeItem : MenuItem { | |||
AudioInterface *audioInterface; | |||
int blockSize; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
audioInterface->setBlockSize(blockSize); | |||
} | |||
}; | |||
struct BlockSizeChoice : ChoiceButton { | |||
AudioInterface *audioInterface; | |||
void onAction() override { | |||
void onAction(EventAction &e) override { | |||
Menu *menu = gScene->createMenu(); | |||
menu->box.pos = getAbsoluteOffset(Vec(0, box.size.y)).round(); | |||
menu->box.size.x = box.size.x; | |||
@@ -10,20 +10,21 @@ struct ModuleResizeHandle : Widget { | |||
ModuleResizeHandle() { | |||
box.size = Vec(RACK_GRID_WIDTH * 1, RACK_GRID_HEIGHT); | |||
} | |||
Widget *onMouseDown(Vec pos, int button) override { | |||
if (button == 0) | |||
return this; | |||
return NULL; | |||
void onMouseDown(EventMouseDown &e) override { | |||
if (e.button == 0) { | |||
e.consumed = true; | |||
e.target = this; | |||
} | |||
} | |||
void onDragStart() override { | |||
void onDragStart(EventDragStart &e) override { | |||
assert(parent); | |||
originalWidth = parent->box.size.x; | |||
totalX = 0.0; | |||
} | |||
void onDragMove(Vec mouseRel) override { | |||
void onDragMove(EventDragMove &e) override { | |||
ModuleWidget *m = dynamic_cast<ModuleWidget*>(parent); | |||
assert(m); | |||
totalX += mouseRel.x; | |||
totalX += e.mouseRel.x; | |||
float targetWidth = originalWidth; | |||
if (right) | |||
targetWidth += totalX; | |||
@@ -41,8 +41,8 @@ float Light::getBrightness() { | |||
void Light::setBrightnessSmooth(float brightness) { | |||
float v = brightness * brightness; | |||
if (v < value) { | |||
// Fade out light with lambda = 3 * framerate | |||
value += (v - value) * sampleTime * (60.0 * 3.0); | |||
// Fade out light with lambda = 2 * framerate | |||
value += (v - value) * sampleTime * (60.0 * 2.0); | |||
} | |||
else { | |||
// Immediately illuminate light | |||
@@ -54,25 +54,36 @@ void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { | |||
#endif | |||
if (action == GLFW_PRESS) { | |||
Widget *w = NULL; | |||
// onMouseDown | |||
Widget *w = gScene->onMouseDown(gMousePos, button); | |||
{ | |||
EventMouseDown e; | |||
e.pos = gMousePos; | |||
e.button = button; | |||
gScene->onMouseDown(e); | |||
w = e.target; | |||
} | |||
if (button == GLFW_MOUSE_BUTTON_LEFT) { | |||
if (w) { | |||
// onDragStart | |||
w->onDragStart(); | |||
EventDragStart e; | |||
w->onDragStart(e); | |||
} | |||
gDraggedWidget = w; | |||
if (w != gFocusedWidget) { | |||
if (gFocusedWidget) { | |||
// onDefocus | |||
w->onDefocus(); | |||
EventDefocus e; | |||
w->onDefocus(e); | |||
} | |||
gFocusedWidget = NULL; | |||
if (w) { | |||
// onFocus | |||
if (w->onFocus()) { | |||
EventFocus e; | |||
w->onFocus(e); | |||
if (e.consumed) { | |||
gFocusedWidget = w; | |||
} | |||
} | |||
@@ -81,17 +92,27 @@ void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { | |||
} | |||
else if (action == GLFW_RELEASE) { | |||
// onMouseUp | |||
Widget *w = gScene->onMouseUp(gMousePos, button); | |||
Widget *w = NULL; | |||
{ | |||
EventMouseUp e; | |||
e.pos = gMousePos; | |||
e.button = button; | |||
gScene->onMouseUp(e); | |||
w = e.target; | |||
} | |||
if (button == GLFW_MOUSE_BUTTON_LEFT) { | |||
if (gDraggedWidget) { | |||
// onDragDrop | |||
w->onDragDrop(gDraggedWidget); | |||
EventDragDrop e; | |||
e.origin = gDraggedWidget; | |||
w->onDragDrop(e); | |||
} | |||
// gDraggedWidget might have been set to null in the last event, recheck here | |||
if (gDraggedWidget) { | |||
// onDragEnd | |||
gDraggedWidget->onDragEnd(); | |||
EventDragEnd e; | |||
gDraggedWidget->onDragEnd(e); | |||
} | |||
gDraggedWidget = NULL; | |||
gDragHoveredWidget = NULL; | |||
@@ -141,19 +162,32 @@ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { | |||
gMousePos = mousePos; | |||
Widget *hovered = NULL; | |||
// onMouseMove | |||
Widget *hovered = gScene->onMouseMove(gMousePos, mouseRel); | |||
{ | |||
EventMouseMove e; | |||
e.pos = mousePos; | |||
e.mouseRel = mouseRel; | |||
gScene->onMouseMove(e); | |||
hovered = e.target; | |||
} | |||
if (gDraggedWidget) { | |||
// onDragMove | |||
gDraggedWidget->onDragMove(mouseRel); | |||
EventDragMove e; | |||
e.mouseRel = mouseRel; | |||
gDraggedWidget->onDragMove(e); | |||
if (hovered != gDragHoveredWidget) { | |||
if (gDragHoveredWidget) { | |||
gDragHoveredWidget->onDragLeave(gDraggedWidget); | |||
EventDragEnter e; | |||
e.origin = gDraggedWidget; | |||
gDragHoveredWidget->onDragLeave(e); | |||
} | |||
if (hovered) { | |||
hovered->onDragEnter(gDraggedWidget); | |||
EventDragEnter e; | |||
e.origin = gDraggedWidget; | |||
hovered->onDragEnter(e); | |||
} | |||
gDragHoveredWidget = hovered; | |||
} | |||
@@ -162,11 +196,13 @@ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { | |||
if (hovered != gHoveredWidget) { | |||
if (gHoveredWidget) { | |||
// onMouseLeave | |||
gHoveredWidget->onMouseLeave(); | |||
EventMouseLeave e; | |||
gHoveredWidget->onMouseLeave(e); | |||
} | |||
if (hovered) { | |||
// onMouseEnter | |||
hovered->onMouseEnter(); | |||
// onMouseEnter | |||
EventMouseEnter e; | |||
hovered->onMouseEnter(e); | |||
} | |||
gHoveredWidget = hovered; | |||
} | |||
@@ -174,14 +210,19 @@ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { | |||
if (glfwGetMouseButton(gWindow, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS) { | |||
// TODO | |||
// Define a new global called gScrollWidget, which remembers the widget where middle-click was first pressed | |||
gScene->onScroll(mousePos, mouseRel); | |||
EventScroll e; | |||
e.pos = mousePos; | |||
e.scrollRel = mouseRel; | |||
gScene->onScroll(e); | |||
} | |||
} | |||
void cursorEnterCallback(GLFWwindow* window, int entered) { | |||
if (!entered) { | |||
if (gHoveredWidget) { | |||
gHoveredWidget->onMouseLeave(); | |||
// onMouseLeave | |||
EventMouseLeave e; | |||
gHoveredWidget->onMouseLeave(e); | |||
} | |||
gHoveredWidget = NULL; | |||
} | |||
@@ -194,23 +235,47 @@ void scrollCallback(GLFWwindow *window, double x, double y) { | |||
scrollRel = Vec(y, x); | |||
#endif | |||
// onScroll | |||
gScene->onScroll(gMousePos, scrollRel.mult(50.0)); | |||
EventScroll e; | |||
e.pos = gMousePos; | |||
e.scrollRel = scrollRel.mult(50.0); | |||
gScene->onScroll(e); | |||
} | |||
void charCallback(GLFWwindow *window, unsigned int codepoint) { | |||
if (gFocusedWidget) { | |||
gFocusedWidget->onFocusText(codepoint); | |||
// onText | |||
EventText e; | |||
e.codepoint = codepoint; | |||
gFocusedWidget->onText(e); | |||
} | |||
} | |||
void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { | |||
void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) { | |||
if (action == GLFW_PRESS || action == GLFW_REPEAT) { | |||
// onFocusKey | |||
if (gFocusedWidget && gFocusedWidget->onFocusKey(key)) | |||
return; | |||
if (gFocusedWidget) { | |||
// onKey | |||
EventKey e; | |||
e.key = key; | |||
gFocusedWidget->onKey(e); | |||
if (e.consumed) | |||
return; | |||
} | |||
// onHoverKey | |||
gScene->onHoverKey(gMousePos, key); | |||
EventHoverKey e; | |||
e.pos = gMousePos; | |||
e.key = key; | |||
gScene->onHoverKey(e); | |||
} | |||
} | |||
void dropCallback(GLFWwindow *window, int count, const char **paths) { | |||
// 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) { | |||
@@ -272,6 +337,7 @@ void guiInit() { | |||
glfwSetScrollCallback(gWindow, scrollCallback); | |||
glfwSetCharCallback(gWindow, charCallback); | |||
glfwSetKeyCallback(gWindow, keyCallback); | |||
glfwSetDropCallback(gWindow, dropCallback); | |||
// Set up GLEW | |||
glewExperimental = GL_TRUE; | |||
@@ -10,9 +10,15 @@ | |||
using namespace rack; | |||
int main(int argc, char* argv[]) { | |||
char *cwd = getcwd(NULL, 0); | |||
printf("Current working directory is %s\n", cwd); | |||
free(cwd); | |||
{ | |||
char *cwd = getcwd(NULL, 0); | |||
printf("Current working directory: %s\n", cwd); | |||
free(cwd); | |||
std::string globalDir = assetGlobal(""); | |||
std::string localDir = assetLocal(""); | |||
printf("Global directory: %s\n", globalDir.c_str()); | |||
printf("Local directory: %s\n", localDir.c_str()); | |||
} | |||
pluginInit(); | |||
engineInit(); | |||
@@ -7,25 +7,26 @@ void Button::draw(NVGcontext *vg) { | |||
bndToolButton(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, -1, text.c_str()); | |||
} | |||
void Button::onMouseEnter() { | |||
void Button::onMouseEnter(EventMouseEnter &e) { | |||
state = BND_HOVER; | |||
} | |||
void Button::onMouseLeave() { | |||
void Button::onMouseLeave(EventMouseLeave &e) { | |||
state = BND_DEFAULT; | |||
} | |||
void Button::onDragStart() { | |||
void Button::onDragStart(EventDragStart &e) { | |||
state = BND_ACTIVE; | |||
} | |||
void Button::onDragEnd() { | |||
void Button::onDragEnd(EventDragEnd &e) { | |||
state = BND_HOVER; | |||
} | |||
void Button::onDragDrop(Widget *origin) { | |||
if (origin == this) { | |||
onAction(); | |||
void Button::onDragDrop(EventDragDrop &e) { | |||
if (e.origin == this) { | |||
EventAction eAction; | |||
onAction(eAction); | |||
} | |||
} | |||
@@ -117,7 +117,7 @@ int FramebufferWidget::getImageHandle() { | |||
return internal->fb->image; | |||
} | |||
void FramebufferWidget::onZoom() { | |||
void FramebufferWidget::onZoom(EventZoom &e) { | |||
dirty = true; | |||
} | |||
@@ -52,12 +52,12 @@ void Menu::draw(NVGcontext *vg) { | |||
} | |||
bool Menu::onScrollOpaque(Vec scrollRel) { | |||
void Menu::onScroll(EventScroll &e) { | |||
if (!parent) | |||
return true; | |||
return; | |||
if (!parent->box.contains(box)) | |||
box.pos = box.pos.plus(scrollRel); | |||
return true; | |||
box.pos = box.pos.plus(e.scrollRel); | |||
e.consumed = true; | |||
} | |||
@@ -22,7 +22,7 @@ void MenuItem::draw(NVGcontext *vg) { | |||
bndIconLabelValue(vg, x, 0.0, box.size.x, box.size.y, -1, rightColor, BND_LEFT, BND_LABEL_FONT_SIZE, rightText.c_str(), NULL); | |||
} | |||
void MenuItem::onMouseEnter() { | |||
void MenuItem::onMouseEnter(EventMouseEnter &e) { | |||
Menu *parentMenu = dynamic_cast<Menu*>(parent); | |||
if (!parentMenu) | |||
return; | |||
@@ -38,11 +38,12 @@ void MenuItem::onMouseEnter() { | |||
parentMenu->setChildMenu(childMenu); | |||
} | |||
void MenuItem::onDragDrop(Widget *origin) { | |||
if (origin != this) | |||
void MenuItem::onDragDrop(EventDragDrop &e) { | |||
if (e.origin != this) | |||
return; | |||
onAction(); | |||
EventAction eAction; | |||
onAction(eAction); | |||
// deletes `this` | |||
gScene->setOverlay(NULL); | |||
} | |||
@@ -3,18 +3,22 @@ | |||
namespace rack { | |||
void MenuOverlay::onDragDrop(Widget *origin) { | |||
if (origin == this) { | |||
void MenuOverlay::onDragDrop(EventDragDrop &e) { | |||
if (e.origin == this) { | |||
// deletes `this` | |||
gScene->setOverlay(NULL); | |||
} | |||
} | |||
Widget *MenuOverlay::onHoverKey(Vec pos, int key) { | |||
Widget *w = Widget::onHoverKey(pos, key); | |||
if (w) return w; | |||
// Steal all keys | |||
return this; | |||
void MenuOverlay::onScroll(EventScroll &e) { | |||
// Don't recurse children, consume the event | |||
e.consumed = true; | |||
} | |||
void MenuOverlay::onHoverKey(EventHoverKey &e) { | |||
// Recurse children but consume the event | |||
Widget::onHoverKey(e); | |||
e.consumed = true; | |||
} | |||
@@ -4,12 +4,14 @@ | |||
namespace rack { | |||
QuantityWidget::QuantityWidget() { | |||
onChange(); | |||
EventChange e; | |||
onChange(e); | |||
} | |||
void QuantityWidget::setValue(float value) { | |||
this->value = clampf(value, fminf(minValue, maxValue), fmaxf(minValue, maxValue)); | |||
onChange(); | |||
EventChange e; | |||
onChange(e); | |||
} | |||
void QuantityWidget::setLimits(float minValue, float maxValue) { | |||
@@ -7,22 +7,23 @@ void RadioButton::draw(NVGcontext *vg) { | |||
bndRadioButton(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, value == 0.0 ? state : BND_ACTIVE, -1, label.c_str()); | |||
} | |||
void RadioButton::onMouseEnter() { | |||
void RadioButton::onMouseEnter(EventMouseEnter &e) { | |||
state = BND_HOVER; | |||
} | |||
void RadioButton::onMouseLeave() { | |||
void RadioButton::onMouseLeave(EventMouseLeave &e) { | |||
state = BND_DEFAULT; | |||
} | |||
void RadioButton::onDragDrop(Widget *origin) { | |||
if (origin == this) { | |||
void RadioButton::onDragDrop(EventDragDrop &e) { | |||
if (e.origin == this) { | |||
if (value == 0.0) | |||
value = 1.0; | |||
else | |||
value = 0.0; | |||
onAction(); | |||
EventAction eAction; | |||
onAction(eAction); | |||
} | |||
} | |||
@@ -19,21 +19,21 @@ void ScrollBar::draw(NVGcontext *vg) { | |||
bndScrollBar(vg, 0.0, 0.0, box.size.x, box.size.y, state, offset, size); | |||
} | |||
void ScrollBar::onDragStart() { | |||
void ScrollBar::onDragStart(EventDragStart &e) { | |||
state = BND_ACTIVE; | |||
guiCursorLock(); | |||
} | |||
void ScrollBar::onDragMove(Vec mouseRel) { | |||
void ScrollBar::onDragMove(EventDragMove &e) { | |||
ScrollWidget *scrollWidget = dynamic_cast<ScrollWidget*>(parent); | |||
assert(scrollWidget); | |||
if (orientation == HORIZONTAL) | |||
scrollWidget->offset.x += mouseRel.x; | |||
scrollWidget->offset.x += e.mouseRel.x; | |||
else | |||
scrollWidget->offset.y += mouseRel.y; | |||
scrollWidget->offset.y += e.mouseRel.y; | |||
} | |||
void ScrollBar::onDragEnd() { | |||
void ScrollBar::onDragEnd(EventDragEnd &e) { | |||
state = BND_DEFAULT; | |||
guiCursorUnlock(); | |||
} | |||
@@ -58,9 +58,9 @@ void ScrollWidget::step() { | |||
Widget::step(); | |||
} | |||
bool ScrollWidget::onScrollOpaque(Vec scrollRel) { | |||
offset = offset.minus(scrollRel); | |||
return true; | |||
void ScrollWidget::onScroll(EventScroll &e) { | |||
offset = offset.minus(e.scrollRel); | |||
e.consumed = true; | |||
} | |||
@@ -11,26 +11,30 @@ void Slider::draw(NVGcontext *vg) { | |||
bndSlider(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE, state, progress, getText().c_str(), NULL); | |||
} | |||
void Slider::onDragStart() { | |||
void Slider::onDragStart(EventDragStart &e) { | |||
state = BND_ACTIVE; | |||
guiCursorLock(); | |||
} | |||
void Slider::onDragMove(Vec mouseRel) { | |||
setValue(value + SLIDER_SENSITIVITY * (maxValue - minValue) * mouseRel.x); | |||
void Slider::onDragMove(EventDragMove &e) { | |||
setValue(value + SLIDER_SENSITIVITY * (maxValue - minValue) * e.mouseRel.x); | |||
} | |||
void Slider::onDragEnd() { | |||
void Slider::onDragEnd(EventDragEnd &e) { | |||
state = BND_DEFAULT; | |||
guiCursorUnlock(); | |||
onAction(); | |||
EventAction eAction; | |||
onAction(eAction); | |||
} | |||
void Slider::onMouseDownOpaque(int button) { | |||
if (button == 1) { | |||
void Slider::onMouseDown(EventMouseDown &e) { | |||
if (e.button == 1) { | |||
setValue(defaultValue); | |||
onAction(); | |||
EventAction eAction; | |||
onAction(eAction); | |||
} | |||
e.consumed = true; | |||
e.target = this; | |||
} | |||
@@ -24,21 +24,25 @@ void TextField::draw(NVGcontext *vg) { | |||
} | |||
} | |||
Widget *TextField::onMouseDown(Vec pos, int button) { | |||
end = begin = bndTextFieldTextPosition(gVg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str(), pos.x, pos.y); | |||
return OpaqueWidget::onMouseDown(pos, button); | |||
void TextField::onMouseDown(EventMouseDown &e) { | |||
end = begin = bndTextFieldTextPosition(gVg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str(), e.pos.x, e.pos.y); | |||
OpaqueWidget::onMouseDown(e); | |||
} | |||
void TextField::onFocus(EventFocus &e) { | |||
begin = 0; | |||
end = text.size(); | |||
e.consumed = true; | |||
} | |||
bool TextField::onFocusText(int codepoint) { | |||
char c = codepoint; | |||
std::string newText(1, c); | |||
void TextField::onText(EventText &e) { | |||
std::string newText(1, (char) e.codepoint); | |||
insertText(newText); | |||
return true; | |||
e.consumed = true; | |||
} | |||
bool TextField::onFocusKey(int key) { | |||
switch (key) { | |||
void TextField::onKey(EventKey &e) { | |||
switch (e.key) { | |||
case GLFW_KEY_BACKSPACE: | |||
if (begin < end) { | |||
text.erase(begin, end - begin); | |||
@@ -107,20 +111,15 @@ bool TextField::onFocusKey(int key) { | |||
insertText("\n"); | |||
} | |||
else { | |||
onAction(); | |||
EventAction e; | |||
onAction(e); | |||
} | |||
break; | |||
} | |||
begin = mini(maxi(begin, 0), text.size()); | |||
end = mini(maxi(end, 0), text.size()); | |||
return true; | |||
} | |||
bool TextField::onFocus() { | |||
begin = 0; | |||
end = text.size(); | |||
return true; | |||
e.consumed = true; | |||
} | |||
void TextField::insertText(std::string newText) { | |||
@@ -78,18 +78,21 @@ void Widget::clearChildren() { | |||
void Widget::finalizeEvents() { | |||
// Stop dragging and hovering this widget | |||
if (gHoveredWidget == this) { | |||
gHoveredWidget->onMouseLeave(); | |||
EventMouseLeave e; | |||
gHoveredWidget->onMouseLeave(e); | |||
gHoveredWidget = NULL; | |||
} | |||
if (gDraggedWidget == this) { | |||
gDraggedWidget->onDragEnd(); | |||
EventDragEnd e; | |||
gDraggedWidget->onDragEnd(e); | |||
gDraggedWidget = NULL; | |||
} | |||
if (gDragHoveredWidget == this) { | |||
gDragHoveredWidget = NULL; | |||
} | |||
if (gFocusedWidget == this) { | |||
gFocusedWidget->onDefocus(); | |||
EventDefocus e; | |||
gFocusedWidget->onDefocus(e); | |||
gFocusedWidget = NULL; | |||
} | |||
for (Widget *child : children) { | |||
@@ -114,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++) { | |||
Widget *child = *it; | |||
child->onZoom(); | |||
child->onZoom(e); | |||
} | |||
} | |||
@@ -18,8 +18,10 @@ Rect ZoomWidget::getViewport(Rect r) { | |||
} | |||
void ZoomWidget::setZoom(float zoom) { | |||
if (zoom != this->zoom) | |||
onZoom(); | |||
if (zoom != this->zoom) { | |||
EventZoom e; | |||
onZoom(e); | |||
} | |||
this->zoom = zoom; | |||
} | |||
@@ -28,24 +30,39 @@ void ZoomWidget::draw(NVGcontext *vg) { | |||
Widget::draw(vg); | |||
} | |||
Widget *ZoomWidget::onMouseDown(Vec pos, int button) { | |||
return Widget::onMouseDown(pos.div(zoom), button); | |||
void ZoomWidget::onMouseDown(EventMouseDown &e) { | |||
Vec pos = e.pos; | |||
e.pos = e.pos.div(zoom); | |||
Widget::onMouseDown(e); | |||
e.pos = pos; | |||
} | |||
Widget *ZoomWidget::onMouseUp(Vec pos, int button) { | |||
return Widget::onMouseUp(pos.div(zoom), button); | |||
void ZoomWidget::onMouseUp(EventMouseUp &e) { | |||
Vec pos = e.pos; | |||
e.pos = e.pos.div(zoom); | |||
Widget::onMouseUp(e); | |||
e.pos = pos; | |||
} | |||
Widget *ZoomWidget::onMouseMove(Vec pos, Vec mouseRel) { | |||
return Widget::onMouseMove(pos.div(zoom), mouseRel); | |||
void ZoomWidget::onMouseMove(EventMouseMove &e) { | |||
Vec pos = e.pos; | |||
e.pos = e.pos.div(zoom); | |||
Widget::onMouseMove(e); | |||
e.pos = pos; | |||
} | |||
Widget *ZoomWidget::onHoverKey(Vec pos, int key) { | |||
return Widget::onHoverKey(pos.div(zoom), key); | |||
void ZoomWidget::onHoverKey(EventHoverKey &e) { | |||
Vec pos = e.pos; | |||
e.pos = e.pos.div(zoom); | |||
Widget::onHoverKey(e); | |||
e.pos = pos; | |||
} | |||
Widget *ZoomWidget::onScroll(Vec pos, Vec scrollRel) { | |||
return Widget::onScroll(pos.div(zoom), scrollRel); | |||
void ZoomWidget::onScroll(EventScroll &e) { | |||
Vec pos = e.pos; | |||
e.pos = e.pos.div(zoom); | |||
Widget::onScroll(e); | |||
e.pos = pos; | |||
} | |||