Browse Source

Merge event namespace into widget namespace. Event classes are now defined inside the Widget class.

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
c9cf25f66e
14 changed files with 542 additions and 566 deletions
  1. +4
    -4
      include/context.hpp
  2. +0
    -449
      include/event.hpp
  3. +1
    -0
      include/rack.hpp
  4. +0
    -1
      include/ui/RadioButton.hpp
  5. +305
    -32
      include/widget/Widget.hpp
  6. +155
    -0
      include/widget/event.hpp
  7. +0
    -1
      src/app/CableWidget.cpp
  8. +0
    -1
      src/ui/Button.cpp
  9. +0
    -1
      src/ui/ChoiceButton.cpp
  10. +1
    -1
      src/ui/MenuItem.cpp
  11. +1
    -1
      src/widget/ZoomWidget.cpp
  12. +73
    -73
      src/widget/event.cpp
  13. +1
    -1
      src/window.cpp
  14. +1
    -1
      standalone/main.cpp

+ 4
- 4
include/context.hpp View File

@@ -19,9 +19,9 @@ struct Window;
struct PatchManager;


namespace event {
struct State;
} // namespace event
namespace widget {
struct EventState;
} // namespace widget


namespace app {
@@ -31,7 +31,7 @@ struct Scene;

/** Contains the application state */
struct Context {
event::State* event = NULL;
widget::EventState* event = NULL;
app::Scene* scene = NULL;
engine::Engine* engine = NULL;
Window* window = NULL;


+ 0
- 449
include/event.hpp View File

@@ -1,449 +0,0 @@
#pragma once
#include <vector>
#include <set>

#include <common.hpp>
#include <math.hpp>



/** Remaps Ctrl to Cmd on Mac
Use this instead of GLFW_MOD_CONTROL, since Cmd should be used on Mac in place of Ctrl on Linux/Windows.
*/
#if defined ARCH_MAC
#define RACK_MOD_CTRL GLFW_MOD_SUPER
#define RACK_MOD_CTRL_NAME "⌘"
#else
#define RACK_MOD_CTRL GLFW_MOD_CONTROL
#define RACK_MOD_CTRL_NAME "Ctrl"
#endif
#define RACK_MOD_SHIFT_NAME "Shift"
#define RACK_MOD_ALT_NAME "Alt"

/** Filters actual mod keys from the mod flags.
Use this if you don't care about GLFW_MOD_CAPS_LOCK and GLFW_MOD_NUM_LOCK.
Example usage:
if ((e.mod & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) ...
*/
#define RACK_MOD_MASK (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER)


namespace rack {


namespace widget {
struct Widget;
}


/** Handles user interaction with Widget.
*/
namespace event {


/** A per-event state shared and writable by all widgets that recursively handle an event. */
struct Context {
/** Whether the event should continue recursing to children Widgets. */
bool propagating = true;
/** Whether the event has been consumed by an event handler and no more handlers should consume the event. */
bool consumed = false;
/** The widget that responded to the event. */
widget::Widget* target = NULL;
};


/** Base class for all events. */
struct Base {
Context* context = NULL;

/** Prevents the event from being handled by more Widgets.
*/
void stopPropagating() const {
if (!context)
return;
context->propagating = false;
}
bool isPropagating() const {
if (!context)
return true;
return context->propagating;
}
/** Tells the event handler that a particular Widget consumed the event.
You usually want to stop propagation as well, so call consume() instead.
*/
void setTarget(widget::Widget* w) const {
if (!context)
return;
context->target = w;
}
widget::Widget* getTarget() const {
if (!context)
return NULL;
return context->target;
}
/** Sets the target Widget and stops propagating.
A NULL Widget may be passed to consume but not set a target.
*/
void consume(widget::Widget* w) const {
if (!context)
return;
context->propagating = false;
context->consumed = true;
context->target = w;
}
void unconsume() const {
if (!context)
return;
context->consumed = false;
}
bool isConsumed() const {
if (!context)
return false;
return context->consumed;
}
};


/** An event prototype with a vector position. */
struct PositionBase {
/** The pixel coordinate where the event occurred, relative to the Widget it is called on. */
math::Vec pos;
};


#define RACK_HELD 3


/** An event prototype with a GLFW key. */
struct KeyBase {
/** The key corresponding to what it would be called in its position on a QWERTY US keyboard.
For example, the WASD directional keys used for first-person shooters will always be reported as "WASD", regardless if they say "ZQSD" on an AZERTY keyboard.
You should usually not use these for printable characters such as "Ctrl+V" key commands. Instead, use `keyName`.
You *should* use these for non-printable keys, such as Escape, arrow keys, Home, F1-12, etc.
You should also use this for Enter, Tab, and Space. Although they are printable keys, they do not appear in `keyName`.
See GLFW_KEY_* for the list of possible values.
*/
int key;
/** Platform-dependent "software" key code.
This variable is only included for completion. There should be no reason for you to use this.
You should instead use `key` (for non-printable characters) or `keyName` (for printable characters).
Values are platform independent and can change between different keyboards or keyboard layouts on the same OS.
*/
int scancode;
/** String containing the lowercase key name, if it produces a printable character.
This is the only variable that correctly represents the label printed on any keyboard layout, whether it's QWERTY, AZERTY, QWERTZ, Dvorak, etc.
For example, if the user presses the key labeled "q" regardless of the key position, `keyName` will be "q".
For non-printable characters this is an empty string.
Enter, Tab, and Space do not give a `keyName`. Use `key` instead.
Shift has no effect on the key name. Shift+1 results in "1", Shift+q results in "q", etc.
*/
std::string keyName;
/** The type of event occurring with the key.
Possible values are GLFW_RELEASE, GLFW_PRESS, GLFW_REPEAT, or RACK_HELD.
RACK_HELD is sent every frame while the key is held.
*/
int action;
/** Bitwise OR of key modifiers, such as Ctrl or Shift.
Use (mods & RACK_MOD_MASK) == RACK_MOD_CTRL to check for Ctrl on Linux and Windows but Cmd on Mac.
See GLFW_MOD_* for the list of possible values.
*/
int mods;
};


/** An event prototype with a Unicode character. */
struct TextBase {
/** Unicode code point of the character */
int codepoint;
};


/** Occurs every frame when the mouse is hovering over a Widget.
Recurses.
Consume this event to allow Enter and Leave to occur.
*/
struct Hover : Base, PositionBase {
/** Change in mouse position since the last frame. Can be zero. */
math::Vec mouseDelta;
};


/** Occurs each mouse button press or release.
Recurses.
Consume this event to allow DoubleClick, Select, Deselect, SelectKey, SelectText, DragStart, DragEnd, DragMove, and DragDrop to occur.
*/
struct Button : Base, PositionBase {
/** GLFW_MOUSE_BUTTON_LEFT, GLFW_MOUSE_BUTTON_RIGHT, GLFW_MOUSE_BUTTON_MIDDLE, etc. */
int button;
/** GLFW_PRESS or GLFW_RELEASE */
int action;
/** GLFW_MOD_* */
int mods;
};


/** Occurs when the left mouse button is pressed a second time on the same Widget within a time duration.
Must consume the Button event (on left button press) to receive this event.
*/
struct DoubleClick : Base {
};


/** Occurs when a key is pressed, released, or repeated while the mouse is hovering a Widget.
Recurses.
*/
struct HoverKey : Base, PositionBase, KeyBase {
};


/** Occurs when a character is typed while the mouse is hovering a Widget.
Recurses.
*/
struct HoverText : Base, PositionBase, TextBase {
};


/** Occurs when the mouse scroll wheel is moved while the mouse is hovering a Widget.
Recurses.
*/
struct HoverScroll : Base, PositionBase {
/** Change of scroll wheel position. */
math::Vec scrollDelta;
};


/** Occurs when a Widget begins consuming the Hover event.
Must consume the Hover event to receive this event.
The target sets `hoveredWidget`, which allows Leave to occur.
*/
struct Enter : Base {
};


/** Occurs when a different Widget is entered.
Must consume the Hover event (when a Widget is entered) to receive this event.
*/
struct Leave : Base {
};


/** Occurs when a Widget begins consuming the Button press event for the left mouse button.
Must consume the Button event (on left button press) to receive this event.
The target sets `selectedWidget`, which allows SelectText and SelectKey to occur.
*/
struct Select : Base {
};


/** Occurs when a different Widget is selected.
Must consume the Button event (on left button press, when the Widget is selected) to receive this event.
*/
struct Deselect : Base {
};


/** Occurs when a key is pressed, released, or repeated while a Widget is selected.
Must consume to prevent HoverKey from being triggered.
*/
struct SelectKey : Base, KeyBase {
};


/** Occurs when text is typed while a Widget is selected.
Must consume to prevent HoverKey from being triggered.
*/
struct SelectText : Base, TextBase {
};


struct DragBase : Base {
/** The mouse button held while dragging. */
int button;
};


/** Occurs when a Widget begins being dragged.
Must consume the Button event (on press) to receive this event.
The target sets `draggedWidget`, which allows DragEnd, DragMove, DragHover, DragEnter, and DragDrop to occur.
*/
struct DragStart : DragBase {
};


/** Occurs when a Widget stops being dragged by releasing the mouse button.
Must consume the Button event (on press, when the Widget drag begins) to receive this event.
*/
struct DragEnd : DragBase {
};


/** Occurs every frame on the dragged Widget.
Must consume the Button event (on press, when the Widget drag begins) to receive this event.
*/
struct DragMove : DragBase {
/** Change in mouse position since the last frame. Can be zero. */
math::Vec mouseDelta;
};


/** Occurs every frame when the mouse is hovering over a Widget while another Widget (possibly the same one) is being dragged.
Recurses.
Consume this event to allow DragEnter and DragLeave to occur.
*/
struct DragHover : DragBase, PositionBase {
/** The dragged widget */
widget::Widget* origin = NULL;
/** Change in mouse position since the last frame. Can be zero. */
math::Vec mouseDelta;
};


/** Occurs when the mouse enters a Widget while dragging.
Must consume the DragHover event to receive this event.
The target sets `draggedWidget`, which allows DragLeave to occur.
*/
struct DragEnter : DragBase {
/** The dragged widget */
widget::Widget* origin = NULL;
};


/** Occurs when the mouse leaves a Widget while dragging.
Must consume the DragHover event (when the Widget is entered) to receive this event.
*/
struct DragLeave : DragBase {
/** The dragged widget */
widget::Widget* origin = NULL;
};


/** Occurs when the mouse button is released over a Widget while dragging.
Must consume the Button event (on release) to receive this event.
*/
struct DragDrop : DragBase {
/** The dragged widget */
widget::Widget* origin = NULL;
};


/** Occurs when a selection of files from the operating system is dropped onto a Widget.
Recurses.
*/
struct PathDrop : Base, PositionBase {
PathDrop(const std::vector<std::string>& paths) : paths(paths) {}

/** List of file paths in the dropped selection */
const std::vector<std::string>& paths;
};


/** Occurs after a certain action is triggered on a Widget.
The concept of an "action" is defined by the type of Widget.
*/
struct Action : Base {
};


/** Occurs after the value of a Widget changes.
The concept of a "value" is defined by the type of Widget.
*/
struct Change : Base {
};


/** Occurs when the pixel buffer of this module must be refreshed.
Recurses.
*/
struct Dirty : Base {
};


/** Occurs after a Widget's position is set by Widget::setPosition().
*/
struct Reposition : Base {
};


/** Occurs after a Widget's size is set by Widget::setSize().
*/
struct Resize : Base {
};


/** Occurs after a Widget is added to a parent.
*/
struct Add : Base {
};


/** Occurs before a Widget is removed from its parent.
*/
struct Remove : Base {
};


/** Occurs after a Widget is shown with Widget::show().
Recurses.
*/
struct Show : Base {
};


/** Occurs after a Widget is hidden with Widget::hide().
Recurses.
*/
struct Hide : Base {
};


struct State {
widget::Widget* rootWidget = NULL;
/** State widgets
Don't set these directly unless you know what you're doing. Use the set*() methods instead.
*/
widget::Widget* hoveredWidget = NULL;
widget::Widget* draggedWidget = NULL;
int dragButton = 0;
widget::Widget* dragHoveredWidget = NULL;
widget::Widget* selectedWidget = NULL;
/** For double-clicking */
double lastClickTime = -INFINITY;
widget::Widget* lastClickedWidget = NULL;
std::set<int> heldKeys;

widget::Widget* getRootWidget() {
return rootWidget;
}
widget::Widget* getHoveredWidget() {
return hoveredWidget;
}
widget::Widget* getDraggedWidget() {
return draggedWidget;
}
widget::Widget* getDragHoveredWidget() {
return dragHoveredWidget;
}
widget::Widget* getSelectedWidget() {
return selectedWidget;
}

void setHovered(widget::Widget* w);
void setDragged(widget::Widget* w, int button);
void setDragHovered(widget::Widget* w);
void setSelected(widget::Widget* w);
/** Prepares a widget for deletion */
void finalizeWidget(widget::Widget* w);

bool handleButton(math::Vec pos, int button, int action, int mods);
bool handleHover(math::Vec pos, math::Vec mouseDelta);
bool handleLeave();
bool handleScroll(math::Vec pos, math::Vec scrollDelta);
bool handleText(math::Vec pos, int codepoint);
bool handleKey(math::Vec pos, int key, int scancode, int action, int mods);
bool handleDrop(math::Vec pos, const std::vector<std::string>& paths);
bool handleDirty();
};


} // namespace event
} // namespace rack

+ 1
- 0
include/rack.hpp View File

@@ -16,6 +16,7 @@
#include <helpers.hpp>
#include <componentlibrary.hpp>

#include <widget/event.hpp>
#include <widget/Widget.hpp>
#include <widget/TransparentWidget.hpp>
#include <widget/OpaqueWidget.hpp>


+ 0
- 1
include/ui/RadioButton.hpp View File

@@ -3,7 +3,6 @@
#include <widget/OpaqueWidget.hpp>
#include <Quantity.hpp>
#include <context.hpp>
#include <event.hpp>


namespace rack {


+ 305
- 32
include/widget/Widget.hpp View File

@@ -5,7 +5,7 @@
#include <math.hpp>
#include <window.hpp>
#include <color.hpp>
#include <event.hpp>
#include <widget/event.hpp>
#include <weakptr.hpp>


@@ -168,60 +168,333 @@ struct Widget : WeakBase {
}
}

/** Override these event callbacks to respond to events.
See event.hpp for a description of each event.
using BaseEvent = widget::BaseEvent;

/** An event prototype with a vector position. */
struct PositionBaseEvent {
/** The pixel coordinate where the event occurred, relative to the Widget it is called on. */
math::Vec pos;
};

/** Occurs every frame when the mouse is hovering over a Widget.
Recurses.
Consume this event to allow Enter and Leave to occur.
*/
virtual void onHover(const event::Hover& e) {
struct HoverEvent : BaseEvent, PositionBaseEvent {
/** Change in mouse position since the last frame. Can be zero. */
math::Vec mouseDelta;
};
virtual void onHover(const HoverEvent& e) {
recursePositionEvent(&Widget::onHover, e);
}
virtual void onButton(const event::Button& e) {

/** Occurs each mouse button press or release.
Recurses.
Consume this event to allow DoubleClick, Select, Deselect, SelectKey, SelectText, DragStart, DragEnd, DragMove, and DragDrop to occur.
*/
struct ButtonEvent : BaseEvent, PositionBaseEvent {
/** GLFW_MOUSE_BUTTON_LEFT, GLFW_MOUSE_BUTTON_RIGHT, GLFW_MOUSE_BUTTON_MIDDLE, etc. */
int button;
/** GLFW_PRESS or GLFW_RELEASE */
int action;
/** GLFW_MOD_* */
int mods;
};
virtual void onButton(const ButtonEvent& e) {
recursePositionEvent(&Widget::onButton, e);
}
virtual void onDoubleClick(const event::DoubleClick& e) {}
virtual void onHoverKey(const event::HoverKey& e) {

/** Occurs when the left mouse button is pressed a second time on the same Widget within a time duration.
Must consume the Button event (on left button press) to receive this event.
*/
struct DoubleClickEvent : BaseEvent {};
virtual void onDoubleClick(const DoubleClickEvent& e) {}

/** An event prototype with a GLFW key. */
struct KeyBaseEvent {
/** The key corresponding to what it would be called in its position on a QWERTY US keyboard.
For example, the WASD directional keys used for first-person shooters will always be reported as "WASD", regardless if they say "ZQSD" on an AZERTY keyboard.
You should usually not use these for printable characters such as "Ctrl+V" key commands. Instead, use `keyName`.
You *should* use these for non-printable keys, such as Escape, arrow keys, Home, F1-12, etc.
You should also use this for Enter, Tab, and Space. Although they are printable keys, they do not appear in `keyName`.
See GLFW_KEY_* for the list of possible values.
*/
int key;
/** Platform-dependent "software" key code.
This variable is only included for completion. There should be no reason for you to use this.
You should instead use `key` (for non-printable characters) or `keyName` (for printable characters).
Values are platform independent and can change between different keyboards or keyboard layouts on the same OS.
*/
int scancode;
/** String containing the lowercase key name, if it produces a printable character.
This is the only variable that correctly represents the label printed on any keyboard layout, whether it's QWERTY, AZERTY, QWERTZ, Dvorak, etc.
For example, if the user presses the key labeled "q" regardless of the key position, `keyName` will be "q".
For non-printable characters this is an empty string.
Enter, Tab, and Space do not give a `keyName`. Use `key` instead.
Shift has no effect on the key name. Shift+1 results in "1", Shift+q results in "q", etc.
*/
std::string keyName;
/** The type of event occurring with the key.
Possible values are GLFW_RELEASE, GLFW_PRESS, GLFW_REPEAT, or RACK_HELD.
RACK_HELD is sent every frame while the key is held.
*/
int action;
/** Bitwise OR of key modifiers, such as Ctrl or Shift.
Use (mods & RACK_MOD_MASK) == RACK_MOD_CTRL to check for Ctrl on Linux and Windows but Cmd on Mac.
See GLFW_MOD_* for the list of possible values.
*/
int mods;
};

/** Occurs when a key is pressed, released, or repeated while the mouse is hovering a Widget.
Recurses.
*/
struct HoverKeyEvent : BaseEvent, PositionBaseEvent, KeyBaseEvent {};
virtual void onHoverKey(const HoverKeyEvent& e) {
recursePositionEvent(&Widget::onHoverKey, e);
}
virtual void onHoverText(const event::HoverText& e) {

/** An event prototype with a Unicode character. */
struct TextBaseEvent {
/** Unicode code point of the character */
int codepoint;
};
/** Occurs when a character is typed while the mouse is hovering a Widget.
Recurses.
*/
struct HoverTextEvent : BaseEvent, PositionBaseEvent, TextBaseEvent {};
virtual void onHoverText(const HoverTextEvent& e) {
recursePositionEvent(&Widget::onHoverText, e);
}
virtual void onHoverScroll(const event::HoverScroll& e) {

/** Occurs when the mouse scroll wheel is moved while the mouse is hovering a Widget.
Recurses.
*/
struct HoverScrollEvent : BaseEvent, PositionBaseEvent {
/** Change of scroll wheel position. */
math::Vec scrollDelta;
};
virtual void onHoverScroll(const HoverScrollEvent& e) {
recursePositionEvent(&Widget::onHoverScroll, e);
}
virtual void onEnter(const event::Enter& e) {}
virtual void onLeave(const event::Leave& e) {}
virtual void onSelect(const event::Select& e) {}
virtual void onDeselect(const event::Deselect& e) {}
virtual void onSelectKey(const event::SelectKey& e) {}
virtual void onSelectText(const event::SelectText& e) {}
virtual void onDragStart(const event::DragStart& e) {}
virtual void onDragEnd(const event::DragEnd& e) {}
virtual void onDragMove(const event::DragMove& e) {}
virtual void onDragHover(const event::DragHover& e) {

/** Occurs when a Widget begins consuming the Hover event.
Must consume the Hover event to receive this event.
The target sets `hoveredWidget`, which allows Leave to occur.
*/
struct EnterEvent : BaseEvent {};
virtual void onEnter(const EnterEvent& e) {}

/** Occurs when a different Widget is entered.
Must consume the Hover event (when a Widget is entered) to receive this event.
*/
struct LeaveEvent : BaseEvent {};
virtual void onLeave(const LeaveEvent& e) {}

/** Occurs when a Widget begins consuming the Button press event for the left mouse button.
Must consume the Button event (on left button press) to receive this event.
The target sets `selectedWidget`, which allows SelectText and SelectKey to occur.
*/
struct SelectEvent : BaseEvent {};
virtual void onSelect(const SelectEvent& e) {}

/** Occurs when a different Widget is selected.
Must consume the Button event (on left button press, when the Widget is selected) to receive this event.
*/
struct DeselectEvent : BaseEvent {};
virtual void onDeselect(const DeselectEvent& e) {}

/** Occurs when a key is pressed, released, or repeated while a Widget is selected.
Must consume to prevent HoverKey from being triggered.
*/
struct SelectKeyEvent : BaseEvent, KeyBaseEvent {};
virtual void onSelectKey(const SelectKeyEvent& e) {}

/** Occurs when text is typed while a Widget is selected.
Must consume to prevent HoverKey from being triggered.
*/
struct SelectTextEvent : BaseEvent, TextBaseEvent {};
virtual void onSelectText(const SelectTextEvent& e) {}

struct DragBaseEvent : BaseEvent {
/** The mouse button held while dragging. */
int button;
};
/** Occurs when a Widget begins being dragged.
Must consume the Button event (on press) to receive this event.
The target sets `draggedWidget`, which allows DragEnd, DragMove, DragHover, DragEnter, and DragDrop to occur.
*/
struct DragStartEvent : DragBaseEvent {};
virtual void onDragStart(const DragStartEvent& e) {}

/** Occurs when a Widget stops being dragged by releasing the mouse button.
Must consume the Button event (on press, when the Widget drag begins) to receive this event.
*/
struct DragEndEvent : DragBaseEvent {};
virtual void onDragEnd(const DragEndEvent& e) {}

/** Occurs every frame on the dragged Widget.
Must consume the Button event (on press, when the Widget drag begins) to receive this event.
*/
struct DragMoveEvent : DragBaseEvent {
/** Change in mouse position since the last frame. Can be zero. */
math::Vec mouseDelta;
};
virtual void onDragMove(const DragMoveEvent& e) {}

/** Occurs every frame when the mouse is hovering over a Widget while another Widget (possibly the same one) is being dragged.
Recurses.
Consume this event to allow DragEnter and DragLeave to occur.
*/
struct DragHoverEvent : DragBaseEvent, PositionBaseEvent {
/** The dragged widget */
Widget* origin = NULL;
/** Change in mouse position since the last frame. Can be zero. */
math::Vec mouseDelta;
};
virtual void onDragHover(const DragHoverEvent& e) {
recursePositionEvent(&Widget::onDragHover, e);
}
virtual void onDragEnter(const event::DragEnter& e) {}
virtual void onDragLeave(const event::DragLeave& e) {}
virtual void onDragDrop(const event::DragDrop& e) {}
virtual void onPathDrop(const event::PathDrop& e) {

/** Occurs when the mouse enters a Widget while dragging.
Must consume the DragHover event to receive this event.
The target sets `draggedWidget`, which allows DragLeave to occur.
*/
struct DragEnterEvent : DragBaseEvent {
/** The dragged widget */
Widget* origin = NULL;
};
virtual void onDragEnter(const DragEnterEvent& e) {}

/** Occurs when the mouse leaves a Widget while dragging.
Must consume the DragHover event (when the Widget is entered) to receive this event.
*/
struct DragLeaveEvent : DragBaseEvent {
/** The dragged widget */
Widget* origin = NULL;
};
virtual void onDragLeave(const DragLeaveEvent& e) {}

/** Occurs when the mouse button is released over a Widget while dragging.
Must consume the Button event (on release) to receive this event.
*/
struct DragDropEvent : DragBaseEvent {
/** The dragged widget */
Widget* origin = NULL;
};
virtual void onDragDrop(const DragDropEvent& e) {}

/** Occurs when a selection of files from the operating system is dropped onto a Widget.
Recurses.
*/
struct PathDropEvent : BaseEvent, PositionBaseEvent {
PathDropEvent(const std::vector<std::string>& paths) : paths(paths) {}

/** List of file paths in the dropped selection */
const std::vector<std::string>& paths;
};
virtual void onPathDrop(const PathDropEvent& e) {
recursePositionEvent(&Widget::onPathDrop, e);
}
virtual void onAction(const event::Action& e) {}
virtual void onChange(const event::Change& e) {}
virtual void onDirty(const event::Dirty& e) {

/** Occurs after a certain action is triggered on a Widget.
The concept of an "action" is defined by the type of Widget.
*/
struct ActionEvent : BaseEvent {};
virtual void onAction(const ActionEvent& e) {}

/** Occurs after the value of a Widget changes.
The concept of a "value" is defined by the type of Widget.
*/
struct ChangeEvent : BaseEvent {};
virtual void onChange(const ChangeEvent& e) {}

/** Occurs when the pixel buffer of this module must be refreshed.
Recurses.
*/
struct DirtyEvent : BaseEvent {};
virtual void onDirty(const DirtyEvent& e) {
recurseEvent(&Widget::onDirty, e);
}
virtual void onReposition(const event::Reposition& e) {}
virtual void onResize(const event::Resize& e) {}
virtual void onAdd(const event::Add& e) {}
virtual void onRemove(const event::Remove& e) {}
virtual void onShow(const event::Show& e) {

/** Occurs after a Widget's position is set by Widget::setPosition().
*/
struct RepositionEvent : BaseEvent {};
virtual void onReposition(const RepositionEvent& e) {}

/** Occurs after a Widget's size is set by Widget::setSize().
*/
struct ResizeEvent : BaseEvent {};
virtual void onResize(const ResizeEvent& e) {}

/** Occurs after a Widget is added to a parent.
*/
struct AddEvent : BaseEvent {};
virtual void onAdd(const AddEvent& e) {}

/** Occurs before a Widget is removed from its parent.
*/
struct RemoveEvent : BaseEvent {};
virtual void onRemove(const RemoveEvent& e) {}

/** Occurs after a Widget is shown with Widget::show().
Recurses.
*/
struct ShowEvent : BaseEvent {};
virtual void onShow(const ShowEvent& e) {
recurseEvent(&Widget::onShow, e);
}
virtual void onHide(const event::Hide& e) {

/** Occurs after a Widget is hidden with Widget::hide().
Recurses.
*/
struct HideEvent : BaseEvent {};
virtual void onHide(const HideEvent& e) {
recurseEvent(&Widget::onHide, e);
}
};


} // namespace widget

/** Deprecated Rack v1 event namespace.
Use `ExampleWidget` instead of `event::Example` in new code.
*/
namespace event {
using Base = widget::BaseEvent;
using PositionBase = widget::Widget::PositionBaseEvent;
using KeyBase = widget::Widget::KeyBaseEvent;
using TextBase = widget::Widget::TextBaseEvent;
using Hover = widget::Widget::HoverEvent;
using Button = widget::Widget::ButtonEvent;
using DoubleClick = widget::Widget::DoubleClickEvent;
using HoverKey = widget::Widget::HoverKeyEvent;
using HoverText = widget::Widget::HoverTextEvent;
using HoverScroll = widget::Widget::HoverScrollEvent;
using Enter = widget::Widget::EnterEvent;
using Leave = widget::Widget::LeaveEvent;
using Select = widget::Widget::SelectEvent;
using Deselect = widget::Widget::DeselectEvent;
using SelectKey = widget::Widget::SelectKeyEvent;
using SelectText = widget::Widget::SelectTextEvent;
using DragBase = widget::Widget::DragBaseEvent;
using DragStart = widget::Widget::DragStartEvent;
using DragEnd = widget::Widget::DragEndEvent;
using DragMove = widget::Widget::DragMoveEvent;
using DragHover = widget::Widget::DragHoverEvent;
using DragEnter = widget::Widget::DragEnterEvent;
using DragLeave = widget::Widget::DragLeaveEvent;
using DragDrop = widget::Widget::DragDropEvent;
using PathDrop = widget::Widget::PathDropEvent;
using Action = widget::Widget::ActionEvent;
using Change = widget::Widget::ChangeEvent;
using Dirty = widget::Widget::DirtyEvent;
using Reposition = widget::Widget::RepositionEvent;
using Resize = widget::Widget::ResizeEvent;
using Add = widget::Widget::AddEvent;
using Remove = widget::Widget::RemoveEvent;
using Show = widget::Widget::ShowEvent;
using Hide = widget::Widget::HideEvent;
}

} // namespace rack

+ 155
- 0
include/widget/event.hpp View File

@@ -0,0 +1,155 @@
#pragma once
#include <vector>
#include <set>

#include <common.hpp>
#include <math.hpp>



/** Remaps Ctrl to Cmd on Mac
Use this instead of GLFW_MOD_CONTROL, since Cmd should be used on Mac in place of Ctrl on Linux/Windows.
*/
#if defined ARCH_MAC
#define RACK_MOD_CTRL GLFW_MOD_SUPER
#define RACK_MOD_CTRL_NAME "⌘"
#else
#define RACK_MOD_CTRL GLFW_MOD_CONTROL
#define RACK_MOD_CTRL_NAME "Ctrl"
#endif
#define RACK_MOD_SHIFT_NAME "Shift"
#define RACK_MOD_ALT_NAME "Alt"

/** Filters actual mod keys from the mod flags.
Use this if you don't care about GLFW_MOD_CAPS_LOCK and GLFW_MOD_NUM_LOCK.
Example usage:
if ((e.mod & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) ...
*/
#define RACK_MOD_MASK (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER)

/** A key action state representing the the key is (still) being held.
*/
#define RACK_HELD 3


namespace rack {
namespace widget {


struct Widget;


/** A per-event state shared and writable by all widgets that recursively handle an event. */
struct EventContext {
/** Whether the event should continue recursing to children Widgets. */
bool propagating = true;
/** Whether the event has been consumed by an event handler and no more handlers should consume the event. */
bool consumed = false;
/** The widget that responded to the event. */
Widget* target = NULL;
};


/** Base class for all events. */
struct BaseEvent {
EventContext* context = NULL;

/** Prevents the event from being handled by more Widgets.
*/
void stopPropagating() const {
if (!context)
return;
context->propagating = false;
}
bool isPropagating() const {
if (!context)
return true;
return context->propagating;
}
/** Tells the event handler that a particular Widget consumed the event.
You usually want to stop propagation as well, so call consume() instead.
*/
void setTarget(Widget* w) const {
if (!context)
return;
context->target = w;
}
Widget* getTarget() const {
if (!context)
return NULL;
return context->target;
}
/** Sets the target Widget and stops propagating.
A NULL Widget may be passed to consume but not set a target.
*/
void consume(Widget* w) const {
if (!context)
return;
context->propagating = false;
context->consumed = true;
context->target = w;
}
void unconsume() const {
if (!context)
return;
context->consumed = false;
}
bool isConsumed() const {
if (!context)
return false;
return context->consumed;
}
};


struct EventState {
Widget* rootWidget = NULL;
/** State widgets
Don't set these directly unless you know what you're doing. Use the set*() methods instead.
*/
Widget* hoveredWidget = NULL;
Widget* draggedWidget = NULL;
int dragButton = 0;
Widget* dragHoveredWidget = NULL;
Widget* selectedWidget = NULL;
/** For double-clicking */
double lastClickTime = -INFINITY;
Widget* lastClickedWidget = NULL;
std::set<int> heldKeys;

Widget* getRootWidget() {
return rootWidget;
}
Widget* getHoveredWidget() {
return hoveredWidget;
}
Widget* getDraggedWidget() {
return draggedWidget;
}
Widget* getDragHoveredWidget() {
return dragHoveredWidget;
}
Widget* getSelectedWidget() {
return selectedWidget;
}

void setHovered(Widget* w);
void setDragged(Widget* w, int button);
void setDragHovered(Widget* w);
void setSelected(Widget* w);
/** Prepares a widget for deletion */
void finalizeWidget(Widget* w);

bool handleButton(math::Vec pos, int button, int action, int mods);
bool handleHover(math::Vec pos, math::Vec mouseDelta);
bool handleLeave();
bool handleScroll(math::Vec pos, math::Vec scrollDelta);
bool handleText(math::Vec pos, int codepoint);
bool handleKey(math::Vec pos, int key, int scancode, int action, int mods);
bool handleDrop(math::Vec pos, const std::vector<std::string>& paths);
bool handleDirty();
};


} // namespace widget
} // namespace rack

+ 0
- 1
src/app/CableWidget.cpp View File

@@ -5,7 +5,6 @@
#include <context.hpp>
#include <patch.hpp>
#include <settings.hpp>
#include <event.hpp>
#include <engine/Engine.hpp>
#include <engine/Port.hpp>



+ 0
- 1
src/ui/Button.cpp View File

@@ -1,6 +1,5 @@
#include <ui/Button.hpp>
#include <context.hpp>
#include <event.hpp>


namespace rack {


+ 0
- 1
src/ui/ChoiceButton.cpp View File

@@ -1,6 +1,5 @@
#include <ui/ChoiceButton.hpp>
#include <context.hpp>
#include <event.hpp>


namespace rack {


+ 1
- 1
src/ui/MenuItem.cpp View File

@@ -70,7 +70,7 @@ void MenuItem::doAction() {
if (disabled)
return;

event::Context cAction;
widget::EventContext cAction;
event::Action eAction;
eAction.context = &cAction;
// Consume event by default, but allow action to un-consume it to prevent the menu from being removed.


+ 1
- 1
src/widget/ZoomWidget.cpp View File

@@ -33,7 +33,7 @@ void ZoomWidget::setZoom(float zoom) {
this->zoom = zoom;

// Trigger Dirty event
event::Context cDirty;
widget::EventContext cDirty;
event::Dirty eDirty;
eDirty.context = &cDirty;
Widget::onDirty(eDirty);


src/event.cpp → src/widget/event.cpp View File

@@ -1,42 +1,42 @@
#include <event.hpp>
#include <widget/event.hpp>
#include <widget/Widget.hpp>
#include <context.hpp>
#include <window.hpp>


namespace rack {
namespace event {
namespace widget {


void State::setHovered(widget::Widget* w) {
void EventState::setHovered(widget::Widget* w) {
if (w == hoveredWidget)
return;

if (hoveredWidget) {
// Trigger Leave event
Leave eLeave;
// Trigger LeaveEvent
Widget::LeaveEvent eLeave;
hoveredWidget->onLeave(eLeave);
hoveredWidget = NULL;
}

if (w) {
// Trigger Enter event
Context cEnter;
// Trigger EnterEvent
EventContext cEnter;
cEnter.target = w;
Enter eEnter;
Widget::EnterEvent eEnter;
eEnter.context = &cEnter;
w->onEnter(eEnter);
hoveredWidget = cEnter.target;
}
}

void State::setDragged(widget::Widget* w, int button) {
void EventState::setDragged(widget::Widget* w, int button) {
if (w == draggedWidget)
return;

if (draggedWidget) {
// Trigger DragEnd event
DragEnd eDragEnd;
// Trigger DragEndEvent
Widget::DragEndEvent eDragEnd;
eDragEnd.button = dragButton;
draggedWidget->onDragEnd(eDragEnd);
draggedWidget = NULL;
@@ -45,10 +45,10 @@ void State::setDragged(widget::Widget* w, int button) {
dragButton = button;

if (w) {
// Trigger DragStart event
Context cDragStart;
// Trigger DragStartEvent
EventContext cDragStart;
cDragStart.target = w;
DragStart eDragStart;
Widget::DragStartEvent eDragStart;
eDragStart.context = &cDragStart;
eDragStart.button = dragButton;
w->onDragStart(eDragStart);
@@ -56,13 +56,13 @@ void State::setDragged(widget::Widget* w, int button) {
}
}

void State::setDragHovered(widget::Widget* w) {
void EventState::setDragHovered(widget::Widget* w) {
if (w == dragHoveredWidget)
return;

if (dragHoveredWidget) {
// Trigger DragLeave event
DragLeave eDragLeave;
// Trigger DragLeaveEvent
Widget::DragLeaveEvent eDragLeave;
eDragLeave.button = dragButton;
eDragLeave.origin = draggedWidget;
dragHoveredWidget->onDragLeave(eDragLeave);
@@ -70,10 +70,10 @@ void State::setDragHovered(widget::Widget* w) {
}

if (w) {
// Trigger DragEnter event
Context cDragEnter;
// Trigger DragEnterEvent
EventContext cDragEnter;
cDragEnter.target = w;
DragEnter eDragEnter;
Widget::DragEnterEvent eDragEnter;
eDragEnter.context = &cDragEnter;
eDragEnter.button = dragButton;
eDragEnter.origin = draggedWidget;
@@ -82,29 +82,29 @@ void State::setDragHovered(widget::Widget* w) {
}
}

void State::setSelected(widget::Widget* w) {
void EventState::setSelected(widget::Widget* w) {
if (w == selectedWidget)
return;

if (selectedWidget) {
// Trigger Deselect event
Deselect eDeselect;
// Trigger DeselectEvent
Widget::DeselectEvent eDeselect;
selectedWidget->onDeselect(eDeselect);
selectedWidget = NULL;
}

if (w) {
// Trigger Select event
Context cSelect;
// Trigger SelectEvent
EventContext cSelect;
cSelect.target = w;
Select eSelect;
Widget::SelectEvent eSelect;
eSelect.context = &cSelect;
w->onSelect(eSelect);
selectedWidget = cSelect.target;
}
}

void State::finalizeWidget(widget::Widget* w) {
void EventState::finalizeWidget(widget::Widget* w) {
if (hoveredWidget == w)
setHovered(NULL);
if (draggedWidget == w)
@@ -117,14 +117,14 @@ void State::finalizeWidget(widget::Widget* w) {
lastClickedWidget = NULL;
}

bool State::handleButton(math::Vec pos, int button, int action, int mods) {
bool EventState::handleButton(math::Vec pos, int button, int action, int mods) {
bool cursorLocked = APP->window->isCursorLocked();

widget::Widget* clickedWidget = NULL;
if (!cursorLocked) {
// Trigger Button event
Context cButton;
Button eButton;
// Trigger ButtonEvent
EventContext cButton;
Widget::ButtonEvent eButton;
eButton.context = &cButton;
eButton.pos = pos;
eButton.button = button;
@@ -142,8 +142,8 @@ bool State::handleButton(math::Vec pos, int button, int action, int mods) {
setDragHovered(NULL);

if (clickedWidget && draggedWidget) {
// Trigger DragDrop event
DragDrop eDragDrop;
// Trigger DragDropEvent
Widget::DragDropEvent eDragDrop;
eDragDrop.button = dragButton;
eDragDrop.origin = draggedWidget;
clickedWidget->onDragDrop(eDragDrop);
@@ -163,8 +163,8 @@ bool State::handleButton(math::Vec pos, int button, int action, int mods) {
if (clickedWidget
&& clickTime - lastClickTime <= doubleClickDuration
&& lastClickedWidget == clickedWidget) {
// Trigger DoubleClick event
DoubleClick eDoubleClick;
// Trigger DoubleClickEvent
Widget::DoubleClickEvent eDoubleClick;
clickedWidget->onDoubleClick(eDoubleClick);
// Reset double click
lastClickTime = -INFINITY;
@@ -180,7 +180,7 @@ bool State::handleButton(math::Vec pos, int button, int action, int mods) {
return !!clickedWidget;
}

bool State::handleHover(math::Vec pos, math::Vec mouseDelta) {
bool EventState::handleHover(math::Vec pos, math::Vec mouseDelta) {
bool cursorLocked = APP->window->isCursorLocked();

// Fake a key RACK_HELD event for each held key
@@ -195,9 +195,9 @@ bool State::handleHover(math::Vec pos, math::Vec mouseDelta) {
if (draggedWidget) {
bool dragHovered = false;
if (!cursorLocked) {
// Trigger DragHover event
Context cDragHover;
DragHover eDragHover;
// Trigger DragHoverEvent
EventContext cDragHover;
Widget::DragHoverEvent eDragHover;
eDragHover.context = &cDragHover;
eDragHover.button = dragButton;
eDragHover.pos = pos;
@@ -206,13 +206,13 @@ bool State::handleHover(math::Vec pos, math::Vec mouseDelta) {
rootWidget->onDragHover(eDragHover);

setDragHovered(cDragHover.target);
// If consumed, don't continue after DragMove so Hover is not triggered.
// If consumed, don't continue after DragMoveEvent so HoverEvent is not triggered.
if (cDragHover.target)
dragHovered = true;
}

// Trigger DragMove event
DragMove eDragMove;
// Trigger DragMoveEvent
Widget::DragMoveEvent eDragMove;
eDragMove.button = dragButton;
eDragMove.mouseDelta = mouseDelta;
draggedWidget->onDragMove(eDragMove);
@@ -221,9 +221,9 @@ bool State::handleHover(math::Vec pos, math::Vec mouseDelta) {
}

if (!cursorLocked) {
// Trigger Hover event
Context cHover;
Hover eHover;
// Trigger HoverEvent
EventContext cHover;
Widget::HoverEvent eHover;
eHover.context = &cHover;
eHover.pos = pos;
eHover.mouseDelta = mouseDelta;
@@ -236,7 +236,7 @@ bool State::handleHover(math::Vec pos, math::Vec mouseDelta) {
return false;
}

bool State::handleLeave() {
bool EventState::handleLeave() {
heldKeys.clear();
// When leaving the window, don't un-hover widgets because the mouse might be dragging.
// setDragHovered(NULL);
@@ -244,10 +244,10 @@ bool State::handleLeave() {
return true;
}

bool State::handleScroll(math::Vec pos, math::Vec scrollDelta) {
// Trigger HoverScroll event
Context cHoverScroll;
HoverScroll eHoverScroll;
bool EventState::handleScroll(math::Vec pos, math::Vec scrollDelta) {
// Trigger HoverScrollEvent
EventContext cHoverScroll;
Widget::HoverScrollEvent eHoverScroll;
eHoverScroll.context = &cHoverScroll;
eHoverScroll.pos = pos;
eHoverScroll.scrollDelta = scrollDelta;
@@ -256,10 +256,10 @@ bool State::handleScroll(math::Vec pos, math::Vec scrollDelta) {
return !!cHoverScroll.target;
}

bool State::handleDrop(math::Vec pos, const std::vector<std::string>& paths) {
// Trigger PathDrop event
Context cPathDrop;
PathDrop ePathDrop(paths);
bool EventState::handleDrop(math::Vec pos, const std::vector<std::string>& paths) {
// Trigger PathDropEvent
EventContext cPathDrop;
Widget::PathDropEvent ePathDrop(paths);
ePathDrop.context = &cPathDrop;
ePathDrop.pos = pos;
rootWidget->onPathDrop(ePathDrop);
@@ -267,11 +267,11 @@ bool State::handleDrop(math::Vec pos, const std::vector<std::string>& paths) {
return !!cPathDrop.target;
}

bool State::handleText(math::Vec pos, int codepoint) {
bool EventState::handleText(math::Vec pos, int codepoint) {
if (selectedWidget) {
// Trigger SelectText event
Context cSelectText;
SelectText eSelectText;
// Trigger SelectTextEvent
EventContext cSelectText;
Widget::SelectTextEvent eSelectText;
eSelectText.context = &cSelectText;
eSelectText.codepoint = codepoint;
selectedWidget->onSelectText(eSelectText);
@@ -279,9 +279,9 @@ bool State::handleText(math::Vec pos, int codepoint) {
return true;
}

// Trigger HoverText event
Context cHoverText;
HoverText eHoverText;
// Trigger HoverText
EventContext cHoverText;
Widget::HoverTextEvent eHoverText;
eHoverText.context = &cHoverText;
eHoverText.pos = pos;
eHoverText.codepoint = codepoint;
@@ -290,7 +290,7 @@ bool State::handleText(math::Vec pos, int codepoint) {
return !!cHoverText.target;
}

bool State::handleKey(math::Vec pos, int key, int scancode, int action, int mods) {
bool EventState::handleKey(math::Vec pos, int key, int scancode, int action, int mods) {
// Update heldKey state
if (action == GLFW_PRESS) {
heldKeys.insert(key);
@@ -302,9 +302,9 @@ bool State::handleKey(math::Vec pos, int key, int scancode, int action, int mods
}

if (selectedWidget) {
// Trigger SelectKey event
Context cSelectKey;
SelectKey eSelectKey;
// Trigger SelectKeyEvent
EventContext cSelectKey;
Widget::SelectKeyEvent eSelectKey;
eSelectKey.context = &cSelectKey;
eSelectKey.key = key;
eSelectKey.scancode = scancode;
@@ -318,9 +318,9 @@ bool State::handleKey(math::Vec pos, int key, int scancode, int action, int mods
return true;
}

// Trigger HoverKey event
Context cHoverKey;
HoverKey eHoverKey;
// Trigger HoverKeyEvent
EventContext cHoverKey;
Widget::HoverKeyEvent eHoverKey;
eHoverKey.context = &cHoverKey;
eHoverKey.pos = pos;
eHoverKey.key = key;
@@ -334,15 +334,15 @@ bool State::handleKey(math::Vec pos, int key, int scancode, int action, int mods
return !!cHoverKey.target;
}

bool State::handleDirty() {
// Trigger Dirty event
Context cDirty;
Dirty eDirty;
bool EventState::handleDirty() {
// Trigger DirtyEvent
EventContext cDirty;
Widget::DirtyEvent eDirty;
eDirty.context = &cDirty;
rootWidget->onDirty(eDirty);
return true;
}


} // namespace event
} // namespace widget
} // namespace rack

+ 1
- 1
src/window.cpp View File

@@ -12,10 +12,10 @@

#include <window.hpp>
#include <asset.hpp>
#include <widget/Widget.hpp>
#include <app/Scene.hpp>
#include <keyboard.hpp>
#include <gamepad.hpp>
#include <event.hpp>
#include <context.hpp>
#include <patch.hpp>
#include <settings.hpp>


+ 1
- 1
standalone/main.cpp View File

@@ -183,7 +183,7 @@ int main(int argc, char* argv[]) {
contextSet(new Context);
APP->engine = new engine::Engine;
if (!settings::headless) {
APP->event = new event::State;
APP->event = new widget::EventState;
APP->history = new history::State;
APP->window = new Window;
APP->scene = new app::Scene;


Loading…
Cancel
Save