1#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
10pub struct Sense {
11 pub click: bool,
13 pub drag: bool,
15 pub hover: bool,
17 pub focus: bool,
19}
20
21impl Sense {
23 pub const NONE: Sense = Sense {
25 click: false,
26 drag: false,
27 hover: false,
28 focus: false,
29 };
30
31 pub const HOVER: Sense = Sense {
33 click: false,
34 drag: false,
35 hover: true,
36 focus: false,
37 };
38
39 pub const CLICK: Sense = Sense {
41 click: true,
42 drag: false,
43 hover: true,
44 focus: false,
45 };
46
47 pub const DRAG: Sense = Sense {
49 click: false,
50 drag: true,
51 hover: true,
52 focus: false,
53 };
54
55 pub const CLICK_AND_DRAG: Sense = Sense {
57 click: true,
58 drag: true,
59 hover: true,
60 focus: false,
61 };
62
63 pub const FOCUSABLE: Sense = Sense {
65 click: false,
66 drag: false,
67 hover: true,
68 focus: true,
69 };
70
71 pub const ALL: Sense = Sense {
73 click: true,
74 drag: true,
75 hover: true,
76 focus: true,
77 };
78}
79
80impl Sense {
82 #[inline]
84 pub fn none() -> Self {
85 Self::NONE
86 }
87
88 #[inline]
90 pub fn hover() -> Self {
91 Self::HOVER
92 }
93
94 #[inline]
96 pub fn click() -> Self {
97 Self::CLICK
98 }
99
100 #[inline]
102 pub fn drag() -> Self {
103 Self::DRAG
104 }
105
106 #[inline]
108 pub fn click_and_drag() -> Self {
109 Self::CLICK_AND_DRAG
110 }
111
112 #[inline]
114 pub fn focusable() -> Self {
115 Self::FOCUSABLE
116 }
117
118 #[inline]
120 pub fn all() -> Self {
121 Self::ALL
122 }
123}
124
125impl Sense {
127 #[inline]
129 pub fn union(self, other: Sense) -> Sense {
130 Sense {
131 click: self.click || other.click,
132 drag: self.drag || other.drag,
133 hover: self.hover || other.hover,
134 focus: self.focus || other.focus,
135 }
136 }
137
138 #[inline]
140 pub fn intersection(self, other: Sense) -> Sense {
141 Sense {
142 click: self.click && other.click,
143 drag: self.drag && other.drag,
144 hover: self.hover && other.hover,
145 focus: self.focus && other.focus,
146 }
147 }
148
149 #[inline]
151 pub fn with_click(mut self) -> Self {
152 self.click = true;
153 self.hover = true;
154 self
155 }
156
157 #[inline]
159 pub fn with_drag(mut self) -> Self {
160 self.drag = true;
161 self.hover = true;
162 self
163 }
164
165 #[inline]
167 pub fn with_focus(mut self) -> Self {
168 self.focus = true;
169 self
170 }
171}
172
173impl Sense {
175 #[inline]
177 pub fn interactive(&self) -> bool {
178 self.click || self.drag || self.focus
179 }
180
181 #[inline]
183 pub fn has_click_and_drag(&self) -> bool {
184 self.click && self.drag
185 }
186
187 #[inline]
189 pub fn is_passive(&self) -> bool {
190 !self.click && !self.drag && !self.focus
191 }
192}
193
194impl std::ops::BitOr for Sense {
195 type Output = Sense;
196
197 #[inline]
199 fn bitor(self, rhs: Self) -> Self::Output {
200 self.union(rhs)
201 }
202}
203
204impl std::ops::BitOrAssign for Sense {
205 #[inline]
207 fn bitor_assign(&mut self, rhs: Self) {
208 *self = self.union(rhs);
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn test_predefined_constants() {
218 assert!(!Sense::NONE.click);
219 assert!(!Sense::NONE.drag);
220 assert!(!Sense::NONE.hover);
221 assert!(!Sense::NONE.focus);
222
223 assert!(!Sense::HOVER.click);
224 assert!(Sense::HOVER.hover);
225
226 assert!(Sense::CLICK.click);
227 assert!(!Sense::CLICK.drag);
228 assert!(Sense::CLICK.hover);
229
230 assert!(!Sense::DRAG.click);
231 assert!(Sense::DRAG.drag);
232 assert!(Sense::DRAG.hover);
233
234 assert!(Sense::CLICK_AND_DRAG.click);
235 assert!(Sense::CLICK_AND_DRAG.drag);
236 assert!(Sense::CLICK_AND_DRAG.hover);
237
238 assert!(!Sense::FOCUSABLE.click);
239 assert!(Sense::FOCUSABLE.hover);
240 assert!(Sense::FOCUSABLE.focus);
241
242 assert!(Sense::ALL.click);
243 assert!(Sense::ALL.drag);
244 assert!(Sense::ALL.hover);
245 assert!(Sense::ALL.focus);
246 }
247
248 #[test]
249 fn test_constructor_methods() {
250 assert_eq!(Sense::none(), Sense::NONE);
251 assert_eq!(Sense::hover(), Sense::HOVER);
252 assert_eq!(Sense::click(), Sense::CLICK);
253 assert_eq!(Sense::drag(), Sense::DRAG);
254 assert_eq!(Sense::click_and_drag(), Sense::CLICK_AND_DRAG);
255 assert_eq!(Sense::focusable(), Sense::FOCUSABLE);
256 assert_eq!(Sense::all(), Sense::ALL);
257 }
258
259 #[test]
260 fn test_union() {
261 let click = Sense::click();
262 let drag = Sense::drag();
263 let combined = click.union(drag);
264
265 assert!(combined.click);
266 assert!(combined.drag);
267 assert!(combined.hover);
268 assert!(!combined.focus);
269 assert_eq!(combined, Sense::CLICK_AND_DRAG);
270 }
271
272 #[test]
273 fn test_intersection() {
274 let click_and_drag = Sense::CLICK_AND_DRAG;
275 let click = Sense::click();
276 let common = click_and_drag.intersection(click);
277
278 assert!(common.click);
279 assert!(!common.drag);
280 assert!(common.hover);
281 assert!(!common.focus);
282 }
283
284 #[test]
285 fn test_with_methods() {
286 let sense = Sense::none().with_click();
287 assert!(sense.click);
288 assert!(sense.hover);
289 assert!(!sense.drag);
290
291 let sense = Sense::none().with_drag();
292 assert!(sense.drag);
293 assert!(sense.hover);
294 assert!(!sense.click);
295
296 let sense = Sense::click().with_focus();
297 assert!(sense.click);
298 assert!(sense.focus);
299 assert!(sense.hover);
300
301 let sense = Sense::none().with_click().with_drag().with_focus();
302 assert_eq!(sense, Sense::ALL);
303 }
304
305 #[test]
306 fn test_query_methods() {
307 assert!(Sense::click().interactive());
308 assert!(Sense::drag().interactive());
309 assert!(Sense::focusable().interactive());
310 assert!(!Sense::hover().interactive());
311 assert!(!Sense::none().interactive());
312
313 assert!(Sense::CLICK_AND_DRAG.has_click_and_drag());
314 assert!(Sense::ALL.has_click_and_drag());
315 assert!(!Sense::click().has_click_and_drag());
316 assert!(!Sense::drag().has_click_and_drag());
317
318 assert!(Sense::none().is_passive());
319 assert!(Sense::hover().is_passive());
320 assert!(!Sense::click().is_passive());
321 assert!(!Sense::drag().is_passive());
322 assert!(!Sense::focusable().is_passive());
323 }
324
325 #[test]
326 fn test_bitor_operator() {
327 let combined = Sense::click() | Sense::drag();
328 assert_eq!(combined, Sense::CLICK_AND_DRAG);
329
330 let mut sense = Sense::click();
331 sense |= Sense::drag();
332 assert_eq!(sense, Sense::CLICK_AND_DRAG);
333
334 let complex = Sense::click() | Sense::drag() | Sense::focusable();
335 assert!(complex.click);
336 assert!(complex.drag);
337 assert!(complex.focus);
338 assert!(complex.hover);
339 }
340
341 #[test]
342 fn test_default() {
343 let default_sense = Sense::default();
344 assert_eq!(default_sense, Sense::NONE);
345 }
346
347 #[test]
348 fn test_eq_and_hash() {
349 use std::collections::HashSet;
350
351 let mut set = HashSet::new();
352 set.insert(Sense::click());
353 set.insert(Sense::click());
354 set.insert(Sense::drag());
355
356 assert_eq!(set.len(), 2);
357 assert!(set.contains(&Sense::click()));
358 assert!(set.contains(&Sense::drag()));
359 }
360
361 #[test]
362 fn test_clone_and_copy() {
363 let original = Sense::click();
364 let cloned = original.clone();
365 let copied = original;
366
367 assert_eq!(original, cloned);
368 assert_eq!(original, copied);
369 }
370}