Skip to main content

oo_ide/input/
mouse_event.rs

1use crate::input::Modifiers;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub struct MouseEvent {
5    pub kind: MouseEventKind,
6    pub column: u16,
7    pub row: u16,
8    pub modifiers: Modifiers,
9}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum MouseEventKind {
13    Down(MouseButton),
14    Up(MouseButton),
15    Drag(MouseButton),
16    Moved,
17    ScrollUp,
18    ScrollDown,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum MouseButton {
23    Left,
24    Right,
25    Middle,
26}
27
28impl TryFrom<crossterm::event::MouseButton> for MouseButton {
29    type Error = ();
30
31    fn try_from(b: crossterm::event::MouseButton) -> Result<Self, ()> {
32        match b {
33            crossterm::event::MouseButton::Left => Ok(MouseButton::Left),
34            crossterm::event::MouseButton::Right => Ok(MouseButton::Right),
35            crossterm::event::MouseButton::Middle => Ok(MouseButton::Middle),
36        }
37    }
38}
39
40impl TryFrom<crossterm::event::MouseEventKind> for MouseEventKind {
41    type Error = ();
42
43    fn try_from(k: crossterm::event::MouseEventKind) -> Result<Self, ()> {
44        use crossterm::event::MouseEventKind as Ck;
45        match k {
46            Ck::Down(b) => Ok(MouseEventKind::Down(b.try_into()?)),
47            Ck::Up(b) => Ok(MouseEventKind::Up(b.try_into()?)),
48            Ck::Drag(b) => Ok(MouseEventKind::Drag(b.try_into()?)),
49            Ck::Moved => Ok(MouseEventKind::Moved),
50            Ck::ScrollUp => Ok(MouseEventKind::ScrollUp),
51            Ck::ScrollDown => Ok(MouseEventKind::ScrollDown),
52            _ => Err(()),
53        }
54    }
55}
56
57impl TryFrom<crossterm::event::MouseEvent> for MouseEvent {
58    type Error = ();
59
60    fn try_from(m: crossterm::event::MouseEvent) -> Result<Self, ()> {
61        Ok(MouseEvent {
62            kind: m.kind.try_into()?,
63            column: m.column,
64            row: m.row,
65            modifiers: m.modifiers.into(),
66        })
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    use crossterm::event as ct;
74
75    // --- MouseButton ---
76    #[test]
77    fn button_left() {
78        assert_eq!(
79            MouseButton::try_from(ct::MouseButton::Left),
80            Ok(MouseButton::Left)
81        );
82    }
83
84    #[test]
85    fn button_right() {
86        assert_eq!(
87            MouseButton::try_from(ct::MouseButton::Right),
88            Ok(MouseButton::Right)
89        );
90    }
91
92    #[test]
93    fn button_middle() {
94        assert_eq!(
95            MouseButton::try_from(ct::MouseButton::Middle),
96            Ok(MouseButton::Middle)
97        );
98    }
99
100    // --- MouseEventKind ---
101    #[test]
102    fn kind_down_left() {
103        assert_eq!(
104            MouseEventKind::try_from(ct::MouseEventKind::Down(ct::MouseButton::Left)),
105            Ok(MouseEventKind::Down(MouseButton::Left))
106        );
107    }
108
109    #[test]
110    fn kind_up_right() {
111        assert_eq!(
112            MouseEventKind::try_from(ct::MouseEventKind::Up(ct::MouseButton::Right)),
113            Ok(MouseEventKind::Up(MouseButton::Right))
114        );
115    }
116
117    #[test]
118    fn kind_drag_middle() {
119        assert_eq!(
120            MouseEventKind::try_from(ct::MouseEventKind::Drag(ct::MouseButton::Middle)),
121            Ok(MouseEventKind::Drag(MouseButton::Middle))
122        );
123    }
124
125    #[test]
126    fn kind_moved() {
127        assert_eq!(
128            MouseEventKind::try_from(ct::MouseEventKind::Moved),
129            Ok(MouseEventKind::Moved)
130        );
131    }
132
133    #[test]
134    fn kind_scroll_up() {
135        assert_eq!(
136            MouseEventKind::try_from(ct::MouseEventKind::ScrollUp),
137            Ok(MouseEventKind::ScrollUp)
138        );
139    }
140
141    #[test]
142    fn kind_scroll_down() {
143        assert_eq!(
144            MouseEventKind::try_from(ct::MouseEventKind::ScrollDown),
145            Ok(MouseEventKind::ScrollDown)
146        );
147    }
148
149    // Fallback arm — ScrollLeft is present in crossterm ≥0.27
150    #[test]
151    fn kind_scroll_left_is_err() {
152        assert!(
153            MouseEventKind::try_from(ct::MouseEventKind::ScrollLeft).is_err()
154        );
155    }
156
157    // --- MouseEvent (full round-trip) ---
158    fn make_ct_event(
159        kind: ct::MouseEventKind,
160        col: u16,
161        row: u16,
162        mods: ct::KeyModifiers,
163    ) -> ct::MouseEvent {
164        ct::MouseEvent {
165            kind,
166            column: col,
167            row,
168            modifiers: mods,
169        }
170    }
171
172    #[test]
173    fn mouse_event_success() {
174        let ev = MouseEvent::try_from(make_ct_event(
175            ct::MouseEventKind::Down(ct::MouseButton::Left),
176            10,
177            5,
178            ct::KeyModifiers::empty(),
179        ))
180        .unwrap();
181        assert_eq!(ev.kind, MouseEventKind::Down(MouseButton::Left));
182        assert_eq!(ev.column, 10);
183        assert_eq!(ev.row, 5);
184        assert!(ev.modifiers.is_empty());
185    }
186
187    #[test]
188    fn mouse_event_with_ctrl_modifier() {
189        let ev = MouseEvent::try_from(make_ct_event(
190            ct::MouseEventKind::ScrollUp,
191            0,
192            0,
193            ct::KeyModifiers::CONTROL,
194        ))
195        .unwrap();
196        assert!(ev.modifiers.contains(Modifiers::CTRL));
197    }
198
199    #[test]
200    fn mouse_event_unknown_kind_is_err() {
201        assert!(MouseEvent::try_from(make_ct_event(
202            ct::MouseEventKind::ScrollLeft,
203            0,
204            0,
205            ct::KeyModifiers::empty(),
206        ))
207        .is_err());
208    }
209
210    // --- Derived trait smoke tests ---
211    #[test]
212    fn mouse_event_clone_eq() {
213        let ev = MouseEvent {
214            kind: MouseEventKind::Moved,
215            column: 1,
216            row: 2,
217            modifiers: Modifiers::empty(),
218        };
219        assert_eq!(ev.clone(), ev);
220    }
221}