1use crate::dock::sanitize_gap;
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub enum Axis {
8 Horizontal,
10 Vertical,
12}
13
14impl Axis {
15 pub const fn is_horizontal(self) -> bool {
17 matches!(self, Self::Horizontal)
18 }
19
20 pub const fn is_vertical(self) -> bool {
22 matches!(self, Self::Vertical)
23 }
24
25 pub fn split_main_cross(self, width: f32, height: f32) -> (f32, f32) {
27 match self {
28 Self::Horizontal => (width, height),
29 Self::Vertical => (height, width),
30 }
31 }
32
33 pub fn merge_main_cross(self, main: f32, cross: f32) -> (f32, f32) {
35 match self {
36 Self::Horizontal => (main, cross),
37 Self::Vertical => (cross, main),
38 }
39 }
40}
41
42#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
44#[non_exhaustive]
45pub enum Justify {
46 #[default]
48 Start,
49 Center,
51 End,
53 SpaceBetween,
55 SpaceAround,
57 SpaceEvenly,
59}
60
61impl Justify {
62 pub fn distribute(self, count: usize, _base_gap: f32, extra: f32) -> (f32, f32) {
67 let extra = if extra.is_finite() {
68 extra.max(0.0)
69 } else {
70 0.0
71 };
72 match self {
73 Self::Start => (0.0, 0.0),
74 Self::Center => (extra * 0.5, 0.0),
75 Self::End => (extra, 0.0),
76 Self::SpaceBetween => {
77 if count > 1 {
78 (0.0, extra / (count - 1) as f32)
79 } else if count == 1 {
80 (extra * 0.5, 0.0)
81 } else {
82 (0.0, 0.0)
83 }
84 }
85 Self::SpaceAround => {
86 if count > 0 {
87 let step = extra / count as f32;
88 (step * 0.5, step)
89 } else {
90 (0.0, 0.0)
91 }
92 }
93 Self::SpaceEvenly => {
94 if count > 0 {
95 let step = extra / (count + 1) as f32;
96 (step, step)
97 } else {
98 (0.0, 0.0)
99 }
100 }
101 }
102 }
103
104 pub fn start_offset(self, extra: f32) -> f32 {
106 let (start, _) = self.distribute(0, 0.0, extra);
107 match self {
108 Self::Start | Self::Center | Self::End => start,
109 _ => start,
110 }
111 }
112}
113
114#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
116pub enum Align {
117 #[default]
119 Start,
120 Center,
122 End,
124 Stretch,
126 Baseline,
128}
129
130impl Align {
131 pub const fn is_stretch(self) -> bool {
133 matches!(self, Self::Stretch)
134 }
135
136 pub fn offset(self, avail: f32, child: f32) -> f32 {
140 if !avail.is_finite() {
141 return 0.0;
142 }
143 let slack = (avail - child).max(0.0);
144 match self {
145 Self::Start | Self::Stretch | Self::Baseline => 0.0,
146 Self::Center => slack * 0.5,
147 Self::End => slack,
148 }
149 }
150
151 pub fn resolve(child: Option<Align>, container: Align) -> Align {
153 child.unwrap_or(container)
154 }
155}
156
157#[derive(Clone, Copy, Debug, PartialEq)]
159pub struct ContainerStyle {
160 pub axis: Axis,
162 pub gap: f32,
164 pub cross_gap: f32,
166 pub align: Align,
168 pub justify: Justify,
170 pub wrap: bool,
172 pub align_content: Align,
174}
175
176impl Default for ContainerStyle {
177 fn default() -> Self {
178 Self {
179 axis: Axis::Horizontal,
180 gap: 0.0,
181 cross_gap: 0.0,
182 align: Align::Start,
183 justify: Justify::Start,
184 wrap: false,
185 align_content: Align::Start,
186 }
187 }
188}
189
190impl ContainerStyle {
191 pub fn new(axis: Axis, gap: f32) -> Self {
193 let gap = sanitize_gap(gap);
194 Self {
195 axis,
196 gap,
197 cross_gap: gap,
198 ..Self::default()
199 }
200 }
201
202 pub fn gap(mut self, gap: f32) -> Self {
204 let gap = sanitize_gap(gap);
205 self.gap = gap;
206 self.cross_gap = gap;
207 self
208 }
209
210 pub fn main_gap(mut self, gap: f32) -> Self {
212 self.gap = sanitize_gap(gap);
213 self
214 }
215
216 pub fn cross_gap(mut self, gap: f32) -> Self {
218 self.cross_gap = sanitize_gap(gap);
219 self
220 }
221
222 pub fn gaps(mut self, main: f32, cross: f32) -> Self {
224 self.gap = sanitize_gap(main);
225 self.cross_gap = sanitize_gap(cross);
226 self
227 }
228
229 pub fn align_items(mut self, align: Align) -> Self {
231 self.align = align;
232 self
233 }
234
235 pub fn justify_content(mut self, justify: Justify) -> Self {
237 self.justify = justify;
238 self
239 }
240
241 pub fn wrap(mut self, wrap: bool) -> Self {
243 self.wrap = wrap;
244 self
245 }
246
247 pub fn wrapped(mut self) -> Self {
249 self.wrap = true;
250 self
251 }
252
253 pub fn align_content(mut self, align: Align) -> Self {
255 self.align_content = align;
256 self
257 }
258
259 pub fn axis(mut self, axis: Axis) -> Self {
261 self.axis = axis;
262 self
263 }
264
265 pub fn main_gaps_total(self, count: usize) -> f32 {
267 if count > 1 {
268 self.gap * (count - 1) as f32
269 } else {
270 0.0
271 }
272 }
273}