1use std::marker::PhantomData;
9use std::ops::Range;
10
11use super::{AxisInfo, SizeRules};
12use super::{RowStorage, RowTemp, RulesSetter, RulesSolver};
13use crate::dir::{Direction, Directional};
14use crate::geom::{Coord, Rect};
15use crate::{Collection, Tile};
16
17pub struct RowSolver<S: RowStorage> {
23 axis: AxisInfo,
25 axis_is_vertical: bool,
26 axis_is_reversed: bool,
27 rules: Option<SizeRules>,
28 _s: PhantomData<S>,
29}
30
31impl<S: RowStorage> RowSolver<S> {
32 pub fn new<D: Directional>(axis: AxisInfo, (dir, len): (D, usize), storage: &mut S) -> Self {
40 storage.set_dim(len);
41
42 let axis_is_vertical = axis.is_vertical() ^ dir.is_vertical();
43
44 if axis.has_fixed && axis_is_vertical {
45 let (widths, rules) = storage.widths_and_rules();
47 SizeRules::solve_seq(widths, rules, axis.other_axis);
48 }
49
50 RowSolver {
51 axis,
52 axis_is_vertical,
53 axis_is_reversed: dir.is_reversed(),
54 rules: None,
55 _s: Default::default(),
56 }
57 }
58}
59
60impl<S: RowStorage> RulesSolver for RowSolver<S> {
61 type Storage = S;
62 type ChildInfo = usize;
63
64 fn for_child<CR: FnOnce(AxisInfo) -> SizeRules>(
65 &mut self,
66 storage: &mut Self::Storage,
67 index: Self::ChildInfo,
68 child_rules: CR,
69 ) {
70 if self.axis.has_fixed && self.axis_is_vertical {
71 self.axis.other_axis = storage.widths()[index];
72 }
73 let child_rules = child_rules(self.axis);
74
75 if !self.axis_is_vertical {
76 storage.rules()[index] = child_rules;
77 if let Some(rules) = self.rules {
78 if self.axis_is_reversed {
79 self.rules = Some(child_rules.appended(rules));
80 } else {
81 self.rules = Some(rules.appended(child_rules));
82 }
83 } else {
84 self.rules = Some(child_rules);
85 }
86 } else {
87 self.rules = Some(
88 self.rules
89 .map(|rules| rules.max(child_rules))
90 .unwrap_or(child_rules),
91 );
92 }
93 }
94
95 fn finish(self, _: &mut Self::Storage) -> SizeRules {
96 self.rules.unwrap_or(SizeRules::EMPTY)
97 }
98}
99
100pub struct RowSetter<D, T: RowTemp, S: RowStorage> {
108 rect: Rect,
109 offsets: T,
110 direction: D,
111 _s: PhantomData<S>,
112}
113
114impl<D: Directional, T: RowTemp, S: RowStorage> RowSetter<D, T, S> {
115 pub fn new(rect: Rect, (direction, len): (D, usize), storage: &mut S) -> Self {
123 let mut offsets = T::default();
124 offsets.set_len(len);
125 storage.set_dim(len);
126
127 if len > 0 {
128 let is_horiz = direction.is_horizontal();
129 let width = if is_horiz { rect.size.0 } else { rect.size.1 };
130 let (widths, rules) = storage.widths_and_rules();
131 SizeRules::solve_seq(widths, rules, width);
132 }
133
134 let _s = Default::default();
135 let mut row = RowSetter {
136 rect,
137 offsets,
138 direction,
139 _s,
140 };
141 row.update_offsets(storage);
142 row
143 }
144
145 pub fn new_unsolved(rect: Rect, (direction, len): (D, usize), storage: &mut S) -> Self {
152 let mut offsets = T::default();
153 offsets.set_len(len);
154 storage.set_dim(len);
155
156 let _s = Default::default();
157 RowSetter {
158 rect,
159 offsets,
160 direction,
161 _s,
162 }
163 }
164
165 pub fn update_offsets(&mut self, storage: &mut S) {
166 let offsets = self.offsets.as_mut();
167 let len = offsets.len();
168 if len == 0 {
169 return;
170 }
171
172 let pos = if self.direction.is_horizontal() {
173 self.rect.pos.0
174 } else {
175 self.rect.pos.1
176 };
177
178 if self.direction.is_reversed() {
179 offsets[len - 1] = pos;
180 for i in (0..(len - 1)).rev() {
181 let i1 = i + 1;
182 let m1 = storage.rules()[i1].margins_i32().1;
183 let m0 = storage.rules()[i].margins_i32().0;
184 offsets[i] = offsets[i1] + storage.widths()[i1] + m1.max(m0);
185 }
186 } else {
187 offsets[0] = pos;
188 for i in 1..len {
189 let i1 = i - 1;
190 let m1 = storage.rules()[i1].margins_i32().1;
191 let m0 = storage.rules()[i].margins_i32().0;
192 offsets[i] = offsets[i1] + storage.widths()[i1] + m1.max(m0);
193 }
194 }
195 }
196
197 pub fn solve_range(&mut self, storage: &mut S, range: Range<usize>, width: i32) {
198 assert!(range.end <= self.offsets.as_mut().len());
199
200 let (widths, rules) = storage.widths_and_rules();
201 SizeRules::solve_seq(&mut widths[range.clone()], &rules[range], width);
202 }
203}
204
205impl<D: Directional, T: RowTemp, S: RowStorage> RulesSetter for RowSetter<D, T, S> {
206 type Storage = S;
207 type ChildInfo = usize;
208
209 fn child_rect(&mut self, storage: &mut Self::Storage, index: Self::ChildInfo) -> Rect {
210 let mut rect = self.rect;
211 if self.direction.is_horizontal() {
212 rect.pos.0 = self.offsets.as_mut()[index];
213 rect.size.0 = storage.widths()[index];
214 } else {
215 rect.pos.1 = self.offsets.as_mut()[index];
216 rect.size.1 = storage.widths()[index];
217 }
218 rect
219 }
220
221 fn maximal_rect_of(&mut self, storage: &mut Self::Storage, index: Self::ChildInfo) -> Rect {
222 let pre_rules = SizeRules::min_sum(&storage.rules()[0..index]);
223 let m = storage.rules()[index].margins();
224 let len = storage.widths().len();
225 let post_rules = SizeRules::min_sum(&storage.rules()[(index + 1)..len]);
226
227 let size1 = pre_rules.min_size() + i32::from(pre_rules.margins().1.max(m.0));
228 let size2 = size1 + post_rules.min_size() + i32::from(post_rules.margins().0.max(m.1));
229
230 let mut rect = self.rect;
231 if self.direction.is_horizontal() {
232 rect.pos.0 = self.rect.pos.0 + size1;
233 rect.size.0 = (self.rect.size.0 - size2).max(0);
234 } else {
235 rect.pos.1 = self.rect.pos.1 + size1;
236 rect.size.1 = (self.rect.size.1 - size2).max(0);
237 }
238 rect
239 }
240}
241
242#[derive(Clone, Copy, Debug)]
247pub struct RowPositionSolver<D: Directional> {
248 direction: D,
249}
250
251impl<D: Directional> RowPositionSolver<D> {
252 pub fn new(direction: D) -> Self {
254 RowPositionSolver { direction }
255 }
256
257 fn binary_search<C: Collection + ?Sized>(
258 self,
259 widgets: &C,
260 coord: Coord,
261 ) -> Option<Result<usize, usize>> {
262 match self.direction.as_direction() {
263 Direction::Right => widgets.binary_search_by(|w| w.rect().pos.0.cmp(&coord.0)),
264 Direction::Down => widgets.binary_search_by(|w| w.rect().pos.1.cmp(&coord.1)),
265 Direction::Left => widgets.binary_search_by(|w| w.rect().pos.0.cmp(&coord.0).reverse()),
266 Direction::Up => widgets.binary_search_by(|w| w.rect().pos.1.cmp(&coord.1).reverse()),
267 }
268 }
269
270 pub fn find_child_index<C: Collection + ?Sized>(
277 self,
278 widgets: &C,
279 coord: Coord,
280 ) -> Option<usize> {
281 match self.binary_search(widgets, coord)? {
282 Ok(i) => Some(i),
283 Err(i) if self.direction.is_reversed() => {
284 if i == widgets.len() || !widgets.get_tile(i)?.rect().contains(coord) {
285 None
286 } else {
287 Some(i)
288 }
289 }
290 Err(i) => {
291 if i == 0 || !widgets.get_tile(i - 1)?.rect().contains(coord) {
292 None
293 } else {
294 Some(i - 1)
295 }
296 }
297 }
298 }
299
300 #[inline]
307 pub fn find_child<C: Collection + ?Sized>(
308 self,
309 widgets: &C,
310 coord: Coord,
311 ) -> Option<&dyn Tile> {
312 self.find_child_index(widgets, coord)
313 .and_then(|i| widgets.get_tile(i))
314 }
315
316 #[inline]
323 pub fn find_child_mut<C: Collection + ?Sized>(
324 self,
325 widgets: &mut C,
326 coord: Coord,
327 ) -> Option<&mut dyn Tile> {
328 self.find_child_index(widgets, coord)
329 .and_then(|i| widgets.get_mut_tile(i))
330 }
331
332 pub fn for_children<C: Collection + ?Sized, F: FnMut(&dyn Tile)>(
334 self,
335 widgets: &C,
336 rect: Rect,
337 mut f: F,
338 ) {
339 let (pos, end) = match self.direction.is_reversed() {
340 false => (rect.pos, rect.pos2()),
341 true => (rect.pos2(), rect.pos),
342 };
343 let start = match self.binary_search(widgets, pos) {
344 Some(Ok(i)) => i,
345 Some(Err(i)) if i > 0 => {
346 let mut j = i - 1;
347 if let Some(rect) = widgets.get_tile(j).map(|l| l.rect()) {
348 let cond = match self.direction.as_direction() {
349 Direction::Right => pos.0 < rect.pos2().0,
350 Direction::Down => pos.1 < rect.pos2().1,
351 Direction::Left => rect.pos.0 <= pos.0,
352 Direction::Up => rect.pos.1 <= pos.1,
353 };
354 if !cond {
355 j = i;
356 }
357 }
358 j
359 }
360 _ => 0,
361 };
362
363 for i in start..widgets.len() {
364 if let Some(child) = widgets.get_tile(i) {
365 let do_break = match self.direction.as_direction() {
366 Direction::Right => child.rect().pos.0 >= end.0,
367 Direction::Down => child.rect().pos.1 >= end.1,
368 Direction::Left => child.rect().pos2().0 < end.0,
369 Direction::Up => child.rect().pos2().1 < end.1,
370 };
371 if do_break {
372 break;
373 }
374 f(child);
375 }
376 }
377 }
378}