nightshade 0.14.0

A cross-platform data-oriented game engine.
Documentation
use crate::ecs::world::World;

use crate::prelude::*;
pub fn ui_event_bubble_system(world: &mut World) {
    if !world.resources.retained_ui.enabled {
        return;
    }

    world.resources.retained_ui.frame.bubbled_events.clear();

    let events: Vec<crate::ecs::ui::resources::UiEvent> =
        world.resources.retained_ui.events_for_active().to_vec();

    if !world.resources.transform_state.children_cache_valid {
        validate_and_rebuild_children_cache(world);
    }

    for event in &events {
        if !event.bubbles() {
            continue;
        }
        let target = event.target_entity();
        let mut current = target;

        loop {
            let parent_opt = world.core.get_parent(current).and_then(|p| p.0);

            let Some(parent) = parent_opt else {
                break;
            };

            world.resources.retained_ui.frame.bubbled_events.push(
                crate::ecs::ui::resources::BubbledUiEvent {
                    event: event.clone(),
                    target,
                    ancestor: parent,
                    stopped: false,
                },
            );

            current = parent;
        }
    }
}

pub fn ui_emit_click_events_system(world: &mut World) {
    if !world.resources.retained_ui.enabled {
        return;
    }

    let already_emitted: std::collections::HashSet<freecs::Entity> = world
        .resources
        .retained_ui
        .events_for_active()
        .iter()
        .filter_map(|event| match event {
            crate::ecs::ui::resources::UiEvent::ButtonClicked(entity)
            | crate::ecs::ui::resources::UiEvent::SelectableLabelClicked { entity, .. } => {
                Some(*entity)
            }
            _ => None,
        })
        .collect();

    let candidates: Vec<freecs::Entity> = world
        .ui
        .query_entities(crate::ecs::world::UI_NODE_INTERACTION)
        .collect();

    for entity in candidates {
        if already_emitted.contains(&entity) {
            continue;
        }
        let clicked = world
            .ui
            .get_ui_node_interaction(entity)
            .is_some_and(|interaction| interaction.clicked);
        if clicked {
            world
                .resources
                .retained_ui
                .events_for_active_mut()
                .push(crate::ecs::ui::resources::UiEvent::ButtonClicked(entity));
        }
    }
}