1use crate::{Point, Rectangle, Transformation, Vector};
23/// The mouse cursor state.
4#[derive(Debug, Clone, Copy, PartialEq, Default)]
5pub enum Cursor {
6/// The cursor has a defined position.
7Available(Point),
89/// The cursor has a defined position, but it's levitating over a layer above.
10Levitating(Point),
1112/// The cursor is currently unavailable (i.e. out of bounds or busy).
13#[default]
14Unavailable,
15}
1617impl Cursor {
18/// Returns the absolute position of the [`Cursor`], if available.
19pub fn position(self) -> Option<Point> {
20match self {
21 Cursor::Available(position) => Some(position),
22 Cursor::Levitating(_) | Cursor::Unavailable => None,
23 }
24 }
2526/// Returns the absolute position of the [`Cursor`], if available and inside
27 /// the given bounds.
28 ///
29 /// If the [`Cursor`] is not over the provided bounds, this method will
30 /// return `None`.
31pub fn position_over(self, bounds: Rectangle) -> Option<Point> {
32self.position().filter(|p| bounds.contains(*p))
33 }
3435/// Returns the relative position of the [`Cursor`] inside the given bounds,
36 /// if available.
37 ///
38 /// If the [`Cursor`] is not over the provided bounds, this method will
39 /// return `None`.
40pub fn position_in(self, bounds: Rectangle) -> Option<Point> {
41self.position_over(bounds)
42 .map(|p| p - Vector::new(bounds.x, bounds.y))
43 }
4445/// Returns the relative position of the [`Cursor`] from the given origin,
46 /// if available.
47pub fn position_from(self, origin: Point) -> Option<Point> {
48self.position().map(|p| p - Vector::new(origin.x, origin.y))
49 }
5051/// Returns true if the [`Cursor`] is over the given `bounds`.
52pub fn is_over(self, bounds: Rectangle) -> bool {
53self.position_over(bounds).is_some()
54 }
5556/// Returns true if the [`Cursor`] is levitating over a layer above.
57pub fn is_levitating(self) -> bool {
58matches!(self, Self::Levitating(_))
59 }
6061/// Makes the [`Cursor`] levitate over a layer above.
62pub fn levitate(self) -> Self {
63match self {
64Self::Available(position) => Self::Levitating(position),
65_ => self,
66 }
67 }
6869/// Brings the [`Cursor`] back to the current layer.
70pub fn land(self) -> Self {
71match self {
72 Cursor::Levitating(position) => Cursor::Available(position),
73_ => self,
74 }
75 }
76}
7778impl std::ops::Mul<Transformation> for Cursor {
79type Output = Self;
8081fn mul(self, transformation: Transformation) -> Self {
82match self {
83Self::Available(position) => {
84Self::Available(position * transformation)
85 }
86Self::Levitating(position) => {
87Self::Levitating(position * transformation)
88 }
89Self::Unavailable => Self::Unavailable,
90 }
91 }
92}