retroglyph_core/event/
mouse.rs1use super::key::KeyModifiers;
4use crate::grid::Pos;
5
6pub type PhysicalPos = ixy::Pos<u32>;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[non_exhaustive]
16pub enum MouseButton {
18 Left,
20 Right,
22 Middle,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
28#[non_exhaustive]
29pub enum MouseEventKind {
33 Down(MouseButton),
35 Up(MouseButton),
37 Drag(MouseButton),
39 Moved,
41 Scroll {
48 dx: f32,
50 dy: f32,
52 },
53}
54
55#[derive(Debug, Clone, Copy, PartialEq)]
56#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
57#[non_exhaustive]
58pub struct MouseEvent {
63 pub kind: MouseEventKind,
65 pub position: Pos,
67 pub pixel_position: Option<PhysicalPos>,
72 pub modifiers: KeyModifiers,
74}
75
76impl MouseEvent {
77 #[must_use]
79 pub const fn new(kind: MouseEventKind, position: Pos, modifiers: KeyModifiers) -> Self {
80 Self {
81 kind,
82 position,
83 pixel_position: None,
84 modifiers,
85 }
86 }
87
88 #[must_use]
91 pub const fn with_pixel_position(
92 kind: MouseEventKind,
93 position: Pos,
94 modifiers: KeyModifiers,
95 pixel_position: PhysicalPos,
96 ) -> Self {
97 Self {
98 kind,
99 position,
100 pixel_position: Some(pixel_position),
101 modifiers,
102 }
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::super::Event;
109 use super::*;
110
111 #[test]
112 fn test_mouse_event_no_pixel_position() {
113 let mouse_event = MouseEvent {
114 kind: MouseEventKind::Down(MouseButton::Left),
115 position: Pos { x: 10, y: 5 },
116 pixel_position: None,
117 modifiers: KeyModifiers::NONE,
118 };
119 assert!(mouse_event.pixel_position.is_none());
120 assert!(matches!(Event::Mouse(mouse_event), Event::Mouse(_)));
121 }
122
123 #[test]
124 fn test_mouse_event_with_pixel_position() {
125 let mouse_event = MouseEvent {
126 kind: MouseEventKind::Moved,
127 position: Pos { x: 3, y: 2 },
128 pixel_position: Some(PhysicalPos { x: 55, y: 38 }),
129 modifiers: KeyModifiers::NONE,
130 };
131 let px = mouse_event.pixel_position.unwrap();
132 assert_eq!(px.x, 55);
133 assert_eq!(px.y, 38);
134 assert_ne!(px.x, u32::from(mouse_event.position.x));
136 }
137
138 #[test]
139 fn test_mouse_event_new_has_no_pixel_position() {
140 let mouse_event = MouseEvent::new(
141 MouseEventKind::Down(MouseButton::Left),
142 Pos { x: 10, y: 5 },
143 KeyModifiers::NONE,
144 );
145 assert_eq!(mouse_event.kind, MouseEventKind::Down(MouseButton::Left));
146 assert_eq!(mouse_event.position, Pos { x: 10, y: 5 });
147 assert!(mouse_event.pixel_position.is_none());
148 }
149
150 #[test]
151 fn test_mouse_event_with_pixel_position_constructor() {
152 let mouse_event = MouseEvent::with_pixel_position(
153 MouseEventKind::Moved,
154 Pos { x: 3, y: 2 },
155 KeyModifiers::NONE,
156 PhysicalPos { x: 55, y: 38 },
157 );
158 assert_eq!(
159 mouse_event.pixel_position,
160 Some(PhysicalPos { x: 55, y: 38 })
161 );
162 }
163
164 #[cfg(feature = "serde")]
165 #[test]
166 fn mouse_event_round_trips_through_serde_json() {
167 let mouse_event = MouseEvent::with_pixel_position(
168 MouseEventKind::Scroll { dx: 1.0, dy: -2.5 },
169 Pos { x: 3, y: 2 },
170 KeyModifiers::CONTROL,
171 PhysicalPos { x: 55, y: 38 },
172 );
173 let json = serde_json::to_string(&mouse_event).expect("serialize");
174 assert_eq!(
175 serde_json::from_str::<MouseEvent>(&json).expect("deserialize"),
176 mouse_event
177 );
178 }
179
180 #[test]
181 fn test_physical_pos_is_copy() {
182 let p = PhysicalPos { x: 10, y: 20 };
183 let q = p; assert_eq!(p, q);
185 }
186}