Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
6c8ca56
Draft the structure for the calc impl
ickshonpe Nov 1, 2026
251a64e
calc module
ickshonpe Nov 1, 2026
a873e94
Calc as a tree
ickshonpe Nov 1, 2026
b58e0f1
Apply calc scaling to leaves and fix compile errors
ickshonpe Nov 1, 2026
aa12725
Renamed `CalOps` to `CalcOp`
ickshonpe Nov 1, 2026
b6ba44d
Added min, max and clamp heleprs to Val.
ickshonpe Nov 1, 2026
406a3ee
Changed Calc to use an Arc instead of a Box
ickshonpe Nov 1, 2026
cba4c35
Added some minimal doc comments, make Calc inner value pub (crate).
ickshonpe Nov 1, 2026
c45d571
Added `ValUnit` discriminator enum, to be used for representing Val u…
ickshonpe Nov 1, 2026
981dc19
Add inline Val::Sum, Val::Min and Val::Max variants
ickshonpe Nov 1, 2026
55d73a9
Add inline Val::Clamp variant
ickshonpe Nov 1, 2026
345a088
Added a check that val units count is <= 8.
ickshonpe Nov 1, 2026
021e1b5
Renamed `Val` methods in convert.
ickshonpe Nov 1, 2026
5d3136b
Use `bevy_platform::sync::Arc` instead of `std::sync::Arc`.
ickshonpe Nov 1, 2026
fe6ff82
Resolve calc expressions to physical pixels before layout
ickshonpe Nov 1, 2026
77c6329
Move LayoutContext into the style conversion module
ickshonpe Nov 1, 2026
ace3da0
Make negating a clamp negate its result
ickshonpe Nov 1, 2026
d573e85
Test that negating min and max negates their results
ickshonpe Nov 1, 2026
869f982
Serialize Calc as its CalcOp
ickshonpe Nov 1, 2026
faf842c
Added failing clamp tests
ickshonpe Nov 1, 2026
6b96f93
Negate directly built clamps with inverted bounds correctly
ickshonpe Nov 1, 2026
067eedb
Renamed LayoutCalc to PercentageCalc
ickshonpe Nov 2, 2026
1d4afb0
Updated doc comments for convert
ickshonpe Nov 2, 2026
084ca8a
Renamed `LayoutContext` to `ValContext`.
ickshonpe Nov 2, 2026
a2aaed6
Moved `ValContext` into the `calc` module and added doc comments.
ickshonpe Nov 2, 2026
41c25fb
Renamed `calc` module to `val`.
ickshonpe Nov 2, 2026
9cda3bd
Dereference calc pointers directly instead of mapping them
ickshonpe Nov 2, 2026
e5b3d43
Fix unbalanced backtick in to_physical doc comment
ickshonpe Nov 2, 2026
3b6a72e
Added a `resolve` method to `ValUnit`.
ickshonpe Nov 2, 2026
3b74bdc
Renamings for clarity: `Terms` to `Operands`, `TermOp` to `ReduceUp`.…
ickshonpe Nov 2, 2026
0a1054c
Added release note stub
ickshonpe Nov 2, 2026
b197e14
Internal renaming.
ickshonpe Nov 2, 2026
2d55755
Prove MeasureArgs cannot be built outside the crate
ickshonpe Nov 2, 2026
dc27709
Val resolve now has a ValContext parameter in place of the individual…
ickshonpe Nov 2, 2026
88b10b8
Changed CalcOp resolve to take ValContext
ickshonpe Nov 2, 2026
2b176ab
Updated BorderRadius, UiPosition, Val2, UiTransform and CornerRadius …
ickshonpe Nov 2, 2026
a684051
Update and clean up doc comments some more.
ickshonpe Nov 2, 2026
5060720
More doc comments
ickshonpe Nov 2, 2026
8cd29d2
More doc comments.
ickshonpe Nov 2, 2026
b4822dc
More doc comments
ickshonpe Nov 2, 2026
c88416f
More Val doc comments
ickshonpe Nov 2, 2026
89b22f3
More doc comments
ickshonpe Nov 2, 2026
86ce06e
ValUnitSet doc comments
ickshonpe Nov 2, 2026
b978b6a
Renamed `ValUnitSet::slot` to `index`, updated doc comments.
ickshonpe Nov 2, 2026
70ef450
Added doc test doing interpolation between two sums.
ickshonpe Nov 2, 2026
673091d
More doc comments for new `Val` methods.
ickshonpe Nov 2, 2026
19277ed
More doc comment edits.
ickshonpe Nov 2, 2026
6ee50c9
Added migration guide, added PR # to release note stub
ickshonpe Nov 3, 2026
3f20973
Added SAFETY comment
ickshonpe Nov 3, 2026
42453de
Fixed double backtick in doc comment
ickshonpe Nov 3, 2026
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
11 changes: 11 additions & 0 deletions _release-content/migration-guides/val_refactor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
title: "Val refactor"
pull_requests: [26409]
---

- `LayoutContext` has been renamed to `ValContext`.
- `Val::resolve`, `Val2::resolve`, `UiPosition::resolve`, `CornerRadius::resolve`,
`RadialGradientShape::resolve`, `BorderRadius::resolve`, and `UiTransform::compute_affine`
now take `&ValContext` instead of separate scale factor, target size, `EmSize`, and `RemSize`
arguments. The basis for percent values remains a separate argument.
- `Val` has been moved from the `bevy_ui` crate's `geometry` module to a new module `val`.
5 changes: 5 additions & 0 deletions _release-content/release-notes/val_calc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
title: "Val calc"
authors: ["@ickshonope"]
pull_requests: [26409]
---
4 changes: 2 additions & 2 deletions benches/benches/bevy_ui/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ fn layout(c: &mut Criterion) {
for &leaf in &leaves {
let mut node = app.world_mut().get_mut::<Node>(leaf).unwrap();
let length = if node.width == px(1) { px(2) } else { px(1) };
node.width = length;
node.width = length.clone();
node.height = length;
}
app.update();
Expand All @@ -254,7 +254,7 @@ fn layout(c: &mut Criterion) {
b.iter(|| {
let mut node = app.world_mut().get_mut::<Node>(leaf).unwrap();
let length = if node.width == px(1) { px(2) } else { px(1) };
node.width = length;
node.width = length.clone();
node.height = length;
app.update();
});
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_dev_tools/src/diagnostics_overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const BACKGROUND_COLOR_ALPHA: f32 = 0.75;
/// Row and column gap for the diagnostics overlay
const ROW_COLUMN_GAP: Val = Val::Px(4.);
/// Padding for cels of the diagnostics overlay
const DEFAULT_PADDING: UiRect = UiRect::all(Val::Px(4.));
const DEFAULT_PADDING: UiRect = UiRect::px(4., 4., 4., 4.);
/// Initial Z-index for the [`DiagnosticsOverlayPlane`]
pub const INITIAL_DIAGNOSTICS_OVERLAY_PLANE_Z_INDEX: GlobalZIndex = GlobalZIndex(1_000_000);
/// Alias to shorten the name
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_feathers/src/controls/color_plane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ fn update_plane_thumb_position(
};
let inner_size = inner_node.size() * inner_node.inverse_scale_factor;
if inner_size.x > 0.0 && inner_size.y > 0.0 {
let mut updated_transform = *thumb_transform;
let mut updated_transform = thumb_transform.clone();
// `ColorPlaneValue` is in channel space, where y increases upward, while
// the transform is in screen space (+y down), so the y component is inverted.
updated_transform.translation = Val2::new(
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_feathers/src/controls/color_slider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ fn update_slider_pos(
{
let track_width = track_node.size().x * track_node.inverse_scale_factor;
let thumb_offset = range.thumb_position(value.0) * track_width - THUMB_SIZE * 0.5;
let mut updated_transform = *thumb_transform;
let mut updated_transform = thumb_transform.clone();
updated_transform.translation.x = px(thumb_offset);
thumb_transform.set_if_neq(updated_transform);
}
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_feathers/src/controls/color_wheel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ fn position_thumb(q_transform: &mut Query<&mut UiTransform>, thumb_ent: Entity,
let Ok(mut thumb_transform) = q_transform.get_mut(thumb_ent) else {
return;
};
let mut updated_transform = *thumb_transform;
let mut updated_transform = thumb_transform.clone();
updated_transform.translation =
Val2::px(position.x - THUMB_SIZE * 0.5, position.y - THUMB_SIZE * 0.5);
thumb_transform.set_if_neq(updated_transform);
Expand Down
6 changes: 5 additions & 1 deletion crates/bevy_feathers/src/controls/scrollbar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ fn update_scrollbar_visibility(
if let Ok(child_of) = q_parents.get(scrollbar_ent)
&& let Ok((gutter, mut node)) = q_gutters.get_mut(child_of.parent())
{
let padding = if overflows { gutter.0 } else { Val::ZERO };
let padding = if overflows {
gutter.0.clone()
} else {
Val::ZERO
};
match scrollbar.orientation {
ControlOrientation::Vertical => {
if node.padding.right != padding {
Expand Down
18 changes: 10 additions & 8 deletions crates/bevy_feathers/src/controls/tabs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,12 +526,12 @@ fn arrange_tab_lists(
if let Ok(mut node) = start.get_mut(child)
&& node.margin != start_margin
{
node.margin = start_margin;
node.margin = start_margin.clone();
}
if let Ok(mut node) = end.get_mut(child)
&& node.margin != end_margin
{
node.margin = end_margin;
node.margin = end_margin.clone();
}
}
let rank = |child: &Entity| {
Expand Down Expand Up @@ -684,8 +684,8 @@ fn fillet_node(visible: bool, edge: PhysicalEdge) -> Node {
true => Display::Flex,
false => Display::None,
},
width: size,
height: size,
width: size.clone(),
height: size.clone(),
..Default::default()
};
match edge {
Expand Down Expand Up @@ -942,8 +942,8 @@ fn spawn_tab_drag_proxy(
align_items: AlignItems::Center,
padding: UiRect::horizontal(px(TAB_PADDING)),
column_gap: px(TAB_GAP),
border: tab_node.border,
border_radius: tab_node.border_radius,
border: tab_node.border.clone(),
border_radius: tab_node.border_radius.clone(),
..Default::default()
},
GlobalZIndex(DRAG_PROXY_Z),
Expand Down Expand Up @@ -1320,7 +1320,7 @@ mod tests {
assert_eq!(drag_proxy.pointer_id, PointerId::Touch(4));
let ghost = app.world().entity(proxy);
assert_eq!(
ghost.get::<Outline>().map(|outline| outline.width),
ghost.get::<Outline>().map(|outline| outline.width.clone()),
Some(px(1))
);
assert!(ghost.contains::<BoxShadow>());
Expand Down Expand Up @@ -1774,7 +1774,9 @@ mod tests {
let world = app.world();
let list = world.entity(list).get::<Node>().unwrap();
let tab = world.entity(tab).get::<Node>().unwrap();
let (Val::Px(tab_height), Val::Px(min_height)) = (tab.min_height, list.min_height) else {
let (Val::Px(tab_height), Val::Px(min_height)) =
(tab.min_height.clone(), list.min_height.clone())
else {
panic!("expected pixel heights");
};
let Val::Px(top) = list.padding.top else {
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_feathers/src/controls/tree_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ fn update_row_indent(
if let Ok(mut node) = headers.get_mut(child)
&& node.padding.left != left
{
node.padding.left = left;
node.padding.left = left.clone();
}
}
}
Expand Down
32 changes: 16 additions & 16 deletions crates/bevy_feathers/src/rounded_corners.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,49 +45,49 @@ impl RoundedCorners {
RoundedCorners::All => BorderRadius::all(radius),
RoundedCorners::TopLeft => BorderRadius {
top_left: radius,
top_right: zero,
bottom_right: zero,
top_right: zero.clone(),
bottom_right: zero.clone(),
bottom_left: zero,
},
RoundedCorners::TopRight => BorderRadius {
top_left: zero,
top_left: zero.clone(),
top_right: radius,
bottom_right: zero,
bottom_right: zero.clone(),
bottom_left: zero,
},
RoundedCorners::BottomRight => BorderRadius {
top_left: zero,
top_right: zero,
top_left: zero.clone(),
top_right: zero.clone(),
bottom_right: radius,
bottom_left: zero,
},
RoundedCorners::BottomLeft => BorderRadius {
top_left: zero,
top_right: zero,
top_left: zero.clone(),
top_right: zero.clone(),
bottom_right: zero,
bottom_left: radius,
},
RoundedCorners::Top => BorderRadius {
top_left: radius,
top_left: radius.clone(),
top_right: radius,
bottom_right: zero,
bottom_right: zero.clone(),
bottom_left: zero,
},
RoundedCorners::Right => BorderRadius {
top_left: zero,
top_right: radius,
top_left: zero.clone(),
top_right: radius.clone(),
bottom_right: radius,
bottom_left: zero,
},
RoundedCorners::Bottom => BorderRadius {
top_left: zero,
top_left: zero.clone(),
top_right: zero,
bottom_right: radius,
bottom_right: radius.clone(),
bottom_left: radius,
},
RoundedCorners::Left => BorderRadius {
top_left: radius,
top_right: zero,
top_left: radius.clone(),
top_right: zero.clone(),
bottom_right: zero,
bottom_left: radius,
},
Expand Down
14 changes: 7 additions & 7 deletions crates/bevy_inspector/src/column_split.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ fn border_box(entity: Entity, nodes: &Query<Geometry>, scale: f32) -> Option<[f3
let [left, right] = inner_box(parent?.parent(), nodes, scale, true)?;
let margin = &node.margin;
Some([
left + px_value(margin.left) * scale,
right - px_value(margin.right) * scale,
left + px_value(margin.left.clone()) * scale,
right - px_value(margin.right.clone()) * scale,
])
}

Expand All @@ -171,8 +171,8 @@ fn inner_box(
};
let [inset_left, inset_right] = match computed.is_added() {
true => [
side(node.border.left, node.padding.left),
side(node.border.right, node.padding.right),
side(node.border.left.clone(), node.padding.left.clone()),
side(node.border.right.clone(), node.padding.right.clone()),
],
false => [inset.min_inset.x, inset.max_inset.x],
};
Expand Down Expand Up @@ -237,7 +237,7 @@ fn update_column_splits(
if is_handle && node.left != value {
node.left = value;
} else if !is_handle && node.width != value {
node.width = value;
node.width = value.clone();
node.min_width = value;
}
}
Expand Down Expand Up @@ -509,7 +509,7 @@ mod tests {
assert_eq!(app.world().get::<Children>(split).unwrap().len(), 1);
let node = app.world().get::<Node>(handle).unwrap();
assert_eq!(node.position_type, PositionType::Absolute);
assert_eq!((node.top, node.bottom), (px(0), px(0)));
assert_eq!((node.top.clone(), node.bottom.clone()), (px(0), px(0)));
assert_eq!(
app.world().get::<EntityCursor>(handle),
Some(&EntityCursor::System(SystemCursorIcon::ColResize))
Expand Down Expand Up @@ -701,7 +701,7 @@ mod tests {
fn widths(app: &App, nodes: &[Entity]) -> Vec<Val> {
nodes
.iter()
.map(|&entity| app.world().get::<Node>(entity).unwrap().width)
.map(|&entity| app.world().get::<Node>(entity).unwrap().width.clone())
.collect()
}

Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_ui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ taffy = { version = "0.15", default-features = false, features = [
"flexbox",
"grid",
"content_size",
"calc",
] }
serde = { version = "1", features = ["derive"], optional = true }
uuid = { version = "1.21.0", features = ["v4"], optional = true }
Expand All @@ -56,6 +57,7 @@ tracing = { version = "0.1", default-features = false, features = ["std"] }

[dev-dependencies]
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.20.0-dev" }
ron = "0.12"

[features]
default = []
Expand Down
Loading
Loading