diff --git a/include/WidgetState.hpp b/include/WidgetState.hpp index cf69ef7c..4c9e5a28 100644 --- a/include/WidgetState.hpp +++ b/include/WidgetState.hpp @@ -14,7 +14,7 @@ struct WidgetState { Widget *selectedWidget; WidgetState(); - + void handleButton(math::Vec pos, int button, int action, int mods); }; diff --git a/include/event.hpp b/include/event.hpp index 7d5626ce..e615e2c7 100644 --- a/include/event.hpp +++ b/include/event.hpp @@ -152,7 +152,6 @@ struct SelectText : Event, Text { Must consume to allow the drag to occur. */ struct DragStart : Event { - int button; EVENT_TRIGGER_DECLARATION(); }; @@ -160,7 +159,6 @@ struct DragStart : Event { /** Occurs when a Widget stops being dragged by releasing the mouse button. */ struct DragEnd : Event { - int button; EVENT_TRIGGER_DECLARATION(); }; @@ -169,7 +167,6 @@ struct DragEnd : Event { Called once per frame, even when mouseDelta is zero. */ struct DragMove : Event { - int button; math::Vec mouseDelta; EVENT_TRIGGER_DECLARATION(); }; @@ -179,7 +176,6 @@ struct DragMove : Event { */ struct DragEnter : Event { Widget *origin = NULL; - int button; EVENT_TRIGGER_DECLARATION(); }; @@ -188,7 +184,6 @@ struct DragEnter : Event { */ struct DragLeave : Event { Widget *origin = NULL; - int button; EVENT_TRIGGER_DECLARATION(); }; @@ -197,7 +192,6 @@ struct DragLeave : Event { */ struct DragDrop : Event { Widget *origin = NULL; - int button; EVENT_TRIGGER_DECLARATION(); }; diff --git a/include/widgets/EventWidget.hpp b/include/widgets/EventWidget.hpp index 5af0b4bd..e2808f99 100644 --- a/include/widgets/EventWidget.hpp +++ b/include/widgets/EventWidget.hpp @@ -9,6 +9,7 @@ namespace rack { /** A widget that responds to events */ struct EventWidget : Widget { void handleEvent(event::Event &e) override { + // Call visitor's visit method e.trigger(this); } @@ -20,11 +21,14 @@ struct EventWidget : Widget { continue; if (!child->box.contains(e.pos)) continue; + + // Clone event so modifications do not up-propagate TEvent e2 = e; e2.pos = e.pos.minus(child->box.pos); child->handleEvent(e2); + // Up-propagate target if consumed if (e2.target) { - e.target = e.target; + e.target = e2.target; break; } } diff --git a/include/widgets/Widget.hpp b/include/widgets/Widget.hpp index a0ce8920..01895a1c 100644 --- a/include/widgets/Widget.hpp +++ b/include/widgets/Widget.hpp @@ -20,9 +20,10 @@ struct Event; struct Widget { /** Stores position and size */ math::Rect box = math::Rect(math::Vec(), math::Vec(INFINITY, INFINITY)); + /** Automatically set when Widget is added as a child to another Widget */ Widget *parent = NULL; std::list children; - /** Disable rendering but continue stepping */ + /** Disables rendering but allow stepping */ bool visible = true; /** If set to true, parent will delete Widget in the next step() */ bool requestedDelete = false; @@ -75,7 +76,9 @@ struct Widget { virtual void draw(NVGcontext *vg); /** Trigger an event on this Widget. */ - virtual void handleEvent(event::Event &e) {} + virtual void handleEvent(event::Event &e) { + // Basic widgets do not handle events, but the EventWidget subclass does. + } }; diff --git a/src/WidgetState.cpp b/src/WidgetState.cpp index 7130ae80..28af2a40 100644 --- a/src/WidgetState.cpp +++ b/src/WidgetState.cpp @@ -12,6 +12,51 @@ WidgetState::WidgetState() { } +void WidgetState::handleButton(math::Vec pos, int button, int action, int mods) { + // Button event + event::Button eButton; + eButton.button = button; + eButton.action = action; + eButton.mods = mods; + rootWidget->handleEvent(eButton); + Widget *clickedWidget = eButton.target; + + if (button == GLFW_MOUSE_BUTTON_LEFT && clickedWidget) { + // Drag events + if (action == GLFW_PRESS && !draggedWidget) { + event::DragStart eDragStart; + clickedWidget->handleEvent(eDragStart); + draggedWidget = eDragStart.target; + } + + if (action == GLFW_RELEASE && draggedWidget) { + event::DragDrop eDragDrop; + eDragDrop.origin = draggedWidget; + clickedWidget->handleEvent(eDragDrop); + + event::DragEnd eDragEnd; + draggedWidget->handleEvent(eDragEnd); + draggedWidget = NULL; + } + + // Select events + if (action == GLFW_PRESS && clickedWidget != selectedWidget) { + if (selectedWidget) { + event::Deselect eDeselect; + selectedWidget->handleEvent(eDeselect); + } + + selectedWidget = clickedWidget; + + if (selectedWidget) { + event::Select eSelect; + selectedWidget->handleEvent(eSelect); + } + } + } +} + + // TODO Move this elsewhere WidgetState *gWidgetState = NULL; diff --git a/src/window.cpp b/src/window.cpp index b5bbadc1..2ed0e2dd 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -60,49 +60,7 @@ static void mouseButtonCallback(GLFWwindow *window, int button, int action, int } #endif - // event::Button - event::Button eButton; - eButton.button = button; - eButton.action = action; - eButton.mods = mods; - gWidgetState->rootWidget->handleEvent(eButton); - Widget *clickedWidget = eButton.target; - - // Dragging - if (clickedWidget) { - // TODO keep track of dragged mouse button - if (action == GLFW_PRESS) { - event::DragStart eDragStart; - eDragStart.button = button; - clickedWidget->handleEvent(eDragStart); - gWidgetState->draggedWidget = eDragStart.target; - } - - if (action == GLFW_RELEASE) { - event::DragEnd eDragEnd; - // TODO Use dragged button - eDragEnd.button = button; - clickedWidget->handleEvent(eDragEnd); - gWidgetState->draggedWidget = eDragEnd.target; - } - } - - // Selection - if (action == GLFW_PRESS && button == GLFW_MOUSE_BUTTON_LEFT) { - if (clickedWidget != gWidgetState->selectedWidget) { - if (gWidgetState->selectedWidget) { - event::Deselect eDeselect; - gWidgetState->selectedWidget->handleEvent(eDeselect); - } - - gWidgetState->selectedWidget = clickedWidget; - - if (gWidgetState->selectedWidget) { - event::Select eSelect; - gWidgetState->selectedWidget->handleEvent(eSelect); - } - } - } + gWidgetState->handleButton(gMousePos, button, action, mods); /* if (action == GLFW_PRESS) { @@ -216,8 +174,6 @@ void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { if (gWidgetState->draggedWidget) { event::DragMove eDragMove; - // TODO - eDragMove.button = 0; eDragMove.mouseDelta = mouseDelta; gWidgetState->draggedWidget->handleEvent(eDragMove); }