1use std::ops::Range;
2
3use glam::Vec2;
4
5use crate::StyleAttributeEnum;
6
7#[derive(Clone, Copy, Debug, PartialEq)]
8pub struct BoxConstraints {
9 pub min: Vec2,
10 pub max: Vec2,
11}
12
13impl BoxConstraints {
14 pub const UNBOUNDED: Self = Self {
15 min: Vec2::ZERO,
16 max: Vec2::splat(f32::INFINITY),
17 };
18
19 pub fn new(min: Vec2, max: Vec2) -> Self {
20 Self {
21 min: min.ceil(),
22 max: max.ceil(),
23 }
24 }
25
26 pub fn window(width: u32, height: u32) -> Self {
27 Self {
28 min: Vec2::ZERO,
29 max: Vec2::new(width as f32, height as f32),
30 }
31 }
32
33 pub fn loose(self) -> Self {
34 Self {
35 min: self.min,
36 max: Vec2::splat(f32::INFINITY),
37 }
38 }
39
40 pub fn loose_x(self) -> Self {
41 Self {
42 min: self.min,
43 max: Vec2::new(f32::INFINITY, self.max.x),
44 }
45 }
46
47 pub fn loose_y(self) -> Self {
48 Self {
49 min: self.min,
50 max: Vec2::new(self.max.y, f32::INFINITY),
51 }
52 }
53
54 pub fn shrink(self, size: Vec2) -> Self {
55 Self {
56 min: self.min - size,
57 max: self.max - size,
58 }
59 }
60
61 pub fn constrain(self, size: Vec2) -> Vec2 {
62 size.clamp(self.min, self.max)
63 }
64
65 pub fn height(self) -> Range<f32> {
66 self.min.y..self.max.y
67 }
68
69 pub fn width(self) -> Range<f32> {
70 self.min.x..self.max.x
71 }
72}
73
74#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
75pub enum Axis {
76 Horizontal,
77 #[default]
78 Vertical,
79}
80
81impl Axis {
82 pub const fn cross(self) -> Self {
83 match self {
84 Axis::Horizontal => Axis::Vertical,
85 Axis::Vertical => Axis::Horizontal,
86 }
87 }
88
89 pub const fn minor(self, size: Vec2) -> f32 {
90 match self {
91 Axis::Horizontal => size.y,
92 Axis::Vertical => size.x,
93 }
94 }
95
96 pub const fn major(self, size: Vec2) -> f32 {
97 match self {
98 Axis::Horizontal => size.x,
99 Axis::Vertical => size.y,
100 }
101 }
102
103 pub const fn pack(self, major: f32, minor: f32) -> Vec2 {
104 match self {
105 Axis::Horizontal => Vec2::new(major, minor),
106 Axis::Vertical => Vec2::new(minor, major),
107 }
108 }
109}
110
111impl StyleAttributeEnum for Axis {
112 fn from_str(s: &str) -> Option<Self> {
113 match s {
114 "horizontal" | "row" => Some(Axis::Horizontal),
115 "vertical" | "column" => Some(Axis::Vertical),
116 _ => None,
117 }
118 }
119
120 fn to_str(&self) -> &str {
121 match self {
122 Axis::Horizontal => "horizontal",
123 Axis::Vertical => "vertical",
124 }
125 }
126}
127
128#[derive(Clone, Copy, Debug, PartialEq, Eq)]
129pub enum JustifyContent {
130 Start,
131 Center,
132 End,
133 SpaceBetween,
134 SpaceAround,
135 SpaceEvenly,
136}
137
138impl JustifyContent {
139 pub fn justify(&self, children: &[f32], container_size: f32, gap: f32) -> Vec<f32> {
140 if children.is_empty() {
141 return Vec::new();
142 }
143
144 let mut positions = Vec::with_capacity(children.len());
145
146 let total_gap = gap * (children.len() - 1) as f32;
147 let total_size = children.iter().sum::<f32>() + total_gap;
148
149 match self {
150 JustifyContent::Start => {
151 let mut position = 0.0;
152
153 for &child in children {
154 positions.push(position);
155 position += child + gap;
156 }
157 }
158 JustifyContent::Center => {
159 let mut position = container_size / 2.0 - total_size / 2.0;
160
161 for &child in children {
162 positions.push(position);
163 position += child + gap;
164 }
165 }
166 JustifyContent::End => {
167 let mut position = container_size - total_size;
168
169 for &child in children {
170 positions.push(position);
171 position += child + gap;
172 }
173 }
174 JustifyContent::SpaceBetween => {
175 let gap = (container_size - total_size) / (children.len() - 1) as f32;
176
177 let mut position = 0.0;
178
179 for &child in children {
180 positions.push(position);
181 position += child + gap;
182 }
183 }
184 JustifyContent::SpaceAround => {
185 let gap = (container_size - total_size) / children.len() as f32;
186
187 let mut position = gap / 2.0;
188
189 for &child in children {
190 positions.push(position);
191 position += child + gap;
192 }
193 }
194 JustifyContent::SpaceEvenly => {
195 let gap = container_size / children.len() as f32;
196
197 let mut position = gap / 2.0;
198
199 for _ in children {
200 positions.push(position);
201 position += gap;
202 }
203 }
204 }
205
206 positions
207 }
208}
209
210impl Default for JustifyContent {
211 fn default() -> Self {
212 Self::Start
213 }
214}
215
216impl StyleAttributeEnum for JustifyContent {
217 fn from_str(s: &str) -> Option<Self> {
218 match s {
219 "start" => Some(JustifyContent::Start),
220 "center" => Some(JustifyContent::Center),
221 "end" => Some(JustifyContent::End),
222 "space-between" => Some(JustifyContent::SpaceBetween),
223 "space-around" => Some(JustifyContent::SpaceAround),
224 "space-evenly" => Some(JustifyContent::SpaceEvenly),
225 _ => None,
226 }
227 }
228
229 fn to_str(&self) -> &str {
230 match self {
231 JustifyContent::Start => "start",
232 JustifyContent::Center => "center",
233 JustifyContent::End => "end",
234 JustifyContent::SpaceBetween => "space-between",
235 JustifyContent::SpaceAround => "space-around",
236 JustifyContent::SpaceEvenly => "space-evenly",
237 }
238 }
239}
240
241#[derive(Clone, Copy, Debug, PartialEq, Eq)]
242pub enum AlignItems {
243 Start,
244 Center,
245 End,
246 Stretch,
247}
248
249impl Default for AlignItems {
250 fn default() -> Self {
251 Self::Start
252 }
253}
254
255impl AlignItems {
256 pub fn align(&self, start: f32, end: f32, size: f32) -> f32 {
257 match self {
258 AlignItems::Start => start,
259 AlignItems::Center => start + (end - start - size) / 2.0,
260 AlignItems::End => end - size,
261 AlignItems::Stretch => start,
262 }
263 }
264}
265
266impl StyleAttributeEnum for AlignItems {
267 fn from_str(s: &str) -> Option<Self> {
268 match s {
269 "start" => Some(AlignItems::Start),
270 "center" => Some(AlignItems::Center),
271 "end" => Some(AlignItems::End),
272 "stretch" => Some(AlignItems::Stretch),
273 _ => None,
274 }
275 }
276
277 fn to_str(&self) -> &str {
278 match self {
279 AlignItems::Start => "start",
280 AlignItems::Center => "center",
281 AlignItems::End => "end",
282 AlignItems::Stretch => "stretch",
283 }
284 }
285}