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, Copy, Debug, Default, PartialEq, Eq)]
632pub enum BlitzWheelPhase {
633 Started,
634 #[default]
636 Moved,
637 Ended,
638 Cancelled,
639 Momentum,
641}
642
643#[derive(Clone, Debug)]
644pub struct BlitzWheelEvent {
645 pub delta: BlitzWheelDelta,
646 pub phase: BlitzWheelPhase,
648 pub coords: PointerCoords,
649 pub buttons: MouseEventButtons,
650 pub mods: Modifiers,
651 pub element: Point<f32>,
652}
653
654impl BlitzWheelEvent {
655 #[inline(always)]
656 pub fn page_x(&self) -> f32 {
657 self.coords.page_x
658 }
659 #[inline(always)]
660 pub fn page_y(&self) -> f32 {
661 self.coords.page_y
662 }
663 #[inline(always)]
664 pub fn client_x(&self) -> f32 {
665 self.coords.client_x
666 }
667 #[inline(always)]
668 pub fn client_y(&self) -> f32 {
669 self.coords.client_y
670 }
671 #[inline(always)]
672 pub fn screen_x(&self) -> f32 {
673 self.coords.screen_x
674 }
675 #[inline(always)]
676 pub fn screen_y(&self) -> f32 {
677 self.coords.screen_y
678 }
679 #[inline(always)]
680 pub fn element_x(&self) -> f32 {
681 self.element.x
682 }
683 #[inline(always)]
684 pub fn element_y(&self) -> f32 {
685 self.element.y
686 }
687}
688
689#[derive(Clone, Debug)]
690pub struct BlitzScrollEvent {
691 pub scroll_top: f64,
692 pub scroll_left: f64,
693 pub scroll_width: i32,
694 pub scroll_height: i32,
695 pub client_width: i32,
696 pub client_height: i32,
697}
698
699bitflags! {
714 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
719 pub struct MouseEventButtons: u8 {
720 const None = 0b0000_0000;
722 const Primary = 0b0000_0001;
724 const Secondary = 0b0000_0010;
726 const Auxiliary = 0b0000_0100;
728 const Fourth = 0b0000_1000;
730 const Fifth = 0b0001_0000;
732 }
733}
734
735impl Default for MouseEventButtons {
736 fn default() -> Self {
737 Self::None
738 }
739}
740
741impl From<MouseEventButton> for MouseEventButtons {
742 fn from(value: MouseEventButton) -> Self {
743 match value {
744 MouseEventButton::Main => Self::Primary,
745 MouseEventButton::Auxiliary => Self::Auxiliary,
746 MouseEventButton::Secondary => Self::Secondary,
747 MouseEventButton::Fourth => Self::Fourth,
748 MouseEventButton::Fifth => Self::Fifth,
749 }
750 }
751}
752
753#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
758pub enum MouseEventButton {
759 #[default]
761 Main = 0,
762 Auxiliary = 1,
764 Secondary = 2,
766 Fourth = 3,
768 Fifth = 4,
770}
771
772#[derive(Copy, Clone, Debug, PartialEq, Eq)]
773pub enum KeyState {
774 Pressed,
775 Released,
776}
777
778impl KeyState {
779 pub fn is_pressed(self) -> bool {
780 matches!(self, Self::Pressed)
781 }
782}
783
784#[derive(Clone, Debug)]
785pub struct BlitzKeyEvent {
786 pub key: Key,
787 pub code: Code,
788 pub modifiers: Modifiers,
789 pub location: Location,
790 pub is_auto_repeating: bool,
791 pub is_composing: bool,
792 pub state: KeyState,
793 pub text: Option<SmolStr>,
794}
795
796#[derive(Clone, Debug)]
797pub struct BlitzInputEvent {
798 pub value: String,
799}
800
801#[derive(Clone, Debug)]
802pub struct BlitzFocusEvent {
803 pub related_target: Option<NodeId>,
804}
805
806#[allow(non_upper_case_globals)]
808pub const BlitzFocusEvent: BlitzFocusEvent = BlitzFocusEvent {
809 related_target: None,
810};
811
812#[derive(Clone, Debug)]
818pub struct BlitzSubmitEvent {
819 pub form: u64,
821 pub submitter: u64,
824}
825
826#[derive(Debug, Clone, PartialEq, Eq, Hash)]
828pub enum BlitzImeEvent {
829 Enabled,
835
836 Preedit(String, Option<(usize, usize)>),
844
845 Commit(String),
849
850 DeleteSurrounding {
858 before_bytes: usize,
860 after_bytes: usize,
862 },
863
864 Disabled,
871}