use crate::ecs::ui::state::UiStateTrait as _;
use crate::ecs::world::World;
use nalgebra_glm::Vec2;
use super::InteractionSnapshot;
pub(super) fn handle_toggle(
world: &mut World,
entity: freecs::Entity,
interaction: &InteractionSnapshot,
data: &crate::ecs::ui::components::UiToggleData,
delta_time: f32,
) {
let mut value = data.value;
let mut changed = false;
let mut animated_position = data.animated_position;
if interaction.clicked {
value = !value;
changed = true;
}
let target = if value { 1.0 } else { 0.0 };
let speed = 8.0;
let diff = target - animated_position;
if diff.abs() > 0.001 {
animated_position += diff.signum() * speed * delta_time;
animated_position = animated_position.clamp(0.0, 1.0);
} else {
animated_position = target;
}
let theme = world.resources.retained_ui.theme_state.active_theme();
let toggle_height = theme.toggle_height;
let toggle_width = theme.toggle_width;
let on_color = theme.accent_color;
let off_color = theme.background_color;
let knob_padding = 2.0;
let knob_size = toggle_height - knob_padding * 2.0;
let knob_travel = toggle_width - knob_size - knob_padding * 2.0;
let knob_x = knob_padding + animated_position * knob_travel;
if let Some(knob_node) = world.ui.get_ui_layout_node_mut(data.knob_entity)
&& let Some(crate::ecs::ui::layout_types::UiLayoutType::Window(window)) =
knob_node.base_layout.as_mut()
{
window.position = crate::ecs::ui::units::Ab(Vec2::new(knob_x, knob_padding)).into();
}
let blended = off_color + (on_color - off_color) * animated_position;
if let Some(color) = world.ui.get_ui_node_color_mut(entity) {
color.colors[crate::ecs::ui::state::UiBase::INDEX] = Some(blended);
}
if let Some(widget_data) = world.ui.get_ui_toggle_mut(entity) {
widget_data.value = value;
widget_data.changed = changed;
widget_data.animated_position = animated_position;
}
if changed {
world
.resources
.retained_ui
.frame
.events
.push(crate::ecs::ui::resources::UiEvent::ToggleChanged { entity, value });
}
}
pub(super) fn handle_checkbox(
world: &mut World,
entity: freecs::Entity,
interaction: &InteractionSnapshot,
data: &crate::ecs::ui::components::UiCheckboxData,
) {
if interaction.clicked {
let new_value = !data.value;
if let Some(node) = world.ui.get_ui_layout_node_mut(data.inner_entity) {
node.visible = new_value;
}
if let Some(widget_data) = world.ui.get_ui_checkbox_mut(entity) {
widget_data.value = new_value;
widget_data.changed = true;
}
world.resources.retained_ui.events_for_active_mut().push(
crate::ecs::ui::resources::UiEvent::CheckboxChanged {
entity,
value: new_value,
},
);
} else if let Some(widget_data) = world.ui.get_ui_checkbox_mut(entity) {
widget_data.changed = false;
}
}
pub(super) fn handle_radio(
world: &mut World,
entity: freecs::Entity,
interaction: &InteractionSnapshot,
data: &crate::ecs::ui::components::UiRadioData,
) {
if let Some(widget_data) = world.ui.get_ui_radio_mut(entity) {
widget_data.changed = false;
}
if interaction.clicked && !data.selected {
if let Some(node) = world.ui.get_ui_layout_node_mut(data.inner_entity) {
node.visible = true;
}
let siblings = world
.resources
.retained_ui
.groups
.radio
.get(&data.group_id)
.cloned()
.unwrap_or_default();
for other_entity in siblings {
if other_entity == entity {
continue;
}
let other_data_clone = world.ui.get_ui_radio(other_entity).cloned();
if let Some(other_radio) = other_data_clone
&& other_radio.selected
{
if let Some(node) = world.ui.get_ui_layout_node_mut(other_radio.inner_entity) {
node.visible = false;
}
if let Some(wd) = world.ui.get_ui_radio_mut(other_entity) {
wd.selected = false;
}
}
}
if let Some(widget_data) = world.ui.get_ui_radio_mut(entity) {
widget_data.selected = true;
widget_data.changed = true;
}
world.resources.retained_ui.events_for_active_mut().push(
crate::ecs::ui::resources::UiEvent::RadioChanged {
entity,
group_id: data.group_id,
option_index: data.option_index,
},
);
}
}
pub(super) fn handle_collapsing_header(
world: &mut World,
entity: freecs::Entity,
interaction: &InteractionSnapshot,
data: &crate::ecs::ui::components::UiCollapsingHeaderData,
) {
if let Some(widget_data) = world.ui.get_ui_collapsing_header_mut(entity) {
widget_data.changed = false;
}
if interaction.clicked {
let new_open = !data.open;
if let Some(node) = world.ui.get_ui_layout_node_mut(data.content_entity) {
node.visible = new_open;
}
world.resources.text.cache.set_text(
data.arrow_text_slot,
if new_open { "\u{25BC}" } else { "\u{25B6}" },
);
if let Some(widget_data) = world.ui.get_ui_collapsing_header_mut(entity) {
widget_data.open = new_open;
widget_data.changed = true;
}
}
}
pub(super) fn handle_spinner(
world: &mut World,
entity: freecs::Entity,
data: &crate::ecs::ui::components::UiSpinnerData,
delta_time: f32,
) {
if data.dots.is_empty() {
return;
}
let dot_count = data.dots.len() as f32;
let phase = (data.phase + delta_time * data.rotation_speed).rem_euclid(dot_count);
let accent = world
.resources
.retained_ui
.theme_state
.active_theme()
.accent_color;
let head = phase;
for (index, dot) in data.dots.iter().enumerate() {
let offset = (head - index as f32).rem_euclid(dot_count);
let normalized = offset / dot_count;
let alpha = 0.18 + (1.0 - normalized) * 0.82;
if let Some(color) = world.ui.get_ui_node_color_mut(*dot) {
color.colors[crate::ecs::ui::state::UiBase::INDEX] = Some(nalgebra_glm::Vec4::new(
accent.x,
accent.y,
accent.z,
alpha * accent.w,
));
}
}
if let Some(widget_data) = world.ui.get_ui_spinner_mut(entity) {
widget_data.phase = phase;
}
world.resources.retained_ui.dirty.render_dirty = true;
}