1use crate::dock::sanitize_gap;
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
4pub enum Axis {
5 Horizontal,
6 Vertical,
7}
8
9impl Axis {
10 pub const fn is_horizontal(self) -> bool {
11 matches!(self, Self::Horizontal)
12 }
13
14 pub const fn is_vertical(self) -> bool {
15 matches!(self, Self::Vertical)
16 }
17
18 pub fn split_main_cross(self, width: f32, height: f32) -> (f32, f32) {
19 match self {
20 Self::Horizontal => (width, height),
21 Self::Vertical => (height, width),
22 }
23 }
24
25 pub fn merge_main_cross(self, main: f32, cross: f32) -> (f32, f32) {
26 match self {
27 Self::Horizontal => (main, cross),
28 Self::Vertical => (cross, main),
29 }
30 }
31}
32
33#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
34#[non_exhaustive]
35pub enum Justify {
36 #[default]
37 Start,
38 Center,
39 End,
40 SpaceBetween,
41 SpaceAround,
42 SpaceEvenly,
43}
44
45impl Justify {
46 pub fn distribute(self, count: usize, _base_gap: f32, extra: f32) -> (f32, f32) {
47 let extra = if extra.is_finite() {
48 extra.max(0.0)
49 } else {
50 0.0
51 };
52 match self {
53 Self::Start => (0.0, 0.0),
54 Self::Center => (extra * 0.5, 0.0),
55 Self::End => (extra, 0.0),
56 Self::SpaceBetween => {
57 if count > 1 {
58 (0.0, extra / (count - 1) as f32)
59 } else if count == 1 {
60 (extra * 0.5, 0.0)
61 } else {
62 (0.0, 0.0)
63 }
64 }
65 Self::SpaceAround => {
66 if count > 0 {
67 let step = extra / count as f32;
68 (step * 0.5, step)
69 } else {
70 (0.0, 0.0)
71 }
72 }
73 Self::SpaceEvenly => {
74 if count > 0 {
75 let step = extra / (count + 1) as f32;
76 (step, step)
77 } else {
78 (0.0, 0.0)
79 }
80 }
81 }
82 }
83
84 pub fn start_offset(self, extra: f32) -> f32 {
85 let (start, _) = self.distribute(0, 0.0, extra);
86 match self {
87 Self::Start | Self::Center | Self::End => start,
88 _ => start,
89 }
90 }
91}
92
93#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
94pub enum Align {
95 #[default]
96 Start,
97 Center,
98 End,
99 Stretch,
100}
101
102impl Align {
103 pub const fn is_stretch(self) -> bool {
104 matches!(self, Self::Stretch)
105 }
106
107 pub fn offset(self, avail: f32, child: f32) -> f32 {
108 if !avail.is_finite() {
109 return 0.0;
110 }
111 let slack = (avail - child).max(0.0);
112 match self {
113 Self::Start | Self::Stretch => 0.0,
114 Self::Center => slack * 0.5,
115 Self::End => slack,
116 }
117 }
118
119 pub fn resolve(child: Option<Align>, container: Align) -> Align {
120 child.unwrap_or(container)
121 }
122}
123
124#[derive(Clone, Copy, Debug, PartialEq)]
125pub struct ContainerStyle {
126 pub axis: Axis,
127
128 pub gap: f32,
129
130 pub cross_gap: f32,
131 pub align: Align,
132 pub justify: Justify,
133
134 pub wrap: bool,
135
136 pub align_content: Align,
137}
138
139impl Default for ContainerStyle {
140 fn default() -> Self {
141 Self {
142 axis: Axis::Horizontal,
143 gap: 0.0,
144 cross_gap: 0.0,
145 align: Align::Start,
146 justify: Justify::Start,
147 wrap: false,
148 align_content: Align::Start,
149 }
150 }
151}
152
153impl ContainerStyle {
154 pub fn new(axis: Axis, gap: f32) -> Self {
155 let gap = sanitize_gap(gap);
156 Self {
157 axis,
158 gap,
159 cross_gap: gap,
160 ..Self::default()
161 }
162 }
163
164 pub fn gap(mut self, gap: f32) -> Self {
165 let gap = sanitize_gap(gap);
166 self.gap = gap;
167 self.cross_gap = gap;
168 self
169 }
170
171 pub fn main_gap(mut self, gap: f32) -> Self {
172 self.gap = sanitize_gap(gap);
173 self
174 }
175
176 pub fn cross_gap(mut self, gap: f32) -> Self {
177 self.cross_gap = sanitize_gap(gap);
178 self
179 }
180
181 pub fn gaps(mut self, main: f32, cross: f32) -> Self {
182 self.gap = sanitize_gap(main);
183 self.cross_gap = sanitize_gap(cross);
184 self
185 }
186
187 pub fn align_items(mut self, align: Align) -> Self {
188 self.align = align;
189 self
190 }
191
192 pub fn justify_content(mut self, justify: Justify) -> Self {
193 self.justify = justify;
194 self
195 }
196
197 pub fn wrap(mut self, wrap: bool) -> Self {
198 self.wrap = wrap;
199 self
200 }
201
202 pub fn wrapped(mut self) -> Self {
203 self.wrap = true;
204 self
205 }
206
207 pub fn align_content(mut self, align: Align) -> Self {
208 self.align_content = align;
209 self
210 }
211
212 pub fn axis(mut self, axis: Axis) -> Self {
213 self.axis = axis;
214 self
215 }
216
217 pub fn main_gaps_total(self, count: usize) -> f32 {
218 if count > 1 {
219 self.gap * (count - 1) as f32
220 } else {
221 0.0
222 }
223 }
224}