Skip to content
83 changes: 83 additions & 0 deletions crates/bevy_ui/src/ui_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,38 @@ impl ComputedNode {

clip_rect
}

/// Returns the node's border-box in object-centered physical coordinates.
/// This is the full rectangle enclosing the node.
#[inline]
pub fn border_box(&self) -> Rect {
Rect::from_center_size(Vec2::ZERO, self.size)
}

/// Returns the node's padding-box in object-centered physical coordinates.
/// This is the region inside the border containing the node's padding and content areas.
#[inline]
pub fn padding_box(&self) -> Rect {
let mut out = self.border_box();
out.min.x += self.border.left;
out.max.x -= self.border.right;
out.min.y += self.border.top;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a stupid comment because I am new, but is this supposed to be out.min.y += self.border.bottom (and the next line should be out.max.y -= self.border.top)? Same comment about this belongs in content_box too

From reading Rect, I had the impression visually that Rect.min is the lower left point defined as (min.x, min.y) and Rect.max is the upper right point e.g (max.x, max.y), and that the BorderRect left/right/top/bottom values are units “towards its center.” If that’s the case, should min.y should be affected by border.bottom instead?

Copy link
Contributor Author

@ickshonpe ickshonpe Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's confusing but, opposite to bevy_sprite, in bevy_ui the y-axis increases downwards. So Rect::min corresponds to the position of the top-left corner of the UI node and Rect::max corresponds to its bottom-right corner.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦 Thanks for clarifying for me, I must commit this to memory!

out.max.y -= self.border.bottom;
out
}

/// Returns the node's padding-box in object-centered physical coordinates.
/// This is the innermost region of the node, where its content is placed.
#[inline]
pub fn content_box(&self) -> Rect {
let mut out = self.border_box();
let content_inset = self.content_inset();
out.min.x += content_inset.left;
out.max.x -= content_inset.right;
out.min.y += content_inset.top;
out.max.y -= content_inset.bottom;
out
}
}

impl ComputedNode {
Expand Down Expand Up @@ -2916,7 +2948,10 @@ impl ComputedUiRenderTargetInfo {

#[cfg(test)]
mod tests {
use crate::ComputedNode;
use crate::GridPlacement;
use bevy_math::Vec2;
use bevy_sprite::BorderRect;

#[test]
fn invalid_grid_placement_values() {
Expand All @@ -2943,4 +2978,52 @@ mod tests {
assert_eq!(GridPlacement::start_span(3, 5).get_end(), None);
assert_eq!(GridPlacement::end_span(-4, 12).get_start(), None);
}

#[test]
fn border_box_is_centered_rect_of_node_size() {
let node = ComputedNode {
size: Vec2::new(100.0, 50.0),
..Default::default()
};
let border_box = node.border_box();

assert_eq!(border_box.min, Vec2::new(-50.0, -25.0));
assert_eq!(border_box.max, Vec2::new(50.0, 25.0));
}

#[test]
fn padding_box_subtracts_border_thickness() {
let node = ComputedNode {
size: Vec2::new(100.0, 60.0),
border: BorderRect {
left: 5.0,
right: 7.0,
top: 3.0,
bottom: 9.0,
},
..Default::default()
};
let padding_box = node.padding_box();

assert_eq!(padding_box.min, Vec2::new(-50.0 + 5.0, -30.0 + 3.0));
assert_eq!(padding_box.max, Vec2::new(50.0 - 7.0, 30.0 - 9.0));
}

#[test]
fn content_box_uses_content_inset() {
let node = ComputedNode {
size: Vec2::new(80.0, 40.0),
padding: BorderRect {
left: 4.0,
right: 6.0,
top: 2.0,
bottom: 8.0,
},
..Default::default()
};
let content_box = node.content_box();

assert_eq!(content_box.min, Vec2::new(-40.0 + 4.0, -20.0 + 2.0));
assert_eq!(content_box.max, Vec2::new(40.0 - 6.0, 20.0 - 8.0));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: "`ComputedNode` helper functions"
authors: ["@ickshonpe"]
pull_requests: [21903]
---

Helper functions `border_box`, `padding_box`, and `content_box` that return a node’s object-centered border, padding, and content boxes have been added to `ComputedNode`.