use bevy_platform::sync::{Arc, OnceLock};
use super::{
element::UiRoot,
raw::{RawElWrapper, observe, register_system, utils::remove_system_holder_on_remove},
utils::clone,
};
use apply::Apply;
use bevy_ecs::{event::PropagateEntityTrigger, prelude::*, traversal::Traversal};
pub trait GlobalEventAware: RawElWrapper {
#[allow(clippy::type_complexity)]
fn on_global_event_with_system<E, const AUTO_PROPAGATE: bool, T, Marker>(
self,
handler: impl IntoSystem<In<(Entity, GlobalEventData<E>)>, (), Marker> + Send + 'static,
) -> Self
where
E: EntityEvent + for<'a> Event<Trigger<'a> = PropagateEntityTrigger<AUTO_PROPAGATE, E, T>> + Clone,
T: Traversal<E> + 'static,
{
self.update_raw_el(|raw_el| {
let system_holder = Arc::new(OnceLock::new());
let observer_holder = Arc::new(OnceLock::new());
raw_el
.on_spawn(clone!((system_holder) move |world, _| {
let _ = system_holder.set(register_system(world, handler));
}))
.apply(remove_system_holder_on_remove(system_holder.clone()))
.on_spawn_with_system(clone!((observer_holder, system_holder) move |In(entity), child_ofs: Query<&ChildOf>, ui_roots: Query<&UiRoot>, mut commands: Commands| {
for ancestor in child_ofs.iter_ancestors(entity) {
if ui_roots.contains(ancestor) {
commands.queue(clone!((system_holder, observer_holder) move |world: &mut World| {
let observer = observe(world, ancestor, clone!((system_holder) move |event: On<E>, mut commands: Commands| {
commands.run_system_with(system_holder.get().copied().unwrap(), (entity, GlobalEventData { original_event_target: event.original_event_target(), event: (*event).clone() }));
})).id();
let _ = observer_holder.set(observer);
}));
break;
}
}
}))
.on_remove(move |world, _| {
if let Some(&observer) = observer_holder.get() {
world.commands().queue(move |world: &mut World| {
let _ = world.try_despawn(observer);
})
}
})
})
}
fn on_global_event<E, const AUTO_PROPAGATE: bool, T>(
self,
mut handler: impl FnMut(E) + Send + Sync + 'static,
) -> Self
where
E: EntityEvent + for<'a> Event<Trigger<'a> = PropagateEntityTrigger<AUTO_PROPAGATE, E, T>> + Clone,
T: Traversal<E> + 'static,
{
self.on_global_event_with_system::<E, AUTO_PROPAGATE, T, _>(
move |In((_, event)): In<(Entity, GlobalEventData<E>)>| handler(event.event),
)
}
}
pub struct GlobalEventData<E> {
pub original_event_target: Entity,
pub event: E,
}