lgui-core 0.2.0

Platform-neutral runtime and UI primitives for LGUI
Documentation
use super::*;

impl HostTree {
    pub(crate) fn has_shadow_ancestor(&self, id: &UiId) -> bool {
        self.shadow_root(id).is_some()
    }

    fn shadow_root(&self, id: &UiId) -> Option<&UiNode> {
        let mut current = self.node(id);
        let mut root = None;
        while let Some(node) = current {
            if node.shadow.is_some() {
                root = Some(node);
            }
            current = node.parent.as_ref().and_then(|parent| self.node(parent));
            if node.render_phase == super::super::RenderPhase::Popup
                && current.is_some_and(|parent| parent.render_phase != node.render_phase)
            {
                break;
            }
        }
        root
    }

    pub fn paint_bounds(&self, ids: impl IntoIterator<Item = UiId>) -> Option<UiRect> {
        ids.into_iter()
            .filter_map(|id| {
                let node = self.node(&id)?;
                let mut bounds = node_dirty_bounds(node);
                if let Some(root) = self.shadow_root(&id) {
                    for command in crate::core::compile_scene_root(self, &root.id).commands() {
                        bounds = bounds.union(command.paint_bounds());
                    }
                }
                Some(bounds)
            })
            .reduce(UiRect::union)
    }

    pub fn full_paint_bounds(&self) -> Option<UiRect> {
        let bounds = self
            .nodes
            .iter()
            .map(|node| node.paint_bounds)
            .reduce(UiRect::union);
        self.nodes
            .iter()
            .filter(|node| node.shadow.is_some())
            .fold(bounds, |bounds, node| {
                crate::core::compile_scene_root(self, &node.id)
                    .commands()
                    .iter()
                    .fold(bounds, |bounds, command| {
                        Some(bounds.map_or(command.paint_bounds(), |bounds| {
                            bounds.union(command.paint_bounds())
                        }))
                    })
            })
    }

    pub fn scene(&self) -> Scene {
        compile_scene(self)
    }
}

fn node_dirty_bounds(node: &UiNode) -> UiRect {
    let (x, y) = node.animation_outset;
    node.paint_bounds.inflate(x, y)
}