Skip to main content

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}