@@ -0,0 +1,25 @@ | |||||
#pragma once | |||||
#include "event.hpp" | |||||
namespace rack { | |||||
struct WidgetState { | |||||
Widget *rootWidget; | |||||
Widget *hoveredWidget; | |||||
Widget *draggedWidget; | |||||
Widget *dragHoveredWidget; | |||||
Widget *selectedWidget; | |||||
WidgetState(); | |||||
}; | |||||
// TODO Move this elsewhere | |||||
extern WidgetState *gWidgetState; | |||||
} // namespace rack |
@@ -3,6 +3,7 @@ | |||||
#include <jansson.h> | #include <jansson.h> | ||||
#include "widgets.hpp" | #include "widgets.hpp" | ||||
#include "ui.hpp" | #include "ui.hpp" | ||||
#include "WidgetState.hpp" | |||||
static const float SVG_DPI = 75.0; | static const float SVG_DPI = 75.0; | ||||
@@ -234,12 +234,4 @@ struct Zoom : Event { | |||||
} // namespace event | } // namespace event | ||||
extern Widget *gHoveredWidget; | |||||
extern Widget *gSelectedWidget; | |||||
extern Widget *gDraggedWidget; | |||||
extern Widget *gDragHoveredWidget; | |||||
} // namespace rack | } // namespace rack |
@@ -1,6 +1,7 @@ | |||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#include "engine.hpp" | #include "engine.hpp" | ||||
#include "app.hpp" | #include "app.hpp" | ||||
#include "WidgetState.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -136,5 +137,17 @@ TMenuItem *createMenuItem(std::string text, std::string rightText = "") { | |||||
return o; | return o; | ||||
} | } | ||||
// TODO Reevaluate this. Does it belong here? | |||||
inline Menu *createMenu() { | |||||
Menu *o = new Menu(); | |||||
o->box.pos = gMousePos; | |||||
MenuOverlay *menuOverlay = new MenuOverlay(); | |||||
menuOverlay->addChild(o); | |||||
gWidgetState->rootWidget->addChild(menuOverlay); | |||||
return o; | |||||
} | |||||
} // namespace rack | } // namespace rack |
@@ -2,6 +2,7 @@ | |||||
#include "widgets.hpp" | #include "widgets.hpp" | ||||
#include "blendish.h" | #include "blendish.h" | ||||
#include "ui/MenuOverlay.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -16,7 +17,7 @@ struct MenuItem : MenuEntry { | |||||
void draw(NVGcontext *vg) override { | void draw(NVGcontext *vg) override { | ||||
// Get state | // Get state | ||||
BNDwidgetState state = (gHoveredWidget == this) ? BND_HOVER : BND_DEFAULT; | |||||
BNDwidgetState state = (gWidgetState->hoveredWidget == this) ? BND_HOVER : BND_DEFAULT; | |||||
Menu *parentMenu = dynamic_cast<Menu*>(parent); | Menu *parentMenu = dynamic_cast<Menu*>(parent); | ||||
if (parentMenu && parentMenu->activeEntry == this) { | if (parentMenu && parentMenu->activeEntry == this) { | ||||
state = BND_ACTIVE; | state = BND_ACTIVE; | ||||
@@ -64,10 +65,11 @@ struct MenuItem : MenuEntry { | |||||
// Consume event by default, but allow action to un-consume it to prevent the menu from being removed. | // Consume event by default, but allow action to un-consume it to prevent the menu from being removed. | ||||
eAction.target = this; | eAction.target = this; | ||||
handleEvent(eAction); | handleEvent(eAction); | ||||
if (eAction.target) { | |||||
// deletes `this` | |||||
gScene->setOverlay(NULL); | |||||
} | |||||
if (!eAction.target) | |||||
return; | |||||
Widget *overlay = getAncestorOfType<MenuOverlay>(); | |||||
overlay->requestedDelete = true; | |||||
} | } | ||||
}; | }; | ||||
@@ -11,50 +11,36 @@ struct MenuOverlay : OpaqueWidget { | |||||
void step() override { | void step() override { | ||||
Widget::step(); | Widget::step(); | ||||
// Adopt parent's size | |||||
box.size = parent->box.size; | |||||
// Fit all children in the box | // Fit all children in the box | ||||
for (Widget *child : children) { | for (Widget *child : children) { | ||||
child->box = child->box.nudge(box.zeroPos()); | child->box = child->box.nudge(box.zeroPos()); | ||||
} | } | ||||
} | } | ||||
void on(event::Button &e) override; | |||||
void on(event::HoverKey &e) override; | |||||
}; | |||||
} // namespace rack | |||||
#include "ui/Scene.hpp" | |||||
void on(event::Button &e) override { | |||||
EventWidget::on(e); | |||||
namespace rack { | |||||
if (!e.target) { | |||||
e.target = this; | |||||
requestedDelete = true; | |||||
} | |||||
} | |||||
void on(event::HoverKey &e) override { | |||||
switch (e.key) { | |||||
case GLFW_KEY_ESCAPE: { | |||||
e.target = this; | |||||
requestedDelete = true; | |||||
return; | |||||
} break; | |||||
} | |||||
inline void MenuOverlay::on(event::Button &e) { | |||||
EventWidget::on(e); | |||||
if (!e.target) { | |||||
// deletes `this` | |||||
gScene->setOverlay(NULL); | |||||
e.target = this; | |||||
EventWidget::on(e); | |||||
} | } | ||||
} | |||||
inline void MenuOverlay::on(event::HoverKey &e) { | |||||
switch (e.key) { | |||||
case GLFW_KEY_ESCAPE: { | |||||
gScene->setOverlay(NULL); | |||||
// e.consumed = true; | |||||
return; | |||||
} break; | |||||
} | |||||
// if (!e.consumed) { | |||||
// // Recurse children but consume the event | |||||
// Widget::onHoverKey(e); | |||||
// e.consumed = true; | |||||
// } | |||||
} | |||||
}; | |||||
} // namespace rack | } // namespace rack |
@@ -1,68 +1,13 @@ | |||||
#pragma once | #pragma once | ||||
#include "widgets.hpp" | #include "widgets.hpp" | ||||
#include "ui/Menu.hpp" | |||||
namespace rack { | namespace rack { | ||||
struct Menu; | |||||
struct Scene : OpaqueWidget { | struct Scene : OpaqueWidget { | ||||
Widget *overlay = NULL; | |||||
/** Takes ownership of `w` */ | |||||
void setOverlay(Widget *w) { | |||||
if (overlay) { | |||||
removeChild(overlay); | |||||
delete overlay; | |||||
overlay = NULL; | |||||
} | |||||
if (w) { | |||||
addChild(w); | |||||
overlay = w; | |||||
overlay->box.pos = math::Vec(); | |||||
} | |||||
} | |||||
Menu *createMenu(); | |||||
void step() override { | |||||
if (overlay) { | |||||
overlay->box.pos = math::Vec(0, 0); | |||||
overlay->box.size = box.size; | |||||
} | |||||
Widget::step(); | |||||
} | |||||
}; | }; | ||||
extern Scene *gScene; | |||||
} // namespace rack | |||||
#include "ui/MenuOverlay.hpp" | |||||
namespace rack { | |||||
inline Menu *Scene::createMenu() { | |||||
// Get relative position of the click | |||||
MenuOverlay *overlay = new MenuOverlay(); | |||||
Menu *menu = new Menu(); | |||||
menu->box.pos = gMousePos; | |||||
overlay->addChild(menu); | |||||
gScene->setOverlay(overlay); | |||||
return menu; | |||||
} | |||||
} // namespace rack | } // namespace rack |
@@ -1,6 +1,7 @@ | |||||
#pragma once | #pragma once | ||||
#include "widgets.hpp" | #include "widgets.hpp" | ||||
#include "WidgetState.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -110,7 +111,7 @@ struct ScrollWidget : OpaqueWidget { | |||||
void on(event::Hover &e) override { | void on(event::Hover &e) override { | ||||
// Scroll with arrow keys | // Scroll with arrow keys | ||||
if (!gSelectedWidget) { | |||||
if (!gWidgetState->selectedWidget) { | |||||
float arrowSpeed = 30.0; | float arrowSpeed = 30.0; | ||||
if (windowIsShiftPressed() && windowIsModPressed()) | if (windowIsShiftPressed() && windowIsModPressed()) | ||||
arrowSpeed /= 16.0; | arrowSpeed /= 16.0; | ||||
@@ -1,6 +1,7 @@ | |||||
#pragma once | #pragma once | ||||
#include "widgets.hpp" | #include "widgets.hpp" | ||||
#include "WidgetState.hpp" | |||||
#include "blendish.h" | #include "blendish.h" | ||||
@@ -26,9 +27,9 @@ struct TextField : OpaqueWidget { | |||||
nvgScissor(vg, 0, 0, box.size.x, box.size.y); | nvgScissor(vg, 0, 0, box.size.x, box.size.y); | ||||
BNDwidgetState state; | BNDwidgetState state; | ||||
if (this == gSelectedWidget) | |||||
if (this == gWidgetState->selectedWidget) | |||||
state = BND_ACTIVE; | state = BND_ACTIVE; | ||||
else if (this == gHoveredWidget) | |||||
else if (this == gWidgetState->hoveredWidget) | |||||
state = BND_HOVER; | state = BND_HOVER; | ||||
else | else | ||||
state = BND_DEFAULT; | state = BND_DEFAULT; | ||||
@@ -52,7 +53,7 @@ struct TextField : OpaqueWidget { | |||||
} | } | ||||
void on(event::Hover &e) override { | void on(event::Hover &e) override { | ||||
if (this == gDraggedWidget) { | |||||
if (this == gWidgetState->draggedWidget) { | |||||
int pos = getTextPosition(e.pos); | int pos = getTextPosition(e.pos); | ||||
if (pos != selection) { | if (pos != selection) { | ||||
cursor = pos; | cursor = pos; | ||||
@@ -10,14 +10,10 @@ namespace rack { | |||||
namespace event { | namespace event { | ||||
struct Event; | |||||
} // namespace event | |||||
struct Event; | |||||
enum PickTarget { | |||||
PICK_MOUSE, | |||||
PICK_SCROLL, | |||||
}; | |||||
} // namespace event | |||||
/** A node in the 2D scene graph */ | /** A node in the 2D scene graph */ | ||||
@@ -2,6 +2,7 @@ | |||||
#include "midi.hpp" | #include "midi.hpp" | ||||
#include "dsp/filter.hpp" | #include "dsp/filter.hpp" | ||||
#include "window.hpp" | #include "window.hpp" | ||||
#include "WidgetState.hpp" | |||||
struct MIDICCToCVInterface : Module { | struct MIDICCToCVInterface : Module { | ||||
@@ -129,8 +130,8 @@ struct MidiCcChoice : GridChoice { | |||||
else { | else { | ||||
text = string::stringf("%d", module->learnedCcs[id]); | text = string::stringf("%d", module->learnedCcs[id]); | ||||
color.a = 1.0; | color.a = 1.0; | ||||
if (gSelectedWidget == this) | |||||
gSelectedWidget = NULL; | |||||
if (gWidgetState->selectedWidget == this) | |||||
gWidgetState->selectedWidget = NULL; | |||||
} | } | ||||
} | } | ||||
@@ -158,11 +159,11 @@ struct MidiCcChoice : GridChoice { | |||||
} | } | ||||
void on(event::SelectKey &e) override { | void on(event::SelectKey &e) override { | ||||
if (gSelectedWidget == this) { | |||||
if (gWidgetState->selectedWidget == this) { | |||||
if (e.key == GLFW_KEY_ENTER || e.key == GLFW_KEY_KP_ENTER) { | if (e.key == GLFW_KEY_ENTER || e.key == GLFW_KEY_KP_ENTER) { | ||||
event::Deselect eDeselect; | event::Deselect eDeselect; | ||||
handleEvent(eDeselect); | handleEvent(eDeselect); | ||||
gSelectedWidget = NULL; | |||||
gWidgetState->selectedWidget = NULL; | |||||
e.target = this; | e.target = this; | ||||
} | } | ||||
} | } | ||||
@@ -1,5 +1,6 @@ | |||||
#include "Core.hpp" | #include "Core.hpp" | ||||
#include "midi.hpp" | #include "midi.hpp" | ||||
#include "WidgetState.hpp" | |||||
struct MIDITriggerToCVInterface : Module { | struct MIDITriggerToCVInterface : Module { | ||||
@@ -171,8 +172,8 @@ struct MidiTrigChoice : GridChoice { | |||||
text = string::stringf("%s%d", noteNames[semi], oct); | text = string::stringf("%s%d", noteNames[semi], oct); | ||||
color.a = 1.0; | color.a = 1.0; | ||||
if (gSelectedWidget == this) | |||||
gSelectedWidget = NULL; | |||||
if (gWidgetState->selectedWidget == this) | |||||
gWidgetState->selectedWidget = NULL; | |||||
} | } | ||||
} | } | ||||
@@ -0,0 +1,19 @@ | |||||
#include "WidgetState.hpp" | |||||
namespace rack { | |||||
WidgetState::WidgetState() { | |||||
rootWidget = NULL; | |||||
hoveredWidget = NULL; | |||||
draggedWidget = NULL; | |||||
dragHoveredWidget = NULL; | |||||
selectedWidget = NULL; | |||||
} | |||||
// TODO Move this elsewhere | |||||
WidgetState *gWidgetState = NULL; | |||||
} // namespace rack |
@@ -17,7 +17,7 @@ struct AudioDriverItem : MenuItem { | |||||
struct AudioDriverChoice : LedDisplayChoice { | struct AudioDriverChoice : LedDisplayChoice { | ||||
AudioWidget *audioWidget; | AudioWidget *audioWidget; | ||||
void on(event::Action &e) override { | void on(event::Action &e) override { | ||||
Menu *menu = gScene->createMenu(); | |||||
Menu *menu = createMenu(); | |||||
menu->addChild(createMenuLabel("Audio driver")); | menu->addChild(createMenuLabel("Audio driver")); | ||||
for (int driver : audioWidget->audioIO->getDrivers()) { | for (int driver : audioWidget->audioIO->getDrivers()) { | ||||
AudioDriverItem *item = new AudioDriverItem(); | AudioDriverItem *item = new AudioDriverItem(); | ||||
@@ -49,7 +49,7 @@ struct AudioDeviceChoice : LedDisplayChoice { | |||||
int maxTotalChannels = 128; | int maxTotalChannels = 128; | ||||
void on(event::Action &e) override { | void on(event::Action &e) override { | ||||
Menu *menu = gScene->createMenu(); | |||||
Menu *menu = createMenu(); | |||||
menu->addChild(createMenuLabel("Audio device")); | menu->addChild(createMenuLabel("Audio device")); | ||||
int deviceCount = audioWidget->audioIO->getDeviceCount(); | int deviceCount = audioWidget->audioIO->getDeviceCount(); | ||||
{ | { | ||||
@@ -97,7 +97,7 @@ struct AudioSampleRateItem : MenuItem { | |||||
struct AudioSampleRateChoice : LedDisplayChoice { | struct AudioSampleRateChoice : LedDisplayChoice { | ||||
AudioWidget *audioWidget; | AudioWidget *audioWidget; | ||||
void on(event::Action &e) override { | void on(event::Action &e) override { | ||||
Menu *menu = gScene->createMenu(); | |||||
Menu *menu = createMenu(); | |||||
menu->addChild(createMenuLabel("Sample rate")); | menu->addChild(createMenuLabel("Sample rate")); | ||||
std::vector<int> sampleRates = audioWidget->audioIO->getSampleRates(); | std::vector<int> sampleRates = audioWidget->audioIO->getSampleRates(); | ||||
if (sampleRates.empty()) { | if (sampleRates.empty()) { | ||||
@@ -129,7 +129,7 @@ struct AudioBlockSizeItem : MenuItem { | |||||
struct AudioBlockSizeChoice : LedDisplayChoice { | struct AudioBlockSizeChoice : LedDisplayChoice { | ||||
AudioWidget *audioWidget; | AudioWidget *audioWidget; | ||||
void on(event::Action &e) override { | void on(event::Action &e) override { | ||||
Menu *menu = gScene->createMenu(); | |||||
Menu *menu = createMenu(); | |||||
menu->addChild(createMenuLabel("Block size")); | menu->addChild(createMenuLabel("Block size")); | ||||
std::vector<int> blockSizes = audioWidget->audioIO->getBlockSizes(); | std::vector<int> blockSizes = audioWidget->audioIO->getBlockSizes(); | ||||
if (blockSizes.empty()) { | if (blockSizes.empty()) { | ||||
@@ -1,6 +1,7 @@ | |||||
#include "app.hpp" | #include "app.hpp" | ||||
#include "asset.hpp" | #include "asset.hpp" | ||||
#include "window.hpp" | #include "window.hpp" | ||||
#include "WidgetState.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -84,7 +85,7 @@ void LedDisplayTextField::draw(NVGcontext *vg) { | |||||
NVGcolor highlightColor = color; | NVGcolor highlightColor = color; | ||||
highlightColor.a = 0.5; | highlightColor.a = 0.5; | ||||
int begin = std::min(cursor, selection); | int begin = std::min(cursor, selection); | ||||
int end = (this == gSelectedWidget) ? std::max(cursor, selection) : -1; | |||||
int end = (this == gWidgetState->selectedWidget) ? std::max(cursor, selection) : -1; | |||||
bndIconLabelCaret(vg, textOffset.x, textOffset.y, | bndIconLabelCaret(vg, textOffset.x, textOffset.y, | ||||
box.size.x - 2*textOffset.x, box.size.y - 2*textOffset.y, | box.size.x - 2*textOffset.x, box.size.y - 2*textOffset.y, | ||||
-1, color, 12, text.c_str(), highlightColor, begin, end); | -1, color, 12, text.c_str(), highlightColor, begin, end); | ||||
@@ -17,7 +17,7 @@ struct MidiDriverItem : MenuItem { | |||||
struct MidiDriverChoice : LedDisplayChoice { | struct MidiDriverChoice : LedDisplayChoice { | ||||
MidiWidget *midiWidget; | MidiWidget *midiWidget; | ||||
void on(event::Action &e) override { | void on(event::Action &e) override { | ||||
Menu *menu = gScene->createMenu(); | |||||
Menu *menu = createMenu(); | |||||
menu->addChild(createMenuLabel("MIDI driver")); | menu->addChild(createMenuLabel("MIDI driver")); | ||||
for (int driverId : midiWidget->midiIO->getDriverIds()) { | for (int driverId : midiWidget->midiIO->getDriverIds()) { | ||||
MidiDriverItem *item = new MidiDriverItem(); | MidiDriverItem *item = new MidiDriverItem(); | ||||
@@ -51,7 +51,7 @@ struct MidiDeviceItem : MenuItem { | |||||
struct MidiDeviceChoice : LedDisplayChoice { | struct MidiDeviceChoice : LedDisplayChoice { | ||||
MidiWidget *midiWidget; | MidiWidget *midiWidget; | ||||
void on(event::Action &e) override { | void on(event::Action &e) override { | ||||
Menu *menu = gScene->createMenu(); | |||||
Menu *menu = createMenu(); | |||||
menu->addChild(createMenuLabel("MIDI device")); | menu->addChild(createMenuLabel("MIDI device")); | ||||
{ | { | ||||
MidiDeviceItem *item = new MidiDeviceItem(); | MidiDeviceItem *item = new MidiDeviceItem(); | ||||
@@ -93,7 +93,7 @@ struct MidiChannelItem : MenuItem { | |||||
struct MidiChannelChoice : LedDisplayChoice { | struct MidiChannelChoice : LedDisplayChoice { | ||||
MidiWidget *midiWidget; | MidiWidget *midiWidget; | ||||
void on(event::Action &e) override { | void on(event::Action &e) override { | ||||
Menu *menu = gScene->createMenu(); | |||||
Menu *menu = createMenu(); | |||||
menu->addChild(createMenuLabel("MIDI channel")); | menu->addChild(createMenuLabel("MIDI channel")); | ||||
for (int channel = -1; channel < 16; channel++) { | for (int channel = -1; channel < 16; channel++) { | ||||
MidiChannelItem *item = new MidiChannelItem(); | MidiChannelItem *item = new MidiChannelItem(); | ||||
@@ -2,6 +2,7 @@ | |||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#include "window.hpp" | #include "window.hpp" | ||||
#include "helpers.hpp" | #include "helpers.hpp" | ||||
#include "WidgetState.hpp" | |||||
#include <set> | #include <set> | ||||
#include <algorithm> | #include <algorithm> | ||||
@@ -92,8 +93,8 @@ struct BrowserListItem : OpaqueWidget { | |||||
eAction.target = this; | eAction.target = this; | ||||
handleEvent(eAction); | handleEvent(eAction); | ||||
if (eAction.target) { | if (eAction.target) { | ||||
// deletes `this` | |||||
gScene->setOverlay(NULL); | |||||
MenuOverlay *overlay = getAncestorOfType<MenuOverlay>(); | |||||
overlay->requestedDelete = true; | |||||
} | } | ||||
} | } | ||||
}; | }; | ||||
@@ -429,7 +430,7 @@ struct ModuleBrowser : OpaqueWidget { | |||||
moduleScroll->box.size.y = std::min(box.size.y - moduleScroll->box.pos.y, moduleList->box.size.y); | moduleScroll->box.size.y = std::min(box.size.y - moduleScroll->box.pos.y, moduleList->box.size.y); | ||||
box.size.y = std::min(box.size.y, moduleScroll->box.getBottomRight().y); | box.size.y = std::min(box.size.y, moduleScroll->box.getBottomRight().y); | ||||
gSelectedWidget = searchField; | |||||
gWidgetState->selectedWidget = searchField; | |||||
Widget::step(); | Widget::step(); | ||||
} | } | ||||
}; | }; | ||||
@@ -492,7 +493,8 @@ void SearchModuleField::on(event::Change &e) { | |||||
void SearchModuleField::on(event::SelectKey &e) { | void SearchModuleField::on(event::SelectKey &e) { | ||||
switch (e.key) { | switch (e.key) { | ||||
case GLFW_KEY_ESCAPE: { | case GLFW_KEY_ESCAPE: { | ||||
gScene->setOverlay(NULL); | |||||
MenuOverlay *overlay = getAncestorOfType<MenuOverlay>(); | |||||
overlay->requestedDelete = true; | |||||
e.target = this; | e.target = this; | ||||
return; | return; | ||||
} break; | } break; | ||||
@@ -539,7 +541,7 @@ void appModuleBrowserCreate() { | |||||
ModuleBrowser *moduleBrowser = new ModuleBrowser(); | ModuleBrowser *moduleBrowser = new ModuleBrowser(); | ||||
overlay->addChild(moduleBrowser); | overlay->addChild(moduleBrowser); | ||||
gScene->setOverlay(overlay); | |||||
gRackScene->addChild(overlay); | |||||
} | } | ||||
json_t *appModuleBrowserToJson() { | json_t *appModuleBrowserToJson() { | ||||
@@ -483,7 +483,7 @@ struct ModuleDeleteItem : MenuItem { | |||||
}; | }; | ||||
Menu *ModuleWidget::createContextMenu() { | Menu *ModuleWidget::createContextMenu() { | ||||
Menu *menu = gScene->createMenu(); | |||||
Menu *menu = createMenu(); | |||||
MenuLabel *menuLabel = new MenuLabel(); | MenuLabel *menuLabel = new MenuLabel(); | ||||
menuLabel->text = model->author + " " + model->name + " " + model->plugin->version; | menuLabel->text = model->author + " " + model->name + " " + model->plugin->version; | ||||
@@ -16,13 +16,13 @@ struct TooltipIconButton : IconButton { | |||||
tooltip = new Tooltip(); | tooltip = new Tooltip(); | ||||
tooltip->box.pos = getAbsoluteOffset(math::Vec(0, BND_WIDGET_HEIGHT)); | tooltip->box.pos = getAbsoluteOffset(math::Vec(0, BND_WIDGET_HEIGHT)); | ||||
tooltip->text = tooltipText; | tooltip->text = tooltipText; | ||||
gScene->addChild(tooltip); | |||||
gRackScene->addChild(tooltip); | |||||
} | } | ||||
IconButton::on(e); | IconButton::on(e); | ||||
} | } | ||||
void on(event::Leave &e) override { | void on(event::Leave &e) override { | ||||
if (tooltip) { | if (tooltip) { | ||||
gScene->removeChild(tooltip); | |||||
gRackScene->removeChild(tooltip); | |||||
delete tooltip; | delete tooltip; | ||||
tooltip = NULL; | tooltip = NULL; | ||||
} | } | ||||
@@ -120,7 +120,7 @@ struct SampleRateButton : TooltipIconButton { | |||||
tooltipText = "Engine sample rate"; | tooltipText = "Engine sample rate"; | ||||
} | } | ||||
void on(event::Action &e) override { | void on(event::Action &e) override { | ||||
Menu *menu = gScene->createMenu(); | |||||
Menu *menu = createMenu(); | |||||
menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); | menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); | ||||
menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
@@ -2,6 +2,7 @@ | |||||
#include "engine.hpp" | #include "engine.hpp" | ||||
#include "componentlibrary.hpp" | #include "componentlibrary.hpp" | ||||
#include "window.hpp" | #include "window.hpp" | ||||
#include "WidgetState.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -171,7 +172,7 @@ void WireWidget::draw(NVGcontext *vg) { | |||||
opacity = 1.0; | opacity = 1.0; | ||||
} | } | ||||
else { | else { | ||||
Port *hoveredPort = dynamic_cast<Port*>(gHoveredWidget); | |||||
Port *hoveredPort = dynamic_cast<Port*>(gWidgetState->hoveredWidget); | |||||
if (hoveredPort && (hoveredPort == outputPort || hoveredPort == inputPort)) | if (hoveredPort && (hoveredPort == outputPort || hoveredPort == inputPort)) | ||||
opacity = 1.0; | opacity = 1.0; | ||||
} | } | ||||
@@ -37,7 +37,9 @@ static void checkVersion() { | |||||
void appInit(bool devMode) { | void appInit(bool devMode) { | ||||
gRackScene = new RackScene(); | gRackScene = new RackScene(); | ||||
gScene = gRackScene; | |||||
gWidgetState = new WidgetState(); | |||||
gWidgetState->rootWidget = gRackScene; | |||||
// Request latest version from server | // Request latest version from server | ||||
if (!devMode && gCheckVersion) { | if (!devMode && gCheckVersion) { | ||||
@@ -46,8 +48,13 @@ void appInit(bool devMode) { | |||||
} | } | ||||
} | } | ||||
void appDestroy() { | void appDestroy() { | ||||
delete gRackScene; | delete gRackScene; | ||||
gRackScene = NULL; | |||||
delete gWidgetState; | |||||
gWidgetState = NULL; | |||||
} | } | ||||
@@ -1,12 +0,0 @@ | |||||
#include "event.hpp" | |||||
namespace rack { | |||||
Widget *gHoveredWidget = NULL; | |||||
Widget *gDraggedWidget = NULL; | |||||
Widget *gDragHoveredWidget = NULL; | |||||
Widget *gSelectedWidget = NULL; | |||||
} // namespace rack |
@@ -69,8 +69,8 @@ int main(int argc, char* argv[]) { | |||||
bridgeInit(); | bridgeInit(); | ||||
keyboard::init(); | keyboard::init(); | ||||
gamepad::init(); | gamepad::init(); | ||||
windowInit(); | |||||
appInit(devMode); | appInit(devMode); | ||||
windowInit(); | |||||
settings::load(asset::local("settings.json")); | settings::load(asset::local("settings.json")); | ||||
if (patchFile.empty()) { | if (patchFile.empty()) { | ||||
@@ -1,9 +0,0 @@ | |||||
#include "ui.hpp" | |||||
namespace rack { | |||||
Scene *gScene = NULL; | |||||
} // namespace rack |
@@ -1,5 +1,6 @@ | |||||
#include "widgets.hpp" | #include "widgets.hpp" | ||||
#include "app.hpp" | #include "app.hpp" | ||||
#include "WidgetState.hpp" | |||||
#include <algorithm> | #include <algorithm> | ||||
@@ -9,10 +10,10 @@ Widget::~Widget() { | |||||
// You should only delete orphaned widgets | // You should only delete orphaned widgets | ||||
assert(!parent); | assert(!parent); | ||||
// Stop dragging and hovering this widget | // Stop dragging and hovering this widget | ||||
if (gHoveredWidget == this) gHoveredWidget = NULL; | |||||
if (gDraggedWidget == this) gDraggedWidget = NULL; | |||||
if (gDragHoveredWidget == this) gDragHoveredWidget = NULL; | |||||
if (gSelectedWidget == this) gSelectedWidget = NULL; | |||||
if (gWidgetState->hoveredWidget == this) gWidgetState->hoveredWidget = NULL; | |||||
if (gWidgetState->draggedWidget == this) gWidgetState->draggedWidget = NULL; | |||||
if (gWidgetState->hoveredWidget == this) gWidgetState->hoveredWidget = NULL; | |||||
if (gWidgetState->selectedWidget == this) gWidgetState->selectedWidget = NULL; | |||||
clearChildren(); | clearChildren(); | ||||
} | } | ||||
@@ -13,6 +13,7 @@ | |||||
#include "rack.hpp" | #include "rack.hpp" | ||||
#include "keyboard.hpp" | #include "keyboard.hpp" | ||||
#include "gamepad.hpp" | #include "gamepad.hpp" | ||||
#include "WidgetState.hpp" | |||||
#define NANOVG_GL2_IMPLEMENTATION 1 | #define NANOVG_GL2_IMPLEMENTATION 1 | ||||
// #define NANOVG_GL3_IMPLEMENTATION 1 | // #define NANOVG_GL3_IMPLEMENTATION 1 | ||||
@@ -45,7 +46,9 @@ math::Vec gMousePos; | |||||
std::string lastWindowTitle; | std::string lastWindowTitle; | ||||
static void windowSizeCallback(GLFWwindow* window, int width, int height) {} | |||||
static void windowSizeCallback(GLFWwindow* window, int width, int height) { | |||||
// Do nothing. Window size is reset each frame anyway. | |||||
} | |||||
static void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { | static void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { | ||||
#ifdef ARCH_MAC | #ifdef ARCH_MAC | ||||
@@ -62,7 +65,7 @@ static void mouseButtonCallback(GLFWwindow *window, int button, int action, int | |||||
eButton.button = button; | eButton.button = button; | ||||
eButton.action = action; | eButton.action = action; | ||||
eButton.mods = mods; | eButton.mods = mods; | ||||
gScene->handleEvent(eButton); | |||||
gWidgetState->rootWidget->handleEvent(eButton); | |||||
Widget *clickedWidget = eButton.target; | Widget *clickedWidget = eButton.target; | ||||
// Dragging | // Dragging | ||||
@@ -72,7 +75,7 @@ static void mouseButtonCallback(GLFWwindow *window, int button, int action, int | |||||
event::DragStart eDragStart; | event::DragStart eDragStart; | ||||
eDragStart.button = button; | eDragStart.button = button; | ||||
clickedWidget->handleEvent(eDragStart); | clickedWidget->handleEvent(eDragStart); | ||||
gDraggedWidget = eDragStart.target; | |||||
gWidgetState->draggedWidget = eDragStart.target; | |||||
} | } | ||||
if (action == GLFW_RELEASE) { | if (action == GLFW_RELEASE) { | ||||
@@ -80,23 +83,23 @@ static void mouseButtonCallback(GLFWwindow *window, int button, int action, int | |||||
// TODO Use dragged button | // TODO Use dragged button | ||||
eDragEnd.button = button; | eDragEnd.button = button; | ||||
clickedWidget->handleEvent(eDragEnd); | clickedWidget->handleEvent(eDragEnd); | ||||
gDraggedWidget = eDragEnd.target; | |||||
gWidgetState->draggedWidget = eDragEnd.target; | |||||
} | } | ||||
} | } | ||||
// Selection | // Selection | ||||
if (action == GLFW_PRESS && button == GLFW_MOUSE_BUTTON_LEFT) { | if (action == GLFW_PRESS && button == GLFW_MOUSE_BUTTON_LEFT) { | ||||
if (clickedWidget != gSelectedWidget) { | |||||
if (gSelectedWidget) { | |||||
if (clickedWidget != gWidgetState->selectedWidget) { | |||||
if (gWidgetState->selectedWidget) { | |||||
event::Deselect eDeselect; | event::Deselect eDeselect; | ||||
gSelectedWidget->handleEvent(eDeselect); | |||||
gWidgetState->selectedWidget->handleEvent(eDeselect); | |||||
} | } | ||||
gSelectedWidget = clickedWidget; | |||||
gWidgetState->selectedWidget = clickedWidget; | |||||
if (gSelectedWidget) { | |||||
if (gWidgetState->selectedWidget) { | |||||
event::Select eSelect; | event::Select eSelect; | ||||
gSelectedWidget->handleEvent(eSelect); | |||||
gWidgetState->selectedWidget->handleEvent(eSelect); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -109,21 +112,21 @@ static void mouseButtonCallback(GLFWwindow *window, int button, int action, int | |||||
EventDragStart e; | EventDragStart e; | ||||
gTempWidget->onDragStart(e); | gTempWidget->onDragStart(e); | ||||
} | } | ||||
gDraggedWidget = gTempWidget; | |||||
gWidgetState->draggedWidget = gTempWidget; | |||||
if (gTempWidget != gSelectedWidget) { | |||||
if (gSelectedWidget) { | |||||
if (gTempWidget != gWidgetState->selectedWidget) { | |||||
if (gWidgetState->selectedWidget) { | |||||
// onDefocus | // onDefocus | ||||
EventDefocus e; | EventDefocus e; | ||||
gSelectedWidget->onDefocus(e); | |||||
gWidgetState->selectedWidget->onDefocus(e); | |||||
} | } | ||||
gSelectedWidget = NULL; | |||||
gWidgetState->selectedWidget = NULL; | |||||
if (gTempWidget) { | if (gTempWidget) { | ||||
// onFocus | // onFocus | ||||
EventFocus e; | EventFocus e; | ||||
gTempWidget->onFocus(e); | gTempWidget->onFocus(e); | ||||
if (e.consumed) { | if (e.consumed) { | ||||
gSelectedWidget = gTempWidget; | |||||
gWidgetState->selectedWidget = gTempWidget; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -137,25 +140,25 @@ static void mouseButtonCallback(GLFWwindow *window, int button, int action, int | |||||
EventMouseUp e; | EventMouseUp e; | ||||
e.pos = gMousePos; | e.pos = gMousePos; | ||||
e.button = button; | e.button = button; | ||||
gScene->onMouseUp(e); | |||||
gWidgetState->rootWidget->onMouseUp(e); | |||||
gTempWidget = e.target; | gTempWidget = e.target; | ||||
} | } | ||||
if (button == GLFW_MOUSE_BUTTON_LEFT) { | if (button == GLFW_MOUSE_BUTTON_LEFT) { | ||||
if (gDraggedWidget) { | |||||
if (gWidgetState->draggedWidget) { | |||||
// onDragDrop | // onDragDrop | ||||
EventDragDrop e; | EventDragDrop e; | ||||
e.origin = gDraggedWidget; | |||||
e.origin = gWidgetState->draggedWidget; | |||||
gTempWidget->onDragDrop(e); | gTempWidget->onDragDrop(e); | ||||
} | } | ||||
// gDraggedWidget might have been set to null in the last event, recheck here | |||||
if (gDraggedWidget) { | |||||
// gWidgetState->draggedWidget might have been set to null in the last event, recheck here | |||||
if (gWidgetState->draggedWidget) { | |||||
// onDragEnd | // onDragEnd | ||||
EventDragEnd e; | EventDragEnd e; | ||||
gDraggedWidget->onDragEnd(e); | |||||
gWidgetState->draggedWidget->onDragEnd(e); | |||||
} | } | ||||
gDraggedWidget = NULL; | |||||
gDragHoveredWidget = NULL; | |||||
gWidgetState->draggedWidget = NULL; | |||||
gDragWidgetState->hoveredWidget = NULL; | |||||
} | } | ||||
gTempWidget = NULL; | gTempWidget = NULL; | ||||
} | } | ||||
@@ -209,49 +212,49 @@ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { | |||||
event::Hover eHover; | event::Hover eHover; | ||||
eHover.pos = mousePos; | eHover.pos = mousePos; | ||||
eHover.mouseDelta = mouseDelta; | eHover.mouseDelta = mouseDelta; | ||||
gScene->handleEvent(eHover); | |||||
gWidgetState->rootWidget->handleEvent(eHover); | |||||
if (gDraggedWidget) { | |||||
if (gWidgetState->draggedWidget) { | |||||
event::DragMove eDragMove; | event::DragMove eDragMove; | ||||
// TODO | // TODO | ||||
eDragMove.button = 0; | eDragMove.button = 0; | ||||
eDragMove.mouseDelta = mouseDelta; | eDragMove.mouseDelta = mouseDelta; | ||||
gDraggedWidget->handleEvent(eDragMove); | |||||
gWidgetState->draggedWidget->handleEvent(eDragMove); | |||||
} | } | ||||
/* | /* | ||||
if (gDraggedWidget) { | |||||
if (gWidgetState->draggedWidget) { | |||||
// onDragMove | // onDragMove | ||||
EventDragMove e; | EventDragMove e; | ||||
e.mouseDelta = mouseDelta; | e.mouseDelta = mouseDelta; | ||||
gDraggedWidget->onDragMove(e); | |||||
gWidgetState->draggedWidget->onDragMove(e); | |||||
if (gTempWidget != gDragHoveredWidget) { | |||||
if (gDragHoveredWidget) { | |||||
if (gTempWidget != gDragWidgetState->hoveredWidget) { | |||||
if (gDragWidgetState->hoveredWidget) { | |||||
EventDragEnter e; | EventDragEnter e; | ||||
e.origin = gDraggedWidget; | |||||
gDragHoveredWidget->onDragLeave(e); | |||||
e.origin = gWidgetState->draggedWidget; | |||||
gDragWidgetState->hoveredWidget->onDragLeave(e); | |||||
} | } | ||||
gDragHoveredWidget = gTempWidget; | |||||
if (gDragHoveredWidget) { | |||||
gDragWidgetState->hoveredWidget = gTempWidget; | |||||
if (gDragWidgetState->hoveredWidget) { | |||||
EventDragEnter e; | EventDragEnter e; | ||||
e.origin = gDraggedWidget; | |||||
gDragHoveredWidget->onDragEnter(e); | |||||
e.origin = gWidgetState->draggedWidget; | |||||
gDragWidgetState->hoveredWidget->onDragEnter(e); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
else { | else { | ||||
if (gTempWidget != gHoveredWidget) { | |||||
if (gHoveredWidget) { | |||||
if (gTempWidget != gWidgetState->hoveredWidget) { | |||||
if (gWidgetState->hoveredWidget) { | |||||
// onMouseLeave | // onMouseLeave | ||||
EventMouseLeave e; | EventMouseLeave e; | ||||
gHoveredWidget->onMouseLeave(e); | |||||
gWidgetState->hoveredWidget->onMouseLeave(e); | |||||
} | } | ||||
gHoveredWidget = gTempWidget; | |||||
if (gHoveredWidget) { | |||||
gWidgetState->hoveredWidget = gTempWidget; | |||||
if (gWidgetState->hoveredWidget) { | |||||
// onMouseEnter | // onMouseEnter | ||||
EventMouseEnter e; | EventMouseEnter e; | ||||
gHoveredWidget->onMouseEnter(e); | |||||
gWidgetState->hoveredWidget->onMouseEnter(e); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -262,18 +265,18 @@ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { | |||||
EventScroll e; | EventScroll e; | ||||
e.pos = mousePos; | e.pos = mousePos; | ||||
e.scrollRel = mouseDelta; | e.scrollRel = mouseDelta; | ||||
gScene->onScroll(e); | |||||
gWidgetState->rootWidget->onScroll(e); | |||||
} | } | ||||
*/ | */ | ||||
} | } | ||||
void cursorEnterCallback(GLFWwindow* window, int entered) { | void cursorEnterCallback(GLFWwindow* window, int entered) { | ||||
if (!entered) { | if (!entered) { | ||||
if (gHoveredWidget) { | |||||
if (gWidgetState->hoveredWidget) { | |||||
event::Leave eLeave; | event::Leave eLeave; | ||||
gHoveredWidget->handleEvent(eLeave); | |||||
gWidgetState->hoveredWidget->handleEvent(eLeave); | |||||
} | } | ||||
gHoveredWidget = NULL; | |||||
gWidgetState->hoveredWidget = NULL; | |||||
} | } | ||||
} | } | ||||
@@ -287,26 +290,26 @@ void scrollCallback(GLFWwindow *window, double x, double y) { | |||||
event::HoverScroll eHoverScroll; | event::HoverScroll eHoverScroll; | ||||
eHoverScroll.scrollDelta = scrollDelta; | eHoverScroll.scrollDelta = scrollDelta; | ||||
gScene->handleEvent(eHoverScroll); | |||||
gWidgetState->rootWidget->handleEvent(eHoverScroll); | |||||
} | } | ||||
void charCallback(GLFWwindow *window, unsigned int codepoint) { | void charCallback(GLFWwindow *window, unsigned int codepoint) { | ||||
if (gSelectedWidget) { | |||||
if (gWidgetState->selectedWidget) { | |||||
event::SelectText eSelectText; | event::SelectText eSelectText; | ||||
eSelectText.codepoint = codepoint; | eSelectText.codepoint = codepoint; | ||||
gSelectedWidget->handleEvent(eSelectText); | |||||
gWidgetState->selectedWidget->handleEvent(eSelectText); | |||||
} | } | ||||
} | } | ||||
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) { | ||||
if (gSelectedWidget) { | |||||
if (gWidgetState->selectedWidget) { | |||||
event::SelectKey eSelectKey; | event::SelectKey eSelectKey; | ||||
eSelectKey.key = key; | eSelectKey.key = key; | ||||
eSelectKey.scancode = scancode; | eSelectKey.scancode = scancode; | ||||
eSelectKey.action = action; | eSelectKey.action = action; | ||||
eSelectKey.mods = mods; | eSelectKey.mods = mods; | ||||
gSelectedWidget->handleEvent(eSelectKey); | |||||
gWidgetState->selectedWidget->handleEvent(eSelectKey); | |||||
if (eSelectKey.target) | if (eSelectKey.target) | ||||
return; | return; | ||||
} | } | ||||
@@ -317,7 +320,7 @@ void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods | |||||
eHoverKey.action = action; | eHoverKey.action = action; | ||||
eHoverKey.mods = mods; | eHoverKey.mods = mods; | ||||
eHoverKey.pos = gMousePos; | eHoverKey.pos = gMousePos; | ||||
gScene->handleEvent(eHoverKey); | |||||
gWidgetState->rootWidget->handleEvent(eHoverKey); | |||||
} | } | ||||
// Keyboard MIDI driver | // Keyboard MIDI driver | ||||
@@ -337,7 +340,7 @@ void dropCallback(GLFWwindow *window, int count, const char **paths) { | |||||
for (int i = 0; i < count; i++) { | for (int i = 0; i < count; i++) { | ||||
ePathDrop.paths.push_back(paths[i]); | ePathDrop.paths.push_back(paths[i]); | ||||
} | } | ||||
gScene->handleEvent(ePathDrop); | |||||
gWidgetState->rootWidget->handleEvent(ePathDrop); | |||||
} | } | ||||
void errorCallback(int error, const char *description) { | void errorCallback(int error, const char *description) { | ||||
@@ -353,7 +356,7 @@ void renderGui() { | |||||
nvgReset(gVg); | nvgReset(gVg); | ||||
nvgScale(gVg, gPixelRatio, gPixelRatio); | nvgScale(gVg, gPixelRatio, gPixelRatio); | ||||
gScene->draw(gVg); | |||||
gWidgetState->rootWidget->draw(gVg); | |||||
glViewport(0, 0, width, height); | glViewport(0, 0, width, height); | ||||
glClearColor(0.0, 0.0, 0.0, 1.0); | glClearColor(0.0, 0.0, 0.0, 1.0); | ||||
@@ -507,7 +510,7 @@ void windowRun() { | |||||
pixelRatio = roundf(pixelRatio); | pixelRatio = roundf(pixelRatio); | ||||
if (pixelRatio != gPixelRatio) { | if (pixelRatio != gPixelRatio) { | ||||
event::Zoom eZoom; | event::Zoom eZoom; | ||||
gScene->handleEvent(eZoom); | |||||
gWidgetState->rootWidget->handleEvent(eZoom); | |||||
gPixelRatio = pixelRatio; | gPixelRatio = pixelRatio; | ||||
} | } | ||||
@@ -518,10 +521,10 @@ void windowRun() { | |||||
glfwGetWindowSize(gWindow, &windowWidth, &windowHeight); | glfwGetWindowSize(gWindow, &windowWidth, &windowHeight); | ||||
gWindowRatio = (float)width / windowWidth; | gWindowRatio = (float)width / windowWidth; | ||||
gScene->box.size = math::Vec(width, height).div(gPixelRatio); | |||||
gWidgetState->rootWidget->box.size = math::Vec(width, height).div(gPixelRatio); | |||||
// Step scene | // Step scene | ||||
gScene->step(); | |||||
gWidgetState->rootWidget->step(); | |||||
// Render | // Render | ||||
bool visible = glfwGetWindowAttrib(gWindow, GLFW_VISIBLE) && !glfwGetWindowAttrib(gWindow, GLFW_ICONIFIED); | bool visible = glfwGetWindowAttrib(gWindow, GLFW_VISIBLE) && !glfwGetWindowAttrib(gWindow, GLFW_ICONIFIED); | ||||