1use super::*;
9use kas::event::components::ScrollComponent;
10use kas::event::{Command, FocusSource, Scroll};
11use kas::layout::solve_size_rules;
12use kas::prelude::*;
13use kas::theme::SelectionStyle;
14use kas::NavAdvance;
15#[allow(unused)] use kas_widgets::ScrollBars;
17use linear_map::set::LinearSet;
18use std::borrow::Borrow;
19use std::time::Instant;
20
21#[derive(Clone, Copy, Debug, Default)]
22struct Dim {
23 rows: i32,
24 cols: i32,
25}
26
27#[derive(Clone, Debug, Default)]
28struct WidgetData<K, W> {
29 key: Option<K>,
30 widget: W,
31}
32
33impl_scope! {
34 #[derive(Clone, Debug)]
53 #[widget]
54 pub struct MatrixView<A: MatrixData, V: Driver<A::Item, A>> {
55 core: widget_core!(),
56 frame_offset: Offset,
57 frame_size: Size,
58 driver: V,
59 widgets: Vec<WidgetData<A::Key, V::Widget>>,
60 align_hints: AlignHints,
61 ideal_len: Dim,
62 alloc_len: Dim,
63 data_len: Size,
64 cur_len: (u32, u32),
66 first_data: (u32, u32),
67 child_size_min: Size,
68 child_size_ideal: Size,
69 child_inter_margin: Size,
70 child_size: Size,
71 scroll: ScrollComponent,
72 sel_mode: SelectionMode,
73 sel_style: SelectionStyle,
74 selection: LinearSet<A::Key>,
76 press_target: Option<(usize, A::Key)>,
77 }
78
79 impl Self {
80 pub fn new(driver: V) -> Self {
82 MatrixView {
83 core: Default::default(),
84 frame_offset: Default::default(),
85 frame_size: Default::default(),
86 driver,
87 widgets: Default::default(),
88 align_hints: Default::default(),
89 ideal_len: Dim { cols: 3, rows: 5 },
90 alloc_len: Dim::default(),
91 data_len: Size::ZERO,
92 cur_len: (0, 0),
93 first_data: (0, 0),
94 child_size_min: Size::ZERO,
95 child_size_ideal: Size::ZERO,
96 child_inter_margin: Size::ZERO,
97 child_size: Size::ZERO,
98 scroll: Default::default(),
99 sel_mode: SelectionMode::None,
100 sel_style: SelectionStyle::Highlight,
101 selection: Default::default(),
102 press_target: None,
103 }
104 }
105
106 pub fn selection_mode(&self) -> SelectionMode {
108 self.sel_mode
109 }
110 pub fn set_selection_mode(&mut self, mode: SelectionMode) -> Action {
125 self.sel_mode = mode;
126 match mode {
127 SelectionMode::None if !self.selection.is_empty() => {
128 self.selection.clear();
129 Action::REDRAW
130 }
131 SelectionMode::Single if self.selection.len() > 1 => {
132 if let Some(first) = self.selection.iter().next().cloned() {
133 self.selection.retain(|item| *item == first);
134 }
135 Action::REDRAW
136 }
137 _ => Action::empty(),
138 }
139 }
140 #[must_use]
144 pub fn with_selection_mode(mut self, mode: SelectionMode) -> Self {
145 let _ = self.set_selection_mode(mode);
146 self
147 }
148
149 pub fn selection_style(&self) -> SelectionStyle {
151 self.sel_style
152 }
153 pub fn set_selection_style(&mut self, style: SelectionStyle) -> Action {
158 let action = if style.is_external() != self.sel_style.is_external() {
159 Action::RESIZE
160 } else {
161 Action::empty()
162 };
163 self.sel_style = style;
164 action
165 }
166 #[must_use]
170 pub fn with_selection_style(mut self, style: SelectionStyle) -> Self {
171 self.sel_style = style;
172 self
173 }
174
175 pub fn selected_iter(&'_ self) -> impl Iterator<Item = &'_ A::Key> + '_ {
180 self.selection.iter()
181 }
182
183 pub fn is_selected(&self, key: &A::Key) -> bool {
185 self.selection.contains(key)
186 }
187
188 pub fn clear_selected(&mut self) -> Action {
190 if self.selection.is_empty() {
191 Action::empty()
192 } else {
193 self.selection.clear();
194 Action::REDRAW
195 }
196 }
197
198 pub fn select(&mut self, key: A::Key) -> Action {
208 match self.sel_mode {
209 SelectionMode::None => return Action::empty(),
210 SelectionMode::Single => self.selection.clear(),
211 _ => (),
212 }
213 match self.selection.insert(key) {
214 true => Action::REDRAW,
215 false => Action::empty(),
216 }
217 }
218
219 pub fn deselect(&mut self, key: &A::Key) -> Action {
224 match self.selection.remove(key) {
225 true => Action::REDRAW,
226 false => Action::empty(),
227 }
228 }
229
230 #[must_use]
235 pub fn with_num_visible(mut self, cols: i32, rows: i32) -> Self {
236 self.ideal_len = Dim { cols, rows };
237 self
238 }
239
240 fn position_solver(&self) -> PositionSolver {
241 PositionSolver {
242 pos_start: self.core.rect.pos + self.frame_offset,
243 skip: self.child_size + self.child_inter_margin,
244 size: self.child_size,
245 first_data: self.first_data,
246 cur_len: self.cur_len,
247 }
248 }
249
250 fn update_widgets(&mut self, cx: &mut ConfigCx, data: &A) -> PositionSolver {
251 let time = Instant::now();
252
253 let offset = self.scroll_offset();
254 let skip = (self.child_size + self.child_inter_margin).max(Size(1, 1));
255 let data_len = data.len();
256 let col_len = data_len.0.min(self.alloc_len.cols.cast());
257 let row_len = data_len.1.min(self.alloc_len.rows.cast());
258 let first_col = usize::conv(u64::conv(offset.0) / u64::conv(skip.0))
259 .min(data_len.0 - col_len);
260 let first_row = usize::conv(u64::conv(offset.1) / u64::conv(skip.1))
261 .min(data_len.1 - row_len);
262 self.cur_len = (col_len.cast(), row_len.cast());
263 debug_assert!(self.num_children() <= self.widgets.len());
264 self.first_data = (first_row.cast(), first_col.cast());
265
266 let solver = self.position_solver();
267
268 let cols: Vec<_> = data
269 .col_iter_from(first_col, col_len)
270 .collect();
271 if cols.len() < col_len {
272 log::warn!(
273 "{}: data.col_iter_vec_from({}, {}) yielded insufficient items (possibly incorrect data.len())", self.identify(),
274 first_col,
275 col_len,
276 );
277 }
278
279 let row_iter = data.row_iter_from(first_row, row_len);
280
281 let mut row_count = 0;
282 for (rn, row) in row_iter.enumerate() {
283 row_count += 1;
284 let ri = first_row + rn;
285 for (cn, col) in cols.iter().enumerate() {
286 let ci = first_col + cn;
287 let i = solver.data_to_child(ci, ri);
288 let key = data.make_key(col, &row);
289 let id = key.make_id(self.id_ref());
290 let w = &mut self.widgets[i];
291 if w.key.as_ref() != Some(&key) {
292 self.driver.set_key(&mut w.widget, &key);
293
294 if let Some(item) = data.borrow(&key) {
295 cx.configure(w.widget.as_node(item.borrow()), id);
296
297 w.key = Some(key);
298 solve_size_rules(
299 &mut w.widget,
300 cx.size_cx(),
301 Some(self.child_size.0),
302 Some(self.child_size.1),
303 );
304 } else {
305 w.key = None; }
307 } else if let Some(item) = data.borrow(&key) {
308 cx.update(w.widget.as_node(item.borrow()));
309 }
310 w.widget.set_rect(cx, solver.rect(ci, ri), self.align_hints);
311 }
312 }
313
314 if row_count < row_len {
315 log::warn!(
316 "{}: data.row_iter_vec_from({}, {}) yielded insufficient items (possibly incorrect data.len())", self.identify(),
317 first_row,
318 row_len,
319 );
320 }
321
322 let dur = (Instant::now() - time).as_micros();
323 log::trace!(target: "kas_perf::view::matrix_view", "update_widgets: {dur}μs");
324 solver
325 }
326
327 fn update_content_size(&mut self, cx: &mut ConfigCx) {
328 let view_size = self.rect().size - self.frame_size;
329 let skip = self.child_size + self.child_inter_margin;
330 let content_size = (skip.cwise_mul(self.data_len) - self.child_inter_margin)
331 .max(Size::ZERO);
332 let action = self.scroll.set_sizes(view_size, content_size);
333 cx.action(self, action);
334 }
335 }
336
337 impl Scrollable for Self {
338 fn scroll_axes(&self, size: Size) -> (bool, bool) {
339 let m = self.child_inter_margin;
340 let step = self.child_size + m;
341 let content_size = (step.cwise_mul(self.data_len) - m).max(Size::ZERO);
342 (content_size.0 > size.0, content_size.1 > size.1)
343 }
344
345 #[inline]
346 fn max_scroll_offset(&self) -> Offset {
347 self.scroll.max_offset()
348 }
349
350 #[inline]
351 fn scroll_offset(&self) -> Offset {
352 self.scroll.offset()
353 }
354
355 #[inline]
356 fn set_scroll_offset(&mut self, cx: &mut EventCx, offset: Offset) -> Offset {
357 let action = self.scroll.set_offset(offset);
358 cx.action(&self, action);
359 cx.request_update(self.id(), false);
360 self.scroll.offset()
361 }
362 }
363
364 impl Layout for Self {
365 #[inline]
366 fn num_children(&self) -> usize {
367 usize::conv(self.cur_len.0) * usize::conv(self.cur_len.1)
368 }
369 fn get_child(&self, index: usize) -> Option<&dyn Layout> {
370 self.widgets.get(index).map(|w| w.widget.as_layout())
371 }
372 fn find_child_index(&self, id: &Id) -> Option<usize> {
373 let num = self.num_children();
374 let key = A::Key::reconstruct_key(self.id_ref(), id);
375 if key.is_some() {
376 self.widgets[0..num]
377 .iter()
378 .enumerate()
379 .filter_map(|(i, w)| (key == w.key).then_some(i))
380 .next()
381 } else {
382 None
383 }
384 }
385
386 fn size_rules(&mut self, sizer: SizeCx, mut axis: AxisInfo) -> SizeRules {
387 let inner_margin = if self.sel_style.is_external() {
389 sizer.inner_margins().extract(axis)
390 } else {
391 (0, 0)
392 };
393 let frame = kas::layout::FrameRules::new(0, inner_margin, (0, 0));
394
395 let other = axis.other().map(|mut size| {
396 let other_axis = axis.flipped();
398 size -= self.frame_size.extract(other_axis);
399 let div = Size(self.ideal_len.cols, self.ideal_len.rows).extract(other_axis);
400 (size / div)
401 .min(self.child_size_ideal.extract(other_axis))
402 .max(self.child_size_min.extract(other_axis))
403 });
404 axis = AxisInfo::new(axis.is_vertical(), other);
405
406 let mut child_size_min = i32::MAX;
407 let mut rules = SizeRules::EMPTY;
408 for w in self.widgets.iter_mut() {
409 if w.key.is_some() {
410 let child_rules = w.widget.size_rules(sizer.re(), axis);
411 child_size_min = child_size_min.min(child_rules.min_size());
412 rules = rules.max(child_rules);
413 }
414 }
415 self.child_size_min.set_component(axis, child_size_min);
416 self.child_size_ideal.set_component(axis, rules.ideal_size());
417
418 let m = rules.margins();
419 self.child_inter_margin.set_component(
420 axis,
421 m.0.max(m.1).max(inner_margin.0).max(inner_margin.1).cast(),
422 );
423
424 let ideal_len = match axis.is_vertical() {
425 false => self.ideal_len.cols,
426 true => self.ideal_len.rows,
427 };
428 rules.multiply_with_margin(2, ideal_len);
429 rules.set_stretch(rules.stretch().max(Stretch::High));
430
431 let (rules, offset, size) = frame.surround(rules);
432 self.frame_offset.set_component(axis, offset);
433 self.frame_size.set_component(axis, size);
434 rules
435 }
436
437 fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
438 self.core.rect = rect;
439 self.align_hints = hints;
440
441 self.cur_len = (0, 0); cx.request_update(self.id(), false);
444
445 let avail = rect.size - self.frame_size;
446 let child_size = Size(avail.0 / self.ideal_len.cols, avail.1 / self.ideal_len.rows)
447 .min(self.child_size_ideal)
448 .max(self.child_size_min);
449 self.child_size = child_size;
450 self.update_content_size(cx);
451
452 let skip = self.child_size + self.child_inter_margin;
453 if skip.0 == 0 || skip.1 == 0 {
454 self.alloc_len = Dim { cols: 0, rows: 0 };
455 return;
456 }
457 let vis_len = (rect.size + skip - Size::splat(1)).cwise_div(skip) + Size::splat(1);
458 let req_widgets = usize::conv(vis_len.0) * usize::conv(vis_len.1);
459
460 self.alloc_len = Dim {
461 cols: vis_len.0,
462 rows: vis_len.1,
463 };
464
465 let avail_widgets = self.widgets.len();
466 if avail_widgets < req_widgets {
467 log::debug!(
468 "set_rect: allocating widgets (old len = {}, new = {})",
469 avail_widgets,
470 req_widgets
471 );
472 self.widgets.resize_with(req_widgets, || {
473 WidgetData {
474 key: None,
475 widget: self.driver.make(&A::Key::default()),
476 }
477 });
478 } else if req_widgets + 64 <= avail_widgets {
479 self.widgets.truncate(req_widgets);
481 }
482 debug_assert!(self.widgets.len() >= req_widgets);
483 }
484
485 #[inline]
486 fn translation(&self) -> Offset {
487 self.scroll_offset()
488 }
489
490 fn find_id(&mut self, coord: Coord) -> Option<Id> {
491 if !self.rect().contains(coord) {
492 return None;
493 }
494
495 let num = self.num_children();
496 let coord = coord + self.scroll.offset();
497 for child in &mut self.widgets[..num] {
498 if child.key.is_some() {
499 if let Some(id) = child.widget.find_id(coord) {
500 return Some(id);
501 }
502 }
503 }
504 Some(self.id())
505 }
506
507 fn draw(&mut self, mut draw: DrawCx) {
508 let offset = self.scroll_offset();
509 let rect = self.rect() + offset;
510 let num = self.num_children();
511 draw.with_clip_region(self.core.rect, offset, |mut draw| {
512 for child in &mut self.widgets[..num] {
513 if let Some(ref key) = child.key {
514 if rect.intersection(&child.widget.rect()).is_some() {
517 if self.selection.contains(key) {
518 draw.selection(child.widget.rect(), self.sel_style);
519 }
520 draw.recurse(&mut child.widget);
521 }
522 }
523 }
524 });
525 }
526 }
527
528 impl Events for Self {
529 #[inline]
530 fn make_child_id(&mut self, _: usize) -> Id {
531 unimplemented!()
533 }
534
535 fn configure(&mut self, cx: &mut ConfigCx) {
536 if self.widgets.is_empty() {
537 self.child_size = Size::splat(1); let len = self.ideal_len.cols * self.ideal_len.rows;
542 self.widgets.resize_with(len.cast(), || {
543 WidgetData {
544 key: None,
545 widget: self.driver.make(&A::Key::default()),
546 }
547 });
548 self.alloc_len = self.ideal_len;
549 }
550
551 cx.register_nav_fallback(self.id());
552 }
553
554 fn configure_recurse(&mut self, _: &mut ConfigCx, _: &Self::Data) {}
555
556 fn update(&mut self, cx: &mut ConfigCx, data: &A) {
557 self.selection.retain(|key| data.contains_key(key));
558
559 let (d_cols, d_rows) = data.len();
560 let data_len = Size(d_cols.cast(), d_rows.cast());
561 if data_len != self.data_len {
562 self.data_len = data_len;
563 cx.resize(&self);
567 }
568
569 self.update_widgets(cx, data);
570 self.update_content_size(cx);
571 }
572
573 fn update_recurse(&mut self, _: &mut ConfigCx, _: &Self::Data) {}
574
575 fn handle_event(&mut self, cx: &mut EventCx, data: &A, event: Event) -> IsUsed {
576 let is_used = match event {
577 Event::Command(cmd, _) => {
578 if data.is_empty() {
579 return Unused;
580 }
581 let (d_cols, d_rows) = data.len();
582 let (last_col, last_row) = (d_cols.wrapping_sub(1), d_rows.wrapping_sub(1));
583
584 let row_len: usize = self.cur_len.1.cast();
585 let mut solver = self.position_solver();
586 let (ci, ri) = match cx.nav_focus().and_then(|id| self.find_child_index(id)) {
587 Some(index) => solver.child_to_data(index),
588 None => return Unused,
589 };
590
591 use Command as C;
592 let data_index = match cmd {
593 C::DocHome => Some((0, 0)),
594 C::DocEnd => Some((last_col, last_row)),
595 C::Home => Some((0, ri)),
596 C::End => Some((last_col, ri)),
597 C::Left | C::WordLeft if ci > 0 => Some((ci - 1, ri)),
598 C::Up if ri > 0 => Some((ci, ri - 1)),
599 C::Right | C::WordRight if ci < last_col => Some((ci + 1, ri)),
600 C::Down if ri < last_row => Some((ci, ri + 1)),
601 C::PageUp if ri > 0 => Some((ci, ri.saturating_sub(row_len / 2))),
602 C::PageDown if ri < last_row => {
603 Some((ci, (ri + row_len / 2).min(last_row)))
604 }
605 _ => None,
607 };
608 return if let Some((ci, ri)) = data_index {
609 let action = self.scroll.focus_rect(cx, solver.rect(ci, ri), self.core.rect);
611 if !action.is_empty() {
612 cx.action(&self, action);
613 solver = self.update_widgets(&mut cx.config_cx(), data);
614 }
615
616 let index = solver.data_to_child(ci, ri);
617 #[cfg(debug_assertions)]
618 {
619 let rk = data
620 .row_iter_from(ri, 1)
621 .next()
622 .expect("data row len > data.row_iter_vec len");
623 let ck = data
624 .col_iter_from(ci, 1)
625 .next()
626 .expect("data col len > data.col_iter_vec len");
627 let key = data.make_key(&ck, &rk);
628 assert_eq!(
629 self.widgets[index].widget.id(),
630 key.make_id(self.id_ref()),
631 );
632 }
633
634 cx.next_nav_focus(self.widgets[index].widget.id(), false, FocusSource::Key);
635 Used
636 } else {
637 Unused
638 };
639 }
640 Event::PressStart { ref press } if
641 press.is_primary() && cx.config().event().mouse_nav_focus() =>
642 {
643 if let Some(index) = cx.last_child() {
644 self.press_target = self.widgets[index].key.clone().map(|k| (index, k));
645 }
646 if let Some((index, ref key)) = self.press_target {
647 let w = &mut self.widgets[index];
648 if w.key.as_ref().map(|k| k == key).unwrap_or(false) {
649 cx.next_nav_focus(w.widget.id(), false, FocusSource::Pointer);
650 }
651 }
652
653 press.grab(self.id()).with_cx(cx)
656 }
657 Event::PressEnd { ref press, success } if press.is_primary() => {
658 if let Some((index, ref key)) = self.press_target {
659 let w = &mut self.widgets[index];
660 if success
661 && !matches!(self.sel_mode, SelectionMode::None)
662 && !self.scroll.is_gliding()
663 && w.key.as_ref().map(|k| k == key).unwrap_or(false)
664 && w.widget.rect().contains(press.coord + self.scroll.offset())
665 {
666 cx.push(kas::messages::Select);
667 }
668 }
669 Used
670 }
671 _ => Unused, };
673
674 let (moved, used_by_sber) = self
675 .scroll
676 .scroll_by_event(cx, event, self.id(), self.core.rect);
677 if moved {
678 self.update_widgets(&mut cx.config_cx(), data);
679 }
680 is_used | used_by_sber
681 }
682
683 fn handle_messages(&mut self, cx: &mut EventCx, data: &A) {
684 let key;
685 if let Some(index) = cx.last_child() {
686 let w = &mut self.widgets[index];
687 key = match w.key.clone() {
688 Some(k) => k,
689 None => return,
690 };
691
692 self.driver.on_messages(cx, &mut w.widget, data, &key);
693 } else {
694 key = match self.press_target.clone() {
696 Some((_, k)) => k,
697 None => return,
698 };
699 }
700
701 if let Some(kas::messages::Select) = cx.try_pop() {
702 match self.sel_mode {
703 SelectionMode::None => (),
704 SelectionMode::Single => {
705 cx.redraw(&self);
706 self.selection.clear();
707 self.selection.insert(key.clone());
708 cx.push(SelectionMsg::Select(key));
709 }
710 SelectionMode::Multiple => {
711 cx.redraw(&self);
712 if self.selection.remove(&key) {
713 cx.push(SelectionMsg::Deselect(key));
714 } else {
715 self.selection.insert(key.clone());
716 cx.push(SelectionMsg::Select(key));
717 }
718 }
719 }
720 }
721 }
722
723 fn handle_scroll(&mut self, cx: &mut EventCx, data: &A, scroll: Scroll) {
724 let act = self.scroll.scroll(cx, self.rect(), scroll);
725 self.update_widgets(&mut cx.config_cx(), data);
726 cx.action(self, act);
727 }
728 }
729
730 impl Widget for Self {
732 type Data = A;
733
734 fn for_child_node(
735 &mut self,
736 data: &A,
737 index: usize,
738 closure: Box<dyn FnOnce(Node<'_>) + '_>,
739 ) {
740 if let Some(w) = self.widgets.get_mut(index) {
741 if let Some(ref key) = w.key {
742 if let Some(item) = data.borrow(key) {
743 closure(w.widget.as_node(item.borrow()));
744 }
745 }
746 }
747 }
748
749 fn _configure(&mut self, cx: &mut ConfigCx, data: &A, id: Id) {
750 self.core.id = id;
751 #[cfg(debug_assertions)]
752 self.core.status.configure(&self.core.id);
753
754 self.configure(cx);
755 self.update(cx, data);
756 }
757
758 fn _update(&mut self, cx: &mut ConfigCx, data: &A) {
759 #[cfg(debug_assertions)]
760 self.core.status.update(&self.core.id);
761
762 self.update(cx, data);
763 }
764
765 fn _send(
766 &mut self,
767 cx: &mut EventCx,
768 data: &A,
769 id: Id,
770 event: Event,
771 ) -> IsUsed {
772 kas::impls::_send(self, cx, data, id, event)
773 }
774
775 fn _replay(&mut self, cx: &mut EventCx, data: &A, id: Id) {
776 kas::impls::_replay(self, cx, data, id);
777 }
778
779 fn _nav_next(
781 &mut self,
782 cx: &mut ConfigCx,
783 data: &A,
784 focus: Option<&Id>,
785 advance: NavAdvance,
786 ) -> Option<Id> {
787 if cx.is_disabled(self.id_ref()) || self.cur_len == (0, 0) {
788 return None;
789 }
790
791 let mut child = focus.and_then(|id| self.find_child_index(id));
792
793 if let Some(index) = child {
794 if let Some(Some(id)) = self.as_node(data)
795 .for_child(index, |mut w| w._nav_next(cx, focus, advance))
796 {
797 return Some(id);
798 }
799 }
800
801 let reverse = match advance {
802 NavAdvance::None => return None,
803 NavAdvance::Forward(_) => false,
804 NavAdvance::Reverse(_) => true,
805 };
806
807 let mut starting_child = child;
808 loop {
809 let mut solver = self.position_solver();
810 let (d_cols, d_rows) = data.len();
811 let (ci, ri) = if let Some(index) = child {
812 let (ci, ri) = solver.child_to_data(index);
813 if !reverse {
814 if ci + 1 < d_cols {
815 (ci + 1, ri)
816 } else if ri + 1 < d_rows {
817 (0, ri + 1)
818 } else {
819 return None;
820 }
821 } else {
822 if ci > 0 {
823 (ci - 1, ri)
824 } else if ri > 0 {
825 (d_cols - 1, ri - 1)
826 } else {
827 return None;
828 }
829 }
830 } else if !reverse {
831 (0, 0)
832 } else {
833 (d_cols - 1, d_rows - 1)
834 };
835
836 let action = self.scroll.self_focus_rect(solver.rect(ci, ri), self.core.rect);
837 if !action.is_empty() {
838 cx.action(&self, action);
839 solver = self.update_widgets(cx, data);
840 }
841
842 let index = solver.data_to_child(ci, ri);
843 if let Some(Some(id)) = self.as_node(data)
844 .for_child(index, |mut w| w._nav_next(cx, focus, advance))
845 {
846 return Some(id);
847 }
848
849 child = Some(index);
850 if starting_child == child {
851 return None;
852 } else if starting_child.is_none() {
853 starting_child = child;
854 }
855 }
856 }
857 }
858}
859
860#[derive(Debug)]
861struct PositionSolver {
862 pos_start: Coord,
863 skip: Size,
864 size: Size,
865 first_data: (u32, u32),
866 cur_len: (u32, u32),
867}
868
869impl PositionSolver {
870 fn data_to_child(&self, ci: usize, ri: usize) -> usize {
872 let col_len: usize = self.cur_len.0.cast();
873 let row_len: usize = self.cur_len.1.cast();
874 (ci % col_len) + (ri % row_len) * col_len
875 }
876
877 fn child_to_data(&self, index: usize) -> (usize, usize) {
879 let col_len: usize = self.cur_len.0.cast();
880 let row_len: usize = self.cur_len.1.cast();
881 let first_col: usize = self.first_data.0.cast();
882 let first_row: usize = self.first_data.1.cast();
883 let col_start = (first_col / col_len) * col_len;
884 let row_start = (first_row / row_len) * row_len;
885 let mut col_index = col_start + index % col_len;
886 let mut row_index = row_start + index / col_len;
887 if col_index < first_col {
888 col_index += col_len;
889 }
890 if row_index < first_row {
891 row_index += row_len;
892 }
893 (col_index, row_index)
894 }
895
896 fn rect(&self, ci: usize, ri: usize) -> Rect {
898 let pos = self.pos_start + self.skip.cwise_mul(Size(ci.cast(), ri.cast()));
899 Rect::new(pos, self.size)
900 }
901}