// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2026 Martino Ferrari #pragma once #include namespace plot::input { /// Mouse buttons a host can report. The controller never assumes a fixed /// mapping: right-drag pans as well as left, for hosts that reserve left-drag. enum class Button { Left, Middle, Right }; /// Keyboard modifier bits for `PointerEvent::mods` / `WheelEvent::mods`. enum class Mod { None = 0, Shift = 1, Ctrl = 2, Alt = 4, Super = 8 }; /// True when `mods` holds `m`. The single place modifier bits are tested, so a /// call site never hand-rolls a mask. constexpr bool has_mod(u32 mods, Mod m) noexcept { return (mods & static_cast(m)) != 0u; } /// A pointer event in viewport pixels (origin top-left, the same space as /// `Rect`). `dx`/`dy` are the movement since the previous event; the controller /// reads them for panning and the absolute `x`/`y` for anchoring and hit tests. /// `pressed` and `released` are the transitions; `down` is the state after the /// event. A plain move has all three false/true as appropriate (down only). struct PointerEvent { f32 x = 0.0f; f32 y = 0.0f; f32 dx = 0.0f; f32 dy = 0.0f; Button button = Button::Left; u32 mods = 0; bool down = false; ///< the button is held after this event bool pressed = false; ///< a press transition happened on this event bool released = false; ///< a release transition happened on this event /// Host-supplied monotonic seconds (the host's own clock, only differences /// are read). Two presses of the same button within 0.35 s and 4 px are a /// double-click and re-fit every axis. A host that leaves 0 never produces /// one -- the field is optional, not another synchronisation contract. f64 time_s = 0.0; }; /// A pinch/two-finger gesture, in viewport pixels. The toolkit adapters /// translate their native pinch state into one of these per frame of the /// gesture: `scale` is this frame's zoom factor about `(x, y)` (1.0 = no /// change), and `(dx, dy)` the focal point's movement since the previous /// gesture event (a two-finger pan). GLFW has no touch input, so only hosts /// that can deliver one feed this; the controller treats it exactly like the /// equivalent wheel + pointer pair. struct GestureEvent { f32 x = 0.0f; f32 y = 0.0f; f32 scale = 1.0f; f32 dx = 0.0f; f32 dy = 0.0f; }; /// A wheel/scroll event at a pixel position. A positive `dy` (scroll up) zooms /// in; a positive `dx` scrolls right. Only `dy` drives the controller's zoom. struct WheelEvent { f32 x = 0.0f; f32 y = 0.0f; f32 dx = 0.0f; f32 dy = 0.0f; u32 mods = 0; }; /// A key event. `key` is an ASCII codepoint for printable keys; hosts that only /// have scancodes translate them before calling. `down` distinguishes the press /// from the release -- the controller's actions are press-only. struct KeyEvent { int key = 0; u32 mods = 0; bool down = false; }; /// The printable keys the controller reacts to, named so no call site spells a /// bare character literal. `kKeyZoomIn`/`kKeyZoomOut` zoom about the plot centre, /// `kKeyFit` re-fits every axis to its traces. inline constexpr int kKeyZoomIn = '+'; inline constexpr int kKeyZoomOut = '-'; inline constexpr int kKeyFit = 'f'; /// Hosts that report shifted keys uppercase can pass this unchanged. inline constexpr int kKeyFitUpper = 'F'; /// Escape cancels the active drag (pan, box zoom, cursor/region drag): the /// ranges the axes had when the drag began are restored and no box is applied. inline constexpr int kKeyEscape = 27; /// Arrow keys pan: Left/Right move every x axis by 10% of its span per press /// (repeat included), Up/Down move every y axis. Hosts translate their native /// key codes to these, exactly as they do for the ASCII set above. inline constexpr int kKeyLeft = 256; inline constexpr int kKeyRight = 257; inline constexpr int kKeyUp = 258; inline constexpr int kKeyDown = 259; } // namespace plot::input