Skip to main content

sequoia_view/
list.rs

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}