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}