inset_services/mouse_tracking.rs
1//! Flutter counterpart: `services/mouse_tracking.dart`.
2
3use std::fmt;
4
5use inset_gestures::{PointerEnterEventListener, PointerExitEventListener};
6
7use crate::mouse_cursor::{MouseCursor, MouseCursorRef};
8
9/// The annotation object used to annotate regions that are interested in mouse
10/// movements.
11///
12/// To use an annotation, return this object as a `HitTestTarget` in a hit test.
13/// Typically this is done using a `RenderMouseRegion`.
14///
15/// The `MouseTracker` uses this class as a label to filter the hit test results.
16/// Only hit test targets that have this annotation as their target will receive
17/// mouse events.
18///
19/// Dart's constructor takes named optional arguments; write
20/// `MouseTrackerAnnotation { on_enter: Some(..), ..Default::default() }`.
21pub struct MouseTrackerAnnotation {
22 /// Triggered when a mouse pointer, with or without buttons pressed, has
23 /// entered the region and `valid_for_mouse_tracker` is true.
24 ///
25 /// This callback is triggered when the pointer has started to be contained by
26 /// the region, either due to a pointer event, or due to the movement or
27 /// disappearance of the region. This method is always matched by a later
28 /// `on_exit`.
29 pub on_enter: Option<PointerEnterEventListener>,
30
31 /// Triggered when a mouse pointer, with or without buttons pressed, has
32 /// exited the region and `valid_for_mouse_tracker` is true.
33 ///
34 /// This callback is triggered when the pointer has stopped being contained
35 /// by the region, either due to a pointer event, or due to the movement or
36 /// disappearance of the region. This method always matches an earlier
37 /// `on_enter`.
38 pub on_exit: Option<PointerExitEventListener>,
39
40 /// The mouse cursor for mouse pointers that are hovering over the region.
41 ///
42 /// When a mouse enters the region, its cursor will be changed to the `cursor`.
43 /// When the mouse leaves the region, the cursor will be set by the region
44 /// found at the new location.
45 ///
46 /// Defaults to `MouseCursor.defer`, deferring the choice of cursor to the next
47 /// region behind it in hit-test order.
48 pub cursor: MouseCursorRef,
49
50 /// Whether this is included when a `MouseTracker` collects the list of
51 /// annotations.
52 ///
53 /// If [`valid_for_mouse_tracker`](Self::valid_for_mouse_tracker) is false, this
54 /// object is excluded from the current annotation list even if it's included
55 /// in the hit test, affecting mouse-related behavior such as enter events,
56 /// exit events, and mouse cursors. The [`valid_for_mouse_tracker`] does not
57 /// affect hit testing.
58 ///
59 /// Defaults to true.
60 ///
61 /// [`valid_for_mouse_tracker`]: Self::valid_for_mouse_tracker
62 pub valid_for_mouse_tracker: bool,
63}
64
65impl Default for MouseTrackerAnnotation {
66 fn default() -> MouseTrackerAnnotation {
67 MouseTrackerAnnotation {
68 on_enter: None,
69 on_exit: None,
70 cursor: <dyn MouseCursor>::defer(),
71 valid_for_mouse_tracker: true,
72 }
73 }
74}
75
76impl fmt::Debug for MouseTrackerAnnotation {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 let mut callbacks = Vec::new();
79 if self.on_enter.is_some() {
80 callbacks.push("enter");
81 }
82 if self.on_exit.is_some() {
83 callbacks.push("exit");
84 }
85 f.debug_struct("MouseTrackerAnnotation")
86 .field("callbacks", &callbacks)
87 .field("cursor", &self.cursor.debug_description())
88 .field("valid_for_mouse_tracker", &self.valid_for_mouse_tracker)
89 .finish()
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn default_defers_the_cursor_and_is_valid() {
99 let annotation = MouseTrackerAnnotation::default();
100 assert!(annotation.on_enter.is_none());
101 assert!(annotation.on_exit.is_none());
102 assert!(*annotation.cursor == *<dyn MouseCursor>::defer());
103 assert!(annotation.valid_for_mouse_tracker);
104 }
105}