UI Debug Overlay show_hidden and show_clipped options (#17097)

# 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"
/>
This commit is contained in:
ickshonpe 2025-01-02 18:43:14 +00:00 committed by GitHub
parent 2931e350b6
commit 1a18c9f87b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 85 additions and 18 deletions

View File

@ -1,3 +1,7 @@
use crate::CalculatedClip;
use crate::ComputedNode;
use crate::DefaultUiCamera;
use crate::TargetCamera;
use bevy_asset::AssetId;
use bevy_color::Hsla;
use bevy_ecs::entity::Entity;
@ -10,14 +14,11 @@ use bevy_math::Rect;
use bevy_math::Vec2;
use bevy_render::sync_world::RenderEntity;
use bevy_render::sync_world::TemporaryRenderEntity;
use bevy_render::view::ViewVisibility;
use bevy_render::Extract;
use bevy_sprite::BorderRect;
use bevy_transform::components::GlobalTransform;
use crate::ComputedNode;
use crate::DefaultUiCamera;
use crate::TargetCamera;
use super::ExtractedUiItem;
use super::ExtractedUiNode;
use super::ExtractedUiNodes;
@ -30,6 +31,10 @@ pub struct UiDebugOptions {
pub enabled: bool,
/// Width of the overlay's lines in logical pixels
pub line_width: f32,
/// Show outlines for non-visible UI nodes
pub show_hidden: bool,
/// Show outlines for clipped sections of UI nodes
pub show_clipped: bool,
}
impl UiDebugOptions {
@ -43,6 +48,8 @@ impl Default for UiDebugOptions {
Self {
enabled: false,
line_width: 1.,
show_hidden: false,
show_clipped: false,
}
}
}
@ -57,6 +64,8 @@ pub fn extract_debug_overlay(
Query<(
Entity,
&ComputedNode,
&ViewVisibility,
Option<&CalculatedClip>,
&GlobalTransform,
Option<&TargetCamera>,
)>,
@ -67,7 +76,11 @@ pub fn extract_debug_overlay(
return;
}
for (entity, uinode, transform, camera) in &uinode_query {
for (entity, uinode, visibility, maybe_clip, transform, camera) in &uinode_query {
if !debug_options.show_hidden && !visibility.get() {
continue;
}
let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera.get())
else {
continue;
@ -88,7 +101,9 @@ pub fn extract_debug_overlay(
min: Vec2::ZERO,
max: uinode.size,
},
clip: None,
clip: maybe_clip
.filter(|_| !debug_options.show_clipped)
.map(|clip| clip.clip),
image: AssetId::default(),
camera_entity: render_camera_entity,
item: ExtractedUiItem::Node {

View File

@ -60,6 +60,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
..default()
},
BackgroundColor(Color::srgb(0.15, 0.15, 0.15)),
Visibility::Visible,
))
.with_children(|parent| {
// text
@ -77,16 +78,46 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
));
#[cfg(feature = "bevy_ui_debug")]
// Debug overlay text
parent.spawn((
Text::new("Press Space to toggle debug outlines."),
TextFont {
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
..default()
},
Label,
));
{
// Debug overlay text
parent.spawn((
Text::new("Press Space to toggle debug outlines."),
TextFont {
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
..default()
},
Label,
));
parent.spawn((
Text::new("V: toggle UI root's visibility"),
TextFont {
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
font_size: 12.,
..default()
},
Label,
));
parent.spawn((
Text::new("S: toggle outlines for hidden nodes"),
TextFont {
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
font_size: 12.,
..default()
},
Label,
));
parent.spawn((
Text::new("C: toggle outlines for clipped nodes"),
TextFont {
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
font_size: 12.,
..default()
},
Label,
));
}
#[cfg(not(feature = "bevy_ui_debug"))]
parent.spawn((
Text::new("Try enabling feature \"bevy_ui_debug\"."),
@ -346,11 +377,32 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
#[cfg(feature = "bevy_ui_debug")]
// The system that will enable/disable the debug outlines around the nodes
fn toggle_debug_overlay(input: Res<ButtonInput<KeyCode>>, mut options: ResMut<UiDebugOptions>) {
fn toggle_debug_overlay(
input: Res<ButtonInput<KeyCode>>,
mut debug_options: ResMut<UiDebugOptions>,
mut root_node_query: Query<&mut Visibility, (With<Node>, Without<Parent>)>,
) {
info_once!("The debug outlines are enabled, press Space to turn them on/off");
if input.just_pressed(KeyCode::Space) {
// The toggle method will enable the debug_overlay if disabled and disable if enabled
options.toggle();
// The toggle method will enable the debug overlay if disabled and disable if enabled
debug_options.toggle();
}
if input.just_pressed(KeyCode::KeyS) {
// Toggle debug outlines for nodes with `ViewVisibility` set to false.
debug_options.show_hidden = !debug_options.show_hidden;
}
if input.just_pressed(KeyCode::KeyC) {
// Toggle outlines for clipped UI nodes.
debug_options.show_clipped = !debug_options.show_clipped;
}
if input.just_pressed(KeyCode::KeyV) {
for mut visibility in root_node_query.iter_mut() {
// Toggle the UI root node's visibility
visibility.toggle_inherited_hidden();
}
}
}