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;
}
}
}
}