1use std::marker::PhantomData;
9
10use super::{AxisInfo, SizeRules};
11use super::{GridStorage, RowTemp, RulesSetter, RulesSolver};
12use crate::cast::{Cast, Conv};
13use crate::geom::{Coord, Offset, Rect, Size};
14
15pub trait DefaultWithLen {
17 fn default_with_len(len: usize) -> Self;
19}
20impl<T: Copy + Default, const N: usize> DefaultWithLen for [T; N] {
21 fn default_with_len(len: usize) -> Self {
22 assert_eq!(len, N);
23 [Default::default(); N]
24 }
25}
26impl<T: Clone + Default> DefaultWithLen for Vec<T> {
27 fn default_with_len(len: usize) -> Self {
28 let mut v = Vec::new();
29 v.resize_with(len, Default::default);
30 v
31 }
32}
33
34#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
36pub struct GridDimensions {
37 pub cols: u32,
41 pub col_spans: u32,
43 pub rows: u32,
47 pub row_spans: u32,
49}
50
51#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
53pub struct GridCellInfo {
54 pub col: u32,
56 pub last_col: u32,
58 pub row: u32,
60 pub last_row: u32,
62}
63
64impl GridCellInfo {
65 pub fn new(col: u32, row: u32) -> Self {
67 GridCellInfo {
68 col,
69 last_col: col,
70 row,
71 last_row: row,
72 }
73 }
74}
75
76pub struct GridSolver<CSR, RSR, S: GridStorage> {
80 axis: AxisInfo,
81 col_spans: CSR,
82 row_spans: RSR,
83 next_col_span: usize,
84 next_row_span: usize,
85 _s: PhantomData<S>,
86}
87
88impl<CSR: DefaultWithLen, RSR: DefaultWithLen, S: GridStorage> GridSolver<CSR, RSR, S> {
89 pub fn new(axis: AxisInfo, dim: GridDimensions, storage: &mut S) -> Self {
97 let col_spans = CSR::default_with_len(dim.col_spans.cast());
98 let row_spans = RSR::default_with_len(dim.row_spans.cast());
99
100 storage.set_dims(dim.cols.cast(), dim.rows.cast());
101
102 let mut solver = GridSolver {
103 axis,
104 col_spans,
105 row_spans,
106 next_col_span: 0,
107 next_row_span: 0,
108 _s: Default::default(),
109 };
110 solver.prepare(storage);
111 solver
112 }
113
114 fn prepare(&mut self, storage: &mut S) {
115 if self.axis.has_fixed {
116 if self.axis.is_vertical() {
117 let (widths, rules) = storage.widths_and_rules();
118 SizeRules::solve_widths(widths, rules, self.axis.other_axis);
119 } else {
120 let (heights, rules) = storage.heights_and_rules();
121 SizeRules::solve_widths(heights, rules, self.axis.other_axis);
122 }
123 }
124
125 if self.axis.is_horizontal() {
126 for n in 0..storage.width_rules().len() {
127 storage.width_rules()[n] = SizeRules::EMPTY;
128 }
129 } else {
130 for n in 0..storage.height_rules().len() {
131 storage.height_rules()[n] = SizeRules::EMPTY;
132 }
133 }
134 }
135}
136
137impl<CSR, RSR, S: GridStorage> RulesSolver for GridSolver<CSR, RSR, S>
138where
139 CSR: AsRef<[(SizeRules, u32, u32)]> + AsMut<[(SizeRules, u32, u32)]>,
140 RSR: AsRef<[(SizeRules, u32, u32)]> + AsMut<[(SizeRules, u32, u32)]>,
141{
142 type Storage = S;
143 type ChildInfo = GridCellInfo;
144
145 fn for_child<CR: FnOnce(AxisInfo) -> SizeRules>(
146 &mut self,
147 storage: &mut Self::Storage,
148 info: Self::ChildInfo,
149 child_rules: CR,
150 ) {
151 if self.axis.has_fixed {
152 if self.axis.is_horizontal() {
153 self.axis.other_axis = ((info.row + 1)..=info.last_row)
154 .fold(storage.heights()[usize::conv(info.row)], |h, i| {
155 h + storage.heights()[usize::conv(i)]
156 });
157 } else {
158 self.axis.other_axis = ((info.col + 1)..=info.last_col)
159 .fold(storage.widths()[usize::conv(info.col)], |w, i| {
160 w + storage.widths()[usize::conv(i)]
161 });
162 }
163 }
164 let child_rules = child_rules(self.axis);
165 if self.axis.is_horizontal() {
166 if info.last_col > info.col {
167 let span = &mut self.col_spans.as_mut()[self.next_col_span];
168 span.0.max_with(child_rules);
169 span.1 = info.col;
170 span.2 = info.last_col + 1;
171 self.next_col_span += 1;
172 } else {
173 storage.width_rules()[usize::conv(info.col)].max_with(child_rules);
174 }
175 } else if info.last_row > info.row {
176 let span = &mut self.row_spans.as_mut()[self.next_row_span];
177 span.0.max_with(child_rules);
178 span.1 = info.row;
179 span.2 = info.last_row + 1;
180 self.next_row_span += 1;
181 } else {
182 storage.height_rules()[usize::conv(info.row)].max_with(child_rules);
183 };
184 }
185
186 fn finish(mut self, storage: &mut Self::Storage) -> SizeRules {
187 fn calculate(widths: &mut [SizeRules], spans: &mut [(SizeRules, u32, u32)]) -> SizeRules {
188 const BASE_WEIGHT: u32 = 100;
192 const SPAN_WEIGHT: u32 = 10;
193 let mut scores: Vec<u32> = widths
194 .iter()
195 .map(|w| w.stretch() as u32 * BASE_WEIGHT)
196 .collect();
197 for span in spans.iter() {
198 let w = span.0.stretch() as u32 * SPAN_WEIGHT;
199 for score in &mut scores[(usize::conv(span.1))..(usize::conv(span.2))] {
200 *score += w;
201 }
202 }
203 for span in spans.iter() {
204 let range = (usize::conv(span.1))..(usize::conv(span.2));
205 span.0
206 .distribute_stretch_over_by(&mut widths[range.clone()], &scores[range]);
207 }
208
209 spans.sort_by_key(|span| span.2.saturating_sub(span.1));
211
212 for span in spans {
215 let rules = span.0;
216 let begin = usize::conv(span.1);
217 let end = usize::conv(span.2);
218 rules.distribute_span_over(&mut widths[begin..end]);
219 }
220
221 SizeRules::sum(widths)
222 }
223
224 if self.axis.is_horizontal() {
225 calculate(storage.width_rules(), self.col_spans.as_mut())
226 } else {
227 calculate(storage.height_rules(), self.row_spans.as_mut())
228 }
229 }
230}
231
232pub struct GridSetter<CT: RowTemp, RT: RowTemp, S: GridStorage> {
234 w_offsets: CT,
235 h_offsets: RT,
236 pos: Coord,
237 _s: PhantomData<S>,
238}
239
240impl<CT: RowTemp, RT: RowTemp, S: GridStorage> GridSetter<CT, RT, S> {
241 pub fn new(rect: Rect, dim: GridDimensions, storage: &mut S) -> Self {
249 let (cols, rows) = (dim.cols.cast(), dim.rows.cast());
250 let mut w_offsets = CT::default();
251 w_offsets.set_len(cols);
252 let mut h_offsets = RT::default();
253 h_offsets.set_len(rows);
254
255 storage.set_dims(cols, rows);
256
257 if cols > 0 {
258 let (widths, rules) = storage.widths_and_rules();
259 let target = rect.size.0;
260 SizeRules::solve_widths(widths, rules, target);
261
262 w_offsets.as_mut()[0] = 0;
263 for i in 1..w_offsets.as_mut().len() {
264 let i1 = i - 1;
265 let m1 = storage.width_rules()[i1].margins_i32().1;
266 let m0 = storage.width_rules()[i].margins_i32().0;
267 w_offsets.as_mut()[i] = w_offsets.as_mut()[i1] + storage.widths()[i1] + m1.max(m0);
268 }
269 }
270
271 if rows > 0 {
272 let (heights, rules) = storage.heights_and_rules();
273 let target = rect.size.1;
274 SizeRules::solve_widths(heights, rules, target);
275
276 h_offsets.as_mut()[0] = 0;
277 for i in 1..h_offsets.as_mut().len() {
278 let i1 = i - 1;
279 let m1 = storage.height_rules()[i1].margins_i32().1;
280 let m0 = storage.height_rules()[i].margins_i32().0;
281 h_offsets.as_mut()[i] = h_offsets.as_mut()[i1] + storage.heights()[i1] + m1.max(m0);
282 }
283 }
284
285 GridSetter {
286 w_offsets,
287 h_offsets,
288 pos: rect.pos,
289 _s: Default::default(),
290 }
291 }
292}
293
294impl<CT: RowTemp, RT: RowTemp, S: GridStorage> RulesSetter for GridSetter<CT, RT, S> {
295 type Storage = S;
296 type ChildInfo = GridCellInfo;
297
298 fn child_rect(&mut self, storage: &mut Self::Storage, info: Self::ChildInfo) -> Rect {
299 let x = self.w_offsets.as_mut()[usize::conv(info.col)];
300 let y = self.h_offsets.as_mut()[usize::conv(info.row)];
301 let pos = self.pos + Offset(x, y);
302
303 let i1 = usize::conv(info.last_col);
304 let w = storage.widths()[i1] + self.w_offsets.as_mut()[i1]
305 - self.w_offsets.as_mut()[usize::conv(info.col)];
306 let i1 = usize::conv(info.last_row);
307 let h = storage.heights()[i1] + self.h_offsets.as_mut()[i1]
308 - self.h_offsets.as_mut()[usize::conv(info.row)];
309 let size = Size(w, h);
310
311 Rect { pos, size }
312 }
313}