nightshade 0.14.0

A cross-platform data-oriented game engine.
Documentation
use crate::ecs::ui::components::{
    ThemeEffect, ThemeShadow, UiNodeContent, UiNodeEffect, UiNodeShadow,
};
use crate::ecs::ui::theme::UiTheme;
use crate::ecs::world::World;

fn resolve_shadow(theme: &UiTheme, role: ThemeShadow) -> Option<UiNodeShadow> {
    Some(match role {
        ThemeShadow::PanelShadow => theme.panel_shadow,
        ThemeShadow::ButtonShadow => theme.button_shadow,
        ThemeShadow::ButtonShadowHover => theme.button_shadow_hover,
        ThemeShadow::ButtonShadowPressed => theme.button_shadow_pressed,
        ThemeShadow::ModalShadow => theme.modal_shadow,
        ThemeShadow::FocusGlow => theme.focus_glow?,
    })
}

fn resolve_effect(theme: &UiTheme, role: ThemeEffect) -> UiNodeEffect {
    let preset = match role {
        ThemeEffect::PanelEffect => theme.panel_effect,
        ThemeEffect::ButtonEffect => theme.button_effect,
        ThemeEffect::InputEffect => theme.input_effect,
    };
    let (kind, params) = preset.encode();
    UiNodeEffect { kind, params }
}

pub fn ui_theme_transition_tick_system(world: &mut World) {
    if !world.resources.retained_ui.enabled {
        return;
    }
    let delta_time = world.resources.window.timing.delta_time;
    world
        .resources
        .retained_ui
        .theme_state
        .tick_transition(delta_time);
}

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

    let generation = world.resources.retained_ui.theme_state.generation;
    if generation
        == world
            .resources
            .retained_ui
            .theme_state
            .last_applied_generation
    {
        return;
    }
    world
        .resources
        .retained_ui
        .theme_state
        .last_applied_generation = generation;

    let theme = world
        .resources
        .retained_ui
        .theme_state
        .active_theme()
        .clone();

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

    for entity in entities {
        let binding = match world.ui.get_ui_theme_binding(entity) {
            Some(binding) => *binding,
            None => continue,
        };

        if let Some(node_color) = world.ui.get_ui_node_color_mut(entity) {
            for (state_index, role) in binding.color_roles.iter().enumerate() {
                if let Some(role) = role {
                    node_color.colors[state_index] = Some(role.resolve(&theme));
                }
            }
        }

        if let Some(border_role) = binding.border_color_role
            && let Some(content) = world.ui.get_ui_node_content_mut(entity)
            && let UiNodeContent::Rect { border_color, .. } = content
        {
            *border_color = border_role.resolve(&theme);
        }

        let has_any_shadow = binding.shadow_roles.iter().any(|r| r.is_some());
        if has_any_shadow {
            let mut state_shadows = [None; crate::ecs::ui::state::STATE_COUNT];
            for (state_index, role) in binding.shadow_roles.iter().enumerate() {
                if let Some(role) = role {
                    state_shadows[state_index] = resolve_shadow(&theme, *role);
                }
            }
            world
                .ui
                .add_components(entity, crate::ecs::world::UI_NODE_SHADOW_STATES);
            if let Some(slot) = world.ui.get_ui_node_shadow_states_mut(entity) {
                slot.shadows = state_shadows;
            }
            let base_shadow = state_shadows[0].unwrap_or_default();
            world
                .ui
                .add_components(entity, crate::ecs::world::UI_NODE_SHADOW);
            if let Some(slot) = world.ui.get_ui_node_shadow_mut(entity) {
                *slot = base_shadow;
            }
        }

        if let Some(role) = binding.effect_role {
            let effect = resolve_effect(&theme, role);
            world
                .ui
                .add_components(entity, crate::ecs::world::UI_NODE_EFFECT);
            if let Some(slot) = world.ui.get_ui_node_effect_mut(entity) {
                *slot = effect;
            }
        }
    }
}