use bevy_platform::sync::{Arc, OnceLock};
use super::{
element::{BuilderWrapper, UiRoot},
utils::{clone, observe, register_system, remove_system_holder_on_despawn},
};
use apply::Apply;
use bevy_ecs::{event::PropagateEntityTrigger, prelude::*, traversal::Traversal};
use jonmo::utils::LazyEntity;
pub trait GlobalEventAware: BuilderWrapper {
#[allow(clippy::type_complexity)]
fn on_global_event<E, const AUTO_PROPAGATE: bool, T, Marker>(
self,
handler: impl IntoSystem<In<(Entity, GlobalEventData<E>)>, (), Marker> + Send + Sync + 'static,
) -> Self
where
E: EntityEvent + for<'a> Event<Trigger<'a> = PropagateEntityTrigger<AUTO_PROPAGATE, E, T>> + Clone,
T: Traversal<E> + 'static,
{
self.with_builder(|builder| {
let system_holder = Arc::new(OnceLock::new());
let observer_holder = LazyEntity::new();
builder
.on_spawn(clone!((system_holder) move |world, _| {
let _ = system_holder.set(register_system(world, handler));
}))
.apply(remove_system_holder_on_despawn(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();
observer_holder.set(observer);
}));
return;
}
}
if cfg!(debug_assertions) {
panic!("element must be a descendent of a `UiRoot` in order for `GlobalEventAware`ness to function; please call `.ui_root()` on your ui root")
}
}))
.on_despawn(move |world, _| {
world.commands().queue(clone!((observer_holder) move |world: &mut World| {
world.despawn(*observer_holder);
}))
})
})
}
}
pub struct GlobalEventData<E> {
pub original_event_target: Entity,
pub event: E,
}