torin/values/
position.rs

1use crate::{
2    prelude::{
3        Area,
4        Point2D,
5        Size2D,
6    },
7    scaled::Scaled,
8};
9
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11#[derive(Default, PartialEq, Clone, Debug)]
12pub struct PositionSides {
13    pub top: Option<f32>,
14    pub right: Option<f32>,
15    pub bottom: Option<f32>,
16    pub left: Option<f32>,
17}
18
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20#[derive(PartialEq, Clone, Debug)]
21pub enum Position {
22    Stacked(Box<PositionSides>),
23
24    Absolute(Box<PositionSides>),
25    Global(Box<PositionSides>),
26}
27
28impl Default for Position {
29    fn default() -> Self {
30        Self::new_stacked()
31    }
32}
33
34impl Position {
35    pub fn new_absolute() -> Self {
36        Self::Absolute(Box::new(PositionSides {
37            top: None,
38            right: None,
39            bottom: None,
40            left: None,
41        }))
42    }
43
44    pub fn new_global() -> Self {
45        Self::Global(Box::new(PositionSides {
46            top: None,
47            right: None,
48            bottom: None,
49            left: None,
50        }))
51    }
52
53    pub fn new_stacked() -> Self {
54        Self::Stacked(Box::new(PositionSides {
55            top: None,
56            right: None,
57            bottom: None,
58            left: None,
59        }))
60    }
61
62    #[must_use]
63    pub fn top(mut self, value: f32) -> Self {
64        self.position_mut().top = Some(value);
65        self
66    }
67
68    #[must_use]
69    pub fn right(mut self, value: f32) -> Self {
70        self.position_mut().right = Some(value);
71        self
72    }
73
74    #[must_use]
75    pub fn bottom(mut self, value: f32) -> Self {
76        self.position_mut().bottom = Some(value);
77        self
78    }
79
80    #[must_use]
81    pub fn left(mut self, value: f32) -> Self {
82        self.position_mut().left = Some(value);
83        self
84    }
85
86    fn position_mut(&mut self) -> &mut PositionSides {
87        match self {
88            Self::Absolute(position) | Self::Global(position) | Self::Stacked(position) => position,
89        }
90    }
91
92    pub fn is_stacked(&self) -> bool {
93        matches!(self, Self::Stacked { .. })
94    }
95
96    pub fn is_absolute(&self) -> bool {
97        matches!(self, Self::Absolute { .. })
98    }
99
100    pub fn is_global(&self) -> bool {
101        matches!(self, Self::Global { .. })
102    }
103
104    pub(crate) fn get_origin(
105        &self,
106        available_parent_area: &Area,
107        parent_area: &Area,
108        area_size: Size2D,
109        root_area: &Area,
110    ) -> Point2D {
111        match self {
112            Self::Stacked(_) => available_parent_area.origin,
113            Self::Absolute(absolute_position) => {
114                let PositionSides {
115                    top,
116                    right,
117                    bottom,
118                    left,
119                } = &**absolute_position;
120                let y = {
121                    let mut y = parent_area.min_y();
122                    if let Some(top) = top {
123                        y += top;
124                    } else if let Some(bottom) = bottom {
125                        y = parent_area.max_y() - bottom - area_size.height;
126                    }
127                    y
128                };
129                let x = {
130                    let mut x = parent_area.min_x();
131                    if let Some(left) = left {
132                        x += left;
133                    } else if let Some(right) = right {
134                        x = parent_area.max_x() - right - area_size.width;
135                    }
136                    x
137                };
138                Point2D::new(x, y)
139            }
140            Self::Global(global_position) => {
141                let PositionSides {
142                    top,
143                    right,
144                    bottom,
145                    left,
146                } = &**global_position;
147                let y = {
148                    let mut y = 0.;
149                    if let Some(top) = top {
150                        y = *top;
151                    } else if let Some(bottom) = bottom {
152                        y = root_area.max_y() - bottom - area_size.height;
153                    }
154                    y
155                };
156                let x = {
157                    let mut x = 0.;
158                    if let Some(left) = left {
159                        x = *left;
160                    } else if let Some(right) = right {
161                        x = root_area.max_x() - right - area_size.width;
162                    }
163                    x
164                };
165                Point2D::new(x, y)
166            }
167        }
168    }
169}
170
171impl Scaled for Position {
172    fn scale(&mut self, scale_factor: f32) {
173        match self {
174            Self::Absolute(position) | Self::Global(position) => {
175                if let Some(top) = &mut position.top {
176                    *top *= scale_factor;
177                }
178                if let Some(right) = &mut position.right {
179                    *right *= scale_factor;
180                }
181                if let Some(bottom) = &mut position.bottom {
182                    *bottom *= scale_factor;
183                }
184                if let Some(left) = &mut position.left {
185                    *left *= scale_factor;
186                }
187            }
188            Self::Stacked(_) => {}
189        }
190    }
191}
192
193impl Position {
194    pub fn pretty(&self) -> String {
195        match self {
196            Self::Stacked(_) => "stacked".to_string(),
197            Self::Absolute(positions) | Self::Global(positions) => format!(
198                "{}, {}, {}, {}",
199                positions.top.unwrap_or_default(),
200                positions.right.unwrap_or_default(),
201                positions.bottom.unwrap_or_default(),
202                positions.left.unwrap_or_default()
203            ),
204        }
205    }
206}