sequoia-view 0.1.0

Sequoia GUI framework — view tree and runtime
Documentation
use std::rc::Rc;

use sequoia_core::{Constraints, Length, Rect, Size};
use sequoia_layout::{LayoutCtx, LayoutStyle, resolve_cross};

use crate::any::AnyView;
use crate::runtime::{ElementId, Runtime};
use crate::view::View;
use crate::views::Unit;

pub struct List<T> {
    items: Rc<dyn Fn() -> Vec<T>>,
    key: Option<Rc<dyn Fn(&T) -> u64>>,
    item: Rc<dyn Fn(&T) -> AnyView>,
}

impl<T: 'static> List<T> {
    pub fn new<F: Fn() -> Vec<T> + 'static>(items: F) -> Self {
        Self {
            items: Rc::new(items),
            key: None,
            item: Rc::new(|_| AnyView::new(Unit)),
        }
    }

    pub fn key<K: Fn(&T) -> u64 + 'static>(mut self, key: K) -> Self {
        self.key = Some(Rc::new(key));
        self
    }

    pub fn item<I, F>(mut self, item: F) -> Self
    where
        I: View + 'static,
        F: Fn(&T) -> I + 'static,
    {
        self.item = Rc::new(move |t: &T| AnyView::new(item(t)));
        self
    }
}

impl<T: 'static> View for List<T> {
    fn body(&self) -> impl View + 'static {
        Unit
    }

    fn keyed_children(&self) -> Option<Vec<(u64, AnyView)>> {
        let items = (self.items)();
        let key = self.key.clone();
        let item = self.item.clone();
        Some(
            items
                .iter()
                .enumerate()
                .map(|(i, it)| {
                    let k = match &key {
                        Some(f) => f(it),
                        None => i as u64,
                    };
                    (k, item(it))
                })
                .collect(),
        )
    }

    fn layout_style(&self) -> LayoutStyle {
        LayoutStyle {
            width: Length::Fill(1.0),
            height: Length::Fit,
            ..LayoutStyle::default()
        }
    }

    fn arrange_override(
        &self,
        rt: &Runtime,
        el: ElementId,
        rect: Rect,
        ctx: &mut LayoutCtx,
    ) -> bool {
        let children = rt.children(el);
        if children.is_empty() {
            return true;
        }
        let mut rows: Vec<(ElementId, f32, f32)> = Vec::with_capacity(children.len());
        let mut total = 0.0_f32;
        for child in children {
            let cs = rt.child_layout_style(child);
            let m = rt.measure_node(
                child,
                Constraints {
                    min: Size::ZERO,
                    max: Size::new(rect.size.width, f32::INFINITY),
                },
                ctx,
            );
            let w = cs
                .clamp_width(resolve_cross(cs.width, m.width, rect.size.width))
                .max(0.0);
            let h = cs.clamp_height(m.height).max(0.0);
            total += h;
            rows.push((child, w, h));
        }

        if total <= 0.0 && rect.size.height.is_finite() && rect.size.height > 0.0 {
            let even = rect.size.height / rows.len() as f32;
            for row in &mut rows {
                row.2 = even;
            }
        }
        let mut cursor = rect.top();
        for (child, w, h) in rows {
            rt.arrange_node(child, Rect::from_xywh(rect.left(), cursor, w, h), ctx);
            cursor += h;
        }
        true
    }
}