#pragma once #include #include #include #include /** 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 "Cmd" #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; } 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& paths) : paths(paths) {} /** List of file paths in the dropped selection */ const std::vector& 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 after the zoom level of a Widget is changed. Recurses. */ struct Zoom : 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 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& paths); bool handleZoom(); }; } // namespace event } // namespace rack