Skip to content

Commit d44b9f8

Browse files
authored
Adds UIDebug Overlay centered scene to examples/testbed/ui (#22052)
# Objective - Fixes #22019 ## Solution - Adds a new scene in the ui testbed that tests the generation of the Ui Debug Overlay. It only is viewable if you run the example with `--features bevy_ui_debug`. - Added a way to override the color used by the overlay to ensure that screenshots are consistent between CI runs (the line colors are generated based on the `Entity`, which changes every time you change the scene.) - Added the `--features bevy_ui_debug` flag to `example-run.yml`, ensuring that screenshots and their validations take this new scene into account. (I assumed I’m not supposed to add this to `validation-jobs.yml` under `run-examples-on-wasm`, but if I’m supposed to, let me know and I can add it. I figured a debug feature does not need that specific validation). ## Testing - I ran the command `cargo run --example testbed_ui --features bevy_ui_debug` and verified that debug lines showed up for regular outlines, for a node with `Visibility::Hidden` with `show_hidden = true`, and that clipped areas have outlines with `show_clipped = true`. I carouseled through all the scenes a couple of times - I also ran `cargo run --example testbed_ui ` and made sure nothing was ruined after multiple carousels through all the scenes. --- ## Showcase `cargo run --example testbed_ui --features bevy_ui_debug` , press spacebar 11x to see the scene. <img width="1282" height="750" alt="Screenshot 2025-12-06 at 10 03 25 PM" src="https://github.com/user-attachments/assets/f76ef3ac-b762-4eef-9843-573f362fe45a" />
1 parent 0af6fc1 commit d44b9f8

File tree

3 files changed

+107
-4
lines changed

3 files changed

+107
-4
lines changed

.github/workflows/example-run.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
example_name=`basename $example .ron`
4949
echo -n $example_name > last_example_run
5050
echo "running $example_name - "`date`
51-
time TRACE_CHROME=trace-$example_name.json CI_TESTING_CONFIG=$example cargo run --example $example_name --features "bevy_ci_testing,trace,trace_chrome"
51+
time TRACE_CHROME=trace-$example_name.json CI_TESTING_CONFIG=$example cargo run --example $example_name --features "bevy_ci_testing,trace,trace_chrome,bevy_ui_debug"
5252
sleep 10
5353
if [ `find ./ -maxdepth 1 -name 'screenshot-*.png' -print -quit` ]; then
5454
mkdir screenshots-$example_name
@@ -123,7 +123,7 @@ jobs:
123123
example_name=`basename $example .ron`
124124
echo -n $example_name > last_example_run
125125
echo "running $example_name - "`date`
126-
time TRACE_CHROME=trace-$example_name.json CI_TESTING_CONFIG=$example xvfb-run cargo run --example $example_name --features "bevy_ci_testing,trace,trace_chrome"
126+
time TRACE_CHROME=trace-$example_name.json CI_TESTING_CONFIG=$example xvfb-run cargo run --example $example_name --features "bevy_ci_testing,trace,trace_chrome,bevy_ui_debug"
127127
sleep 10
128128
if [ `find ./ -maxdepth 1 -name 'screenshot-*.png' -print -quit` ]; then
129129
mkdir screenshots-$example_name
@@ -187,7 +187,7 @@ jobs:
187187
example_name=`basename $example .ron`
188188
echo -n $example_name > last_example_run
189189
echo "running $example_name - "`date`
190-
time WGPU_BACKEND=dx12 TRACE_CHROME=trace-$example_name.json CI_TESTING_CONFIG=$example cargo run --example $example_name --features "statically-linked-dxc,bevy_ci_testing,trace,trace_chrome"
190+
time WGPU_BACKEND=dx12 TRACE_CHROME=trace-$example_name.json CI_TESTING_CONFIG=$example cargo run --example $example_name --features "statically-linked-dxc,bevy_ci_testing,trace,trace_chrome,bevy_ui_debug"
191191
sleep 10
192192
if [ `find ./ -maxdepth 1 -name 'screenshot-*.png' -print -quit` ]; then
193193
mkdir screenshots-$example_name

crates/bevy_ui_render/src/debug_overlay.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::shader_flags;
77
use bevy_asset::AssetId;
88
use bevy_camera::visibility::InheritedVisibility;
99
use bevy_color::Hsla;
10+
use bevy_color::LinearRgba;
1011
use bevy_ecs::entity::Entity;
1112
use bevy_ecs::prelude::ReflectResource;
1213
use bevy_ecs::resource::Resource;
@@ -34,6 +35,8 @@ pub struct UiDebugOptions {
3435
pub enabled: bool,
3536
/// Width of the overlay's lines in logical pixels
3637
pub line_width: f32,
38+
/// Override Color for the overlay's lines
39+
pub line_color_override: Option<LinearRgba>,
3740
/// Show outlines for non-visible UI nodes
3841
pub show_hidden: bool,
3942
/// Show outlines for clipped sections of UI nodes
@@ -51,6 +54,7 @@ impl Default for UiDebugOptions {
5154
Self {
5255
enabled: false,
5356
line_width: 1.,
57+
line_color_override: None,
5458
show_hidden: false,
5559
show_clipped: false,
5660
}
@@ -101,7 +105,9 @@ pub fn extract_debug_overlay(
101105
extracted_camera_entity,
102106
transform: transform.into(),
103107
item: ExtractedUiItem::Node {
104-
color: Hsla::sequential_dispersed(entity.index_u32()).into(),
108+
color: debug_options
109+
.line_color_override
110+
.unwrap_or_else(|| Hsla::sequential_dispersed(entity.index_u32()).into()),
105111
rect: Rect {
106112
min: Vec2::ZERO,
107113
max: uinode.size,

examples/testbed/ui.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ fn main() {
2525
.add_systems(OnEnter(Scene::Transformations), transformations::setup)
2626
.add_systems(Update, switch_scene);
2727

28+
#[cfg(feature = "bevy_ui_debug")]
29+
{
30+
app.add_systems(OnEnter(Scene::DebugOutlines), debug_outlines::setup);
31+
app.add_systems(OnExit(Scene::DebugOutlines), debug_outlines::teardown);
32+
}
33+
2834
#[cfg(feature = "bevy_ci_testing")]
2935
app.add_systems(Update, helpers::switch_scene_in_ci::<Scene>);
3036

@@ -47,6 +53,8 @@ enum Scene {
4753
LinearGradient,
4854
RadialGradient,
4955
Transformations,
56+
#[cfg(feature = "bevy_ui_debug")]
57+
DebugOutlines,
5058
}
5159

5260
impl Next for Scene {
@@ -62,6 +70,11 @@ impl Next for Scene {
6270
Scene::Slice => Scene::LayoutRounding,
6371
Scene::LayoutRounding => Scene::LinearGradient,
6472
Scene::LinearGradient => Scene::RadialGradient,
73+
#[cfg(feature = "bevy_ui_debug")]
74+
Scene::RadialGradient => Scene::DebugOutlines,
75+
#[cfg(feature = "bevy_ui_debug")]
76+
Scene::DebugOutlines => Scene::Transformations,
77+
#[cfg(not(feature = "bevy_ui_debug"))]
6578
Scene::RadialGradient => Scene::Transformations,
6679
Scene::Transformations => Scene::Image,
6780
}
@@ -969,3 +982,87 @@ mod transformations {
969982
});
970983
}
971984
}
985+
986+
#[cfg(feature = "bevy_ui_debug")]
987+
mod debug_outlines {
988+
use bevy::{
989+
color::palettes::css::{BLUE, GRAY, RED},
990+
prelude::*,
991+
ui_render::UiDebugOptions,
992+
};
993+
994+
pub fn setup(mut commands: Commands, mut debug_options: ResMut<UiDebugOptions>) {
995+
debug_options.enabled = true;
996+
debug_options.line_width = 5.;
997+
debug_options.line_color_override = Some(LinearRgba::GREEN);
998+
debug_options.show_hidden = true;
999+
debug_options.show_clipped = true;
1000+
commands.spawn((Camera2d, DespawnOnExit(super::Scene::DebugOutlines)));
1001+
commands
1002+
.spawn((
1003+
Node {
1004+
width: percent(100),
1005+
height: percent(100),
1006+
align_items: AlignItems::Center,
1007+
justify_content: JustifyContent::SpaceAround,
1008+
..default()
1009+
},
1010+
DespawnOnExit(super::Scene::DebugOutlines),
1011+
))
1012+
.with_children(|parent| {
1013+
parent.spawn((
1014+
Node {
1015+
width: px(100),
1016+
height: px(100),
1017+
..default()
1018+
},
1019+
BackgroundColor(GRAY.into()),
1020+
UiTransform::from_rotation(Rot2::degrees(45.)),
1021+
));
1022+
1023+
parent.spawn((Text::new("Regular Text"), TextFont::default()));
1024+
1025+
parent.spawn((
1026+
Node {
1027+
width: px(100),
1028+
height: px(100),
1029+
..default()
1030+
},
1031+
Text::new("Invisible"),
1032+
BackgroundColor(GRAY.into()),
1033+
TextFont::default(),
1034+
Visibility::Hidden,
1035+
));
1036+
1037+
parent
1038+
.spawn((
1039+
Node {
1040+
width: px(100),
1041+
height: px(100),
1042+
padding: UiRect {
1043+
left: px(25),
1044+
top: px(25),
1045+
..Default::default()
1046+
},
1047+
overflow: Overflow::clip(),
1048+
..default()
1049+
},
1050+
BackgroundColor(RED.into()),
1051+
))
1052+
.with_children(|child| {
1053+
child.spawn((
1054+
Node {
1055+
min_width: px(100),
1056+
min_height: px(100),
1057+
..default()
1058+
},
1059+
BackgroundColor(BLUE.into()),
1060+
));
1061+
});
1062+
});
1063+
}
1064+
1065+
pub fn teardown(mut debug_options: ResMut<UiDebugOptions>) {
1066+
*debug_options = UiDebugOptions::default();
1067+
}
1068+
}

0 commit comments

Comments
 (0)