use crate::ecs::world::World;
pub fn ui_event_bubble_system(world: &mut World) {
if !world.resources.retained_ui.enabled {
return;
}
world.resources.retained_ui.bubbled_events.clear();
let events = world.resources.retained_ui.frame_events.clone();
if !world.resources.children_cache_valid {
world.validate_and_rebuild_children_cache();
}
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.bubbled_events.push(
crate::ecs::ui::resources::BubbledUiEvent {
event: event.clone(),
target,
ancestor: parent,
stopped: false,
},
);
current = parent;
}
}
}
pub fn ui_event_dispatch_system(world: &mut World) {
if !world.resources.retained_ui.enabled {
return;
}
let events = world.resources.retained_ui.frame_events.clone();
if !events.is_empty() {
let mut handlers = std::mem::take(&mut world.resources.retained_ui.event_handlers);
for event in &events {
let target = event.target_entity();
if let Some(entity_handlers) = handlers.get_mut(&target) {
for handler in entity_handlers.iter_mut() {
handler(world, event);
}
}
}
let newly_registered = std::mem::take(&mut world.resources.retained_ui.event_handlers);
for (entity, mut new_handlers) in newly_registered {
handlers
.entry(entity)
.or_default()
.append(&mut new_handlers);
}
world.resources.retained_ui.event_handlers = handlers;
}
let mut click_entities: Vec<freecs::Entity> = events
.iter()
.filter_map(|event| match event {
crate::ecs::ui::resources::UiEvent::ButtonClicked(entity)
| crate::ecs::ui::resources::UiEvent::SelectableLabelClicked { entity, .. } => {
Some(*entity)
}
_ => None,
})
.collect();
for &entity in world.resources.retained_ui.click_reactions.keys() {
if !click_entities.contains(&entity)
&& world
.ui
.get_ui_node_interaction(entity)
.is_some_and(|interaction| interaction.clicked)
{
click_entities.push(entity);
}
}
if !click_entities.is_empty() {
let mut click_reactions = std::mem::take(&mut world.resources.retained_ui.click_reactions);
for entity in &click_entities {
if let Some(reaction_list) = click_reactions.get_mut(entity) {
for reaction in reaction_list.iter_mut() {
reaction(world);
}
}
}
let newly_registered_clicks =
std::mem::take(&mut world.resources.retained_ui.click_reactions);
for (entity, mut new_reactions) in newly_registered_clicks {
click_reactions
.entry(entity)
.or_default()
.append(&mut new_reactions);
}
world.resources.retained_ui.click_reactions = click_reactions;
}
let submit_events: Vec<(freecs::Entity, String)> = events
.iter()
.filter_map(|event| {
if let crate::ecs::ui::resources::UiEvent::TextInputSubmitted { entity, text } = event {
Some((*entity, text.clone()))
} else {
None
}
})
.collect();
if !submit_events.is_empty() {
let mut reactions = std::mem::take(&mut world.resources.retained_ui.submit_reactions);
for (entity, text) in &submit_events {
if let Some(reaction_list) = reactions.get_mut(entity) {
for reaction in reaction_list.iter_mut() {
reaction(text.clone(), world);
}
}
}
let newly = std::mem::take(&mut world.resources.retained_ui.submit_reactions);
for (entity, mut new_reactions) in newly {
reactions
.entry(entity)
.or_default()
.append(&mut new_reactions);
}
world.resources.retained_ui.submit_reactions = reactions;
}
let confirm_events: Vec<(freecs::Entity, bool)> = events
.iter()
.filter_map(|event| {
if let crate::ecs::ui::resources::UiEvent::ModalClosed { entity, confirmed } = event {
Some((*entity, *confirmed))
} else {
None
}
})
.collect();
if !confirm_events.is_empty() {
let mut reactions = std::mem::take(&mut world.resources.retained_ui.confirm_reactions);
for (entity, confirmed) in &confirm_events {
if let Some(reaction_list) = reactions.get_mut(entity) {
for reaction in reaction_list.iter_mut() {
reaction(*confirmed, world);
}
}
}
let newly = std::mem::take(&mut world.resources.retained_ui.confirm_reactions);
for (entity, mut new_reactions) in newly {
reactions
.entry(entity)
.or_default()
.append(&mut new_reactions);
}
world.resources.retained_ui.confirm_reactions = reactions;
}
let menu_events: Vec<(freecs::Entity, usize)> = events
.iter()
.filter_map(|event| match event {
crate::ecs::ui::resources::UiEvent::ContextMenuItemClicked { entity, item_index }
| crate::ecs::ui::resources::UiEvent::MenuItemClicked { entity, item_index } => {
Some((*entity, *item_index))
}
crate::ecs::ui::resources::UiEvent::BreadcrumbClicked {
entity,
segment_index,
} => Some((*entity, *segment_index)),
_ => None,
})
.collect();
if !menu_events.is_empty() {
let mut reactions = std::mem::take(&mut world.resources.retained_ui.menu_select_reactions);
for (entity, index) in &menu_events {
if let Some(reaction_list) = reactions.get_mut(entity) {
for reaction in reaction_list.iter_mut() {
reaction(*index, world);
}
}
}
let newly = std::mem::take(&mut world.resources.retained_ui.menu_select_reactions);
for (entity, mut new_reactions) in newly {
reactions
.entry(entity)
.or_default()
.append(&mut new_reactions);
}
world.resources.retained_ui.menu_select_reactions = reactions;
}
let command_events: Vec<(freecs::Entity, usize)> = events
.iter()
.filter_map(|event| {
if let crate::ecs::ui::resources::UiEvent::CommandPaletteExecuted {
entity,
command_index,
} = event
{
Some((*entity, *command_index))
} else {
None
}
})
.collect();
if !command_events.is_empty() {
let mut reactions = std::mem::take(&mut world.resources.retained_ui.command_reactions);
for (entity, index) in &command_events {
if let Some(reaction_list) = reactions.get_mut(entity) {
for reaction in reaction_list.iter_mut() {
reaction(*index, world);
}
}
}
let newly = std::mem::take(&mut world.resources.retained_ui.command_reactions);
for (entity, mut new_reactions) in newly {
reactions
.entry(entity)
.or_default()
.append(&mut new_reactions);
}
world.resources.retained_ui.command_reactions = reactions;
}
let tree_events: Vec<(freecs::Entity, freecs::Entity)> = events
.iter()
.filter_map(|event| {
if let crate::ecs::ui::resources::UiEvent::TreeNodeSelected { tree, node, .. } = event {
Some((*tree, *node))
} else {
None
}
})
.collect();
if !tree_events.is_empty() {
let mut reactions = std::mem::take(&mut world.resources.retained_ui.tree_select_reactions);
for (tree_entity, node) in &tree_events {
if let Some(reaction_list) = reactions.get_mut(tree_entity) {
for reaction in reaction_list.iter_mut() {
reaction(*node, world);
}
}
}
let newly = std::mem::take(&mut world.resources.retained_ui.tree_select_reactions);
for (entity, mut new_reactions) in newly {
reactions
.entry(entity)
.or_default()
.append(&mut new_reactions);
}
world.resources.retained_ui.tree_select_reactions = reactions;
}
let tree_context_menu_events: Vec<(freecs::Entity, freecs::Entity, nalgebra_glm::Vec2)> =
events
.iter()
.filter_map(|event| {
if let crate::ecs::ui::resources::UiEvent::TreeNodeContextMenu {
tree,
node,
position,
} = event
{
Some((*tree, *node, *position))
} else {
None
}
})
.collect();
if !tree_context_menu_events.is_empty() {
let mut reactions =
std::mem::take(&mut world.resources.retained_ui.tree_context_menu_reactions);
for (tree_entity, node, position) in &tree_context_menu_events {
if let Some(reaction_list) = reactions.get_mut(tree_entity) {
for reaction in reaction_list.iter_mut() {
reaction(*node, *position, world);
}
}
}
let newly = std::mem::take(&mut world.resources.retained_ui.tree_context_menu_reactions);
for (entity, mut new_reactions) in newly {
reactions
.entry(entity)
.or_default()
.append(&mut new_reactions);
}
world.resources.retained_ui.tree_context_menu_reactions = reactions;
}
let multi_select_events: Vec<(freecs::Entity, Vec<usize>)> = events
.iter()
.filter_map(|event| {
if let crate::ecs::ui::resources::UiEvent::MultiSelectChanged {
entity,
selected_indices,
} = event
{
Some((*entity, selected_indices.clone()))
} else {
None
}
})
.collect();
if !multi_select_events.is_empty() {
let mut reactions = std::mem::take(&mut world.resources.retained_ui.multi_select_reactions);
for (entity, indices) in &multi_select_events {
if let Some(reaction_list) = reactions.get_mut(entity) {
for reaction in reaction_list.iter_mut() {
reaction(indices.clone(), world);
}
}
}
let newly = std::mem::take(&mut world.resources.retained_ui.multi_select_reactions);
for (entity, mut new_reactions) in newly {
reactions
.entry(entity)
.or_default()
.append(&mut new_reactions);
}
world.resources.retained_ui.multi_select_reactions = reactions;
}
let date_events: Vec<(freecs::Entity, i32, u32, u32)> = events
.iter()
.filter_map(|event| {
if let crate::ecs::ui::resources::UiEvent::DatePickerChanged {
entity,
year,
month,
day,
} = event
{
Some((*entity, *year, *month, *day))
} else {
None
}
})
.collect();
if !date_events.is_empty() {
let mut reactions = std::mem::take(&mut world.resources.retained_ui.date_changed_reactions);
for (entity, year, month, day) in &date_events {
if let Some(reaction_list) = reactions.get_mut(entity) {
for reaction in reaction_list.iter_mut() {
reaction(*year, *month, *day, world);
}
}
}
let newly = std::mem::take(&mut world.resources.retained_ui.date_changed_reactions);
for (entity, mut new_reactions) in newly {
reactions
.entry(entity)
.or_default()
.append(&mut new_reactions);
}
world.resources.retained_ui.date_changed_reactions = reactions;
}
let changed_entity_keys: Vec<freecs::Entity> = world
.resources
.retained_ui
.changed_reactions
.keys()
.copied()
.collect();
if !changed_entity_keys.is_empty() {
let changed_entities: Vec<freecs::Entity> = changed_entity_keys
.into_iter()
.filter(|entity| world.ui_changed(*entity))
.collect();
if !changed_entities.is_empty() {
let mut reactions = std::mem::take(&mut world.resources.retained_ui.changed_reactions);
for entity in &changed_entities {
if let Some(reaction_list) = reactions.get_mut(entity) {
for reaction in reaction_list.iter_mut() {
reaction(world);
}
}
}
let newly = std::mem::take(&mut world.resources.retained_ui.changed_reactions);
for (entity, mut new_reactions) in newly {
reactions
.entry(entity)
.or_default()
.append(&mut new_reactions);
}
world.resources.retained_ui.changed_reactions = reactions;
}
}
}