Skip to main content

iced_core/mouse/
cursor.rs

1use crate::{Point, Rectangle, Transformation, Vector};
2
3/// The mouse cursor state.
4#[derive(Debug, Clone, Copy, PartialEq, Default)]
5pub enum Cursor {
6    /// The cursor has a defined position.
7    Available(Point),
8
9    /// The cursor has a defined position, but it's levitating over a layer above.
10    ///
11    /// You can [`land`](Self::land) and [`observe`](Self::observe) it safely,
12    /// and make it [`Available`](Self::Available) again.
13    Levitating(Point),
14
15    /// The cursor has a defined position, but it's obstructed by a layer above.
16    ///
17    /// It cannot [`land`](Self::land), but you can [`observe`](Self::observe) it from below.
18    Obstructed(Point),
19
20    /// The cursor is currently unavailable (i.e. out of bounds or busy).
21    #[default]
22    Unavailable,
23}
24
25impl Cursor {
26    /// Returns the absolute position of the [`Cursor`], if available.
27    pub fn position(self) -> Option<Point> {
28        match self {
29            Cursor::Available(position) => Some(position),
30            Cursor::Levitating(_) | Cursor::Obstructed(_) | Cursor::Unavailable => None,
31        }
32    }
33
34    /// Returns the absolute position of the [`Cursor`], if available and inside
35    /// the given bounds.
36    ///
37    /// If the [`Cursor`] is not over the provided bounds, this method will
38    /// return `None`.
39    pub fn position_over(self, bounds: Rectangle) -> Option<Point> {
40        self.position().filter(|p| bounds.contains(*p))
41    }
42
43    /// Returns the relative position of the [`Cursor`] inside the given bounds,
44    /// if available.
45    ///
46    /// If the [`Cursor`] is not over the provided bounds, this method will
47    /// return `None`.
48    pub fn position_in(self, bounds: Rectangle) -> Option<Point> {
49        self.position_over(bounds)
50            .map(|p| p - Vector::new(bounds.x, bounds.y))
51    }
52
53    /// Returns the relative position of the [`Cursor`] from the given origin,
54    /// if available.
55    pub fn position_from(self, origin: Point) -> Option<Point> {
56        self.position().map(|p| p - Vector::new(origin.x, origin.y))
57    }
58
59    /// Returns true if the [`Cursor`] is over the given `bounds`.
60    pub fn is_over(self, bounds: Rectangle) -> bool {
61        self.position_over(bounds).is_some()
62    }
63
64    /// Returns true if the [`Cursor`] is levitating over a layer above.
65    pub fn is_levitating(self) -> bool {
66        matches!(self, Self::Levitating(_))
67    }
68
69    /// Makes the [`Cursor`] levitate over a layer above.
70    pub fn levitate(self) -> Self {
71        match self {
72            Self::Available(position) => Self::Levitating(position),
73            _ => self,
74        }
75    }
76
77    /// Makes the [`Cursor`] obstructed over a layer above.
78    pub fn obstruct(self) -> Self {
79        match self {
80            Self::Available(position) => Self::Obstructed(position),
81            _ => self,
82        }
83    }
84
85    /// If the [`Cursor`] is levitating, it makes it available again.
86    pub fn land(self) -> Self {
87        match self {
88            Cursor::Levitating(position) => Cursor::Available(position),
89            _ => self,
90        }
91    }
92
93    /// If the [`Cursor`] is either levitating or obstructed, it makes it available again.
94    pub fn observe(self) -> Self {
95        match self {
96            Cursor::Obstructed(position) | Cursor::Levitating(position) => {
97                Cursor::Available(position)
98            }
99            _ => self,
100        }
101    }
102}
103
104impl std::ops::Add<Vector> for Cursor {
105    type Output = Self;
106
107    fn add(self, translation: Vector) -> Self::Output {
108        match self {
109            Cursor::Available(point) => Cursor::Available(point + translation),
110            Cursor::Levitating(point) => Cursor::Levitating(point + translation),
111            Cursor::Obstructed(point) => Cursor::Obstructed(point + translation),
112            Cursor::Unavailable => Cursor::Unavailable,
113        }
114    }
115}
116
117impl std::ops::Sub<Vector> for Cursor {
118    type Output = Self;
119
120    fn sub(self, translation: Vector) -> Self::Output {
121        match self {
122            Cursor::Available(point) => Cursor::Available(point - translation),
123            Cursor::Levitating(point) => Cursor::Levitating(point - translation),
124            Cursor::Obstructed(point) => Cursor::Obstructed(point - translation),
125            Cursor::Unavailable => Cursor::Unavailable,
126        }
127    }
128}
129
130impl std::ops::Mul<Transformation> for Cursor {
131    type Output = Self;
132
133    fn mul(self, transformation: Transformation) -> Self {
134        match self {
135            Self::Available(position) => Self::Available(position * transformation),
136            Self::Levitating(position) => Self::Levitating(position * transformation),
137            Self::Obstructed(position) => Self::Obstructed(position * transformation),
138            Self::Unavailable => Self::Unavailable,
139        }
140    }
141}