1#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9pub enum MouseButton {
10 Left,
12 Right,
14 Middle,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
21pub enum MouseEventKind {
22 Down(MouseButton),
24 Up(MouseButton),
26 Drag(MouseButton),
28 Moved,
30 ScrollDown,
32 ScrollUp,
34 ScrollLeft,
36 ScrollRight,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
42#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
43pub struct MouseEvent {
44 pub kind: MouseEventKind,
46 pub column: u16,
48 pub row: u16,
50}
51
52impl MouseEvent {
53 #[must_use]
55 pub const fn new(kind: MouseEventKind, column: u16, row: u16) -> Self {
56 Self { kind, column, row }
57 }
58
59 #[must_use]
61 pub const fn is_click_at(&self, column: u16, row: u16) -> bool {
62 matches!(self.kind, MouseEventKind::Down(_)) && self.column == column && self.row == row
63 }
64
65 #[must_use]
67 pub fn is_click_in(&self, area: crate::geometry::Rect) -> bool {
68 matches!(self.kind, MouseEventKind::Down(_))
69 && self.column >= area.left()
70 && self.column < area.right()
71 && self.row >= area.top()
72 && self.row < area.bottom()
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
78#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
79pub struct KeyModifiers {
80 pub shift: bool,
82 pub ctrl: bool,
84 pub alt: bool,
86 pub meta: bool,
88}
89
90impl KeyModifiers {
91 pub const NONE: Self = Self {
93 shift: false,
94 ctrl: false,
95 alt: false,
96 meta: false,
97 };
98
99 pub const SHIFT: Self = Self {
101 shift: true,
102 ctrl: false,
103 alt: false,
104 meta: false,
105 };
106
107 pub const CTRL: Self = Self {
109 shift: false,
110 ctrl: true,
111 alt: false,
112 meta: false,
113 };
114
115 pub const ALT: Self = Self {
117 shift: false,
118 ctrl: false,
119 alt: true,
120 meta: false,
121 };
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127 use crate::geometry::Rect;
128
129 #[test]
130 fn test_mouse_event_click_detection() {
131 let event = MouseEvent::new(MouseEventKind::Down(MouseButton::Left), 5, 10);
132 assert!(event.is_click_at(5, 10));
133 assert!(!event.is_click_at(6, 10));
134 }
135
136 #[test]
137 fn test_mouse_event_area_detection() {
138 let event = MouseEvent::new(MouseEventKind::Down(MouseButton::Left), 5, 10);
139 let area = Rect::new(0, 0, 10, 20);
140 assert!(event.is_click_in(area));
141
142 let outside_area = Rect::new(20, 20, 10, 10);
143 assert!(!event.is_click_in(outside_area));
144 }
145}