This commit is contained in:
Talin 2025-07-18 15:32:07 +05:30 committed by GitHub
commit aa09589613
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 142 additions and 3 deletions

View File

@ -1,5 +1,7 @@
use bevy_ecs::system::{Commands, SystemId, SystemInput};
use bevy_ecs::world::{DeferredWorld, World};
use bevy_ecs::system::{Commands, EntityCommands, IntoSystem, SystemId, SystemInput};
use bevy_ecs::world::{DeferredWorld, EntityWorldMut, World};
use crate::owner::OwnedBy;
/// A callback defines how we want to be notified when a widget changes state. Unlike an event
/// or observer, callbacks are intended for "point-to-point" communication that cuts across the
@ -111,3 +113,88 @@ impl Notify for DeferredWorld<'_> {
}
}
}
/// Methods for registering scoped callbacks.
pub trait RegisterOwnedCallback {
/// Registers a scoped one-shot system, with no input, that will be removed when the parent
/// entity is despawned.
fn register_owned_callback<M, I: IntoSystem<(), (), M> + 'static>(
&mut self,
callback: I,
) -> Callback;
/// Registers a scoped one-shot systemm, with input, that will be removed when the
/// parent entity is despawned.
fn register_owned_callback_with<
M,
A: SystemInput + Send + 'static,
I: IntoSystem<A, (), M> + 'static,
>(
&mut self,
callback: I,
) -> Callback<A>;
}
impl RegisterOwnedCallback for EntityCommands<'_> {
fn register_owned_callback<M, I: IntoSystem<(), (), M> + 'static>(
&mut self,
callback: I,
) -> Callback {
let system_id = self.commands().register_system(callback);
let owner = self.id();
self.commands()
.entity(owner)
.add_one_related::<OwnedBy>(system_id.entity());
Callback::System(system_id)
}
fn register_owned_callback_with<
M,
A: SystemInput + Send + 'static,
I: IntoSystem<A, (), M> + 'static,
>(
&mut self,
callback: I,
) -> Callback<A> {
let owner = self.id();
let system_id = self.commands().register_system(callback);
self.commands()
.entity(owner)
.add_one_related::<OwnedBy>(system_id.entity());
Callback::System(system_id)
}
}
impl RegisterOwnedCallback for EntityWorldMut<'_> {
fn register_owned_callback<M, I: IntoSystem<(), (), M> + 'static>(
&mut self,
callback: I,
) -> Callback {
let owner = self.id();
let system_id = self.world_scope(|world| world.register_system(callback));
self.world_scope(|world| {
world
.entity_mut(owner)
.add_one_related::<OwnedBy>(system_id.entity());
});
Callback::System(system_id)
}
fn register_owned_callback_with<
M,
A: SystemInput + Send + 'static,
I: IntoSystem<A, (), M> + 'static,
>(
&mut self,
callback: I,
) -> Callback<A> {
let owner = self.id();
let system_id = self.world_scope(|world| world.register_system(callback));
self.world_scope(|world| {
world
.entity_mut(owner)
.add_one_related::<OwnedBy>(system_id.entity());
});
Callback::System(system_id)
}
}

View File

@ -20,11 +20,12 @@ mod core_checkbox;
mod core_radio;
mod core_scrollbar;
mod core_slider;
pub mod owner;
use bevy_app::{PluginGroup, PluginGroupBuilder};
use bevy_ecs::entity::Entity;
pub use callback::{Callback, Notify};
pub use callback::{Callback, Notify, RegisterOwnedCallback};
pub use core_button::{CoreButton, CoreButtonPlugin};
pub use core_checkbox::{CoreCheckbox, CoreCheckboxPlugin, SetChecked, ToggleChecked};
pub use core_radio::{CoreRadio, CoreRadioGroup, CoreRadioGroupPlugin};

View File

@ -0,0 +1,51 @@
//! Defines relationships for ownership of an entity, with no other inherited semantics.
use core::slice;
use bevy_ecs::{component::Component, entity::Entity};
/// A component that represents the owner of an entity. Ownership only determines lifetime,
/// such that the owned entity will be despawned when its owner is despawned. It does not imply
/// any other kind of semantic connection between the two entities.
// TODO: Consider renaming and/or moving this.
#[derive(Component, Clone, PartialEq, Eq, Debug)]
#[relationship(relationship_target = Owned)]
pub struct OwnedBy(pub Entity);
impl OwnedBy {
/// Return the owned entity.
pub fn get(&self) -> Entity {
self.0
}
}
impl Default for OwnedBy {
fn default() -> Self {
OwnedBy(Entity::PLACEHOLDER)
}
}
/// A component that represents a collection of entities that are owned by another entity.
// #[derive(Component, Default, Reflect)]
// #[reflect(Component)]
#[derive(Component, Default)]
#[relationship_target(relationship = OwnedBy, linked_spawn)]
pub struct Owned(Vec<Entity>);
impl<'a> IntoIterator for &'a Owned {
type Item = <Self::IntoIter as Iterator>::Item;
type IntoIter = slice::Iter<'a, Entity>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl core::ops::Deref for Owned {
type Target = [Entity];
fn deref(&self) -> &Self::Target {
&self.0
}
}