| @@ -14,7 +14,7 @@ struct WidgetState { | |||
| Widget *selectedWidget; | |||
| WidgetState(); | |||
| void handleButton(math::Vec pos, int button, int action, int mods); | |||
| }; | |||
| @@ -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(); | |||
| }; | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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<Widget*> 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. | |||
| } | |||
| }; | |||
| @@ -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; | |||
| @@ -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); | |||
| } | |||