gpui_component/
geometry.rs

1use std::fmt::{self, Display, Formatter};
2
3use gpui::{AbsoluteLength, Axis, Length, Pixels};
4use serde::{Deserialize, Serialize};
5
6/// A enum for defining the placement of the element.
7///
8/// See also: [`Side`] if you need to define the left, right side.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10pub enum Placement {
11    #[serde(rename = "top")]
12    Top,
13    #[serde(rename = "bottom")]
14    Bottom,
15    #[serde(rename = "left")]
16    Left,
17    #[serde(rename = "right")]
18    Right,
19}
20
21impl Display for Placement {
22    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
23        match self {
24            Placement::Top => write!(f, "Top"),
25            Placement::Bottom => write!(f, "Bottom"),
26            Placement::Left => write!(f, "Left"),
27            Placement::Right => write!(f, "Right"),
28        }
29    }
30}
31
32impl Placement {
33    #[inline]
34    pub fn is_horizontal(&self) -> bool {
35        match self {
36            Placement::Left | Placement::Right => true,
37            _ => false,
38        }
39    }
40
41    #[inline]
42    pub fn is_vertical(&self) -> bool {
43        match self {
44            Placement::Top | Placement::Bottom => true,
45            _ => false,
46        }
47    }
48
49    #[inline]
50    pub fn axis(&self) -> Axis {
51        match self {
52            Placement::Top | Placement::Bottom => Axis::Vertical,
53            Placement::Left | Placement::Right => Axis::Horizontal,
54        }
55    }
56}
57
58/// A enum for defining the side of the element.
59///
60/// See also: [`Placement`] if you need to define the 4 edges.
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
62pub enum Side {
63    #[serde(rename = "left")]
64    Left,
65    #[serde(rename = "right")]
66    Right,
67}
68
69impl Side {
70    /// Returns true if the side is left.
71    #[inline]
72    pub fn is_left(&self) -> bool {
73        matches!(self, Self::Left)
74    }
75
76    /// Returns true if the side is right.
77    #[inline]
78    pub fn is_right(&self) -> bool {
79        matches!(self, Self::Right)
80    }
81}
82
83/// A trait to extend the [`Axis`] enum with utility methods.
84pub trait AxisExt {
85    fn is_horizontal(self) -> bool;
86    fn is_vertical(self) -> bool;
87}
88
89impl AxisExt for Axis {
90    #[inline]
91    fn is_horizontal(self) -> bool {
92        self == Axis::Horizontal
93    }
94
95    #[inline]
96    fn is_vertical(self) -> bool {
97        self == Axis::Vertical
98    }
99}
100
101/// A trait for converting [`Pixels`] to `f32` and `f64`.
102pub trait PixelsExt {
103    fn as_f32(&self) -> f32;
104    fn as_f64(self) -> f64;
105}
106impl PixelsExt for Pixels {
107    fn as_f32(&self) -> f32 {
108        f32::from(self)
109    }
110
111    fn as_f64(self) -> f64 {
112        f64::from(self)
113    }
114}
115
116/// A trait to extend the [`Length`] enum with utility methods.
117pub trait LengthExt {
118    /// Converts the [`Length`] to [`Pixels`] based on a given `base_size` and `rem_size`.
119    ///
120    /// If the [`Length`] is [`Length::Auto`], it returns `None`.
121    fn to_pixels(&self, base_size: AbsoluteLength, rem_size: Pixels) -> Option<Pixels>;
122}
123
124impl LengthExt for Length {
125    fn to_pixels(&self, base_size: AbsoluteLength, rem_size: Pixels) -> Option<Pixels> {
126        match self {
127            Length::Auto => None,
128            Length::Definite(len) => Some(len.to_pixels(base_size, rem_size)),
129        }
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use super::Placement;
136    #[test]
137    fn test_placement() {
138        assert!(Placement::Left.is_horizontal());
139        assert!(Placement::Right.is_horizontal());
140        assert!(!Placement::Top.is_horizontal());
141        assert!(!Placement::Bottom.is_horizontal());
142
143        assert!(Placement::Top.is_vertical());
144        assert!(Placement::Bottom.is_vertical());
145        assert!(!Placement::Left.is_vertical());
146        assert!(!Placement::Right.is_vertical());
147
148        assert_eq!(Placement::Top.axis(), gpui::Axis::Vertical);
149        assert_eq!(Placement::Bottom.axis(), gpui::Axis::Vertical);
150        assert_eq!(Placement::Left.axis(), gpui::Axis::Horizontal);
151        assert_eq!(Placement::Right.axis(), gpui::Axis::Horizontal);
152
153        assert_eq!(Placement::Top.to_string(), "Top");
154        assert_eq!(Placement::Bottom.to_string(), "Bottom");
155        assert_eq!(Placement::Left.to_string(), "Left");
156        assert_eq!(Placement::Right.to_string(), "Right");
157
158        assert_eq!(serde_json::to_string(&Placement::Top).unwrap(), r#""top""#);
159        assert_eq!(
160            serde_json::to_string(&Placement::Bottom).unwrap(),
161            r#""bottom""#
162        );
163        assert_eq!(
164            serde_json::to_string(&Placement::Left).unwrap(),
165            r#""left""#
166        );
167        assert_eq!(
168            serde_json::to_string(&Placement::Right).unwrap(),
169            r#""right""#
170        );
171
172        assert_eq!(
173            serde_json::from_str::<Placement>(r#""top""#).unwrap(),
174            Placement::Top
175        );
176        assert_eq!(
177            serde_json::from_str::<Placement>(r#""bottom""#).unwrap(),
178            Placement::Bottom
179        );
180        assert_eq!(
181            serde_json::from_str::<Placement>(r#""left""#).unwrap(),
182            Placement::Left
183        );
184        assert_eq!(
185            serde_json::from_str::<Placement>(r#""right""#).unwrap(),
186            Placement::Right
187        );
188    }
189
190    #[test]
191    fn test_side() {
192        use super::Side;
193        let left = Side::Left;
194        let right = Side::Right;
195
196        assert!(left.is_left());
197        assert!(!left.is_right());
198
199        assert!(right.is_right());
200        assert!(!right.is_left());
201
202        // Test serialization
203        assert_eq!(serde_json::to_string(&left).unwrap(), r#""left""#);
204        assert_eq!(serde_json::to_string(&right).unwrap(), r#""right""#);
205        assert_eq!(
206            serde_json::from_str::<Side>(r#""left""#).unwrap(),
207            Side::Left
208        );
209        assert_eq!(
210            serde_json::from_str::<Side>(r#""right""#).unwrap(),
211            Side::Right
212        );
213    }
214}