
# Objective On the web, it's common to attach observers to windows. As @viridia has discovered, this can be quite a nice paradigm in bevy as well when applied to observers. The changes here are intended to make this possible. + Adds a new default picking back-end as part to the core picking plugin (which can be disabled) that causes pointers on windows to treat the window entity as the final hit, behind everything else. This means clicking empty space now dispatches normal picking events to the window, and is especially nice for drag-and-drop functionality. + Adds a new traversal type, specific to picking events, that causes them to bubble up to the window entity after they reach the root of the hierarchy. ## Solution The window picking back-end is extremely simple, but the bubbling changes are much more complex, since they require doing a different traversal depending on the picking event. To achieve this, `Traversal` has been made generic over an associated sized data type `D`. Observer bounds have been changed such that `Event::Traversal<D>` is required for `Trigger<D>`. A blanket implementation has been added for `()` and `Parent` that preserves the existing functionality. A new `PointerTraversal` traversal has been implemented, with a blanket implementation for `Traversal<Pointer<E>>`. It is still possible to use `Parent` as the traversal for any event, because of the blanket implementation. It is now possible for users to add other custom traversals, which read event data during traversal. ## Testing I tested these changes locally on some picking UI prototypes I have been playing with. I also tested them on the picking examples. --------- Co-authored-by: Martín Maita <47983254+mnmaita@users.noreply.github.com>
33 lines
1.5 KiB
Rust
33 lines
1.5 KiB
Rust
//! A trait for components that let you traverse the ECS.
|
|
|
|
use crate::{entity::Entity, query::ReadOnlyQueryData};
|
|
|
|
/// A component that can point to another entity, and which can be used to define a path through the ECS.
|
|
///
|
|
/// Traversals are used to [specify the direction] of [event propagation] in [observers].
|
|
/// The default query is `()`.
|
|
///
|
|
/// Infinite loops are possible, and are not checked for. While looping can be desirable in some contexts
|
|
/// (for example, an observer that triggers itself multiple times before stopping), following an infinite
|
|
/// traversal loop without an eventual exit will cause your application to hang. Each implementer of `Traversal`
|
|
/// for documenting possible looping behavior, and consumers of those implementations are responsible for
|
|
/// avoiding infinite loops in their code.
|
|
///
|
|
/// Traversals may be parameterized with additional data. For example, in observer event propagation, the
|
|
/// parameter `D` is the event type given in `Trigger<E>`. This allows traversal to differ depending on event
|
|
/// data.
|
|
///
|
|
/// [specify the direction]: crate::event::Event::Traversal
|
|
/// [event propagation]: crate::observer::Trigger::propagate
|
|
/// [observers]: crate::observer::Observer
|
|
pub trait Traversal<D: ?Sized>: ReadOnlyQueryData {
|
|
/// Returns the next entity to visit.
|
|
fn traverse(item: Self::Item<'_>, data: &D) -> Option<Entity>;
|
|
}
|
|
|
|
impl<D> Traversal<D> for () {
|
|
fn traverse(_: Self::Item<'_>, _data: &D) -> Option<Entity> {
|
|
None
|
|
}
|
|
}
|