term_wm_layout_engine/
mouse_coord.rs1use crate::LayoutRect;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct MousePosition {
11 pub column: i16,
13 pub row: i16,
15 pub space: CoordSpace,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum CoordSpace {
22 Screen,
25}
26
27impl MousePosition {
28 pub fn is_inside(&self, area: LayoutRect) -> bool {
35 self.column >= area.x as i16
36 && self.column < (area.x.saturating_add(i32::from(area.width))) as i16
37 && self.row >= area.y as i16
38 && self.row < (area.y.saturating_add(i32::from(area.height))) as i16
39 }
40
41 pub fn to_local(&self, area: LayoutRect) -> Option<(u16, u16)> {
50 if !self.is_inside(area) {
51 return None;
52 }
53 let local_col = self.column.saturating_sub(area.x as i16);
54 let local_row = self.row.saturating_sub(area.y as i16);
55 Some((local_col as u16, local_row as u16))
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn is_inside_returns_true_for_contained_point() {
67 let area = LayoutRect {
68 x: 5,
69 y: 10,
70 width: 20,
71 height: 30,
72 };
73 let pos = MousePosition {
74 column: 10,
75 row: 15,
76 space: CoordSpace::Screen,
77 };
78 assert!(pos.is_inside(area));
79 }
80
81 #[test]
82 fn is_inside_returns_false_for_outside_point() {
83 let area = LayoutRect {
84 x: 5,
85 y: 10,
86 width: 20,
87 height: 30,
88 };
89 let pos = MousePosition {
90 column: 100,
91 row: 100,
92 space: CoordSpace::Screen,
93 };
94 assert!(!pos.is_inside(area));
95 }
96
97 #[test]
98 fn is_inside_handles_edge_boundary() {
99 let area = LayoutRect {
100 x: 5,
101 y: 10,
102 width: 20,
103 height: 30,
104 };
105 let pos = MousePosition {
107 column: 5,
108 row: 10,
109 space: CoordSpace::Screen,
110 };
111 assert!(pos.is_inside(area));
112 let pos = MousePosition {
114 column: 25,
115 row: 10,
116 space: CoordSpace::Screen,
117 };
118 assert!(!pos.is_inside(area));
119 let pos = MousePosition {
121 column: 5,
122 row: 40,
123 space: CoordSpace::Screen,
124 };
125 assert!(!pos.is_inside(area));
126 }
127
128 #[test]
129 fn to_local_returns_correct_offset() {
130 let area = LayoutRect {
131 x: 10,
132 y: 20,
133 width: 50,
134 height: 60,
135 };
136 let pos = MousePosition {
137 column: 25,
138 row: 35,
139 space: CoordSpace::Screen,
140 };
141 let local = pos.to_local(area).unwrap();
142 assert_eq!(local, (15, 15));
143 }
144
145 #[test]
146 fn to_local_returns_none_when_outside() {
147 let area = LayoutRect {
148 x: 10,
149 y: 20,
150 width: 50,
151 height: 60,
152 };
153 let pos = MousePosition {
154 column: 5,
155 row: 35,
156 space: CoordSpace::Screen,
157 };
158 assert!(pos.to_local(area).is_none());
159 }
160
161 #[test]
162 fn negative_coordinates_dont_underflow() {
163 let area = LayoutRect {
164 x: 10,
165 y: 20,
166 width: 50,
167 height: 60,
168 };
169 let pos = MousePosition {
170 column: -5,
171 row: -10,
172 space: CoordSpace::Screen,
173 };
174 assert!(!pos.is_inside(area));
175 assert!(pos.to_local(area).is_none());
176 }
177}