1use incular_core::{Offset, Size};
2
3#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
5pub enum Axis {
6 #[default]
7 Horizontal,
8 Vertical,
9}
10
11impl Axis {
12 #[must_use]
13 pub const fn is_horizontal(self) -> bool {
14 matches!(self, Self::Horizontal)
15 }
16
17 #[must_use]
18 pub const fn is_vertical(self) -> bool {
19 matches!(self, Self::Vertical)
20 }
21
22 #[must_use]
23 pub const fn main_extent(self, size: Size) -> f32 {
24 match self {
25 Self::Horizontal => size.width,
26 Self::Vertical => size.height,
27 }
28 }
29
30 #[must_use]
31 pub const fn cross_extent(self, size: Size) -> f32 {
32 match self {
33 Self::Horizontal => size.height,
34 Self::Vertical => size.width,
35 }
36 }
37
38 #[must_use]
39 pub fn size(self, main: f32, cross: f32) -> Size {
40 match self {
41 Self::Horizontal => Size::new(main, cross),
42 Self::Vertical => Size::new(cross, main),
43 }
44 }
45
46 #[must_use]
47 pub const fn offset(self, main: f32, cross: f32) -> Offset {
48 match self {
49 Self::Horizontal => Offset::new(main, cross),
50 Self::Vertical => Offset::new(cross, main),
51 }
52 }
53}
54
55#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
57pub enum AxisDirection {
58 #[default]
59 Right,
60 Left,
61 Down,
62 Up,
63}
64
65impl AxisDirection {
66 #[must_use]
67 pub const fn axis(self) -> Axis {
68 match self {
69 Self::Right | Self::Left => Axis::Horizontal,
70 Self::Down | Self::Up => Axis::Vertical,
71 }
72 }
73
74 #[must_use]
75 pub const fn is_reversed(self) -> bool {
76 matches!(self, Self::Left | Self::Up)
77 }
78}
79
80#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
81pub enum TextDirection {
82 #[default]
83 Ltr,
84 Rtl,
85}
86
87#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
88pub enum VerticalDirection {
89 #[default]
90 Down,
91 Up,
92}
93
94#[derive(Clone, Copy, Debug, Default, PartialEq)]
97pub struct Alignment {
98 pub x: f32,
99 pub y: f32,
100}
101
102impl Alignment {
103 pub const TOP_LEFT: Self = Self { x: -1.0, y: -1.0 };
104 pub const TOP_CENTER: Self = Self { x: 0.0, y: -1.0 };
105 pub const TOP_RIGHT: Self = Self { x: 1.0, y: -1.0 };
106 pub const CENTER_LEFT: Self = Self { x: -1.0, y: 0.0 };
107 pub const CENTER: Self = Self { x: 0.0, y: 0.0 };
108 pub const CENTER_RIGHT: Self = Self { x: 1.0, y: 0.0 };
109 pub const BOTTOM_LEFT: Self = Self { x: -1.0, y: 1.0 };
110 pub const BOTTOM_CENTER: Self = Self { x: 0.0, y: 1.0 };
111 pub const BOTTOM_RIGHT: Self = Self { x: 1.0, y: 1.0 };
112
113 #[must_use]
114 pub const fn new(x: f32, y: f32) -> Self {
115 Self { x, y }
116 }
117
118 #[must_use]
119 pub const fn along_size(self, size: Size) -> Offset {
120 Offset::new(size.width * self.x * 0.5, size.height * self.y * 0.5)
121 }
122
123 #[must_use]
126 pub const fn within(self, parent: Size, child: Size) -> Offset {
127 Offset::new(
128 (parent.width - child.width) * (self.x + 1.0) * 0.5,
129 (parent.height - child.height) * (self.y + 1.0) * 0.5,
130 )
131 }
132
133 #[must_use]
134 pub fn inscribe(self, child: Size, parent: incular_core::Rect) -> incular_core::Rect {
135 incular_core::Rect::from_origin_size(parent.origin + self.within(parent.size, child), child)
136 }
137
138 #[must_use]
139 pub const fn resolve(self, _direction: TextDirection) -> Self {
140 self
141 }
142}
143
144impl std::ops::Add for Alignment {
145 type Output = Self;
146
147 fn add(self, rhs: Self) -> Self::Output {
148 Self::new(self.x + rhs.x, self.y + rhs.y)
149 }
150}
151
152impl std::ops::Sub for Alignment {
153 type Output = Self;
154
155 fn sub(self, rhs: Self) -> Self::Output {
156 Self::new(self.x - rhs.x, self.y - rhs.y)
157 }
158}
159
160impl std::ops::Mul<f32> for Alignment {
161 type Output = Self;
162
163 fn mul(self, rhs: f32) -> Self::Output {
164 Self::new(self.x * rhs, self.y * rhs)
165 }
166}
167
168impl std::ops::Div<f32> for Alignment {
169 type Output = Self;
170
171 fn div(self, rhs: f32) -> Self::Output {
172 Self::new(self.x / rhs, self.y / rhs)
173 }
174}
175
176impl std::ops::Neg for Alignment {
177 type Output = Self;
178
179 fn neg(self) -> Self::Output {
180 Self::new(-self.x, -self.y)
181 }
182}
183
184impl incular_core::Lerp for Alignment {
185 fn lerp(&self, other: &Self, t: f32) -> Self {
186 let t = t.clamp(0.0, 1.0);
187 let mix = |a: f32, b: f32| a + (b - a) * t;
188 Self::new(mix(self.x, other.x), mix(self.y, other.y))
189 }
190}
191
192#[derive(Clone, Copy, Debug, Default, PartialEq)]
194pub struct FractionalOffset {
195 pub dx: f32,
196 pub dy: f32,
197}
198
199impl FractionalOffset {
200 pub const TOP_LEFT: Self = Self { dx: 0.0, dy: 0.0 };
201 pub const TOP_CENTER: Self = Self { dx: 0.5, dy: 0.0 };
202 pub const TOP_RIGHT: Self = Self { dx: 1.0, dy: 0.0 };
203 pub const CENTER_LEFT: Self = Self { dx: 0.0, dy: 0.5 };
204 pub const CENTER: Self = Self { dx: 0.5, dy: 0.5 };
205 pub const CENTER_RIGHT: Self = Self { dx: 1.0, dy: 0.5 };
206 pub const BOTTOM_LEFT: Self = Self { dx: 0.0, dy: 1.0 };
207 pub const BOTTOM_CENTER: Self = Self { dx: 0.5, dy: 1.0 };
208 pub const BOTTOM_RIGHT: Self = Self { dx: 1.0, dy: 1.0 };
209
210 #[must_use]
211 pub const fn new(dx: f32, dy: f32) -> Self {
212 Self { dx, dy }
213 }
214
215 #[must_use]
216 pub const fn from_alignment(alignment: Alignment) -> Self {
217 Self {
218 dx: (alignment.x + 1.0) / 2.0,
219 dy: (alignment.y + 1.0) / 2.0,
220 }
221 }
222
223 #[must_use]
224 pub const fn to_alignment(self) -> Alignment {
225 Alignment::new(self.dx * 2.0 - 1.0, self.dy * 2.0 - 1.0)
226 }
227}
228
229impl incular_core::Lerp for FractionalOffset {
230 fn lerp(&self, other: &Self, t: f32) -> Self {
231 let t = t.clamp(0.0, 1.0);
232 let mix = |a: f32, b: f32| a + (b - a) * t;
233 Self::new(mix(self.dx, other.dx), mix(self.dy, other.dy))
234 }
235}
236
237#[derive(Clone, Copy, Debug, Default, PartialEq)]
239pub struct AlignmentDirectional {
240 pub start: f32,
241 pub y: f32,
242}
243
244impl AlignmentDirectional {
245 pub const TOP_START: Self = Self {
246 start: -1.0,
247 y: -1.0,
248 };
249 pub const TOP_CENTER: Self = Self {
250 start: 0.0,
251 y: -1.0,
252 };
253 pub const TOP_END: Self = Self {
254 start: 1.0,
255 y: -1.0,
256 };
257 pub const CENTER_START: Self = Self {
258 start: -1.0,
259 y: 0.0,
260 };
261 pub const CENTER: Self = Self { start: 0.0, y: 0.0 };
262 pub const CENTER_END: Self = Self { start: 1.0, y: 0.0 };
263 pub const BOTTOM_START: Self = Self {
264 start: -1.0,
265 y: 1.0,
266 };
267 pub const BOTTOM_CENTER: Self = Self { start: 0.0, y: 1.0 };
268 pub const BOTTOM_END: Self = Self { start: 1.0, y: 1.0 };
269
270 #[must_use]
271 pub const fn new(start: f32, y: f32) -> Self {
272 Self { start, y }
273 }
274
275 #[must_use]
276 pub const fn resolve(self, direction: TextDirection) -> Alignment {
277 Alignment::new(
278 match direction {
279 TextDirection::Ltr => self.start,
280 TextDirection::Rtl => -self.start,
281 },
282 self.y,
283 )
284 }
285}
286
287impl incular_core::Lerp for AlignmentDirectional {
288 fn lerp(&self, other: &Self, t: f32) -> Self {
289 let t = t.clamp(0.0, 1.0);
290 let mix = |a: f32, b: f32| a + (b - a) * t;
291 Self::new(mix(self.start, other.start), mix(self.y, other.y))
292 }
293}
294
295#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
296pub enum MainAxisSize {
297 Min,
298 #[default]
299 Max,
300}
301
302#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
303pub enum MainAxisAlignment {
304 #[default]
305 Start,
306 End,
307 Center,
308 SpaceBetween,
309 SpaceAround,
310 SpaceEvenly,
311}
312
313impl MainAxisAlignment {
314 #[must_use]
315 pub const fn is_distributed(self) -> bool {
316 matches!(
317 self,
318 Self::SpaceBetween | Self::SpaceAround | Self::SpaceEvenly
319 )
320 }
321}
322
323#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
324pub enum CrossAxisAlignment {
325 #[default]
326 Start,
327 End,
328 Center,
329 Stretch,
330 Baseline,
331}
332
333#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
334pub enum FlexFit {
335 #[default]
336 Tight,
337 Loose,
338}
339
340#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
341pub enum WrapAlignment {
342 #[default]
343 Start,
344 End,
345 Center,
346 SpaceBetween,
347 SpaceAround,
348 SpaceEvenly,
349}
350
351#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
352pub enum WrapCrossAlignment {
353 #[default]
354 Start,
355 End,
356 Center,
357}
358
359#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
360pub enum Clip {
361 None,
362 #[default]
363 HardEdge,
364 AntiAlias,
365 AntiAliasWithSaveLayer,
366}
367
368#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
369pub enum StackFit {
370 #[default]
371 Loose,
372 Expand,
373 Passthrough,
374}