# Objective
allow specifying the left/top/right/bottom border colors separately for
ui elements
fixes#14773
## Solution
- change `BorderColor` to
```rs
pub struct BorderColor {
pub left: Color,
pub top: Color,
pub right: Color,
pub bottom: Color,
}
```
- generate one ui node per distinct border color, set flags for the
active borders
- render only the active borders
i chose to do this rather than adding multiple colors to the
ExtractedUiNode in order to minimize the impact for the common case
where all border colors are the same.
## Testing
modified the `borders` example to use separate colors:

the behaviour is a bit weird but it mirrors html/css border behaviour.
---
## Migration:
To keep the existing behaviour, just change `BorderColor(color)` into
`BorderColor::all(color)`.
---------
Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
# Objective
- Alternative to and builds on top of #16284.
- Fixes#15849.
## Solution
- Rename component `StateScoped` to `DespawnOnExitState`.
- Rename system `clear_state_scoped_entities` to
`despawn_entities_on_exit_state`.
- Add `DespawnOnEnterState` and `despawn_entities_on_enter_state` which
is the `OnEnter` equivalent.
> [!NOTE]
> Compared to #16284, the main change is that I did the rename in such a
way as to keep the terms `OnExit` and `OnEnter` together. In my own
game, I was adding `VisibleOnEnterState` and `HiddenOnExitState` and
when naming those, I kept the `OnExit` and `OnEnter` together. When I
checked #16284 it stood out to me that the naming was a bit awkward.
Putting the `State` in the middle and breaking up `OnEnter` and `OnExit`
also breaks searching for those terms.
## Open questions
1. Should we split `enable_state_scoped_entities` into two functions,
one for the `OnEnter` and one for the `OnExit`? I personally have zero
need thus far for the `OnEnter` version, so I'd be interested in not
having this enabled unless I ask for it.
2. If yes to 1., should we follow my lead in my `Visibility` state
components (see below) and name these
`app.enable_despawn_entities_on_enter_state()` and
`app.enable_despawn_entities_on_exit_state()`, which IMO says what it
does on the tin?
## Testing
Ran all changed examples.
## Side note: `VisibleOnEnterState` and `HiddenOnExitState`
For reference to anyone else and to help with the open questions, I'm
including the code I wrote for controlling entity visibility when a
state is entered/exited.
<details>
<summary>visibility.rs</summary>
```rust
use bevy_app::prelude::*;
use bevy_ecs::prelude::*;
use bevy_reflect::prelude::*;
use bevy_render::prelude::*;
use bevy_state::{prelude::*, state::StateTransitionSteps};
use tracing::*;
pub trait AppExtStates {
fn enable_visible_entities_on_enter_state<S: States>(&mut self) -> &mut Self;
fn enable_hidden_entities_on_exit_state<S: States>(&mut self) -> &mut Self;
}
impl AppExtStates for App {
fn enable_visible_entities_on_enter_state<S: States>(&mut self) -> &mut Self {
self.main_mut()
.enable_visible_entities_on_enter_state::<S>();
self
}
fn enable_hidden_entities_on_exit_state<S: States>(&mut self) -> &mut Self {
self.main_mut().enable_hidden_entities_on_exit_state::<S>();
self
}
}
impl AppExtStates for SubApp {
fn enable_visible_entities_on_enter_state<S: States>(&mut self) -> &mut Self {
if !self
.world()
.contains_resource::<Events<StateTransitionEvent<S>>>()
{
let name = core::any::type_name::<S>();
warn!("Visible entities on enter state are enabled for state `{}`, but the state isn't installed in the app!", name);
}
// We work with [`StateTransition`] in set
// [`StateTransitionSteps::ExitSchedules`] as opposed to [`OnExit`],
// because [`OnExit`] only runs for one specific variant of the state.
self.add_systems(
StateTransition,
update_to_visible_on_enter_state::<S>.in_set(StateTransitionSteps::ExitSchedules),
)
}
fn enable_hidden_entities_on_exit_state<S: States>(&mut self) -> &mut Self {
if !self
.world()
.contains_resource::<Events<StateTransitionEvent<S>>>()
{
let name = core::any::type_name::<S>();
warn!("Hidden entities on exit state are enabled for state `{}`, but the state isn't installed in the app!", name);
}
// We work with [`StateTransition`] in set
// [`StateTransitionSteps::ExitSchedules`] as opposed to [`OnExit`],
// because [`OnExit`] only runs for one specific variant of the state.
self.add_systems(
StateTransition,
update_to_hidden_on_exit_state::<S>.in_set(StateTransitionSteps::ExitSchedules),
)
}
}
#[derive(Clone, Component, Debug, Reflect)]
#[reflect(Component, Debug)]
pub struct VisibleOnEnterState<S: States>(pub S);
#[derive(Clone, Component, Debug, Reflect)]
#[reflect(Component, Debug)]
pub struct HiddenOnExitState<S: States>(pub S);
/// Makes entities marked with [`VisibleOnEnterState<S>`] visible when the state
/// `S` is entered.
pub fn update_to_visible_on_enter_state<S: States>(
mut transitions: EventReader<StateTransitionEvent<S>>,
mut query: Query<(&VisibleOnEnterState<S>, &mut Visibility)>,
) {
// We use the latest event, because state machine internals generate at most
// 1 transition event (per type) each frame. No event means no change
// happened and we skip iterating all entities.
let Some(transition) = transitions.read().last() else {
return;
};
if transition.entered == transition.exited {
return;
}
let Some(entered) = &transition.entered else {
return;
};
for (binding, mut visibility) in query.iter_mut() {
if binding.0 == *entered {
visibility.set_if_neq(Visibility::Visible);
}
}
}
/// Makes entities marked with [`HiddenOnExitState<S>`] invisible when the state
/// `S` is exited.
pub fn update_to_hidden_on_exit_state<S: States>(
mut transitions: EventReader<StateTransitionEvent<S>>,
mut query: Query<(&HiddenOnExitState<S>, &mut Visibility)>,
) {
// We use the latest event, because state machine internals generate at most
// 1 transition event (per type) each frame. No event means no change
// happened and we skip iterating all entities.
let Some(transition) = transitions.read().last() else {
return;
};
if transition.entered == transition.exited {
return;
}
let Some(exited) = &transition.exited else {
return;
};
for (binding, mut visibility) in query.iter_mut() {
if binding.0 == *exited {
visibility.set_if_neq(Visibility::Hidden);
}
}
}
```
</details>
---------
Co-authored-by: Benjamin Brienen <Benjamin.Brienen@outlook.com>
Co-authored-by: Ben Frankel <ben.frankel7@gmail.com>
# Objective
Contributes to #18238
Updates the `text2d`, example to use the `children!` macro.
~~The SpawnIter usage in this example is maybe not the best. Very open
to opinions. I even left one `with_children` that I thought was just
much better than any alternative.~~
## Solution
Updates examples to use the Improved Spawning API merged in
https://github.com/bevyengine/bevy/pull/17521
## Testing
- Did you test these changes? If so, how?
- Opened the examples before and after and verified the same behavior
was observed. I did this on Ubuntu 24.04.2 LTS using `--features
wayland`.
- Are there any parts that need more testing?
- Other OS's and features can't hurt, but this is such a small change it
shouldn't be a problem.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Run the examples yourself with and without these changes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- see above
---
## Showcase
n/a
## Migration Guide
n/a
# Objective
- have a testbed for UI
## Solution
- move previous `ui` example to `full_ui`
- add a testbed ui with several scenes
- `ui_layout_rounding` is one of those scenes, so remove it as a
standalone example
the previous `ui` / new `full_ui` is I think still useful as it has some
things like scroll, debug ui that are not shown anywhere else
Fixes#17412
## Objective
`Parent` uses the "has a X" naming convention. There is increasing
sentiment that we should use the "is a X" naming convention for
relationships (following #17398). This leaves `Children` as-is because
there is prevailing sentiment that `Children` is clearer than `ParentOf`
in many cases (especially when treating it like a collection).
This renames `Parent` to `ChildOf`.
This is just the implementation PR. To discuss the path forward, do so
in #17412.
## Migration Guide
- The `Parent` component has been renamed to `ChildOf`.
# Objective
PR #17225 allowed for sprite picking to be opt-in. After some
discussion, it was agreed that `PickingBehavior` should be used to
opt-in to sprite picking behavior for entities. This leads to
`PickingBehavior` having two purposes: mark an entity for use in a
backend, and describe how it should be picked. Discussion led to the
name `Pickable`making more sense (also: this is what the component was
named before upstreaming).
A follow-up pass will be made after this PR to unify backends.
## Solution
Replace all instances of `PickingBehavior` and `picking_behavior` with
`Pickable` and `pickable`, respectively.
## Testing
CI
## Migration Guide
Change all instances of `PickingBehavior` to `Pickable`.
# Objective
The UI debug overlay draws an outline for every UI node even if it is
invisible or clipped.
Disable debug outlines for hidden and clipped nodes by default and add
options to renable them if needed.
## Solution
* Add `show_hidden` and `show_clipped` fields to `UiDebugOptions`:
```rust
/// Show outlines for non-visible UI nodes
pub show_hidden: bool,
/// Show outlines for clipped sections of UI nodes
pub show_clipped: bool,
```
* Only extract debug outlines for hidden and clipped UI nodes if the
respective field in `UiDebugOptions` is set to `true`.
## Testing
Also added some extra features to the `testbed_ui` example that
demonstrate the new options:
cargo run --example testbed_ui --features "bevy_ui_debug"
<img width="641" alt="show-hidden-and-clipped"
src="https://github.com/user-attachments/assets/16a68600-170c-469e-a3c7-f7dae411dc40"
/>
# Objective
With the introduction of bevy_input_focus, the uses of "focus" in
bevy_picking are quite confusing and make searching hard.
Users will intuitively think these concepts are related, but they
actually aren't.
## Solution
Rename / rephrase all uses of "focus" in bevy_picking to refer to
"hover", since this is ultimately related to creating the `HoverMap`.
## Migration Guide
Various terms related to "focus" in `bevy_picking` have been renamed to
refer to "hover" to avoid confusion with `bevy_input_focus`. In
particular:
- The `update_focus` system has been renamed to `generate_hovermap`
- `PickSet::Focus` and `PostFocus` have been renamed to `Hover` and
`PostHover`
- The `bevy_picking::focus` module has been renamed to
`bevy_picking::hover`
- The `is_focus_enabled` field on `PickingPlugin` has been renamed to
`is_hover_enabled`
- The `focus_should_run` run condition has been renamed to
`hover_should_run`
# Objective
Draw the UI debug overlay using the UI renderer.
Significantly simpler and easier to use than
`bevy_dev_tools::ui_debug_overlay` which uses `bevy_gizmos`.
* Supports multiple windows and UI rendered to texture.
* Draws rounded debug rects for rounded UI nodes.
Fixes#16666
## Solution
Removed the `ui_debug_overlay` module from `bevy_dev_tools`.
Added a `bevy_ui_debug` feature gate.
Draw the UI debug overlay using the UI renderer.
Adds a new module `bevy_ui::render::debug_overlay`.
The debug overlay extraction function queries for the existing UI layout
and then adds a border around each UI node with `u32::MAX / 2` added to
each stack index so it's drawn on top.
There is a `UiDebugOptions` resource that can be used to enable or
disable the debug overlay and set the line width.
## Testing
The `testbed_ui` example has been changed to use the new debug overlay:
```
cargo run --example testbed_ui --features bevy_ui_debug
```
Press Space to toggle the debug overlay on and off.
---
## Showcase
<img width="961" alt="testbed-ui-new-debug"
src="https://github.com/user-attachments/assets/e9523d18-39ae-46a8-adbe-7d3f3ab8e951">
## Migration Guide
The `ui_debug_overlay` module has been removed from `bevy_dev_tools`.
There is a new debug overlay implemented using the `bevy_ui` renderer.
To use it, enable the `bevy_ui_debug` feature and set the `enable` field
of the `UiDebugOptions` resource to `true`.
# Objective
The `UiBoxShadowSamples` resource should be renamed to
`BoxShadowSamples` so it matches the `BoxShadow` component.
## Migration Guide
`UiBoxShadowSamples` has been renamed to `BoxShadowSamples`
# Objective
Add support for multiple box shadows on a single `Node`.
## Solution
* Rename `BoxShadow` to `ShadowStyle` and remove its `Component` derive.
* Create a new `BoxShadow` component that newtypes a `Vec<ShadowStyle>`.
* Add a `new` constructor method to `BoxShadow` for single shadows.
* Change `extract_shadows` to iterate through a list of shadows per
node.
Render order is determined implicitly from the order of the shadows
stored in the `BoxShadow` component, back-to-front.
Might be more efficient to use a `SmallVec<[ShadowStyle; 1]>` for the
list of shadows but not sure if the extra friction is worth it.
## Testing
Added a node with four differently coloured shadows to the `box_shadow`
example.
---
## Showcase
```
cargo run --example box_shadow
```
<img width="460" alt="four-shadow"
src="https://github.com/user-attachments/assets/2f728c47-33b4-42e1-96ba-28a774b94b24">
## Migration Guide
Bevy UI now supports multiple shadows per node. A new struct
`ShadowStyle` is used to set the style for each shadow. And the
`BoxShadow` component is changed to a tuple struct wrapping a vector
containing a list of `ShadowStyle`s. To spawn a node with a single
shadow you can use the `new` constructor function:
```rust
commands.spawn((
Node::default(),
BoxShadow::new(
Color::BLACK.with_alpha(0.8),
Val::Percent(offset.x),
Val::Percent(offset.y),
Val::Percent(spread),
Val::Px(blur),
)
));
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Run `testbed_ui` example:
```
cargo run --example testbed_ui
```
The scroll list is non-scrollable because it's blocked by the front
four-icon node.
## Solution
Add `PickingBehavior::IGNORE` for the front node
## Testing
- Did you test these changes? If so, how?
Yes.
- Are there any parts that need more testing?
No, I guess.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
```
cargo run --example testbed_ui
```
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
macOS.
# Objective
- Progress towards #15918
- Add test on UI
## Solution
- Get a single screenshot from the UI testbed example
- Remove older examples from runs in CI as they're covered by the
testbed to reduce CI duration
# Objective
- Fixes#16235
## Solution
- Both Bevy and AccessKit export a `Node` struct, to reduce confusion
Bevy will no longer re-export `AccessKit` from `bevy_a11y`
## Testing
- Tested locally
## Migration Guide
```diff
# main.rs
-- use bevy_a11y::{
-- accesskit::{Node, Rect, Role},
-- AccessibilityNode,
-- };
++ use bevy_a11y::AccessibilityNode;
++ use accesskit::{Node, Rect, Role};
# Cargo.toml
++ accesskit = "0.17"
```
- Users will need to add `accesskit = "0.17"` to the dependencies
section of their `Cargo.toml` file and update their `accesskit` use
statements to come directly from the external crate instead of
`bevy_a11y`.
- Make sure to keep the versions of `accesskit` aligned with the
versions Bevy uses.