tomt_bevycss 0.7.1

Expansion and fixes based on bevy_ecss. Allows for using a slightly wider subset of CSS to interact with Bevy ECS. Now on Bevy 0.13!
Documentation
use super::query;
use crate::prelude::StyleSheetAsset;

use bevy::{
    log::{error, debug, trace},
    prelude::{
        Deref, DerefMut,
        Entity,
        Handle,
    },
    utils::HashMap
};

#[derive(Clone)]
pub(super) struct StyleTreeNode
{
    pub entity: Entity,
    pub sheet_handle: Handle<StyleSheetAsset>,
    pub parent: Option<Handle<StyleSheetAsset>>,
}

#[derive(Default, Deref, DerefMut)]
pub(super) struct StyleTree(
    HashMap<
        Handle<StyleSheetAsset>,
        StyleTreeNode
    >
);

impl StyleTree
{
    fn resolve(
        &self,
        child_node: &Handle<StyleSheetAsset>,
    ) -> Vec<(Entity, Handle<StyleSheetAsset>)> {
        match self.get(child_node)
        {
            Some(style) => {
                let iter = std::iter::once((style.entity, style.sheet_handle.clone()));
                match &style.parent
                {
                    Some(parent) => self.resolve(parent)
                        .into_iter()
                        .chain(iter)
                        .collect(),

                    None => iter.collect(),
                }
            }
            None => vec![],
        }
    }
}

impl<'me, 'w, 's> StyleTree
{
    fn get_or_find_root(
        &'me mut self,
        entity: Entity,
        query: &'w query::QueryUiNodes<'w, 's>,
    ) -> Option<StyleTreeNode> {
        let entity_idx = entity.index();

        let (entity, parent, _c, sheet) = match query.get(entity)
        {
            Ok((e, p, c, s)) => (e, p, c, s),
            Err(err) => {
                error!("Query on entity {entity_idx} failed, {err}");
                return None;
            }
        };

        match (sheet, parent)
        {
            (Some(style), _p) => {
                trace!("Stylesheet found on entity {entity_idx}");
                let result = if let Some(node) = self.get(style.handle())
                {
                    trace!("Entity {entity_idx} is already in the tree, returning early");
                    node
                }
                else
                {
                    trace!("Creating entry in tree for entity {entity_idx}");
                    let parent = match parent
                    {
                        Some(p) => self.get_or_find_root(p.get(), query),
                        None => {
                            debug!("Entity {entity_idx} has no parent UI node, terminating search");
                            None
                        }
                    }
                    .map(|p| p.sheet_handle);

                    self.insert_unique_unchecked(
                        style.handle().clone(),
                        StyleTreeNode
                        {
                            entity,
                            sheet_handle: style.handle().clone(),
                            parent,
                        },
                    ).1
                };
                Some(result.clone())
            }

            (None, Some(parent)) => self.get_or_find_root(parent.get(), query),

            (None, None) => {
                debug!("Entity {entity_idx} has no UI parent, or attached stylesheet");
                None
            }
        }
    }

    pub fn get_style_roots_for(
        &'me mut self,
        entity: Entity,
        query: &'w query::QueryUiNodes<'w, 's>,
    ) -> Vec<(Entity, Handle<StyleSheetAsset>)> {
        let root_node = self.get_or_find_root(entity, query);
        match root_node
        {
            Some(node) => self.resolve(&node.sheet_handle),
            None => vec![],
        }
    }
}