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}
127
128impl Align {
129 pub const fn is_stretch(self) -> bool {
131 matches!(self, Self::Stretch)
132 }
133
134 pub fn offset(self, avail: f32, child: f32) -> f32 {
138 if !avail.is_finite() {
139 return 0.0;
140 }
141 let slack = (avail - child).max(0.0);
142 match self {
143 Self::Start | Self::Stretch => 0.0,
144 Self::Center => slack * 0.5,
145 Self::End => slack,
146 }
147 }
148
149 pub fn resolve(child: Option<Align>, container: Align) -> Align {
151 child.unwrap_or(container)
152 }
153}
154
155#[derive(Clone, Copy, Debug, PartialEq)]
157pub struct ContainerStyle {
158 pub axis: Axis,
160 pub gap: f32,
162 pub cross_gap: f32,
164 pub align: Align,
166 pub justify: Justify,
168 pub wrap: bool,
170 pub align_content: Align,
172}
173
174impl Default for ContainerStyle {
175 fn default() -> Self {
176 Self {
177 axis: Axis::Horizontal,
178 gap: 0.0,
179 cross_gap: 0.0,
180 align: Align::Start,
181 justify: Justify::Start,
182 wrap: false,
183 align_content: Align::Start,
184 }
185 }
186}
187
188impl ContainerStyle {
189 pub fn new(axis: Axis, gap: f32) -> Self {
191 let gap = sanitize_gap(gap);
192 Self {
193 axis,
194 gap,
195 cross_gap: gap,
196 ..Self::default()
197 }
198 }
199
200 pub fn gap(mut self, gap: f32) -> Self {
202 let gap = sanitize_gap(gap);
203 self.gap = gap;
204 self.cross_gap = gap;
205 self
206 }
207
208 pub fn main_gap(mut self, gap: f32) -> Self {
210 self.gap = sanitize_gap(gap);
211 self
212 }
213
214 pub fn cross_gap(mut self, gap: f32) -> Self {
216 self.cross_gap = sanitize_gap(gap);
217 self
218 }
219
220 pub fn gaps(mut self, main: f32, cross: f32) -> Self {
222 self.gap = sanitize_gap(main);
223 self.cross_gap = sanitize_gap(cross);
224 self
225 }
226
227 pub fn align_items(mut self, align: Align) -> Self {
229 self.align = align;
230 self
231 }
232
233 pub fn justify_content(mut self, justify: Justify) -> Self {
235 self.justify = justify;
236 self
237 }
238
239 pub fn wrap(mut self, wrap: bool) -> Self {
241 self.wrap = wrap;
242 self
243 }
244
245 pub fn wrapped(mut self) -> Self {
247 self.wrap = true;
248 self
249 }
250
251 pub fn align_content(mut self, align: Align) -> Self {
253 self.align_content = align;
254 self
255 }
256
257 pub fn axis(mut self, axis: Axis) -> Self {
259 self.axis = axis;
260 self
261 }
262
263 pub fn main_gaps_total(self, count: usize) -> f32 {
265 if count > 1 {
266 self.gap * (count - 1) as f32
267 } else {
268 0.0
269 }
270 }
271}