blockworx_paint/interaction.rs
1use blockworx_geom::{Pos2, Vec2};
2
3use crate::TextOutcome;
4
5/// Per-frame input state passed to the canvas drawing closure.
6///
7/// `event` holds the mouse/pointer interaction (if any) with all positions
8/// already converted to world space. The boolean flags fire independently —
9/// a key press and a mouse event can both be set in the same frame.
10#[derive(Clone, PartialEq, Debug)]
11pub struct Interaction {
12 pub event: Option<Event>,
13 /// The primary button's press in progress, present exactly while the
14 /// button is held. Level-triggered, unlike `event`: press-and-hold
15 /// affordances (route-start targets, new-pin markers) read it every frame,
16 /// where the edge events only report the gesture's resolution.
17 pub press: Option<Press>,
18 /// How the in-place editor the tool opened ended, if it did this frame:
19 /// the edited text on a commit or a Tab, or a cancel.
20 pub text: Option<TextOutcome>,
21 /// Escape was pressed while the canvas held keyboard focus. Cancels a
22 /// gesture in progress.
23 pub escape_pressed: bool,
24 /// Delete or Backspace was pressed while the canvas held keyboard focus.
25 pub delete_pressed: bool,
26 /// Shift was held this frame — extends a selection (shift-click / shift-marquee).
27 pub shift: bool,
28}
29
30/// A primary-button press being held, carrying where (world space) it began.
31#[derive(Clone, Copy, PartialEq, Debug)]
32pub struct Press {
33 pub origin: Pos2,
34}
35
36#[derive(Clone, Copy, PartialEq, Debug)]
37pub enum Event {
38 HoverAt(Pos2),
39 DragStarted { pos: Pos2 },
40 Dragging { pos: Pos2, delta: Vec2 },
41 DragStopped { pos: Pos2 },
42 Clicked { pos: Pos2 },
43 DoubleClicked { pos: Pos2 },
44}
45
46/// What a host says about the pointer, before anything is made of it: the
47/// motions and the button edges, in **screen** space, in the order they
48/// happened. Resolving them into an [`Event`] — a click, a drag, a hover —
49/// is the core's, so every host resolves them the same way.
50#[derive(Clone, Copy, PartialEq, Debug, serde::Serialize, serde::Deserialize)]
51pub enum Raw {
52 /// The pointer is over the canvas, here.
53 Moved(Pos2),
54 Down {
55 pos: Pos2,
56 button: Button,
57 },
58 Up {
59 pos: Pos2,
60 button: Button,
61 },
62 /// The pointer left the canvas, or the host lost it: nothing hovers.
63 Gone,
64 /// The host abandoned the gesture in progress — Escape mid-drag, a
65 /// touch the platform cancelled. A drag ends where it stands.
66 Cancelled,
67 /// The host is moving the camera with this pointer this frame, so
68 /// nothing it does is a tool's gesture.
69 Panning,
70}
71
72#[derive(Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
73pub enum Button {
74 Primary,
75 Secondary,
76 Middle,
77}
78
79/// The keys a frame carries beside the pointer, as the host read them:
80/// scoped by the host's own focus rules, since which widget holds the
81/// keyboard is the toolkit's to know. Each flag lands on its namesake in
82/// [`Interaction`].
83#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, serde::Serialize, serde::Deserialize)]
84pub struct Keys {
85 pub escape: bool,
86 pub delete: bool,
87 pub shift: bool,
88}
89
90impl Keys {
91 /// Both frames' keys, where two hosts' readings land on one frame.
92 #[must_use]
93 pub fn or(self, other: Keys) -> Keys {
94 Keys {
95 escape: self.escape || other.escape,
96 delete: self.delete || other.delete,
97 shift: self.shift || other.shift,
98 }
99 }
100}
101
102/// Whether the camera is being worked — a drag pan, or a two-finger pan/pinch
103/// in flight.
104///
105/// One answer, two readers, because they are the same question asked twice:
106/// the gesture is consumed by the host, so the active tool must not also read
107/// it as a selection or a move; and the selection overlay hides while it
108/// lasts rather than jittering along behind the object.
109#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
110pub enum Camera {
111 Moving,
112 #[default]
113 Settled,
114}
115
116/// One frame's input as a host states it: the pointer's raw events and
117/// the keys beside them.
118#[derive(Clone, PartialEq, Debug, Default)]
119pub struct Input {
120 pub raw: Vec<Raw>,
121 pub keys: Keys,
122}
123
124/// The keys a chord can name. Not a keyboard: the keys this app actually
125/// binds, so a binding table cannot name one no host knows how to read.
126#[derive(Clone, Copy, PartialEq, Eq, Debug)]
127pub enum Key {
128 Num0,
129 Num1,
130 Num2,
131 Num3,
132 Num4,
133 Num5,
134 Num6,
135 Num7,
136 Num8,
137 B,
138 E,
139 I,
140 K,
141 M,
142 N,
143 P,
144 R,
145 T,
146 Y,
147 Z,
148 Equals,
149 Plus,
150 Minus,
151 ArrowLeft,
152 ArrowRight,
153 ArrowUp,
154 ArrowDown,
155}
156
157/// Which modifiers a chord wants held. Three, because three are bound: none,
158/// the platform command modifier (Ctrl; ⌘ on mac), and that with Shift.
159#[derive(Clone, Copy, PartialEq, Eq, Debug)]
160pub enum Modifiers {
161 None,
162 Command,
163 CommandShift,
164}
165
166/// One key with its modifiers — what a user presses.
167#[derive(Clone, Copy, PartialEq, Eq, Debug)]
168pub struct Chord {
169 pub modifiers: Modifiers,
170 pub key: Key,
171}