Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a gizmo-based overlay to show UI node outlines (Adopted) #11237

Merged
merged 71 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
d929a43
Add a gizmo-based overlay to show UI node outlines
nicopap Nov 6, 2023
2b94433
Document cargo feature
nicopap Nov 6, 2023
09900de
Merge branch 'main' into debug-ui-rects
Jan 5, 2024
7e6092c
[alt] Changed debug feature name
pablo-lua Jan 6, 2024
e9dd91b
[alt] Changed DebugUiPlugin to DefaultPlugins
pablo-lua Jan 6, 2024
c1b88de
[fix] Fixed new changes conflicts
pablo-lua Jan 6, 2024
981e519
[alt] Changed types make easier customize toggle_key
pablo-lua Jan 6, 2024
6766d90
[rem] Removed unnecessary import
pablo-lua Jan 6, 2024
59729e0
[style] Cargo fmt
pablo-lua Jan 6, 2024
7ea6b57
[fix] Clippy warnings
pablo-lua Jan 6, 2024
15ad9ec
[fix] Fixed missing semicolon
pablo-lua Jan 6, 2024
1dd32a5
[alt] Removed DebugUiPlugin from DefaultPlugins
pablo-lua Jan 6, 2024
d822a29
[alt] Removed keybinding and changed DebugOptions name
pablo-lua Jan 6, 2024
c35f8f2
[add] Added suport to Hidden visibility
pablo-lua Jan 9, 2024
19fd896
Merge branch 'main' into debug-ui-rects
pablo-lua Jan 9, 2024
fad14d7
[add] Added support to UiScale
pablo-lua Jan 9, 2024
c5bbbc6
[fix] Clippy warning
pablo-lua Jan 10, 2024
5f2f9f3
[doc] Added extra docs
pablo-lua Jan 12, 2024
0b8ef8f
Merge branch 'main' into debug-ui-rects
pablo-lua Jan 13, 2024
47022f2
[add] Added toggle_overlay system in ui example
pablo-lua Jan 13, 2024
cb57e6e
[add] Added text to warn the user about the feature
pablo-lua Jan 13, 2024
27332f7
[fix] Fixed comment position
pablo-lua Jan 13, 2024
bfee273
[add] Added info to enabled feature
pablo-lua Jan 13, 2024
4089834
[doc] Fixed docs
pablo-lua Jan 13, 2024
202fb95
[add] Added text when user doesn't enable bevy_ui_debug
pablo-lua Jan 15, 2024
15353a0
[style] Cargo fmt
pablo-lua Jan 15, 2024
81f2566
Merge branch 'debug-ui-rects' of github.com:pablo-lua/bevy into debug…
pablo-lua Jan 15, 2024
cf74585
Merge branch 'main' into debug-ui-rects
pablo-lua Jan 16, 2024
2dfbe86
Merge branch 'main' into debug-ui-rects
pablo-lua Jan 18, 2024
d51bcf2
Merge branch 'main' into debug-ui-rects
pablo-lua Jan 20, 2024
7aa6540
Merge branch 'main' into debug-ui-rects
pablo-lua Jan 22, 2024
ff0d3da
Merge branch 'main' into debug-ui-rects
pablo-lua Feb 3, 2024
4e3b422
[fix] Fixed wrong behavior caused by update in ui
pablo-lua Feb 3, 2024
95cfd6e
[alt] Improved warn message to warn only once
pablo-lua Feb 3, 2024
affc06c
[add] Added marker component to Ui example camera
pablo-lua Feb 3, 2024
61d90d5
[style] Cargo fmt
pablo-lua Feb 3, 2024
8455720
[style] Improved Code quality
pablo-lua Feb 3, 2024
60ed352
[docs] Fix docs
pablo-lua Feb 3, 2024
29f8022
Merge branch 'main' into debug-ui-rects
pablo-lua Feb 3, 2024
ec3cd72
Merge branch 'main' into debug-ui-rects
alice-i-cecile Feb 4, 2024
9c52af9
[fix] Little fix on comment
pablo-lua Feb 5, 2024
12f4e64
[doc] Changed docs note
pablo-lua Feb 5, 2024
d20a5d8
[alt] Improvements on options settings
pablo-lua Feb 5, 2024
494c4dd
[doc] Fixed docs mention to extern crate
pablo-lua Feb 5, 2024
cedc4ab
Merge branch 'main' into debug-ui-rects
pablo-lua Feb 23, 2024
4fd89f2
[cargo] Fix version requirement
pablo-lua Feb 23, 2024
3c52c7b
Merge branch 'main' into debug-ui-rects
pablo-lua Mar 1, 2024
61a0eee
Merge branch 'main' into debug-ui-rects
pablo-lua Mar 1, 2024
56509e6
[style] Cargo fmt
pablo-lua Mar 1, 2024
a50f02a
Update docs.yml
pablo-lua Mar 5, 2024
dd1d3bb
Merge branch 'main' into debug-ui-rects
pablo-lua Mar 6, 2024
785538a
Merge branch 'main' of https://github.com/bevyengine/bevy
pablo-lua Mar 6, 2024
6c1a1ec
Merge branch 'bevyengine:main' into debug-ui-rects
pablo-lua Mar 6, 2024
2f22e53
Merge branch 'main' of github.com:pablo-lua/bevy
pablo-lua Mar 7, 2024
d6a674b
Merge branch 'main' of github.com:pablo-lua/bevy
pablo-lua Mar 7, 2024
d2060e8
Merge branch 'main' into debug-ui-rects
pablo-lua Mar 7, 2024
e3e0061
Merge branch 'main' of github.com:pablo-lua/bevy
pablo-lua Mar 7, 2024
36d4f1f
Merge branch 'main' into debug-ui-rects
pablo-lua Mar 7, 2024
7419481
[alt] Move debug_overlay to bevy_dev_tools crate
pablo-lua Mar 9, 2024
3f978ad
[alt] Revert local change added by mistake
pablo-lua Mar 9, 2024
51ef533
[alt] Revert changes on ui toml
pablo-lua Mar 9, 2024
bd26750
[alt] Revert changes on ui toml
pablo-lua Mar 9, 2024
f78f747
Merge branch 'debug-ui-rects' of github.com:pablo-lua/bevy into debug…
pablo-lua Mar 9, 2024
6477000
[style] Cargo fmt
pablo-lua Mar 9, 2024
44c728c
Merge branch 'main' into debug-ui-rects
pablo-lua Mar 9, 2024
0d74b08
Merge branch 'main' into debug-ui-rects
pablo-lua Mar 9, 2024
d1787a5
[rem] Removed bevy_ui_debug from top level features
pablo-lua Mar 10, 2024
434cd2e
[rem] Removed trait ApproxF32
pablo-lua Mar 10, 2024
5fc4458
[alt] Fixed CI
pablo-lua Mar 10, 2024
13985d6
Merge branch 'main' into debug-ui-rects
pablo-lua Mar 18, 2024
2cfffd8
[fix] Duplicate entry on dev_tools TOML
Mar 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ bevy_ui = [
"bevy_sprite",
]

# Enable the bevy_ui debug overlay
bevy_ui_debug = ["bevy_internal/bevy_ui_debug"]
pablo-lua marked this conversation as resolved.
Show resolved Hide resolved

# winit window and input backend
bevy_winit = ["bevy_internal/bevy_winit"]

Expand Down
3 changes: 3 additions & 0 deletions crates/bevy_internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ file_watcher = ["bevy_asset?/file_watcher"]
# Enables watching embedded files for Bevy Asset hot-reloading
embedded_watcher = ["bevy_asset?/embedded_watcher"]

# Enable the bevy_ui debug overlay
bevy_ui_debug = ["bevy_ui?/debug_layout"]

[dependencies]
# bevy
bevy_a11y = { path = "../bevy_a11y", version = "0.12.0" }
Expand Down
12 changes: 8 additions & 4 deletions crates/bevy_ui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,21 @@ repository = "https://github.com/bevyengine/bevy"
license = "MIT OR Apache-2.0"
keywords = ["bevy"]

[features]
default = []
debug_layout = ["bevy_gizmos", "bevy_core"]
serialize = ["serde"]

[dependencies]
# bevy
bevy_a11y = { path = "../bevy_a11y", version = "0.12.0" }
bevy_app = { path = "../bevy_app", version = "0.12.0" }
bevy_asset = { path = "../bevy_asset", version = "0.12.0" }
bevy_core = { path = "../bevy_core", version = "0.12.0", optional = true }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.12.0" }
bevy_derive = { path = "../bevy_derive", version = "0.12.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.12.0" }
bevy_gizmos = { path = "../bevy_gizmos", version = "0.12.0", optional = true }
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.12.0" }
bevy_input = { path = "../bevy_input", version = "0.12.0" }
bevy_log = { path = "../bevy_log", version = "0.12.0" }
Expand All @@ -27,17 +34,14 @@ bevy_render = { path = "../bevy_render", version = "0.12.0" }
bevy_sprite = { path = "../bevy_sprite", version = "0.12.0" }
bevy_text = { path = "../bevy_text", version = "0.12.0", optional = true }
bevy_transform = { path = "../bevy_transform", version = "0.12.0" }
bevy_window = { path = "../bevy_window", version = "0.12.0" }
bevy_utils = { path = "../bevy_utils", version = "0.12.0" }
bevy_window = { path = "../bevy_window", version = "0.12.0" }

# other
taffy = { version = "0.3.10" }
serde = { version = "1", features = ["derive"], optional = true }
bytemuck = { version = "1.5", features = ["derive"] }
thiserror = "1.0.0"

[features]
serialize = ["serde"]

[lints]
workspace = true
189 changes: 189 additions & 0 deletions crates/bevy_ui/src/debug_overlay/inset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
use bevy_gizmos::prelude::Gizmos;
use bevy_math::{Vec2, Vec2Swizzles};
use bevy_render::prelude::Color;
use bevy_transform::prelude::GlobalTransform;
use bevy_utils::HashMap;

use super::{CameraQuery, LayoutRect};

trait ApproxF32 {
fn is(self, other: f32) -> bool;
}
impl ApproxF32 for f32 {
fn is(self, other: f32) -> bool {
let diff = (self - other).abs();
diff < 0.001
}
}

fn rect_border_axis(rect: LayoutRect) -> (f32, f32, f32, f32) {
let pos = rect.pos;
let size = rect.size;
let offset = pos + size;
(pos.x, offset.x, pos.y, offset.y)
}

#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
enum Dir {
Start,
End,
}
impl Dir {
const fn increments(self) -> i64 {
match self {
Dir::Start => 1,
Dir::End => -1,
}
}
}
impl From<i64> for Dir {
fn from(value: i64) -> Self {
if value.is_positive() {
Dir::Start
} else {
Dir::End
}
}
}
/// Collection of axis aligned "lines" (actually just their coordinate on
/// a given axis).
#[derive(Debug, Clone)]
struct DrawnLines {
lines: HashMap<i64, Dir>,
width: f32,
}
#[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)]
impl DrawnLines {
fn new(width: f32) -> Self {
DrawnLines {
lines: HashMap::new(),
width,
}
}
/// Return `value` offset by as many `increment`s as necessary to make it
/// not overlap with already drawn lines.
fn inset(&self, value: f32) -> f32 {
let scaled = value / self.width;
let fract = scaled.fract();
let mut on_grid = scaled.floor() as i64;
for _ in 0..10 {
let Some(dir) = self.lines.get(&on_grid) else {
break;
};
// TODO(clean): This fixes a panic, but I'm not sure how valid this is
let Some(added) = on_grid.checked_add(dir.increments()) else {
break;
};
on_grid = added;
}
((on_grid as f32) + fract) * self.width
}
/// Remove a line from the collection of drawn lines.
///
/// Typically, we only care for pre-existing lines when drawing the children
/// of a container, nothing more. So we remove it after we are done with
/// the children.
fn remove(&mut self, value: f32, increment: i64) {
let mut on_grid = (value / self.width).floor() as i64;
loop {
// TODO(clean): This fixes a panic, but I'm not sure how valid this is
let Some(next_cell) = on_grid.checked_add(increment) else {
return;
};
if !self.lines.contains_key(&next_cell) {
self.lines.remove(&on_grid);
return;
}
on_grid = next_cell;
}
}
/// Add a line from the collection of drawn lines.
fn add(&mut self, value: f32, increment: i64) {
let mut on_grid = (value / self.width).floor() as i64;
loop {
let old_value = self.lines.insert(on_grid, increment.into());
if old_value.is_none() {
return;
}
// TODO(clean): This fixes a panic, but I'm not sure how valid this is
let Some(added) = on_grid.checked_add(increment) else {
return;
};
on_grid = added;
}
}
}

pub(super) struct InsetGizmo<'w, 's> {
draw: Gizmos<'s>,
cam: CameraQuery<'w, 's>,
known_y: DrawnLines,
known_x: DrawnLines,
}
impl<'w, 's> InsetGizmo<'w, 's> {
pub(super) fn new(draw: Gizmos<'s>, cam: CameraQuery<'w, 's>, line_width: f32) -> Self {
InsetGizmo {
draw,
cam,
known_y: DrawnLines::new(line_width),
known_x: DrawnLines::new(line_width),
}
}
fn relative(&self, mut position: Vec2) -> Vec2 {
let zero = GlobalTransform::IDENTITY;
let Ok(cam) = self.cam.get_single() else {
return Vec2::ZERO;
};
if let Some(new_position) = cam.world_to_viewport(&zero, position.extend(0.)) {
position = new_position;
};
position.xy()
}
fn line_2d(&mut self, mut start: Vec2, mut end: Vec2, color: Color) {
if start.x.is(end.x) {
start.x = self.known_x.inset(start.x);
end.x = start.x;
} else if start.y.is(end.y) {
start.y = self.known_y.inset(start.y);
end.y = start.y;
}
let (start, end) = (self.relative(start), self.relative(end));
self.draw.line_2d(start, end, color);
}
pub(super) fn set_scope(&mut self, rect: LayoutRect) {
let (left, right, top, bottom) = rect_border_axis(rect);
self.known_x.add(left, 1);
self.known_x.add(right, -1);
self.known_y.add(top, 1);
self.known_y.add(bottom, -1);
}
pub(super) fn clear_scope(&mut self, rect: LayoutRect) {
let (left, right, top, bottom) = rect_border_axis(rect);
self.known_x.remove(left, 1);
self.known_x.remove(right, -1);
self.known_y.remove(top, 1);
self.known_y.remove(bottom, -1);
}
pub(super) fn rect_2d(&mut self, rect: LayoutRect, color: Color) {
let (left, right, top, bottom) = rect_border_axis(rect);
if left.is(right) {
self.line_2d(Vec2::new(left, top), Vec2::new(left, bottom), color);
} else if top.is(bottom) {
self.line_2d(Vec2::new(left, top), Vec2::new(right, top), color);
} else {
let inset_x = |v| self.known_x.inset(v);
let inset_y = |v| self.known_y.inset(v);
let (left, right) = (inset_x(left), inset_x(right));
let (top, bottom) = (inset_y(top), inset_y(bottom));
let strip = [
Vec2::new(left, top),
Vec2::new(left, bottom),
Vec2::new(right, bottom),
Vec2::new(right, top),
Vec2::new(left, top),
];
self.draw
.linestrip_2d(strip.map(|v| self.relative(v)), color);
}
}
}
Loading