1use std::rc::Rc;
2
3use sequoia_core::{Constraints, Length, Rect, Size};
4use sequoia_layout::{LayoutCtx, LayoutStyle, resolve_cross};
5
6use crate::any::AnyView;
7use crate::runtime::{ElementId, Runtime};
8use crate::view::View;
9use crate::views::Unit;
10
11pub struct List<T> {
12 items: Rc<dyn Fn() -> Vec<T>>,
13 key: Option<Rc<dyn Fn(&T) -> u64>>,
14 item: Rc<dyn Fn(&T) -> AnyView>,
15}
16
17impl<T: 'static> List<T> {
18 pub fn new<F: Fn() -> Vec<T> + 'static>(items: F) -> Self {
19 Self {
20 items: Rc::new(items),
21 key: None,
22 item: Rc::new(|_| AnyView::new(Unit)),
23 }
24 }
25
26 pub fn key<K: Fn(&T) -> u64 + 'static>(mut self, key: K) -> Self {
27 self.key = Some(Rc::new(key));
28 self
29 }
30
31 pub fn item<I, F>(mut self, item: F) -> Self
32 where
33 I: View + 'static,
34 F: Fn(&T) -> I + 'static,
35 {
36 self.item = Rc::new(move |t: &T| AnyView::new(item(t)));
37 self
38 }
39}
40
41impl<T: 'static> View for List<T> {
42 fn body(&self) -> impl View + 'static {
43 Unit
44 }
45
46 fn keyed_children(&self) -> Option<Vec<(u64, AnyView)>> {
47 let items = (self.items)();
48 let key = self.key.clone();
49 let item = self.item.clone();
50 Some(
51 items
52 .iter()
53 .enumerate()
54 .map(|(i, it)| {
55 let k = match &key {
56 Some(f) => f(it),
57 None => i as u64,
58 };
59 (k, item(it))
60 })
61 .collect(),
62 )
63 }
64
65 fn layout_style(&self) -> LayoutStyle {
66 LayoutStyle {
67 width: Length::Fill(1.0),
68 height: Length::Fit,
69 ..LayoutStyle::default()
70 }
71 }
72
73 fn arrange_override(
74 &self,
75 rt: &Runtime,
76 el: ElementId,
77 rect: Rect,
78 ctx: &mut LayoutCtx,
79 ) -> bool {
80 let children = rt.children(el);
81 if children.is_empty() {
82 return true;
83 }
84 let mut rows: Vec<(ElementId, f32, f32)> = Vec::with_capacity(children.len());
85 let mut total = 0.0_f32;
86 for child in children {
87 let cs = rt.child_layout_style(child);
88 let m = rt.measure_node(
89 child,
90 Constraints {
91 min: Size::ZERO,
92 max: Size::new(rect.size.width, f32::INFINITY),
93 },
94 ctx,
95 );
96 let w = cs
97 .clamp_width(resolve_cross(cs.width, m.width, rect.size.width))
98 .max(0.0);
99 let h = cs.clamp_height(m.height).max(0.0);
100 total += h;
101 rows.push((child, w, h));
102 }
103
104 if total <= 0.0 && rect.size.height.is_finite() && rect.size.height > 0.0 {
105 let even = rect.size.height / rows.len() as f32;
106 for row in &mut rows {
107 row.2 = even;
108 }
109 }
110 let mut cursor = rect.top();
111 for (child, w, h) in rows {
112 rt.arrange_node(child, Rect::from_xywh(rect.left(), cursor, w, h), ctx);
113 cursor += h;
114 }
115 true
116 }
117}