Improve UI stack docs and other small tweaks (#8094)
This commit is contained in:
parent
5144a2ac25
commit
803b9ef601
@ -171,10 +171,10 @@ pub fn ui_focus_system(
|
||||
.iter()
|
||||
.filter(|(_, camera_ui)| !is_ui_disabled(*camera_ui))
|
||||
.filter_map(|(camera, _)| {
|
||||
if let Some(NormalizedRenderTarget::Window(window_id)) =
|
||||
if let Some(NormalizedRenderTarget::Window(window_ref)) =
|
||||
camera.target.normalize(primary_window)
|
||||
{
|
||||
Some(window_id)
|
||||
Some(window_ref)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -192,7 +192,7 @@ pub fn ui_focus_system(
|
||||
// prepare an iterator that contains all the nodes that have the cursor in their rect,
|
||||
// from the top node to the bottom one. this will also reset the interaction to `None`
|
||||
// for all nodes encountered that are no longer hovered.
|
||||
let mut moused_over_nodes = ui_stack
|
||||
let mut hovered_nodes = ui_stack
|
||||
.uinodes
|
||||
.iter()
|
||||
// reverse the iterator to traverse the tree from closest nodes to furthest
|
||||
@ -263,7 +263,7 @@ pub fn ui_focus_system(
|
||||
|
||||
// set Clicked or Hovered on top nodes. as soon as a node with a `Block` focus policy is detected,
|
||||
// the iteration will stop on it because it "captures" the interaction.
|
||||
let mut iter = node_query.iter_many_mut(moused_over_nodes.by_ref());
|
||||
let mut iter = node_query.iter_many_mut(hovered_nodes.by_ref());
|
||||
while let Some(node) = iter.fetch_next() {
|
||||
if let Some(mut interaction) = node.interaction {
|
||||
if mouse_clicked {
|
||||
@ -290,7 +290,7 @@ pub fn ui_focus_system(
|
||||
}
|
||||
// reset `Interaction` for the remaining lower nodes to `None`. those are the nodes that remain in
|
||||
// `moused_over_nodes` after the previous loop is exited.
|
||||
let mut iter = node_query.iter_many_mut(moused_over_nodes);
|
||||
let mut iter = node_query.iter_many_mut(hovered_nodes);
|
||||
while let Some(node) = iter.fetch_next() {
|
||||
if let Some(mut interaction) = node.interaction {
|
||||
// don't reset clicked nodes because they're handled separately
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! This crate contains Bevy's UI system, which can be used to create UI for both 2D and 3D games
|
||||
//! # Basic usage
|
||||
//! Spawn UI elements with [`node_bundles::ButtonBundle`], [`node_bundles::ImageBundle`], [`node_bundles::TextBundle`] and [`node_bundles::NodeBundle`]
|
||||
//! This UI is laid out with the Flexbox paradigm (see <https://cssreference.io/flexbox/>)
|
||||
//! This UI is laid out with the Flexbox layout model (see <https://cssreference.io/flexbox/>)
|
||||
mod flex;
|
||||
mod focus;
|
||||
mod geometry;
|
||||
|
@ -5,12 +5,13 @@ use bevy_hierarchy::prelude::*;
|
||||
|
||||
use crate::{Node, ZIndex};
|
||||
|
||||
/// The current UI stack, which contains all UI nodes ordered by their depth.
|
||||
/// The current UI stack, which contains all UI nodes ordered by their depth (back-to-front).
|
||||
///
|
||||
/// The first entry is the furthest node from the camera and is the first one to get rendered
|
||||
/// while the last entry is the first node to receive interactions.
|
||||
#[derive(Debug, Resource, Default)]
|
||||
pub struct UiStack {
|
||||
/// List of UI nodes ordered from back-to-front
|
||||
pub uinodes: Vec<Entity>,
|
||||
}
|
||||
|
||||
@ -26,15 +27,19 @@ struct StackingContextEntry {
|
||||
}
|
||||
|
||||
/// Generates the render stack for UI nodes.
|
||||
///
|
||||
/// First generate a UI node tree (`StackingContext`) based on z-index.
|
||||
/// Then flatten that tree into back-to-front ordered `UiStack`.
|
||||
pub fn ui_stack_system(
|
||||
mut ui_stack: ResMut<UiStack>,
|
||||
root_node_query: Query<Entity, (With<Node>, Without<Parent>)>,
|
||||
zindex_query: Query<&ZIndex, With<Node>>,
|
||||
children_query: Query<&Children>,
|
||||
) {
|
||||
// Generate `StackingContext` tree
|
||||
let mut global_context = StackingContext::default();
|
||||
|
||||
let mut total_entry_count: usize = 0;
|
||||
|
||||
for entity in &root_node_query {
|
||||
insert_context_hierarchy(
|
||||
&zindex_query,
|
||||
@ -46,11 +51,13 @@ pub fn ui_stack_system(
|
||||
);
|
||||
}
|
||||
|
||||
// Flatten `StackingContext` into `UiStack`
|
||||
ui_stack.uinodes.clear();
|
||||
ui_stack.uinodes.reserve(total_entry_count);
|
||||
fill_stack_recursively(&mut ui_stack.uinodes, &mut global_context);
|
||||
}
|
||||
|
||||
/// Generate z-index based UI node tree
|
||||
fn insert_context_hierarchy(
|
||||
zindex_query: &Query<&ZIndex, With<Node>>,
|
||||
children_query: &Query<&Children>,
|
||||
@ -60,8 +67,10 @@ fn insert_context_hierarchy(
|
||||
total_entry_count: &mut usize,
|
||||
) {
|
||||
let mut new_context = StackingContext::default();
|
||||
|
||||
if let Ok(children) = children_query.get(entity) {
|
||||
// reserve space for all children. in practice, some may not get pushed.
|
||||
// Reserve space for all children. In practice, some may not get pushed since
|
||||
// nodes with `ZIndex::Global` are pushed to the global (root) context.
|
||||
new_context.entries.reserve_exact(children.len());
|
||||
|
||||
for entity in children {
|
||||
@ -76,6 +85,7 @@ fn insert_context_hierarchy(
|
||||
}
|
||||
}
|
||||
|
||||
// The node will be added either to global/parent based on its z-index type: global/local.
|
||||
let z_index = zindex_query.get(entity).unwrap_or(&ZIndex::Local(0));
|
||||
let (entity_context, z_index) = match z_index {
|
||||
ZIndex::Local(value) => (parent_context.unwrap_or(global_context), *value),
|
||||
@ -90,12 +100,15 @@ fn insert_context_hierarchy(
|
||||
});
|
||||
}
|
||||
|
||||
/// Flatten `StackingContext` (z-index based UI node tree) into back-to-front entities list
|
||||
fn fill_stack_recursively(result: &mut Vec<Entity>, stack: &mut StackingContext) {
|
||||
// sort entries by ascending z_index, while ensuring that siblings
|
||||
// with the same local z_index will keep their ordering.
|
||||
// Sort entries by ascending z_index, while ensuring that siblings
|
||||
// with the same local z_index will keep their ordering. This results
|
||||
// in `back-to-front` ordering, low z_index = back; high z_index = front.
|
||||
stack.entries.sort_by_key(|e| e.z_index);
|
||||
|
||||
for entry in &mut stack.entries {
|
||||
// Parent node renders before/behind childs nodes
|
||||
result.push(entry.entity);
|
||||
fill_stack_recursively(result, &mut entry.stack);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user