termint 0.8.0

Library for colored printing and Terminal User Interfaces
Documentation
use crate::{prelude::Rect, widgets::Widget};

#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct LayoutNode {
    pub area: Rect,
    pub children: Vec<LayoutNode>,
    pub is_dirty: bool,
    pub has_dirty_child: bool,
}

impl LayoutNode {
    /// Constructs new [`LayoutNode`] recursively based on the given [`Widget`]
    /// tree.
    pub fn new<M>(widget: &dyn Widget<M>) -> Self
    where
        M: Clone + 'static,
    {
        let children = widget.children();
        Self {
            area: Rect::default(),
            children: children.iter().map(|c| LayoutNode::new(*c)).collect(),
            is_dirty: true,
            has_dirty_child: true,
        }
    }

    pub fn diff<M>(&mut self, old: &dyn Widget<M>, new: &dyn Widget<M>)
    where
        M: Clone + 'static,
    {
        if old.layout_hash() != new.layout_hash() {
            self.is_dirty = true;
        }

        let old_children = old.children();
        let new_children = new.children();
        if old_children.len() != new_children.len() {
            self.children
                .resize(new_children.len(), LayoutNode::default());
            self.is_dirty = true;
        }

        for (i, child) in new_children.iter().enumerate() {
            let Some(old_child) = old_children.get(i) else {
                self.children[i] = LayoutNode::new(*child);
                continue;
            };

            self.children[i].diff(*old_child, *child);
            if self.children[i].is_dirty || self.children[i].has_dirty_child {
                self.has_dirty_child = true;
            }
        }
    }
}