Skip to main content

presentar_core/
event.rs

1//! Input events for widgets.
2
3use crate::geometry::Point;
4use serde::{Deserialize, Serialize};
5
6/// Input event types.
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub enum Event {
9    /// Mouse moved to position
10    MouseMove {
11        /// New position
12        position: Point,
13    },
14    /// Mouse button pressed
15    MouseDown {
16        /// Position of click
17        position: Point,
18        /// Button pressed
19        button: MouseButton,
20    },
21    /// Mouse button released
22    MouseUp {
23        /// Position of release
24        position: Point,
25        /// Button released
26        button: MouseButton,
27    },
28    /// Mouse wheel scrolled
29    Scroll {
30        /// Horizontal scroll delta
31        delta_x: f32,
32        /// Vertical scroll delta
33        delta_y: f32,
34    },
35    /// Key pressed
36    KeyDown {
37        /// Key pressed
38        key: Key,
39        /// Active modifier keys (Ctrl, Alt, Shift, Meta)
40        #[serde(default)]
41        modifiers: crate::shortcut::Modifiers,
42    },
43    /// Key released
44    KeyUp {
45        /// Key released
46        key: Key,
47        /// Active modifier keys (Ctrl, Alt, Shift, Meta)
48        #[serde(default)]
49        modifiers: crate::shortcut::Modifiers,
50    },
51    /// Text input received
52    TextInput {
53        /// Input text
54        text: String,
55    },
56    /// Widget gained focus
57    FocusIn,
58    /// Widget lost focus
59    FocusOut,
60    /// Mouse entered widget bounds
61    MouseEnter,
62    /// Mouse left widget bounds
63    MouseLeave,
64    /// Window resized
65    Resize {
66        /// New width
67        width: f32,
68        /// New height
69        height: f32,
70    },
71    // Touch events
72    /// Touch started
73    TouchStart {
74        /// Touch identifier
75        id: TouchId,
76        /// Touch position
77        position: Point,
78        /// Touch pressure (0.0 to 1.0)
79        pressure: f32,
80    },
81    /// Touch moved
82    TouchMove {
83        /// Touch identifier
84        id: TouchId,
85        /// New position
86        position: Point,
87        /// Touch pressure
88        pressure: f32,
89    },
90    /// Touch ended
91    TouchEnd {
92        /// Touch identifier
93        id: TouchId,
94        /// Final position
95        position: Point,
96    },
97    /// Touch cancelled (e.g., palm rejection)
98    TouchCancel {
99        /// Touch identifier
100        id: TouchId,
101    },
102    // Pointer events (unified mouse/touch/pen)
103    /// Pointer down
104    PointerDown {
105        /// Pointer ID
106        pointer_id: PointerId,
107        /// Pointer type
108        pointer_type: PointerType,
109        /// Position
110        position: Point,
111        /// Pressure
112        pressure: f32,
113        /// Is primary pointer
114        is_primary: bool,
115        /// Button (for mouse pointers)
116        button: Option<MouseButton>,
117    },
118    /// Pointer moved
119    PointerMove {
120        /// Pointer ID
121        pointer_id: PointerId,
122        /// Pointer type
123        pointer_type: PointerType,
124        /// Position
125        position: Point,
126        /// Pressure
127        pressure: f32,
128        /// Is primary pointer
129        is_primary: bool,
130    },
131    /// Pointer up
132    PointerUp {
133        /// Pointer ID
134        pointer_id: PointerId,
135        /// Pointer type
136        pointer_type: PointerType,
137        /// Position
138        position: Point,
139        /// Is primary pointer
140        is_primary: bool,
141        /// Button (for mouse pointers)
142        button: Option<MouseButton>,
143    },
144    /// Pointer cancelled
145    PointerCancel {
146        /// Pointer ID
147        pointer_id: PointerId,
148    },
149    /// Pointer entered element
150    PointerEnter {
151        /// Pointer ID
152        pointer_id: PointerId,
153        /// Pointer type
154        pointer_type: PointerType,
155    },
156    /// Pointer left element
157    PointerLeave {
158        /// Pointer ID
159        pointer_id: PointerId,
160        /// Pointer type
161        pointer_type: PointerType,
162    },
163    // Gesture events
164    /// Pinch gesture
165    GesturePinch {
166        /// Scale factor
167        scale: f32,
168        /// Center point
169        center: Point,
170        /// Gesture state
171        state: GestureState,
172    },
173    /// Rotate gesture
174    GestureRotate {
175        /// Rotation angle in radians
176        angle: f32,
177        /// Center point
178        center: Point,
179        /// Gesture state
180        state: GestureState,
181    },
182    /// Pan/drag gesture
183    GesturePan {
184        /// Translation delta
185        delta: Point,
186        /// Velocity
187        velocity: Point,
188        /// Gesture state
189        state: GestureState,
190    },
191    /// Long press gesture
192    GestureLongPress {
193        /// Position
194        position: Point,
195    },
196    /// Tap gesture
197    GestureTap {
198        /// Position
199        position: Point,
200        /// Number of taps (1 = single, 2 = double)
201        count: u8,
202    },
203}
204
205/// Touch identifier for multi-touch tracking.
206#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
207pub struct TouchId(pub u32);
208
209/// Pointer identifier for pointer events.
210#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
211pub struct PointerId(pub u32);
212
213/// Type of pointer device.
214#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
215pub enum PointerType {
216    /// Mouse pointer
217    #[default]
218    Mouse,
219    /// Touch pointer
220    Touch,
221    /// Pen/stylus pointer
222    Pen,
223}
224
225/// State of a gesture.
226#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
227pub enum GestureState {
228    /// Gesture started
229    #[default]
230    Started,
231    /// Gesture in progress (changed)
232    Changed,
233    /// Gesture ended
234    Ended,
235    /// Gesture cancelled
236    Cancelled,
237}
238
239/// Mouse button identifiers.
240#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
241pub enum MouseButton {
242    /// Left mouse button
243    Left,
244    /// Right mouse button
245    Right,
246    /// Middle mouse button (wheel click)
247    Middle,
248    /// Additional button 1
249    Button4,
250    /// Additional button 2
251    Button5,
252}
253
254/// Keyboard key identifiers.
255#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
256pub enum Key {
257    // Letters
258    /// A key
259    A,
260    /// B key
261    B,
262    /// C key
263    C,
264    /// D key
265    D,
266    /// E key
267    E,
268    /// F key
269    F,
270    /// G key
271    G,
272    /// H key
273    H,
274    /// I key
275    I,
276    /// J key
277    J,
278    /// K key
279    K,
280    /// L key
281    L,
282    /// M key
283    M,
284    /// N key
285    N,
286    /// O key
287    O,
288    /// P key
289    P,
290    /// Q key
291    Q,
292    /// R key
293    R,
294    /// S key
295    S,
296    /// T key
297    T,
298    /// U key
299    U,
300    /// V key
301    V,
302    /// W key
303    W,
304    /// X key
305    X,
306    /// Y key
307    Y,
308    /// Z key
309    Z,
310
311    // Numbers
312    /// 0 key
313    Num0,
314    /// 1 key
315    Num1,
316    /// 2 key
317    Num2,
318    /// 3 key
319    Num3,
320    /// 4 key
321    Num4,
322    /// 5 key
323    Num5,
324    /// 6 key
325    Num6,
326    /// 7 key
327    Num7,
328    /// 8 key
329    Num8,
330    /// 9 key
331    Num9,
332
333    // Function keys
334    /// F1 key
335    F1,
336    /// F2 key
337    F2,
338    /// F3 key
339    F3,
340    /// F4 key
341    F4,
342    /// F5 key
343    F5,
344    /// F6 key
345    F6,
346    /// F7 key
347    F7,
348    /// F8 key
349    F8,
350    /// F9 key
351    F9,
352    /// F10 key
353    F10,
354    /// F11 key
355    F11,
356    /// F12 key
357    F12,
358
359    // Control keys
360    /// Enter/Return key
361    Enter,
362    /// Escape key
363    Escape,
364    /// Backspace key
365    Backspace,
366    /// Tab key
367    Tab,
368    /// Space key
369    Space,
370    /// Delete key
371    Delete,
372    /// Insert key
373    Insert,
374    /// Home key
375    Home,
376    /// End key
377    End,
378    /// Page Up key
379    PageUp,
380    /// Page Down key
381    PageDown,
382
383    // Arrow keys
384    /// Up arrow
385    Up,
386    /// Down arrow
387    Down,
388    /// Left arrow
389    Left,
390    /// Right arrow
391    Right,
392
393    // Modifiers
394    /// Left Shift
395    ShiftLeft,
396    /// Right Shift
397    ShiftRight,
398    /// Left Control
399    ControlLeft,
400    /// Right Control
401    ControlRight,
402    /// Left Alt
403    AltLeft,
404    /// Right Alt
405    AltRight,
406    /// Left Meta (Windows/Command)
407    MetaLeft,
408    /// Right Meta (Windows/Command)
409    MetaRight,
410
411    // Punctuation
412    /// Minus key
413    Minus,
414    /// Equals key
415    Equal,
416    /// Left bracket
417    BracketLeft,
418    /// Right bracket
419    BracketRight,
420    /// Backslash
421    Backslash,
422    /// Semicolon
423    Semicolon,
424    /// Quote/apostrophe
425    Quote,
426    /// Grave/backtick
427    Grave,
428    /// Comma
429    Comma,
430    /// Period
431    Period,
432    /// Slash
433    Slash,
434}
435
436impl Event {
437    /// Create a key down event with no modifiers.
438    #[must_use]
439    pub const fn key_down(key: Key) -> Self {
440        Self::KeyDown {
441            key,
442            modifiers: crate::shortcut::Modifiers::NONE,
443        }
444    }
445
446    /// Create a key up event with no modifiers.
447    #[must_use]
448    pub const fn key_up(key: Key) -> Self {
449        Self::KeyUp {
450            key,
451            modifiers: crate::shortcut::Modifiers::NONE,
452        }
453    }
454
455    /// Check if this is a mouse event.
456    #[must_use]
457    pub const fn is_mouse(&self) -> bool {
458        matches!(
459            self,
460            Self::MouseMove { .. }
461                | Self::MouseDown { .. }
462                | Self::MouseUp { .. }
463                | Self::MouseEnter
464                | Self::MouseLeave
465        )
466    }
467
468    /// Check if this is a keyboard event.
469    #[must_use]
470    pub const fn is_keyboard(&self) -> bool {
471        matches!(
472            self,
473            Self::KeyDown { .. } | Self::KeyUp { .. } | Self::TextInput { .. }
474        )
475    }
476
477    /// Check if this is a focus event.
478    #[must_use]
479    pub const fn is_focus(&self) -> bool {
480        matches!(self, Self::FocusIn | Self::FocusOut)
481    }
482
483    /// Check if this is a touch event.
484    #[must_use]
485    pub const fn is_touch(&self) -> bool {
486        matches!(
487            self,
488            Self::TouchStart { .. }
489                | Self::TouchMove { .. }
490                | Self::TouchEnd { .. }
491                | Self::TouchCancel { .. }
492        )
493    }
494
495    /// Check if this is a pointer event.
496    #[must_use]
497    pub const fn is_pointer(&self) -> bool {
498        matches!(
499            self,
500            Self::PointerDown { .. }
501                | Self::PointerMove { .. }
502                | Self::PointerUp { .. }
503                | Self::PointerCancel { .. }
504                | Self::PointerEnter { .. }
505                | Self::PointerLeave { .. }
506        )
507    }
508
509    /// Check if this is a gesture event.
510    #[must_use]
511    pub const fn is_gesture(&self) -> bool {
512        matches!(
513            self,
514            Self::GesturePinch { .. }
515                | Self::GestureRotate { .. }
516                | Self::GesturePan { .. }
517                | Self::GestureLongPress { .. }
518                | Self::GestureTap { .. }
519        )
520    }
521
522    /// Get the position if this is a positional event.
523    #[must_use]
524    pub const fn position(&self) -> Option<Point> {
525        match self {
526            Self::MouseMove { position }
527            | Self::MouseDown { position, .. }
528            | Self::MouseUp { position, .. }
529            | Self::TouchStart { position, .. }
530            | Self::TouchMove { position, .. }
531            | Self::TouchEnd { position, .. }
532            | Self::PointerDown { position, .. }
533            | Self::PointerMove { position, .. }
534            | Self::PointerUp { position, .. }
535            | Self::GestureLongPress { position }
536            | Self::GestureTap { position, .. } => Some(*position),
537            Self::GesturePinch { center, .. } | Self::GestureRotate { center, .. } => Some(*center),
538            _ => None,
539        }
540    }
541
542    /// Get the touch ID if this is a touch event.
543    #[must_use]
544    pub const fn touch_id(&self) -> Option<TouchId> {
545        match self {
546            Self::TouchStart { id, .. }
547            | Self::TouchMove { id, .. }
548            | Self::TouchEnd { id, .. }
549            | Self::TouchCancel { id } => Some(*id),
550            _ => None,
551        }
552    }
553
554    /// Get the pointer ID if this is a pointer event.
555    #[must_use]
556    pub const fn pointer_id(&self) -> Option<PointerId> {
557        match self {
558            Self::PointerDown { pointer_id, .. }
559            | Self::PointerMove { pointer_id, .. }
560            | Self::PointerUp { pointer_id, .. }
561            | Self::PointerCancel { pointer_id }
562            | Self::PointerEnter { pointer_id, .. }
563            | Self::PointerLeave { pointer_id, .. } => Some(*pointer_id),
564            _ => None,
565        }
566    }
567
568    /// Get the pointer type if this is a pointer event.
569    #[must_use]
570    pub const fn pointer_type(&self) -> Option<PointerType> {
571        match self {
572            Self::PointerDown { pointer_type, .. }
573            | Self::PointerMove { pointer_type, .. }
574            | Self::PointerUp { pointer_type, .. }
575            | Self::PointerEnter { pointer_type, .. }
576            | Self::PointerLeave { pointer_type, .. } => Some(*pointer_type),
577            _ => None,
578        }
579    }
580
581    /// Get pressure if available (0.0 to 1.0).
582    #[must_use]
583    pub const fn pressure(&self) -> Option<f32> {
584        match self {
585            Self::TouchStart { pressure, .. }
586            | Self::TouchMove { pressure, .. }
587            | Self::PointerDown { pressure, .. }
588            | Self::PointerMove { pressure, .. } => Some(*pressure),
589            _ => None,
590        }
591    }
592
593    /// Get gesture state if this is a gesture event.
594    #[must_use]
595    pub const fn gesture_state(&self) -> Option<GestureState> {
596        match self {
597            Self::GesturePinch { state, .. }
598            | Self::GestureRotate { state, .. }
599            | Self::GesturePan { state, .. } => Some(*state),
600            _ => None,
601        }
602    }
603}
604
605impl TouchId {
606    /// Create a new touch ID.
607    #[must_use]
608    pub const fn new(id: u32) -> Self {
609        Self(id)
610    }
611}
612
613impl PointerId {
614    /// Create a new pointer ID.
615    #[must_use]
616    pub const fn new(id: u32) -> Self {
617        Self(id)
618    }
619}
620
621impl PointerType {
622    /// Check if this is a mouse pointer.
623    #[must_use]
624    pub const fn is_mouse(&self) -> bool {
625        matches!(self, Self::Mouse)
626    }
627
628    /// Check if this is a touch pointer.
629    #[must_use]
630    pub const fn is_touch(&self) -> bool {
631        matches!(self, Self::Touch)
632    }
633
634    /// Check if this is a pen pointer.
635    #[must_use]
636    pub const fn is_pen(&self) -> bool {
637        matches!(self, Self::Pen)
638    }
639}
640
641impl GestureState {
642    /// Check if gesture is starting.
643    #[must_use]
644    pub const fn is_start(&self) -> bool {
645        matches!(self, Self::Started)
646    }
647
648    /// Check if gesture is in progress.
649    #[must_use]
650    pub const fn is_active(&self) -> bool {
651        matches!(self, Self::Started | Self::Changed)
652    }
653
654    /// Check if gesture has ended.
655    #[must_use]
656    pub const fn is_end(&self) -> bool {
657        matches!(self, Self::Ended | Self::Cancelled)
658    }
659}
660
661#[cfg(test)]
662#[allow(clippy::unwrap_used, clippy::disallowed_methods)]
663mod tests {
664    use super::*;
665
666    #[test]
667    fn test_event_is_mouse() {
668        assert!(Event::MouseMove {
669            position: Point::ORIGIN
670        }
671        .is_mouse());
672        assert!(Event::MouseEnter.is_mouse());
673        assert!(!Event::key_down(Key::Enter).is_mouse());
674    }
675
676    #[test]
677    fn test_event_is_keyboard() {
678        assert!(Event::key_down(Key::A).is_keyboard());
679        assert!(Event::TextInput {
680            text: "x".to_string()
681        }
682        .is_keyboard());
683        assert!(!Event::MouseMove {
684            position: Point::ORIGIN
685        }
686        .is_keyboard());
687    }
688
689    #[test]
690    fn test_event_is_focus() {
691        assert!(Event::FocusIn.is_focus());
692        assert!(Event::FocusOut.is_focus());
693        assert!(!Event::key_down(Key::Tab).is_focus());
694    }
695
696    #[test]
697    fn test_event_position() {
698        let pos = Point::new(100.0, 200.0);
699        assert_eq!(Event::MouseMove { position: pos }.position(), Some(pos));
700        assert_eq!(
701            Event::MouseDown {
702                position: pos,
703                button: MouseButton::Left
704            }
705            .position(),
706            Some(pos)
707        );
708        assert_eq!(Event::FocusIn.position(), None);
709    }
710
711    #[test]
712    fn test_event_mouse_up_position() {
713        let pos = Point::new(50.0, 75.0);
714        let event = Event::MouseUp {
715            position: pos,
716            button: MouseButton::Right,
717        };
718        assert_eq!(event.position(), Some(pos));
719        assert!(event.is_mouse());
720    }
721
722    #[test]
723    fn test_event_scroll() {
724        let event = Event::Scroll {
725            delta_x: 10.0,
726            delta_y: -5.0,
727        };
728        assert!(!event.is_mouse());
729        assert!(!event.is_keyboard());
730        assert!(event.position().is_none());
731    }
732
733    #[test]
734    fn test_event_resize() {
735        let event = Event::Resize {
736            width: 800.0,
737            height: 600.0,
738        };
739        assert!(!event.is_mouse());
740        assert!(!event.is_keyboard());
741        assert!(!event.is_focus());
742    }
743
744    #[test]
745    fn test_event_key_up() {
746        let event = Event::key_up(Key::Space);
747        assert!(event.is_keyboard());
748        assert!(!event.is_mouse());
749    }
750
751    #[test]
752    fn test_mouse_button_equality() {
753        assert_eq!(MouseButton::Left, MouseButton::Left);
754        assert_ne!(MouseButton::Left, MouseButton::Right);
755    }
756
757    #[test]
758    fn test_key_equality() {
759        assert_eq!(Key::Enter, Key::Enter);
760        assert_ne!(Key::Enter, Key::Space);
761    }
762
763    #[test]
764    fn test_event_mouse_leave() {
765        let event = Event::MouseLeave;
766        assert!(event.is_mouse());
767        assert!(event.position().is_none());
768    }
769
770    // Touch event tests
771    #[test]
772    fn test_touch_start() {
773        let event = Event::TouchStart {
774            id: TouchId::new(1),
775            position: Point::new(100.0, 200.0),
776            pressure: 0.8,
777        };
778        assert!(event.is_touch());
779        assert!(!event.is_mouse());
780        assert!(!event.is_pointer());
781        assert_eq!(event.touch_id(), Some(TouchId(1)));
782        assert_eq!(event.position(), Some(Point::new(100.0, 200.0)));
783        assert_eq!(event.pressure(), Some(0.8));
784    }
785
786    #[test]
787    fn test_touch_move() {
788        let event = Event::TouchMove {
789            id: TouchId::new(2),
790            position: Point::new(150.0, 250.0),
791            pressure: 0.5,
792        };
793        assert!(event.is_touch());
794        assert_eq!(event.touch_id(), Some(TouchId(2)));
795        assert_eq!(event.position(), Some(Point::new(150.0, 250.0)));
796        assert_eq!(event.pressure(), Some(0.5));
797    }
798
799    #[test]
800    fn test_touch_end() {
801        let event = Event::TouchEnd {
802            id: TouchId::new(3),
803            position: Point::new(200.0, 300.0),
804        };
805        assert!(event.is_touch());
806        assert_eq!(event.touch_id(), Some(TouchId(3)));
807        assert_eq!(event.position(), Some(Point::new(200.0, 300.0)));
808        assert!(event.pressure().is_none());
809    }
810
811    #[test]
812    fn test_touch_cancel() {
813        let event = Event::TouchCancel {
814            id: TouchId::new(4),
815        };
816        assert!(event.is_touch());
817        assert_eq!(event.touch_id(), Some(TouchId(4)));
818        assert!(event.position().is_none());
819    }
820
821    #[test]
822    fn test_touch_id_creation() {
823        let id = TouchId::new(42);
824        assert_eq!(id.0, 42);
825        let default_id = TouchId::default();
826        assert_eq!(default_id.0, 0);
827    }
828
829    // Pointer event tests
830    #[test]
831    fn test_pointer_down() {
832        let event = Event::PointerDown {
833            pointer_id: PointerId::new(1),
834            pointer_type: PointerType::Touch,
835            position: Point::new(100.0, 200.0),
836            pressure: 0.7,
837            is_primary: true,
838            button: None,
839        };
840        assert!(event.is_pointer());
841        assert!(!event.is_touch());
842        assert!(!event.is_mouse());
843        assert_eq!(event.pointer_id(), Some(PointerId(1)));
844        assert_eq!(event.pointer_type(), Some(PointerType::Touch));
845        assert_eq!(event.position(), Some(Point::new(100.0, 200.0)));
846        assert_eq!(event.pressure(), Some(0.7));
847    }
848
849    #[test]
850    fn test_pointer_down_with_mouse_button() {
851        let event = Event::PointerDown {
852            pointer_id: PointerId::new(1),
853            pointer_type: PointerType::Mouse,
854            position: Point::new(50.0, 75.0),
855            pressure: 0.5,
856            is_primary: true,
857            button: Some(MouseButton::Left),
858        };
859        assert!(event.is_pointer());
860        assert_eq!(event.pointer_type(), Some(PointerType::Mouse));
861    }
862
863    #[test]
864    fn test_pointer_move() {
865        let event = Event::PointerMove {
866            pointer_id: PointerId::new(2),
867            pointer_type: PointerType::Pen,
868            position: Point::new(150.0, 250.0),
869            pressure: 0.9,
870            is_primary: false,
871        };
872        assert!(event.is_pointer());
873        assert_eq!(event.pointer_id(), Some(PointerId(2)));
874        assert_eq!(event.pointer_type(), Some(PointerType::Pen));
875        assert_eq!(event.pressure(), Some(0.9));
876    }
877
878    #[test]
879    fn test_pointer_up() {
880        let event = Event::PointerUp {
881            pointer_id: PointerId::new(3),
882            pointer_type: PointerType::Mouse,
883            position: Point::new(200.0, 300.0),
884            is_primary: true,
885            button: Some(MouseButton::Right),
886        };
887        assert!(event.is_pointer());
888        assert_eq!(event.pointer_id(), Some(PointerId(3)));
889        assert!(event.pressure().is_none());
890    }
891
892    #[test]
893    fn test_pointer_cancel() {
894        let event = Event::PointerCancel {
895            pointer_id: PointerId::new(4),
896        };
897        assert!(event.is_pointer());
898        assert_eq!(event.pointer_id(), Some(PointerId(4)));
899        assert!(event.pointer_type().is_none());
900        assert!(event.position().is_none());
901    }
902
903    #[test]
904    fn test_pointer_enter() {
905        let event = Event::PointerEnter {
906            pointer_id: PointerId::new(5),
907            pointer_type: PointerType::Mouse,
908        };
909        assert!(event.is_pointer());
910        assert_eq!(event.pointer_id(), Some(PointerId(5)));
911        assert_eq!(event.pointer_type(), Some(PointerType::Mouse));
912        assert!(event.position().is_none());
913    }
914
915    #[test]
916    fn test_pointer_leave() {
917        let event = Event::PointerLeave {
918            pointer_id: PointerId::new(6),
919            pointer_type: PointerType::Touch,
920        };
921        assert!(event.is_pointer());
922        assert_eq!(event.pointer_id(), Some(PointerId(6)));
923        assert_eq!(event.pointer_type(), Some(PointerType::Touch));
924    }
925
926    #[test]
927    fn test_pointer_id_creation() {
928        let id = PointerId::new(99);
929        assert_eq!(id.0, 99);
930        let default_id = PointerId::default();
931        assert_eq!(default_id.0, 0);
932    }
933
934    #[test]
935    fn test_pointer_type_helpers() {
936        assert!(PointerType::Mouse.is_mouse());
937        assert!(!PointerType::Mouse.is_touch());
938        assert!(!PointerType::Mouse.is_pen());
939
940        assert!(!PointerType::Touch.is_mouse());
941        assert!(PointerType::Touch.is_touch());
942        assert!(!PointerType::Touch.is_pen());
943
944        assert!(!PointerType::Pen.is_mouse());
945        assert!(!PointerType::Pen.is_touch());
946        assert!(PointerType::Pen.is_pen());
947    }
948
949    #[test]
950    fn test_pointer_type_default() {
951        let default = PointerType::default();
952        assert_eq!(default, PointerType::Mouse);
953    }
954
955    // Gesture event tests
956    #[test]
957    fn test_gesture_pinch() {
958        let event = Event::GesturePinch {
959            scale: 1.5,
960            center: Point::new(200.0, 200.0),
961            state: GestureState::Changed,
962        };
963        assert!(event.is_gesture());
964        assert!(!event.is_touch());
965        assert!(!event.is_pointer());
966        assert_eq!(event.gesture_state(), Some(GestureState::Changed));
967        assert_eq!(event.position(), Some(Point::new(200.0, 200.0)));
968    }
969
970    #[test]
971    fn test_gesture_rotate() {
972        let event = Event::GestureRotate {
973            angle: std::f32::consts::PI / 4.0,
974            center: Point::new(150.0, 150.0),
975            state: GestureState::Started,
976        };
977        assert!(event.is_gesture());
978        assert_eq!(event.gesture_state(), Some(GestureState::Started));
979        assert_eq!(event.position(), Some(Point::new(150.0, 150.0)));
980    }
981
982    #[test]
983    fn test_gesture_pan() {
984        let event = Event::GesturePan {
985            delta: Point::new(10.0, -5.0),
986            velocity: Point::new(100.0, -50.0),
987            state: GestureState::Ended,
988        };
989        assert!(event.is_gesture());
990        assert_eq!(event.gesture_state(), Some(GestureState::Ended));
991        assert!(event.position().is_none());
992    }
993
994    #[test]
995    fn test_gesture_long_press() {
996        let event = Event::GestureLongPress {
997            position: Point::new(100.0, 100.0),
998        };
999        assert!(event.is_gesture());
1000        assert_eq!(event.position(), Some(Point::new(100.0, 100.0)));
1001        assert!(event.gesture_state().is_none());
1002    }
1003
1004    #[test]
1005    fn test_gesture_tap() {
1006        let single_tap = Event::GestureTap {
1007            position: Point::new(50.0, 50.0),
1008            count: 1,
1009        };
1010        assert!(single_tap.is_gesture());
1011        assert_eq!(single_tap.position(), Some(Point::new(50.0, 50.0)));
1012
1013        let double_tap = Event::GestureTap {
1014            position: Point::new(50.0, 50.0),
1015            count: 2,
1016        };
1017        assert!(double_tap.is_gesture());
1018    }
1019
1020    #[test]
1021    fn test_gesture_state_helpers() {
1022        assert!(GestureState::Started.is_start());
1023        assert!(GestureState::Started.is_active());
1024        assert!(!GestureState::Started.is_end());
1025
1026        assert!(!GestureState::Changed.is_start());
1027        assert!(GestureState::Changed.is_active());
1028        assert!(!GestureState::Changed.is_end());
1029
1030        assert!(!GestureState::Ended.is_start());
1031        assert!(!GestureState::Ended.is_active());
1032        assert!(GestureState::Ended.is_end());
1033
1034        assert!(!GestureState::Cancelled.is_start());
1035        assert!(!GestureState::Cancelled.is_active());
1036        assert!(GestureState::Cancelled.is_end());
1037    }
1038
1039    #[test]
1040    fn test_gesture_state_default() {
1041        let default = GestureState::default();
1042        assert_eq!(default, GestureState::Started);
1043    }
1044
1045    // Cross-category tests
1046    #[test]
1047    fn test_event_category_exclusivity() {
1048        let touch = Event::TouchStart {
1049            id: TouchId::new(1),
1050            position: Point::ORIGIN,
1051            pressure: 0.5,
1052        };
1053        assert!(touch.is_touch());
1054        assert!(!touch.is_pointer());
1055        assert!(!touch.is_gesture());
1056        assert!(!touch.is_mouse());
1057
1058        let pointer = Event::PointerDown {
1059            pointer_id: PointerId::new(1),
1060            pointer_type: PointerType::Touch,
1061            position: Point::ORIGIN,
1062            pressure: 0.5,
1063            is_primary: true,
1064            button: None,
1065        };
1066        assert!(!pointer.is_touch());
1067        assert!(pointer.is_pointer());
1068        assert!(!pointer.is_gesture());
1069        assert!(!pointer.is_mouse());
1070
1071        let gesture = Event::GesturePinch {
1072            scale: 1.0,
1073            center: Point::ORIGIN,
1074            state: GestureState::Started,
1075        };
1076        assert!(!gesture.is_touch());
1077        assert!(!gesture.is_pointer());
1078        assert!(gesture.is_gesture());
1079        assert!(!gesture.is_mouse());
1080    }
1081
1082    #[test]
1083    fn test_mouse_event_has_no_touch_or_pointer_id() {
1084        let mouse = Event::MouseDown {
1085            position: Point::ORIGIN,
1086            button: MouseButton::Left,
1087        };
1088        assert!(mouse.touch_id().is_none());
1089        assert!(mouse.pointer_id().is_none());
1090        assert!(mouse.pointer_type().is_none());
1091        assert!(mouse.pressure().is_none());
1092        assert!(mouse.gesture_state().is_none());
1093    }
1094
1095    #[test]
1096    fn test_serialization_roundtrip() {
1097        let events = vec![
1098            Event::TouchStart {
1099                id: TouchId::new(1),
1100                position: Point::new(100.0, 200.0),
1101                pressure: 0.8,
1102            },
1103            Event::PointerDown {
1104                pointer_id: PointerId::new(2),
1105                pointer_type: PointerType::Pen,
1106                position: Point::new(50.0, 75.0),
1107                pressure: 0.6,
1108                is_primary: true,
1109                button: None,
1110            },
1111            Event::GesturePinch {
1112                scale: 2.0,
1113                center: Point::new(200.0, 200.0),
1114                state: GestureState::Changed,
1115            },
1116        ];
1117
1118        for event in events {
1119            let json = serde_json::to_string(&event).unwrap();
1120            let deserialized: Event = serde_json::from_str(&json).unwrap();
1121            assert_eq!(event, deserialized);
1122        }
1123    }
1124
1125    // ========== Additional edge case tests ==========
1126
1127    #[test]
1128    fn test_mouse_button_all_variants() {
1129        let buttons = [
1130            MouseButton::Left,
1131            MouseButton::Right,
1132            MouseButton::Middle,
1133            MouseButton::Button4,
1134            MouseButton::Button5,
1135        ];
1136        for button in &buttons {
1137            let event = Event::MouseDown {
1138                position: Point::ORIGIN,
1139                button: *button,
1140            };
1141            assert!(event.is_mouse());
1142        }
1143    }
1144
1145    #[test]
1146    fn test_mouse_button_debug() {
1147        assert_eq!(format!("{:?}", MouseButton::Left), "Left");
1148        assert_eq!(format!("{:?}", MouseButton::Middle), "Middle");
1149    }
1150
1151    #[test]
1152    fn test_key_letters() {
1153        let letters = [
1154            Key::A,
1155            Key::B,
1156            Key::C,
1157            Key::D,
1158            Key::E,
1159            Key::F,
1160            Key::G,
1161            Key::H,
1162            Key::I,
1163            Key::J,
1164            Key::K,
1165            Key::L,
1166            Key::M,
1167            Key::N,
1168            Key::O,
1169            Key::P,
1170            Key::Q,
1171            Key::R,
1172            Key::S,
1173            Key::T,
1174            Key::U,
1175            Key::V,
1176            Key::W,
1177            Key::X,
1178            Key::Y,
1179            Key::Z,
1180        ];
1181        for key in &letters {
1182            let event = Event::key_down(*key);
1183            assert!(event.is_keyboard());
1184        }
1185    }
1186
1187    #[test]
1188    fn test_key_numbers() {
1189        let numbers = [
1190            Key::Num0,
1191            Key::Num1,
1192            Key::Num2,
1193            Key::Num3,
1194            Key::Num4,
1195            Key::Num5,
1196            Key::Num6,
1197            Key::Num7,
1198            Key::Num8,
1199            Key::Num9,
1200        ];
1201        for key in &numbers {
1202            let event = Event::key_down(*key);
1203            assert!(event.is_keyboard());
1204        }
1205    }
1206
1207    #[test]
1208    fn test_key_function_keys() {
1209        let function_keys = [
1210            Key::F1,
1211            Key::F2,
1212            Key::F3,
1213            Key::F4,
1214            Key::F5,
1215            Key::F6,
1216            Key::F7,
1217            Key::F8,
1218            Key::F9,
1219            Key::F10,
1220            Key::F11,
1221            Key::F12,
1222        ];
1223        for key in &function_keys {
1224            let event = Event::key_down(*key);
1225            assert!(event.is_keyboard());
1226        }
1227    }
1228
1229    #[test]
1230    fn test_key_control_keys() {
1231        let control_keys = [
1232            Key::Enter,
1233            Key::Escape,
1234            Key::Backspace,
1235            Key::Tab,
1236            Key::Space,
1237            Key::Delete,
1238            Key::Insert,
1239            Key::Home,
1240            Key::End,
1241            Key::PageUp,
1242            Key::PageDown,
1243        ];
1244        for key in &control_keys {
1245            let event = Event::key_down(*key);
1246            assert!(event.is_keyboard());
1247        }
1248    }
1249
1250    #[test]
1251    fn test_key_arrow_keys() {
1252        let arrows = [Key::Up, Key::Down, Key::Left, Key::Right];
1253        for key in &arrows {
1254            let event = Event::key_down(*key);
1255            assert!(event.is_keyboard());
1256        }
1257    }
1258
1259    #[test]
1260    fn test_key_modifiers() {
1261        let modifiers = [
1262            Key::ShiftLeft,
1263            Key::ShiftRight,
1264            Key::ControlLeft,
1265            Key::ControlRight,
1266            Key::AltLeft,
1267            Key::AltRight,
1268            Key::MetaLeft,
1269            Key::MetaRight,
1270        ];
1271        for key in &modifiers {
1272            let event = Event::key_down(*key);
1273            assert!(event.is_keyboard());
1274        }
1275    }
1276
1277    #[test]
1278    fn test_key_punctuation() {
1279        let punctuation = [
1280            Key::Minus,
1281            Key::Equal,
1282            Key::BracketLeft,
1283            Key::BracketRight,
1284            Key::Backslash,
1285            Key::Semicolon,
1286            Key::Quote,
1287            Key::Grave,
1288            Key::Comma,
1289            Key::Period,
1290            Key::Slash,
1291        ];
1292        for key in &punctuation {
1293            let event = Event::key_down(*key);
1294            assert!(event.is_keyboard());
1295        }
1296    }
1297
1298    #[test]
1299    fn test_key_debug() {
1300        assert_eq!(format!("{:?}", Key::Enter), "Enter");
1301        assert_eq!(format!("{:?}", Key::F1), "F1");
1302    }
1303
1304    #[test]
1305    fn test_touch_id_hash() {
1306        use std::collections::HashSet;
1307        let mut set = HashSet::new();
1308        set.insert(TouchId::new(1));
1309        set.insert(TouchId::new(2));
1310        set.insert(TouchId::new(1)); // Duplicate
1311        assert_eq!(set.len(), 2);
1312    }
1313
1314    #[test]
1315    fn test_pointer_id_hash() {
1316        use std::collections::HashSet;
1317        let mut set = HashSet::new();
1318        set.insert(PointerId::new(1));
1319        set.insert(PointerId::new(2));
1320        set.insert(PointerId::new(1)); // Duplicate
1321        assert_eq!(set.len(), 2);
1322    }
1323
1324    #[test]
1325    fn test_pointer_type_hash() {
1326        use std::collections::HashSet;
1327        let mut set = HashSet::new();
1328        set.insert(PointerType::Mouse);
1329        set.insert(PointerType::Touch);
1330        set.insert(PointerType::Pen);
1331        set.insert(PointerType::Mouse); // Duplicate
1332        assert_eq!(set.len(), 3);
1333    }
1334
1335    #[test]
1336    fn test_gesture_state_hash() {
1337        use std::collections::HashSet;
1338        let mut set = HashSet::new();
1339        set.insert(GestureState::Started);
1340        set.insert(GestureState::Changed);
1341        set.insert(GestureState::Ended);
1342        set.insert(GestureState::Cancelled);
1343        assert_eq!(set.len(), 4);
1344    }
1345
1346    #[test]
1347    fn test_event_debug() {
1348        let event = Event::FocusIn;
1349        let debug = format!("{event:?}");
1350        assert!(debug.contains("FocusIn"));
1351    }
1352
1353    #[test]
1354    fn test_event_clone() {
1355        let event = Event::MouseMove {
1356            position: Point::new(100.0, 200.0),
1357        };
1358        let cloned = event.clone();
1359        assert_eq!(event, cloned);
1360    }
1361
1362    #[test]
1363    fn test_text_input_event() {
1364        let event = Event::TextInput {
1365            text: "Hello, 世界!".to_string(),
1366        };
1367        assert!(event.is_keyboard());
1368        assert!(!event.is_mouse());
1369        assert!(event.position().is_none());
1370    }
1371
1372    #[test]
1373    fn test_scroll_event_deltas() {
1374        let event = Event::Scroll {
1375            delta_x: -10.5,
1376            delta_y: 20.3,
1377        };
1378        assert!(!event.is_mouse());
1379        assert!(!event.is_touch());
1380        assert!(!event.is_pointer());
1381    }
1382
1383    #[test]
1384    fn test_resize_event() {
1385        let event = Event::Resize {
1386            width: 1920.0,
1387            height: 1080.0,
1388        };
1389        assert!(!event.is_mouse());
1390        assert!(event.position().is_none());
1391    }
1392
1393    #[test]
1394    fn test_gesture_pan_no_position() {
1395        let event = Event::GesturePan {
1396            delta: Point::new(50.0, 30.0),
1397            velocity: Point::new(200.0, 150.0),
1398            state: GestureState::Changed,
1399        };
1400        assert!(event.is_gesture());
1401        // GesturePan has delta/velocity, not position
1402        assert!(event.position().is_none());
1403    }
1404
1405    #[test]
1406    fn test_all_event_serialization() {
1407        let events = vec![
1408            Event::MouseMove {
1409                position: Point::new(1.0, 2.0),
1410            },
1411            Event::MouseDown {
1412                position: Point::new(1.0, 2.0),
1413                button: MouseButton::Left,
1414            },
1415            Event::MouseUp {
1416                position: Point::new(1.0, 2.0),
1417                button: MouseButton::Right,
1418            },
1419            Event::Scroll {
1420                delta_x: 1.0,
1421                delta_y: -1.0,
1422            },
1423            Event::key_down(Key::A),
1424            Event::key_up(Key::B),
1425            Event::TextInput {
1426                text: "test".to_string(),
1427            },
1428            Event::FocusIn,
1429            Event::FocusOut,
1430            Event::MouseEnter,
1431            Event::MouseLeave,
1432            Event::Resize {
1433                width: 800.0,
1434                height: 600.0,
1435            },
1436        ];
1437
1438        for event in events {
1439            let json = serde_json::to_string(&event).unwrap();
1440            let deserialized: Event = serde_json::from_str(&json).unwrap();
1441            assert_eq!(event, deserialized);
1442        }
1443    }
1444
1445    #[test]
1446    fn test_touch_events_serialization() {
1447        let events = vec![
1448            Event::TouchStart {
1449                id: TouchId(1),
1450                position: Point::new(10.0, 20.0),
1451                pressure: 0.5,
1452            },
1453            Event::TouchMove {
1454                id: TouchId(1),
1455                position: Point::new(15.0, 25.0),
1456                pressure: 0.6,
1457            },
1458            Event::TouchEnd {
1459                id: TouchId(1),
1460                position: Point::new(20.0, 30.0),
1461            },
1462            Event::TouchCancel { id: TouchId(1) },
1463        ];
1464
1465        for event in events {
1466            let json = serde_json::to_string(&event).unwrap();
1467            let deserialized: Event = serde_json::from_str(&json).unwrap();
1468            assert_eq!(event, deserialized);
1469        }
1470    }
1471
1472    #[test]
1473    fn test_gesture_events_serialization() {
1474        let events = vec![
1475            Event::GesturePinch {
1476                scale: 1.5,
1477                center: Point::new(100.0, 100.0),
1478                state: GestureState::Started,
1479            },
1480            Event::GestureRotate {
1481                angle: 0.5,
1482                center: Point::new(100.0, 100.0),
1483                state: GestureState::Changed,
1484            },
1485            Event::GesturePan {
1486                delta: Point::new(10.0, 5.0),
1487                velocity: Point::new(50.0, 25.0),
1488                state: GestureState::Ended,
1489            },
1490            Event::GestureLongPress {
1491                position: Point::new(50.0, 50.0),
1492            },
1493            Event::GestureTap {
1494                position: Point::new(50.0, 50.0),
1495                count: 2,
1496            },
1497        ];
1498
1499        for event in events {
1500            let json = serde_json::to_string(&event).unwrap();
1501            let deserialized: Event = serde_json::from_str(&json).unwrap();
1502            assert_eq!(event, deserialized);
1503        }
1504    }
1505
1506    #[test]
1507    fn test_pointer_events_serialization() {
1508        let events = vec![
1509            Event::PointerDown {
1510                pointer_id: PointerId(1),
1511                pointer_type: PointerType::Mouse,
1512                position: Point::new(10.0, 20.0),
1513                pressure: 0.5,
1514                is_primary: true,
1515                button: Some(MouseButton::Left),
1516            },
1517            Event::PointerMove {
1518                pointer_id: PointerId(1),
1519                pointer_type: PointerType::Touch,
1520                position: Point::new(15.0, 25.0),
1521                pressure: 0.6,
1522                is_primary: true,
1523            },
1524            Event::PointerUp {
1525                pointer_id: PointerId(1),
1526                pointer_type: PointerType::Pen,
1527                position: Point::new(20.0, 30.0),
1528                is_primary: false,
1529                button: None,
1530            },
1531            Event::PointerCancel {
1532                pointer_id: PointerId(1),
1533            },
1534            Event::PointerEnter {
1535                pointer_id: PointerId(2),
1536                pointer_type: PointerType::Mouse,
1537            },
1538            Event::PointerLeave {
1539                pointer_id: PointerId(2),
1540                pointer_type: PointerType::Touch,
1541            },
1542        ];
1543
1544        for event in events {
1545            let json = serde_json::to_string(&event).unwrap();
1546            let deserialized: Event = serde_json::from_str(&json).unwrap();
1547            assert_eq!(event, deserialized);
1548        }
1549    }
1550
1551    #[test]
1552    fn test_key_hash() {
1553        use std::collections::HashSet;
1554        let mut set = HashSet::new();
1555        set.insert(Key::A);
1556        set.insert(Key::B);
1557        set.insert(Key::A); // Duplicate
1558        assert_eq!(set.len(), 2);
1559    }
1560
1561    #[test]
1562    fn test_mouse_button_hash() {
1563        use std::collections::HashSet;
1564        let mut set = HashSet::new();
1565        set.insert(MouseButton::Left);
1566        set.insert(MouseButton::Right);
1567        set.insert(MouseButton::Left); // Duplicate
1568        assert_eq!(set.len(), 2);
1569    }
1570}