1use std::{collections::HashMap, ops::Range, path::PathBuf};
2
3use super::{
4 normalized_f32_bits, AnimProperty, AnimationRegistry, EventPolicy, HitResult, HostTree, Point,
5 UiId,
6};
7
8pub use keyboard_types::{
9 Code as PhysicalKey, Key as LogicalKey, KeyState, KeyboardEvent, Location as KeyLocation,
10 Modifiers as KeyModifiers, NamedKey,
11};
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub enum PointerButton {
15 Left,
16 Right,
17 Middle,
18 Back,
19 Forward,
20 Other(u16),
21}
22
23#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
24pub struct PointerId(pub u64);
25
26#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
27pub enum PointerKind {
28 #[default]
29 Mouse,
30 Touch,
31 Pen,
32 Unknown,
33}
34
35#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36pub struct PointerData {
37 pub id: PointerId,
38 pub kind: PointerKind,
39 pub point: Point,
40 pub pressure: Option<u16>,
41 pub primary: bool,
42}
43
44impl PointerData {
45 pub const fn mouse(point: Point) -> Self {
46 Self {
47 id: PointerId(0),
48 kind: PointerKind::Mouse,
49 point,
50 pressure: None,
51 primary: true,
52 }
53 }
54}
55
56#[derive(Clone, Copy, Debug, PartialEq, Eq)]
57pub enum TouchPhase {
58 Started,
59 Moved,
60 Ended,
61 Cancelled,
62}
63
64#[derive(Clone, Copy, Debug, PartialEq, Eq)]
65pub enum WheelUnit {
66 Lines,
67 Pixels,
68}
69
70#[derive(Clone, Copy, Debug)]
71pub struct WheelDelta {
72 pub x: f32,
73 pub y: f32,
74 pub unit: WheelUnit,
75 pub phase: TouchPhase,
76}
77
78impl PartialEq for WheelDelta {
79 fn eq(&self, other: &Self) -> bool {
80 normalized_f32_bits(self.x) == normalized_f32_bits(other.x)
81 && normalized_f32_bits(self.y) == normalized_f32_bits(other.y)
82 && self.unit == other.unit
83 && self.phase == other.phase
84 }
85}
86
87impl Eq for WheelDelta {}
88
89impl WheelDelta {
90 pub const fn lines(x: f32, y: f32) -> Self {
91 Self {
92 x,
93 y,
94 unit: WheelUnit::Lines,
95 phase: TouchPhase::Moved,
96 }
97 }
98
99 pub const fn pixels(x: f32, y: f32) -> Self {
100 Self {
101 x,
102 y,
103 unit: WheelUnit::Pixels,
104 phase: TouchPhase::Moved,
105 }
106 }
107}
108
109#[derive(Clone, Debug, PartialEq)]
110pub enum InputEvent {
111 PointerMove(PointerData),
112 PointerDown {
113 pointer: PointerData,
114 button: PointerButton,
115 },
116 PointerUp {
117 pointer: PointerData,
118 button: PointerButton,
119 },
120 PointerEnter(PointerData),
121 Wheel {
122 point: Point,
123 delta: WheelDelta,
124 },
125 TextInput(String),
126 Ime(ImeEvent),
127 Keyboard(KeyboardEvent),
128 PointerLeave(PointerData),
129 Touch {
130 pointer: PointerData,
131 phase: TouchPhase,
132 },
133 Platform(PlatformEvent),
134 Semantic(SemanticInput),
135}
136
137#[derive(Clone, Debug, PartialEq)]
138pub enum SemanticInput {
139 Click(UiId),
140 Focus(UiId),
141 Blur(UiId),
142 SetValue {
143 target: UiId,
144 value: String,
145 },
146 Action {
147 target: UiId,
148 action: super::SemanticAction,
149 },
150}
151
152#[derive(Clone, Copy, Debug, PartialEq, Eq)]
153pub enum PlatformTheme {
154 Light,
155 Dark,
156}
157
158#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
159pub struct WindowStateEvent {
160 pub focused: bool,
161 pub minimized: bool,
162 pub maximized: bool,
163 pub fullscreen: bool,
164}
165
166#[derive(Clone, Debug, PartialEq)]
167pub enum PlatformEvent {
168 Focused(bool),
169 FileHovered(PathBuf),
170 FileDropped(PathBuf),
171 FileHoverCancelled,
172 ScaleFactorChanged(f64),
173 ThemeChanged(PlatformTheme),
174 WindowStateChanged(WindowStateEvent),
175}
176
177#[derive(Clone, Debug, PartialEq, Eq)]
178pub enum ImeEvent {
179 Enabled,
180 Preedit {
181 text: String,
182 cursor: Option<Range<usize>>,
183 },
184 Commit(String),
185 Disabled,
186}
187
188#[derive(Clone, Debug, PartialEq, Eq)]
189pub enum UiEvent {
190 HoverChanged {
191 previous: Option<UiId>,
192 current: Option<HitResult>,
193 },
194 PressedChanged {
195 previous: Option<UiId>,
196 current: Option<HitResult>,
197 },
198 Clicked(HitResult),
199 Wheel {
200 hit: HitResult,
201 delta: WheelDelta,
202 },
203 TextInput {
204 target: UiId,
205 text: String,
206 },
207 ImeStarted {
208 target: UiId,
209 },
210 ImeUpdated {
211 target: UiId,
212 text: String,
213 cursor: Option<Range<usize>>,
214 },
215 ImeEnded {
216 target: UiId,
217 },
218 Keyboard {
219 target: UiId,
220 event: KeyboardEvent,
221 },
222 PointerPressed {
223 hit: HitResult,
224 pointer: PointerData,
225 },
226 PointerMoved {
227 hit: HitResult,
228 pointer: PointerData,
229 },
230 PointerDragged {
231 hit: HitResult,
232 pointer: PointerData,
233 },
234 PointerReleased {
235 hit: HitResult,
236 pointer: PointerData,
237 },
238 FocusChanged {
239 previous: Option<UiId>,
240 current: Option<HitResult>,
241 },
242 PointerLeft {
243 previous: Option<UiId>,
244 },
245 SemanticValue {
246 target: UiId,
247 value: String,
248 },
249 SemanticAction {
250 target: UiId,
251 action: super::SemanticAction,
252 },
253}
254
255#[derive(Clone, Debug, Default, PartialEq, Eq)]
256pub struct UiInteractionState {
257 pub hovered: Option<UiId>,
258 pub pressed: Option<UiId>,
259 pub focused: Option<UiId>,
260}
261
262impl UiInteractionState {
263 pub fn flags_for(&self, id: &UiId) -> InteractionFlags {
264 InteractionFlags {
265 hovered: self.hovered.as_ref() == Some(id),
266 pressed: self.pressed.as_ref() == Some(id),
267 focused: self.focused.as_ref() == Some(id),
268 }
269 }
270}
271
272#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
273pub struct InteractionFlags {
274 pub hovered: bool,
275 pub pressed: bool,
276 pub focused: bool,
277}
278
279mod animation;
280mod dispatcher;
281
282pub use animation::apply_events_to_animations;
283pub use dispatcher::UiEventDispatcher;
284
285#[cfg(test)]
286#[path = "event_test.rs"]
287mod tests;