1use super::{AxisInfo, SizeRules};
9use super::{RulesSetter, RulesSolver};
10use crate::dir::{Direction, Directional};
11use crate::geom::{Coord, Rect, Size};
12
13#[derive(Clone, Debug, Default)]
15pub struct FlowStorage {
16 rules: Vec<SizeRules>,
17 height_rules: Vec<SizeRules>,
19 widths: Vec<i32>,
20 breaks: Vec<usize>,
23}
24
25pub struct FlowSolver {
34 axis: AxisInfo,
35 direction: Direction,
36 secondary_is_reversed: bool,
37 opt_rules: Option<SizeRules>,
38 rules: SizeRules,
39 min_cols: i32,
40 ideal_cols: i32,
41}
42
43impl FlowSolver {
44 pub fn new(
55 axis: AxisInfo,
56 direction: Direction,
57 secondary_is_reversed: bool,
58 len: usize,
59 storage: &mut FlowStorage,
60 ) -> Self {
61 storage.rules.resize(len, SizeRules::EMPTY);
62 storage.widths.resize(len, 0);
63
64 if direction.is_horizontal() || axis.is_horizontal() {
65 storage.breaks.clear();
66 storage.height_rules.clear();
67 }
68
69 if axis.has_fixed && direction.is_horizontal() && len != 0 {
72 debug_assert!(axis.is_vertical());
73 let width = axis.other_axis;
75
76 let mut total = storage.rules[0];
77 let mut start = 0;
78 for i in 1..storage.rules.len() {
79 let sum = total.appended(storage.rules[i]);
80 if sum.min_size() <= width {
81 total = sum;
82 continue;
83 }
84
85 SizeRules::solve_widths_with_total(
87 &mut storage.widths[start..i],
88 &storage.rules[start..i],
89 total,
90 width,
91 );
92 storage.breaks.push(i);
93 start = i;
94 total = storage.rules[i];
95 }
96
97 SizeRules::solve_widths_with_total(
99 &mut storage.widths[start..],
100 &storage.rules[start..],
101 total,
102 width,
103 );
104 }
105
106 storage.height_rules.reserve_exact(storage.breaks.len() + 1);
107
108 FlowSolver {
109 axis,
110 direction,
111 secondary_is_reversed,
112 opt_rules: None,
113 rules: SizeRules::EMPTY,
114 min_cols: 1,
115 ideal_cols: 3,
116 }
117 }
118
119 #[inline]
125 pub fn set_num_columns(&mut self, min: i32, ideal: i32) {
126 self.min_cols = min;
127 self.ideal_cols = ideal;
128 }
129
130 pub fn set_column_properties(&mut self, width: i32) {
145 if self.direction.is_vertical() && self.axis.is_vertical() {
146 self.axis.map_other(|w| w.min(width));
147 }
148 }
149}
150
151impl RulesSolver for FlowSolver {
152 type Storage = FlowStorage;
153 type ChildInfo = usize;
154
155 fn for_child<CR: FnOnce(AxisInfo) -> SizeRules>(
156 &mut self,
157 storage: &mut Self::Storage,
158 index: Self::ChildInfo,
159 child_rules: CR,
160 ) {
161 if self.direction.is_horizontal() && self.axis.has_fixed {
162 self.axis.other_axis = storage.widths[index];
164 }
165 let child_rules = child_rules(self.axis);
166 if self.direction.is_horizontal() == self.axis.is_horizontal() {
167 storage.rules[index] = child_rules;
168 }
169
170 if self.direction.is_horizontal() == self.axis.is_horizontal() {
171 self.opt_rules = Some(if let Some(rules) = self.opt_rules {
173 if self.direction.is_reversed() {
174 child_rules.appended(rules)
175 } else {
176 rules.appended(child_rules)
177 }
178 } else {
179 child_rules
180 });
181 } else {
182 if storage.breaks.contains(&index) {
183 storage.height_rules.push(self.rules);
184
185 self.opt_rules = Some(if let Some(rules) = self.opt_rules {
186 if self.secondary_is_reversed {
187 rules.appended(self.rules)
188 } else {
189 self.rules.appended(rules)
190 }
191 } else {
192 self.rules
193 });
194 self.rules = SizeRules::EMPTY;
195 }
196 }
197
198 self.rules = self.rules.max(child_rules);
199 }
200
201 fn finish(self, storage: &mut Self::Storage) -> SizeRules {
202 if self.direction.is_horizontal() == self.axis.is_horizontal() {
203 let mut col_limited_rules = self.rules;
204 col_limited_rules.multiply_with_margin(self.min_cols, self.ideal_cols);
205 let unwrapped_width = self.opt_rules.unwrap_or(SizeRules::EMPTY).ideal_size();
206 let min = col_limited_rules.min_size();
207 let ideal = unwrapped_width.min(col_limited_rules.ideal_size());
208 let stretch = self.rules.stretch();
209 SizeRules::new(min, ideal, stretch).with_margins(self.rules.margins())
210 } else {
211 let rules = if let Some(rules) = self.opt_rules {
212 if self.secondary_is_reversed {
213 rules.appended(self.rules)
214 } else {
215 self.rules.appended(rules)
216 }
217 } else {
218 self.rules
219 };
220
221 storage.height_rules.push(rules);
222 debug_assert_eq!(storage.breaks.len() + 1, storage.height_rules.len());
223 rules
224 }
225 }
226}
227
228pub struct FlowSetter {
230 pos: Coord,
231 offsets: Vec<i32>,
232 direction: Direction,
233 secondary_is_reversed: bool,
234 heights: Vec<i32>, row_offsets: Vec<i32>,
236}
237
238impl FlowSetter {
239 pub fn new(
250 rect: Rect,
251 direction: Direction,
252 secondary_is_reversed: bool,
253 len: usize,
254 storage: &mut FlowStorage,
255 ) -> Self {
256 let offsets = vec![0; len];
257 assert_eq!(storage.rules.len(), len);
258 let mut heights = vec![];
259
260 if direction.is_vertical() {
261 todo!()
265 }
266
267 if len != 0 {
268 let height = rect.size.extract(direction.flipped());
269 heights = vec![0; storage.height_rules.len()];
270 SizeRules::solve_widths(&mut heights, &storage.height_rules, height);
271 }
272
273 let mut row = FlowSetter {
274 pos: rect.pos,
275 offsets,
276 direction,
277 secondary_is_reversed,
278 heights,
279 row_offsets: vec![],
280 };
281 row.update_offsets(storage);
282 row
283 }
284
285 fn update_offsets(&mut self, storage: &mut FlowStorage) {
286 fn set_offsets(
287 pos: i32,
288 rules: &[SizeRules],
289 sizes: &[i32],
290 offsets: &mut [i32],
291 iter: impl ExactSizeIterator<Item = usize>,
292 is_break: impl Fn(usize) -> bool,
293 ) {
294 debug_assert_eq!(rules.len(), sizes.len());
295 debug_assert_eq!(rules.len(), iter.len());
296
297 let mut caret = pos;
298 let mut margin = 0;
299 for i in iter {
300 let margins = rules[i].margins_i32();
301 if is_break(i) {
302 caret = pos;
303 } else {
304 caret += margin.max(margins.0);
305 }
306 margin = margins.1;
307
308 offsets[i] = caret;
309 caret += sizes[i];
310 }
311 }
312
313 let len = self.offsets.len();
314 if len == 0 {
315 return;
316 }
317
318 let pos = self.pos.extract(self.direction);
319 if !self.direction.is_reversed() {
320 set_offsets(
321 pos,
322 &storage.rules,
323 &storage.widths,
324 &mut self.offsets,
325 0..len,
326 |i| i == 0 || storage.breaks.contains(&i),
327 );
328 } else {
329 set_offsets(
330 pos,
331 &storage.rules,
332 &storage.widths,
333 &mut self.offsets,
334 (0..len).rev(),
335 |i| i == len - 1 || storage.breaks.contains(&(i + 1)),
336 );
337 }
338
339 let pos = self.pos.extract(self.direction.flipped());
340 let len = storage.height_rules.len();
341 self.row_offsets.resize(len, 0);
342 let offsets = &mut self.row_offsets;
343 if !self.secondary_is_reversed {
344 set_offsets(
345 pos,
346 &storage.height_rules,
347 &self.heights,
348 offsets,
349 0..len,
350 |_| false,
351 );
352 } else {
353 set_offsets(
354 pos,
355 &storage.height_rules,
356 &self.heights,
357 offsets,
358 (0..len).rev(),
359 |_| false,
360 );
361 }
362 }
363}
364
365impl RulesSetter for FlowSetter {
366 type Storage = FlowStorage;
367 type ChildInfo = usize;
368
369 fn child_rect(&mut self, storage: &mut Self::Storage, index: Self::ChildInfo) -> Rect {
370 let row = match storage.breaks.binary_search(&index) {
371 Ok(i) => i + 1,
372 Err(i) => i,
373 };
374 let w = storage.widths[index];
375 let h = self.heights[row];
376 let x = self.offsets[index];
377 let y = self.row_offsets[row];
378
379 if self.direction.is_horizontal() {
380 Rect::new(Coord(x, y), Size(w, h))
381 } else {
382 Rect::new(Coord(y, x), Size(h, w))
383 }
384 }
385}