2024-07-15 13:39:41 +00:00
|
|
|
//! A trait for components that let you traverse the ECS.
|
|
|
|
|
2024-09-23 18:08:36 +00:00
|
|
|
use crate::{entity::Entity, query::ReadOnlyQueryData};
|
2024-07-15 13:39:41 +00:00
|
|
|
|
|
|
|
/// A component that can point to another entity, and which can be used to define a path through the ECS.
|
|
|
|
///
|
2024-09-23 18:08:36 +00:00
|
|
|
/// Traversals are used to [specify the direction] of [event propagation] in [observers].
|
|
|
|
/// The default query is `()`.
|
2024-07-15 13:39:41 +00:00
|
|
|
///
|
|
|
|
/// 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
|
2024-11-30 19:28:53 +00:00
|
|
|
/// traversal loop without an eventual exit will cause your application to hang. Each implementer of `Traversal`
|
2024-07-15 13:39:41 +00:00
|
|
|
/// for documenting possible looping behavior, and consumers of those implementations are responsible for
|
|
|
|
/// avoiding infinite loops in their code.
|
|
|
|
///
|
Window picking (#16103)
# 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>
2024-12-05 21:14:39 +00:00
|
|
|
/// 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.
|
|
|
|
///
|
2024-07-15 13:39:41 +00:00
|
|
|
/// [specify the direction]: crate::event::Event::Traversal
|
|
|
|
/// [event propagation]: crate::observer::Trigger::propagate
|
|
|
|
/// [observers]: crate::observer::Observer
|
Window picking (#16103)
# 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>
2024-12-05 21:14:39 +00:00
|
|
|
pub trait Traversal<D: ?Sized>: ReadOnlyQueryData {
|
2024-07-15 13:39:41 +00:00
|
|
|
/// Returns the next entity to visit.
|
Window picking (#16103)
# 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>
2024-12-05 21:14:39 +00:00
|
|
|
fn traverse(item: Self::Item<'_>, data: &D) -> Option<Entity>;
|
2024-07-15 13:39:41 +00:00
|
|
|
}
|
|
|
|
|
Window picking (#16103)
# 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>
2024-12-05 21:14:39 +00:00
|
|
|
impl<D> Traversal<D> for () {
|
|
|
|
fn traverse(_: Self::Item<'_>, _data: &D) -> Option<Entity> {
|
2024-07-15 13:39:41 +00:00
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|