1use std::str::FromStr;
4use std::sync::Arc;
5
6use atomic_refcell::AtomicRefCell;
7use bitflags::bitflags;
8use keyboard_types::{Code, Key, Location, Modifiers};
9use smol_str::SmolStr;
10
11use crate::NodeId;
12
13#[derive(Default)]
14pub struct EventState {
15 cancelled: bool,
16 propagation_stopped: bool,
17 redraw_requested: bool,
18}
19impl EventState {
20 #[inline(always)]
21 pub fn prevent_default(&mut self) {
22 self.cancelled = true;
23 }
24
25 #[inline(always)]
26 pub fn stop_propagation(&mut self) {
27 self.propagation_stopped = true;
28 }
29
30 #[inline(always)]
31 pub fn request_redraw(&mut self) {
32 self.redraw_requested = true;
33 }
34
35 #[inline(always)]
36 pub fn is_cancelled(&self) -> bool {
37 self.cancelled
38 }
39
40 #[inline(always)]
41 pub fn propagation_is_stopped(&self) -> bool {
42 self.propagation_stopped
43 }
44
45 #[inline(always)]
46 pub fn redraw_is_requested(&self) -> bool {
47 self.redraw_requested
48 }
49
50 #[inline]
51 pub fn merge(&self, other: &EventState) -> EventState {
52 EventState {
53 cancelled: self.cancelled | other.cancelled,
54 propagation_stopped: self.propagation_stopped | other.propagation_stopped,
55 redraw_requested: self.redraw_requested | other.redraw_requested,
56 }
57 }
58}
59
60#[derive(Debug, Clone)]
61#[repr(u8)]
62pub enum UiEvent {
63 PointerMove(BlitzPointerEvent),
64 PointerUp(BlitzPointerEvent),
65 PointerDown(BlitzPointerEvent),
66 PointerCancel(BlitzPointerEvent),
67 Wheel(BlitzWheelEvent),
68 KeyUp(BlitzKeyEvent),
69 KeyDown(BlitzKeyEvent),
70 Ime(BlitzImeEvent),
71 AppleStandardKeybinding(SmolStr),
72}
73impl UiEvent {
74 pub fn discriminant(&self) -> u8 {
75 unsafe { *<*const _>::from(self).cast::<u8>() }
80 }
81}
82
83#[derive(Debug, Clone)]
84pub struct DomEvent {
85 pub target: NodeId,
86 pub bubbles: bool,
88 pub cancelable: bool,
90
91 pub data: DomEventData,
92 pub request_redraw: bool,
93}
94
95impl DomEvent {
96 pub fn new(target: NodeId, data: DomEventData) -> Self {
97 Self {
98 target,
99 bubbles: data.bubbles(),
100 cancelable: data.cancelable(),
101 data,
102 request_redraw: false,
103 }
104 }
105
106 pub fn name(&self) -> &'static str {
108 self.data.name()
109 }
110}
111
112#[derive(Copy, Clone, Debug, PartialEq)]
113#[repr(u8)]
114pub enum DomEventKind {
115 PointerMove,
116 PointerDown,
117 PointerUp,
118 PointerCancel,
119 PointerEnter,
120 PointerLeave,
121 PointerOver,
122 PointerOut,
123
124 MouseMove,
125 MouseDown,
126 MouseUp,
127 MouseEnter,
128 MouseLeave,
129 MouseOver,
130 MouseOut,
131
132 TouchStart,
133 TouchMove,
134 TouchEnd,
135 TouchCancel,
136
137 Scroll,
138 Wheel,
139
140 Click,
141 ContextMenu,
142 DoubleClick,
143
144 KeyPress,
145 KeyDown,
146 KeyUp,
147 Input,
148 Ime,
149
150 Focus,
151 Blur,
152 FocusIn,
153 FocusOut,
154
155 Submit,
156
157 AppleStandardKeybinding,
158}
159impl DomEventKind {
160 pub fn discriminant(self) -> u8 {
161 self as u8
162 }
163}
164impl FromStr for DomEventKind {
165 type Err = ();
166 fn from_str(s: &str) -> Result<Self, ()> {
167 match s.trim_start_matches("on") {
168 "pointermove" => Ok(Self::PointerMove),
169 "pointerdown" => Ok(Self::PointerDown),
170 "pointerup" => Ok(Self::PointerUp),
171 "pointercancel" => Ok(Self::PointerCancel),
172 "pointerenter" => Ok(Self::PointerEnter),
173 "pointerleave" => Ok(Self::PointerLeave),
174 "pointerover" => Ok(Self::PointerOver),
175 "pointerout" => Ok(Self::PointerOut),
176
177 "mousemove" => Ok(Self::MouseMove),
178 "mousedown" => Ok(Self::MouseDown),
179 "mouseup" => Ok(Self::MouseUp),
180 "mouseenter" => Ok(Self::MouseEnter),
181 "mouseleave" => Ok(Self::MouseLeave),
182 "mouseover" => Ok(Self::MouseOver),
183 "mouseout" => Ok(Self::MouseOut),
184
185 "touchstart" => Ok(Self::TouchStart),
186 "touchmove" => Ok(Self::TouchMove),
187 "touchend" => Ok(Self::TouchEnd),
188 "touchcancel" => Ok(Self::TouchCancel),
189
190 "scroll" => Ok(Self::Scroll),
191 "wheel" => Ok(Self::Wheel),
192
193 "click" => Ok(Self::Click),
194 "contextmenu" => Ok(Self::ContextMenu),
195 "dblclick" => Ok(Self::DoubleClick),
196
197 "keypress" => Ok(Self::KeyPress),
198 "keydown" => Ok(Self::KeyDown),
199 "keyup" => Ok(Self::KeyUp),
200 "input" => Ok(Self::Input),
201 "composition" => Ok(Self::Ime),
202
203 "focus" => Ok(Self::Focus),
204 "blur" => Ok(Self::Blur),
205 "focusin" => Ok(Self::FocusIn),
206 "focusout" => Ok(Self::FocusOut),
207 _ => Err(()),
208 }
209 }
210}
211
212#[derive(Debug, Clone)]
213#[repr(u8)]
214pub enum DomEventData {
215 PointerMove(BlitzPointerEvent),
216 PointerDown(BlitzPointerEvent),
217 PointerUp(BlitzPointerEvent),
218 PointerCancel(BlitzPointerEvent),
219 PointerEnter(BlitzPointerEvent),
220 PointerLeave(BlitzPointerEvent),
221 PointerOver(BlitzPointerEvent),
222 PointerOut(BlitzPointerEvent),
223
224 MouseMove(BlitzPointerEvent),
225 MouseDown(BlitzPointerEvent),
226 MouseUp(BlitzPointerEvent),
227 MouseEnter(BlitzPointerEvent),
228 MouseLeave(BlitzPointerEvent),
229 MouseOver(BlitzPointerEvent),
230 MouseOut(BlitzPointerEvent),
231
232 TouchStart(BlitzPointerEvent),
233 TouchMove(BlitzPointerEvent),
234 TouchEnd(BlitzPointerEvent),
235 TouchCancel(BlitzPointerEvent),
236
237 Scroll(BlitzScrollEvent),
238 Wheel(BlitzWheelEvent),
239
240 Click(BlitzPointerEvent),
241 ContextMenu(BlitzPointerEvent),
242 DoubleClick(BlitzPointerEvent),
243
244 KeyPress(BlitzKeyEvent),
245 KeyDown(BlitzKeyEvent),
246 KeyUp(BlitzKeyEvent),
247 Input(BlitzInputEvent),
248 Ime(BlitzImeEvent),
249
250 Focus(BlitzFocusEvent),
251 Blur(BlitzFocusEvent),
252 FocusIn(BlitzFocusEvent),
253 FocusOut(BlitzFocusEvent),
254
255 Submit(BlitzSubmitEvent),
263
264 AppleStandardKeybinding(SmolStr),
265}
266impl DomEventData {
267 pub fn discriminant(&self) -> u8 {
268 unsafe { *<*const _>::from(self).cast::<u8>() }
273 }
274}
275
276impl DomEventData {
277 pub fn name(&self) -> &'static str {
278 match self {
279 Self::PointerMove { .. } => "pointermove",
280 Self::PointerDown { .. } => "pointerdown",
281 Self::PointerUp { .. } => "pointerup",
282 Self::PointerCancel { .. } => "pointercancel",
283 Self::PointerEnter { .. } => "pointerenter",
284 Self::PointerLeave { .. } => "pointerleave",
285 Self::PointerOver { .. } => "pointerover",
286 Self::PointerOut { .. } => "pointerout",
287
288 Self::MouseMove { .. } => "mousemove",
289 Self::MouseDown { .. } => "mousedown",
290 Self::MouseUp { .. } => "mouseup",
291 Self::MouseEnter { .. } => "mouseenter",
292 Self::MouseLeave { .. } => "mouseleave",
293 Self::MouseOver { .. } => "mouseover",
294 Self::MouseOut { .. } => "mouseout",
295
296 Self::TouchStart { .. } => "touchstart",
297 Self::TouchMove { .. } => "touchmove",
298 Self::TouchEnd { .. } => "touchend",
299 Self::TouchCancel { .. } => "touchcancel",
300
301 Self::Scroll { .. } => "scroll",
302 Self::Wheel { .. } => "wheel",
303
304 Self::Click { .. } => "click",
305 Self::ContextMenu { .. } => "contextmenu",
306 Self::DoubleClick { .. } => "dblclick",
307
308 Self::KeyPress { .. } => "keypress",
309 Self::KeyDown { .. } => "keydown",
310 Self::KeyUp { .. } => "keyup",
311 Self::Input { .. } => "input",
312 Self::Ime { .. } => "composition",
313
314 Self::Focus { .. } => "focus",
315 Self::Blur { .. } => "blur",
316 Self::FocusIn { .. } => "focusin",
317 Self::FocusOut { .. } => "focusout",
318
319 Self::Submit { .. } => "submit",
320
321 Self::AppleStandardKeybinding { .. } => "applekeybinding",
322 }
323 }
324
325 pub fn kind(&self) -> DomEventKind {
326 match self {
327 Self::PointerMove { .. } => DomEventKind::PointerMove,
328 Self::PointerDown { .. } => DomEventKind::PointerDown,
329 Self::PointerUp { .. } => DomEventKind::PointerUp,
330 Self::PointerCancel { .. } => DomEventKind::PointerCancel,
331 Self::PointerEnter { .. } => DomEventKind::PointerEnter,
332 Self::PointerLeave { .. } => DomEventKind::PointerLeave,
333 Self::PointerOver { .. } => DomEventKind::PointerOver,
334 Self::PointerOut { .. } => DomEventKind::PointerOut,
335
336 Self::MouseMove { .. } => DomEventKind::MouseMove,
337 Self::MouseDown { .. } => DomEventKind::MouseDown,
338 Self::MouseUp { .. } => DomEventKind::MouseUp,
339 Self::MouseEnter { .. } => DomEventKind::MouseEnter,
340 Self::MouseLeave { .. } => DomEventKind::MouseLeave,
341 Self::MouseOver { .. } => DomEventKind::MouseOver,
342 Self::MouseOut { .. } => DomEventKind::MouseOut,
343
344 Self::TouchStart { .. } => DomEventKind::TouchStart,
345 Self::TouchMove { .. } => DomEventKind::TouchMove,
346 Self::TouchEnd { .. } => DomEventKind::TouchEnd,
347 Self::TouchCancel { .. } => DomEventKind::TouchCancel,
348
349 Self::Scroll { .. } => DomEventKind::Scroll,
350 Self::Wheel { .. } => DomEventKind::Wheel,
351
352 Self::Click { .. } => DomEventKind::Click,
353 Self::ContextMenu { .. } => DomEventKind::ContextMenu,
354 Self::DoubleClick { .. } => DomEventKind::DoubleClick,
355
356 Self::KeyPress { .. } => DomEventKind::KeyPress,
357 Self::KeyDown { .. } => DomEventKind::KeyDown,
358 Self::KeyUp { .. } => DomEventKind::KeyUp,
359 Self::Input { .. } => DomEventKind::Input,
360 Self::Ime { .. } => DomEventKind::Ime,
361
362 Self::Focus { .. } => DomEventKind::Focus,
363 Self::Blur { .. } => DomEventKind::Blur,
364 Self::FocusIn { .. } => DomEventKind::FocusIn,
365 Self::FocusOut { .. } => DomEventKind::FocusOut,
366 Self::Submit { .. } => DomEventKind::Submit,
367
368 Self::AppleStandardKeybinding { .. } => DomEventKind::AppleStandardKeybinding,
369 }
370 }
371
372 pub fn cancelable(&self) -> bool {
373 match self {
374 Self::PointerMove { .. } => true,
375 Self::PointerDown { .. } => true,
376 Self::PointerUp { .. } => true,
377 Self::PointerCancel { .. } => false,
378 Self::PointerEnter { .. } => false,
379 Self::PointerLeave { .. } => false,
380 Self::PointerOver { .. } => true,
381 Self::PointerOut { .. } => true,
382
383 Self::MouseMove { .. } => true,
384 Self::MouseDown { .. } => true,
385 Self::MouseUp { .. } => true,
386 Self::MouseEnter { .. } => false,
387 Self::MouseLeave { .. } => false,
388 Self::MouseOver { .. } => true,
389 Self::MouseOut { .. } => true,
390
391 Self::TouchStart { .. } => true,
392 Self::TouchMove { .. } => true,
393 Self::TouchEnd { .. } => true,
394 Self::TouchCancel { .. } => false,
395
396 Self::Scroll { .. } => false,
397 Self::Wheel { .. } => true,
398
399 Self::Click { .. } => true,
400 Self::ContextMenu { .. } => true,
401 Self::DoubleClick { .. } => true,
402
403 Self::KeyDown { .. } => true,
404 Self::KeyUp { .. } => true,
405 Self::KeyPress { .. } => true,
406 Self::Ime { .. } => true,
407 Self::Input { .. } => false,
408
409 Self::Focus { .. } => false,
410 Self::Blur { .. } => false,
411 Self::FocusIn { .. } => false,
412 Self::FocusOut { .. } => false,
413
414 Self::Submit { .. } => true,
418
419 Self::AppleStandardKeybinding { .. } => true,
420 }
421 }
422
423 pub fn bubbles(&self) -> bool {
424 match self {
425 Self::PointerMove { .. } => true,
426 Self::PointerDown { .. } => true,
427 Self::PointerUp { .. } => true,
428 Self::PointerCancel { .. } => true,
429 Self::PointerEnter { .. } => false,
430 Self::PointerLeave { .. } => false,
431 Self::PointerOver { .. } => true,
432 Self::PointerOut { .. } => true,
433
434 Self::MouseMove { .. } => true,
435 Self::MouseDown { .. } => true,
436 Self::MouseUp { .. } => true,
437 Self::MouseEnter { .. } => false,
438 Self::MouseLeave { .. } => false,
439 Self::MouseOver { .. } => true,
440 Self::MouseOut { .. } => true,
441
442 Self::TouchStart { .. } => true,
443 Self::TouchMove { .. } => true,
444 Self::TouchEnd { .. } => true,
445 Self::TouchCancel { .. } => true,
446
447 Self::Scroll { .. } => false,
448 Self::Wheel { .. } => true,
449
450 Self::Click { .. } => true,
451 Self::ContextMenu { .. } => true,
452 Self::DoubleClick { .. } => true,
453
454 Self::KeyDown { .. } => true,
455 Self::KeyUp { .. } => true,
456 Self::KeyPress { .. } => true,
457 Self::Ime { .. } => true,
458 Self::Input { .. } => true,
459
460 Self::Focus { .. } => false,
461 Self::Blur { .. } => false,
462 Self::FocusIn { .. } => true,
463 Self::FocusOut { .. } => true,
464
465 Self::Submit { .. } => true,
467
468 Self::AppleStandardKeybinding { .. } => false,
469 }
470 }
471}
472
473#[derive(Debug, Clone, Copy)]
474pub struct HitResult {
475 pub node_id: NodeId,
477 pub is_text: bool,
479 pub x: f32,
481 pub y: f32,
483}
484
485#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
486pub enum BlitzPointerId {
487 Mouse,
488 Pen,
489 Finger(u64),
490}
491
492#[derive(Copy, Clone, Debug)]
493pub struct PointerCoords {
494 pub page_x: f32,
495 pub page_y: f32,
496 pub screen_x: f32,
497 pub screen_y: f32,
498 pub client_x: f32,
499 pub client_y: f32,
500}
501
502#[derive(Copy, Clone, Debug, Default)]
503pub struct PointerDetails {
504 pub pressure: f64, pub tangential_pressure: f32,
506 pub tilt_x: i8,
507 pub tilt_y: i8,
508 pub twist: u16,
509 pub altitude: f64,
510 pub azimuth: f64,
511}
512
513#[derive(Copy, Clone, Debug, Default)]
514pub struct Point<T> {
515 pub x: T,
516 pub y: T,
517}
518
519#[derive(Clone, Debug)]
520pub struct BlitzPointerEvent {
521 pub id: BlitzPointerId,
522 pub is_primary: bool,
523 pub coords: PointerCoords,
524 pub button: MouseEventButton,
525 pub buttons: MouseEventButtons,
526 pub mods: Modifiers,
527 pub details: PointerDetails,
528 pub element: Point<f32>,
529 pub active_pointers: Arc<AtomicRefCell<Vec<BlitzPointerEvent>>>,
540}
541
542impl BlitzPointerEvent {
543 pub fn at(x: f32, y: f32, buttons: MouseEventButtons) -> Self {
556 Self {
557 id: BlitzPointerId::Mouse,
558 is_primary: true,
559 coords: PointerCoords {
560 page_x: x,
561 page_y: y,
562 screen_x: x,
563 screen_y: y,
564 client_x: x,
565 client_y: y,
566 },
567 button: MouseEventButton::Main,
568 buttons,
569 mods: Modifiers::empty(),
570 details: PointerDetails::default(),
571 element: Point::default(),
572 active_pointers: Default::default(),
573 }
574 }
575
576 #[inline(always)]
577 pub fn is_mouse(&self) -> bool {
578 matches!(self.id, BlitzPointerId::Mouse)
579 }
580 #[inline(always)]
581 pub fn is_pen(&self) -> bool {
582 matches!(self.id, BlitzPointerId::Pen)
583 }
584 #[inline(always)]
585 pub fn is_finger(&self) -> bool {
586 matches!(self.id, BlitzPointerId::Finger(_))
587 }
588
589 #[inline(always)]
590 pub fn page_x(&self) -> f32 {
591 self.coords.page_x
592 }
593 #[inline(always)]
594 pub fn page_y(&self) -> f32 {
595 self.coords.page_y
596 }
597 #[inline(always)]
598 pub fn client_x(&self) -> f32 {
599 self.coords.client_x
600 }
601 #[inline(always)]
602 pub fn client_y(&self) -> f32 {
603 self.coords.client_y
604 }
605 #[inline(always)]
606 pub fn screen_x(&self) -> f32 {
607 self.coords.screen_x
608 }
609 #[inline(always)]
610 pub fn screen_y(&self) -> f32 {
611 self.coords.screen_y
612 }
613
614 #[inline(always)]
615 pub fn element_x(&self) -> f32 {
616 self.element.x
617 }
618 #[inline(always)]
619 pub fn element_y(&self) -> f32 {
620 self.element.y
621 }
622}
623
624#[derive(Clone, Debug)]
625pub enum BlitzWheelDelta {
626 Lines(f64, f64),
627 Pixels(f64, f64),
628}
629
630#[derive(Clone, Debug)]
631pub struct BlitzWheelEvent {
632 pub delta: BlitzWheelDelta,
633 pub coords: PointerCoords,
634 pub buttons: MouseEventButtons,
635 pub mods: Modifiers,
636 pub element: Point<f32>,
637}
638
639impl BlitzWheelEvent {
640 #[inline(always)]
641 pub fn page_x(&self) -> f32 {
642 self.coords.page_x
643 }
644 #[inline(always)]
645 pub fn page_y(&self) -> f32 {
646 self.coords.page_y
647 }
648 #[inline(always)]
649 pub fn client_x(&self) -> f32 {
650 self.coords.client_x
651 }
652 #[inline(always)]
653 pub fn client_y(&self) -> f32 {
654 self.coords.client_y
655 }
656 #[inline(always)]
657 pub fn screen_x(&self) -> f32 {
658 self.coords.screen_x
659 }
660 #[inline(always)]
661 pub fn screen_y(&self) -> f32 {
662 self.coords.screen_y
663 }
664 #[inline(always)]
665 pub fn element_x(&self) -> f32 {
666 self.element.x
667 }
668 #[inline(always)]
669 pub fn element_y(&self) -> f32 {
670 self.element.y
671 }
672}
673
674#[derive(Clone, Debug)]
675pub struct BlitzScrollEvent {
676 pub scroll_top: f64,
677 pub scroll_left: f64,
678 pub scroll_width: i32,
679 pub scroll_height: i32,
680 pub client_width: i32,
681 pub client_height: i32,
682}
683
684bitflags! {
699 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
704 pub struct MouseEventButtons: u8 {
705 const None = 0b0000_0000;
707 const Primary = 0b0000_0001;
709 const Secondary = 0b0000_0010;
711 const Auxiliary = 0b0000_0100;
713 const Fourth = 0b0000_1000;
715 const Fifth = 0b0001_0000;
717 }
718}
719
720impl Default for MouseEventButtons {
721 fn default() -> Self {
722 Self::None
723 }
724}
725
726impl From<MouseEventButton> for MouseEventButtons {
727 fn from(value: MouseEventButton) -> Self {
728 match value {
729 MouseEventButton::Main => Self::Primary,
730 MouseEventButton::Auxiliary => Self::Auxiliary,
731 MouseEventButton::Secondary => Self::Secondary,
732 MouseEventButton::Fourth => Self::Fourth,
733 MouseEventButton::Fifth => Self::Fifth,
734 }
735 }
736}
737
738#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
743pub enum MouseEventButton {
744 #[default]
746 Main = 0,
747 Auxiliary = 1,
749 Secondary = 2,
751 Fourth = 3,
753 Fifth = 4,
755}
756
757#[derive(Copy, Clone, Debug, PartialEq, Eq)]
758pub enum KeyState {
759 Pressed,
760 Released,
761}
762
763impl KeyState {
764 pub fn is_pressed(self) -> bool {
765 matches!(self, Self::Pressed)
766 }
767}
768
769#[derive(Clone, Debug)]
770pub struct BlitzKeyEvent {
771 pub key: Key,
772 pub code: Code,
773 pub modifiers: Modifiers,
774 pub location: Location,
775 pub is_auto_repeating: bool,
776 pub is_composing: bool,
777 pub state: KeyState,
778 pub text: Option<SmolStr>,
779}
780
781#[derive(Clone, Debug)]
782pub struct BlitzInputEvent {
783 pub value: String,
784}
785
786#[derive(Clone, Debug)]
787pub struct BlitzFocusEvent;
788
789#[derive(Clone, Debug)]
795pub struct BlitzSubmitEvent {
796 pub form: u64,
798 pub submitter: u64,
801}
802
803#[derive(Debug, Clone, PartialEq, Eq, Hash)]
805pub enum BlitzImeEvent {
806 Enabled,
812
813 Preedit(String, Option<(usize, usize)>),
821
822 Commit(String),
826
827 DeleteSurrounding {
835 before_bytes: usize,
837 after_bytes: usize,
839 },
840
841 Disabled,
848}