bevy/crates/bevy_ui/src/stack.rs

304 lines
10 KiB
Rust
Raw Normal View History

Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
//! This module contains the systems that update the stored UI nodes stack
use bevy_ecs::prelude::*;
use bevy_hierarchy::prelude::*;
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
use crate::{GlobalZIndex, Node, ZIndex};
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
/// The current UI stack, which contains all UI nodes ordered by their depth (back-to-front).
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
///
/// 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
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
pub uinodes: Vec<Entity>,
}
#[derive(Default)]
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
pub(crate) struct ChildBufferCache {
pub inner: Vec<Vec<(Entity, i32)>>,
}
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
impl ChildBufferCache {
fn pop(&mut self) -> Vec<(Entity, i32)> {
self.inner.pop().unwrap_or_default()
}
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
fn push(&mut self, vec: Vec<(Entity, i32)>) {
self.inner.push(vec);
}
}
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
/// Generates the render stack for UI nodes.
///
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
/// Create a list of root nodes from unparented entities and entities with a `GlobalZIndex` component.
/// Then build the `UiStack` from a walk of the existing layout trees starting from each root node,
/// filtering branches by `Without<GlobalZIndex>`so that we don't revisit nodes.
#[allow(clippy::too_many_arguments)]
pub fn ui_stack_system(
mut cache: Local<ChildBufferCache>,
mut root_nodes: Local<Vec<(Entity, (i32, i32))>>,
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
mut ui_stack: ResMut<UiStack>,
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
root_node_query: Query<
(Entity, Option<&GlobalZIndex>, Option<&ZIndex>),
(With<Node>, Without<Parent>),
>,
zindex_global_node_query: Query<
(Entity, &GlobalZIndex, Option<&ZIndex>),
(With<Node>, With<Parent>),
>,
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
children_query: Query<&Children>,
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
zindex_query: Query<Option<&ZIndex>, (With<Node>, Without<GlobalZIndex>)>,
mut update_query: Query<&mut Node>,
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
) {
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
ui_stack.uinodes.clear();
for (id, global_zindex, maybe_zindex) in zindex_global_node_query.iter() {
root_nodes.push((
id,
(
global_zindex.0,
maybe_zindex.map(|zindex| zindex.0).unwrap_or(0),
),
));
}
for (id, maybe_global_zindex, maybe_zindex) in root_node_query.iter() {
root_nodes.push((
id,
(
maybe_global_zindex.map(|zindex| zindex.0).unwrap_or(0),
maybe_zindex.map(|zindex| zindex.0).unwrap_or(0),
),
));
}
root_nodes.sort_by_key(|(_, z)| *z);
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
for (root_entity, _) in root_nodes.drain(..) {
update_uistack_recursive(
&mut cache,
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
root_entity,
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
&children_query,
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
&zindex_query,
&mut ui_stack.uinodes,
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
);
}
for (i, entity) in ui_stack.uinodes.iter().enumerate() {
if let Ok(mut node) = update_query.get_mut(*entity) {
node.bypass_change_detection().stack_index = i as u32;
}
}
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
}
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
fn update_uistack_recursive(
cache: &mut ChildBufferCache,
node_entity: Entity,
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
children_query: &Query<&Children>,
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
zindex_query: &Query<Option<&ZIndex>, (With<Node>, Without<GlobalZIndex>)>,
ui_stack: &mut Vec<Entity>,
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
) {
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
ui_stack.push(node_entity);
if let Ok(children) = children_query.get(node_entity) {
let mut child_buffer = cache.pop();
child_buffer.extend(children.iter().filter_map(|child_entity| {
zindex_query
.get(*child_entity)
.ok()
.map(|zindex| (*child_entity, zindex.map(|zindex| zindex.0).unwrap_or(0)))
}));
child_buffer.sort_by_key(|k| k.1);
for (child_entity, _) in child_buffer.drain(..) {
update_uistack_recursive(cache, child_entity, children_query, zindex_query, ui_stack);
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
}
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
cache.push(child_buffer);
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
}
}
#[cfg(test)]
mod tests {
use bevy_ecs::{
component::Component,
schedule::Schedule,
system::Commands,
world::{CommandQueue, World},
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
};
use bevy_hierarchy::{BuildChildren, ChildBuild};
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
use crate::{GlobalZIndex, Node, UiStack, ZIndex};
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
use super::ui_stack_system;
#[derive(Component, PartialEq, Debug, Clone)]
struct Label(&'static str);
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
fn node_with_global_and_local_zindex(
name: &'static str,
global_zindex: i32,
local_zindex: i32,
) -> (Label, Node, GlobalZIndex, ZIndex) {
(
Label(name),
Node::default(),
GlobalZIndex(global_zindex),
ZIndex(local_zindex),
)
}
fn node_with_global_zindex(
name: &'static str,
global_zindex: i32,
) -> (Label, Node, GlobalZIndex) {
(Label(name), Node::default(), GlobalZIndex(global_zindex))
}
fn node_with_zindex(name: &'static str, zindex: i32) -> (Label, Node, ZIndex) {
(Label(name), Node::default(), ZIndex(zindex))
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
}
fn node_without_zindex(name: &'static str) -> (Label, Node) {
(Label(name), Node::default())
}
/// Tests the UI Stack system.
///
/// This tests for siblings default ordering according to their insertion order, but it
/// can't test the same thing for UI roots. UI roots having no parents, they do not have
/// a stable ordering that we can test against. If we test it, it may pass now and start
/// failing randomly in the future because of some unrelated `bevy_ecs` change.
#[test]
fn test_ui_stack_system() {
let mut world = World::default();
world.init_resource::<UiStack>();
let mut queue = CommandQueue::default();
let mut commands = Commands::new(&mut queue, &world);
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
commands.spawn(node_with_global_zindex("0", 2));
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
commands
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
.spawn(node_with_zindex("1", 1))
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
.with_children(|parent| {
parent
.spawn(node_without_zindex("1-0"))
.with_children(|parent| {
parent.spawn(node_without_zindex("1-0-0"));
parent.spawn(node_without_zindex("1-0-1"));
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
parent.spawn(node_with_zindex("1-0-2", -1));
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
});
parent.spawn(node_without_zindex("1-1"));
parent
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
.spawn(node_with_global_zindex("1-2", -1))
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
.with_children(|parent| {
parent.spawn(node_without_zindex("1-2-0"));
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
parent.spawn(node_with_global_zindex("1-2-1", -3));
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
parent
.spawn(node_without_zindex("1-2-2"))
.with_children(|_| ());
parent.spawn(node_without_zindex("1-2-3"));
});
parent.spawn(node_without_zindex("1-3"));
});
commands
.spawn(node_without_zindex("2"))
.with_children(|parent| {
parent
.spawn(node_without_zindex("2-0"))
.with_children(|_parent| ());
parent
.spawn(node_without_zindex("2-1"))
.with_children(|parent| {
parent.spawn(node_without_zindex("2-1-0"));
});
});
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
commands.spawn(node_with_global_zindex("3", -2));
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
queue.apply(&mut world);
let mut schedule = Schedule::default();
schedule.add_systems(ui_stack_system);
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
schedule.run(&mut world);
let mut query = world.query::<&Label>();
let ui_stack = world.resource::<UiStack>();
let actual_result = ui_stack
.uinodes
.iter()
.map(|entity| query.get(&world, *entity).unwrap().clone())
.collect::<Vec<_>>();
let expected_result = vec![
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
(Label("1-2-1")), // GlobalZIndex(-3)
(Label("3")), // GlobalZIndex(-2)
(Label("1-2")), // GlobalZIndex(-1)
(Label("1-2-0")),
(Label("1-2-2")),
(Label("1-2-3")),
(Label("2")),
(Label("2-0")),
(Label("2-1")),
(Label("2-1-0")),
(Label("1")), // ZIndex(1)
(Label("1-0")),
(Label("1-0-2")), // ZIndex(-1)
(Label("1-0-0")),
(Label("1-0-1")),
(Label("1-1")),
(Label("1-3")),
(Label("0")), // GlobalZIndex(2)
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
];
assert_eq!(actual_result, expected_result);
}
Simplified `ui_stack_system` (#9889) # Objective `ui_stack_system` generates a tree of `StackingContexts` which it then flattens to get the `UiStack`. But there's no need to construct a new tree. We can query for nodes with a global `ZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, ignoring any branches that have a global `Zindex`. Fixes #9877 ## Solution Split the `ZIndex` enum into two separate components, `ZIndex` and `GlobalZIndex` Query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex>` so we don't revisit nodes. ``` cargo run --profile stress-test --features trace_tracy --example many_buttons ``` <img width="672" alt="ui-stack-system-walk-split-enum" src="https://github.com/bevyengine/bevy/assets/27962798/11e357a5-477f-4804-8ada-c4527c009421"> (Yellow is this PR, red is main) --- ## Changelog `Zindex` * The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZIndex` values are equal. `ui_stack_system` * Instead of generating a tree of `StackingContexts`, query for nodes with a `GlobalZIndex`, add those nodes to the root nodes list and then build the `UiStack` from a walk of the existing layout tree, filtering branches by `Without<GlobalZIndex` so we don't revisit nodes. ## Migration Guide The `ZIndex` enum has been split into two separate components `ZIndex` (which replaces `ZIndex::Local`) and `GlobalZIndex` (which replaces `ZIndex::Global`). An entity can have both a `ZIndex` and `GlobalZIndex`, in comparisons `ZIndex` breaks ties if two `GlobalZindex` values are equal. --------- Co-authored-by: Gabriel Bourgeois <gabriel.bourgeoisv4si@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
2024-09-30 18:43:57 +00:00
#[test]
fn test_with_equal_global_zindex_zindex_decides_order() {
let mut world = World::default();
world.init_resource::<UiStack>();
let mut queue = CommandQueue::default();
let mut commands = Commands::new(&mut queue, &world);
commands.spawn(node_with_global_and_local_zindex("0", -1, 1));
commands.spawn(node_with_global_and_local_zindex("1", -1, 2));
commands.spawn(node_with_global_and_local_zindex("2", 1, 3));
commands.spawn(node_with_global_and_local_zindex("3", 1, -3));
commands
.spawn(node_without_zindex("4"))
.with_children(|builder| {
builder.spawn(node_with_global_and_local_zindex("5", 0, -1));
builder.spawn(node_with_global_and_local_zindex("6", 0, 1));
builder.spawn(node_with_global_and_local_zindex("7", -1, -1));
builder.spawn(node_with_global_zindex("8", 1));
});
queue.apply(&mut world);
let mut schedule = Schedule::default();
schedule.add_systems(ui_stack_system);
schedule.run(&mut world);
let mut query = world.query::<&Label>();
let ui_stack = world.resource::<UiStack>();
let actual_result = ui_stack
.uinodes
.iter()
.map(|entity| query.get(&world, *entity).unwrap().clone())
.collect::<Vec<_>>();
let expected_result = vec![
(Label("7")),
(Label("0")),
(Label("1")),
(Label("5")),
(Label("4")),
(Label("6")),
(Label("3")),
(Label("8")),
(Label("2")),
];
assert_eq!(actual_result, expected_result);
}
Add z-index support with a predictable UI stack (#5877) # Objective Add consistent UI rendering and interaction where deep nodes inside two different hierarchies will never render on top of one-another by default and offer an escape hatch (z-index) for nodes to change their depth. ## The problem with current implementation The current implementation of UI rendering is broken in that regard, mainly because [it sets the Z value of the `Transform` component based on a "global Z" space](https://github.com/bevyengine/bevy/blob/main/crates/bevy_ui/src/update.rs#L43) shared by all nodes in the UI. This doesn't account for the fact that each node's final `GlobalTransform` value will be relative to its parent. This effectively makes the depth unpredictable when two deep trees are rendered on top of one-another. At the moment, it's also up to each part of the UI code to sort all of the UI nodes. The solution that's offered here does the full sorting of UI node entities once and offers the result through a resource so that all systems can use it. ## Solution ### New ZIndex component This adds a new optional `ZIndex` enum component for nodes which offers two mechanism: - `ZIndex::Local(i32)`: Overrides the depth of the node relative to its siblings. - `ZIndex::Global(i32)`: Overrides the depth of the node relative to the UI root. This basically allows any node in the tree to "escape" the parent and be ordered relative to the entire UI. Note that in the current implementation, omitting `ZIndex` on a node has the same result as adding `ZIndex::Local(0)`. Additionally, the "global" stacking context is essentially a way to add your node to the root stacking context, so using `ZIndex::Local(n)` on a root node (one without parent) will share that space with all nodes using `Index::Global(n)`. ### New UiStack resource This adds a new `UiStack` resource which is calculated from both hierarchy and `ZIndex` during UI update and contains a vector of all node entities in the UI, ordered by depth (from farthest from camera to closest). This is exposed publicly by the bevy_ui crate with the hope that it can be used for consistent ordering and to reduce the amount of sorting that needs to be done by UI systems (i.e. instead of sorting everything by `global_transform.z` in every system, this array can be iterated over). ### New z_index example This also adds a new z_index example that showcases the new `ZIndex` component. It's also a good general demo of the new UI stack system, because making this kind of UI was very broken with the old system (e.g. nodes would render on top of each other, not respecting hierarchy or insert order at all). ![image](https://user-images.githubusercontent.com/1060971/189015985-8ea8f989-0e9d-4601-a7e0-4a27a43a53f9.png) --- ## Changelog - Added the `ZIndex` component to bevy_ui. - Added the `UiStack` resource to bevy_ui, and added implementation in a new `stack.rs` module. - Removed the previous Z updating system from bevy_ui, because it was replaced with the above. - Changed bevy_ui rendering to use UiStack instead of z ordering. - Changed bevy_ui focus/interaction system to use UiStack instead of z ordering. - Added a new z_index example. ## ZIndex demo Here's a demo I wrote to test these features https://user-images.githubusercontent.com/1060971/188329295-d7beebd6-9aee-43ab-821e-d437df5dbe8a.mp4 Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-11-02 22:06:04 +00:00
}