Skip to content

Simplified UI tree navigation without ghost_nodes #17143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 57 additions & 3 deletions crates/bevy_ui/src/experimental/ghost_hierarchy.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
//! This module contains [`GhostNode`] and utilities to flatten the UI hierarchy, traversing past ghost nodes.

use crate::Node;
use bevy_ecs::{prelude::*, system::SystemParam};
use bevy_hierarchy::{Children, HierarchyQueryExt, Parent};
use bevy_hierarchy::{Children, Parent};
use bevy_reflect::prelude::*;
use bevy_render::view::Visibility;
use bevy_transform::prelude::Transform;
use core::marker::PhantomData;
use smallvec::SmallVec;

use crate::Node;
#[cfg(feature = "ghost_nodes")]
use bevy_hierarchy::HierarchyQueryExt;
#[cfg(feature = "ghost_nodes")]
use smallvec::SmallVec;

/// Marker component for entities that should be ignored within UI hierarchies.
///
Expand Down Expand Up @@ -40,6 +43,7 @@ impl GhostNode {
}
}

#[cfg(feature = "ghost_nodes")]
/// System param that allows iteration of all UI root nodes.
///
/// A UI root node is either a [`Node`] without a [`Parent`], or with only [`GhostNode`] ancestors.
Expand All @@ -51,6 +55,10 @@ pub struct UiRootNodes<'w, 's> {
ui_children: UiChildren<'w, 's>,
}

#[cfg(not(feature = "ghost_nodes"))]
pub type UiRootNodes<'w, 's> = Query<'w, 's, Entity, (With<Node>, Without<Parent>)>;

#[cfg(feature = "ghost_nodes")]
impl<'w, 's> UiRootNodes<'w, 's> {
pub fn iter(&'s self) -> impl Iterator<Item = Entity> + 's {
self.root_node_query
Expand All @@ -62,6 +70,7 @@ impl<'w, 's> UiRootNodes<'w, 's> {
}
}

#[cfg(feature = "ghost_nodes")]
/// System param that gives access to UI children utilities, skipping over [`GhostNode`].
#[derive(SystemParam)]
pub struct UiChildren<'w, 's> {
Expand All @@ -77,6 +86,16 @@ pub struct UiChildren<'w, 's> {
parents_query: Query<'w, 's, &'static Parent>,
}

#[cfg(not(feature = "ghost_nodes"))]
/// System param that gives access to UI children utilities.
#[derive(SystemParam)]
pub struct UiChildren<'w, 's> {
ui_children_query: Query<'w, 's, Option<&'static Children>, With<Node>>,
changed_children_query: Query<'w, 's, Entity, Changed<Children>>,
parents_query: Query<'w, 's, &'static Parent>,
}

#[cfg(feature = "ghost_nodes")]
impl<'w, 's> UiChildren<'w, 's> {
/// Iterates the children of `entity`, skipping over [`GhostNode`].
///
Expand Down Expand Up @@ -134,6 +153,40 @@ impl<'w, 's> UiChildren<'w, 's> {
}
}

#[cfg(not(feature = "ghost_nodes"))]
impl<'w, 's> UiChildren<'w, 's> {
/// Iterates the children of `entity`.
pub fn iter_ui_children(&'s self, entity: Entity) -> impl Iterator<Item = Entity> + 's {
self.ui_children_query
.get(entity)
.ok()
.flatten()
.map(|children| children.as_ref())
.unwrap_or(&[])
.iter()
.copied()
}

/// Returns the UI parent of the provided entity.
pub fn get_parent(&'s self, entity: Entity) -> Option<Entity> {
self.parents_query
.get(entity)
.ok()
.map(|parent| parent.entity())
}

/// Given an entity in the UI hierarchy, check if its set of children has changed, e.g if children has been added/removed or if the order has changed.
pub fn is_changed(&'s self, entity: Entity) -> bool {
self.changed_children_query.contains(entity)
}

/// Returns `true` if the given entity is either a [`Node`] or a [`GhostNode`].
pub fn is_ui_node(&'s self, entity: Entity) -> bool {
self.ui_children_query.contains(entity)
}
}

#[cfg(feature = "ghost_nodes")]
pub struct UiChildrenIter<'w, 's> {
stack: SmallVec<[Entity; 8]>,
query: &'s Query<
Expand All @@ -144,6 +197,7 @@ pub struct UiChildrenIter<'w, 's> {
>,
}

#[cfg(feature = "ghost_nodes")]
impl<'w, 's> Iterator for UiChildrenIter<'w, 's> {
type Item = Entity;
fn next(&mut self) -> Option<Self::Item> {
Expand Down
Loading