Skip to content

Commit 015f2c6

Browse files
authored
Merge Style properties into Node. Use ComputedNode for computed properties. (#15975)
# Objective Continue improving the user experience of our UI Node API in the direction specified by [Bevy's Next Generation Scene / UI System](#14437) ## Solution As specified in the document above, merge `Style` fields into `Node`, and move "computed Node fields" into `ComputedNode` (I chose this name over something like `ComputedNodeLayout` because it currently contains more than just layout info. If we want to break this up / rename these concepts, lets do that in a separate PR). `Style` has been removed. This accomplishes a number of goals: ## Ergonomics wins Specifying both `Node` and `Style` is now no longer required for non-default styles Before: ```rust commands.spawn(( Node::default(), Style { width: Val::Px(100.), ..default() }, )); ``` After: ```rust commands.spawn(Node { width: Val::Px(100.), ..default() }); ``` ## Conceptual clarity `Style` was never a comprehensive "style sheet". It only defined "core" style properties that all `Nodes` shared. Any "styled property" that couldn't fit that mold had to be in a separate component. A "real" style system would style properties _across_ components (`Node`, `Button`, etc). We have plans to build a true style system (see the doc linked above). By moving the `Style` fields to `Node`, we fully embrace `Node` as the driving concept and remove the "style system" confusion. ## Next Steps * Consider identifying and splitting out "style properties that aren't core to Node". This should not happen for Bevy 0.15. --- ## Migration Guide Move any fields set on `Style` into `Node` and replace all `Style` component usage with `Node`. Before: ```rust commands.spawn(( Node::default(), Style { width: Val::Px(100.), ..default() }, )); ``` After: ```rust commands.spawn(Node { width: Val::Px(100.), ..default() }); ``` For any usage of the "computed node properties" that used to live on `Node`, use `ComputedNode` instead: Before: ```rust fn system(nodes: Query<&Node>) { for node in &nodes { let computed_size = node.size(); } } ``` After: ```rust fn system(computed_nodes: Query<&ComputedNode>) { for computed_node in &computed_nodes { let computed_size = computed_node.size(); } } ```
1 parent 624f573 commit 015f2c6

File tree

149 files changed

+1257
-1615
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

149 files changed

+1257
-1615
lines changed

crates/bevy_dev_tools/src/fps_overlay.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ use bevy_ecs::{
1515
use bevy_hierarchy::{BuildChildren, ChildBuild};
1616
use bevy_render::view::Visibility;
1717
use bevy_text::{Font, TextColor, TextFont, TextSpan};
18-
use bevy_ui::Node;
1918
use bevy_ui::{
2019
widget::{Text, TextUiWriter},
21-
GlobalZIndex, PositionType, Style,
20+
GlobalZIndex, Node, PositionType,
2221
};
2322
use bevy_utils::default;
2423

@@ -89,8 +88,7 @@ struct FpsText;
8988
fn setup(mut commands: Commands, overlay_config: Res<FpsOverlayConfig>) {
9089
commands
9190
.spawn((
92-
Node::default(),
93-
Style {
91+
Node {
9492
// We need to make sure the overlay doesn't affect the position of other UI nodes
9593
position_type: PositionType::Absolute,
9694
..default()

crates/bevy_dev_tools/src/ui_debug_overlay/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use bevy_render::{
1515
view::{RenderLayers, VisibilitySystems},
1616
};
1717
use bevy_transform::{prelude::GlobalTransform, TransformSystem};
18-
use bevy_ui::{DefaultUiCamera, Display, Node, Style, TargetCamera, UiScale};
18+
use bevy_ui::{ComputedNode, DefaultUiCamera, Display, Node, TargetCamera, UiScale};
1919
use bevy_utils::{default, warn_once};
2020
use bevy_window::{PrimaryWindow, Window, WindowRef};
2121

@@ -37,7 +37,7 @@ struct LayoutRect {
3737
}
3838

3939
impl LayoutRect {
40-
fn new(trans: &GlobalTransform, node: &Node, scale: f32) -> Self {
40+
fn new(trans: &GlobalTransform, node: &ComputedNode, scale: f32) -> Self {
4141
let mut this = Self {
4242
pos: trans.translation().xy() * scale,
4343
size: node.size() * scale,
@@ -123,8 +123,8 @@ fn outline_nodes(outline: &OutlineParam, draw: &mut InsetGizmo, this_entity: Ent
123123
return;
124124
};
125125

126-
for (entity, trans, node, style, children) in outline.nodes.iter_many(to_iter) {
127-
if style.is_none() || style.is_some_and(|s| matches!(s.display, Display::None)) {
126+
for (entity, trans, node, computed_node, children) in outline.nodes.iter_many(to_iter) {
127+
if matches!(node.display, Display::None) {
128128
continue;
129129
}
130130

@@ -133,7 +133,7 @@ fn outline_nodes(outline: &OutlineParam, draw: &mut InsetGizmo, this_entity: Ent
133133
continue;
134134
}
135135
}
136-
let rect = LayoutRect::new(trans, node, scale);
136+
let rect = LayoutRect::new(trans, computed_node, scale);
137137
outline_node(entity, rect, draw);
138138
if children.is_some() {
139139
outline_nodes(outline, draw, entity, scale);
@@ -146,7 +146,7 @@ type NodesQuery = (
146146
Entity,
147147
&'static GlobalTransform,
148148
&'static Node,
149-
Option<&'static Style>,
149+
&'static ComputedNode,
150150
Option<&'static Children>,
151151
);
152152

@@ -178,7 +178,7 @@ fn outline_roots(
178178
(
179179
Entity,
180180
&GlobalTransform,
181-
&Node,
181+
&ComputedNode,
182182
Option<&ViewVisibility>,
183183
Option<&TargetCamera>,
184184
),

crates/bevy_ecs/src/query/filter.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,9 +352,9 @@ unsafe impl<T: Component> QueryFilter for Without<T> {
352352
/// # #[derive(Component, Debug)]
353353
/// # struct Color {};
354354
/// # #[derive(Component)]
355-
/// # struct Style {};
355+
/// # struct Node {};
356356
/// #
357-
/// fn print_cool_entity_system(query: Query<Entity, Or<(Changed<Color>, Changed<Style>)>>) {
357+
/// fn print_cool_entity_system(query: Query<Entity, Or<(Changed<Color>, Changed<Node>)>>) {
358358
/// for entity in &query {
359359
/// println!("Entity {:?} got a new style or color", entity);
360360
/// }

crates/bevy_text/src/text_access.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,11 @@ impl<'a, R: TextRoot> Iterator for TextSpanIter<'a, R> {
171171
fn next(&mut self) -> Option<Self::Item> {
172172
// Root
173173
if let Some(root_entity) = self.root_entity.take() {
174-
if let Ok((text, style, color, maybe_children)) = self.roots.get(root_entity) {
174+
if let Ok((text, text_font, color, maybe_children)) = self.roots.get(root_entity) {
175175
if let Some(children) = maybe_children {
176176
self.stack.push((children, 0));
177177
}
178-
return Some((root_entity, 0, text.read_span(), style, color.0));
178+
return Some((root_entity, 0, text.read_span(), text_font, color.0));
179179
}
180180
return None;
181181
}
@@ -193,15 +193,15 @@ impl<'a, R: TextRoot> Iterator for TextSpanIter<'a, R> {
193193
*idx += 1;
194194

195195
let entity = *child;
196-
let Ok((span, style, color, maybe_children)) = self.spans.get(entity) else {
196+
let Ok((span, text_font, color, maybe_children)) = self.spans.get(entity) else {
197197
continue;
198198
};
199199

200200
let depth = self.stack.len();
201201
if let Some(children) = maybe_children {
202202
self.stack.push((children, 0));
203203
}
204-
return Some((entity, depth, span.read_span(), style, color.0));
204+
return Some((entity, depth, span.read_span(), text_font, color.0));
205205
}
206206

207207
// All children at this stack entry have been iterated.

crates/bevy_ui/src/accessibility.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::{
22
experimental::UiChildren,
33
prelude::{Button, Label},
44
widget::TextUiReader,
5-
Node, UiImage,
5+
ComputedNode, UiImage,
66
};
77
use bevy_a11y::{
88
accesskit::{NodeBuilder, Rect, Role},
@@ -38,7 +38,11 @@ fn calc_name(
3838

3939
fn calc_bounds(
4040
camera: Query<(&Camera, &GlobalTransform)>,
41-
mut nodes: Query<(&mut AccessibilityNode, Ref<Node>, Ref<GlobalTransform>)>,
41+
mut nodes: Query<(
42+
&mut AccessibilityNode,
43+
Ref<ComputedNode>,
44+
Ref<GlobalTransform>,
45+
)>,
4246
) {
4347
if let Ok((camera, camera_transform)) = camera.get_single() {
4448
for (mut accessible, node, transform) in &mut nodes {

crates/bevy_ui/src/focus.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::{
2-
CalculatedClip, DefaultUiCamera, Node, ResolvedBorderRadius, TargetCamera, UiScale, UiStack,
2+
CalculatedClip, ComputedNode, DefaultUiCamera, ResolvedBorderRadius, TargetCamera, UiScale,
3+
UiStack,
34
};
45
use bevy_ecs::{
56
change_detection::DetectChangesMut,
@@ -74,7 +75,7 @@ impl Default for Interaction {
7475
///
7576
/// It can be used alongside [`Interaction`] to get the position of the press.
7677
///
77-
/// The component is updated when it is in the same entity with [`Node`].
78+
/// The component is updated when it is in the same entity with [`Node`](crate::Node).
7879
#[derive(Component, Copy, Clone, Default, PartialEq, Debug, Reflect)]
7980
#[reflect(Component, Default, PartialEq, Debug)]
8081
#[cfg_attr(
@@ -135,7 +136,7 @@ pub struct State {
135136
#[query_data(mutable)]
136137
pub struct NodeQuery {
137138
entity: Entity,
138-
node: &'static Node,
139+
node: &'static ComputedNode,
139140
global_transform: &'static GlobalTransform,
140141
interaction: Option<&'static mut Interaction>,
141142
relative_cursor_position: Option<&'static mut RelativeCursorPosition>,

crates/bevy_ui/src/geometry.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
88

99
/// Represents the possible value types for layout properties.
1010
///
11-
/// This enum allows specifying values for various [`Style`](crate::Style) properties in different units,
11+
/// This enum allows specifying values for various [`Node`](crate::Node) properties in different units,
1212
/// such as logical pixels, percentages, or automatically determined values.
1313
#[derive(Copy, Clone, Debug, Reflect)]
1414
#[reflect(Default, PartialEq, Debug)]
@@ -18,7 +18,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
1818
reflect(Serialize, Deserialize)
1919
)]
2020
pub enum Val {
21-
/// Automatically determine the value based on the context and other [`Style`](crate::Style) properties.
21+
/// Automatically determine the value based on the context and other [`Node`](crate::Node) properties.
2222
Auto,
2323
/// Set this value in logical pixels.
2424
Px(f32),
@@ -27,7 +27,7 @@ pub enum Val {
2727
/// If the UI node has no parent, the percentage is calculated based on the window's length
2828
/// along the corresponding axis.
2929
///
30-
/// The chosen axis depends on the [`Style`](crate::Style) field set:
30+
/// The chosen axis depends on the [`Node`](crate::Node) field set:
3131
/// * For `flex_basis`, the percentage is relative to the main-axis length determined by the `flex_direction`.
3232
/// * For `gap`, `min_size`, `size`, and `max_size`:
3333
/// - `width` is relative to the parent's width.

crates/bevy_ui/src/layout/convert.rs

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use taffy::style_helpers;
33
use crate::{
44
AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, GridAutoFlow,
55
GridPlacement, GridTrack, GridTrackRepetition, JustifyContent, JustifyItems, JustifySelf,
6-
MaxTrackSizingFunction, MinTrackSizingFunction, OverflowAxis, PositionType, RepeatedGridTrack,
7-
Style, UiRect, Val,
6+
MaxTrackSizingFunction, MinTrackSizingFunction, Node, OverflowAxis, PositionType,
7+
RepeatedGridTrack, UiRect, Val,
88
};
99

1010
use super::LayoutContext;
@@ -63,91 +63,86 @@ impl UiRect {
6363
}
6464
}
6565

66-
pub fn from_style(
67-
context: &LayoutContext,
68-
style: &Style,
69-
ignore_border: bool,
70-
) -> taffy::style::Style {
66+
pub fn from_node(node: &Node, context: &LayoutContext, ignore_border: bool) -> taffy::style::Style {
7167
taffy::style::Style {
72-
display: style.display.into(),
68+
display: node.display.into(),
7369
overflow: taffy::Point {
74-
x: style.overflow.x.into(),
75-
y: style.overflow.y.into(),
70+
x: node.overflow.x.into(),
71+
y: node.overflow.y.into(),
7672
},
7773
scrollbar_width: 0.0,
78-
position: style.position_type.into(),
79-
flex_direction: style.flex_direction.into(),
80-
flex_wrap: style.flex_wrap.into(),
81-
align_items: style.align_items.into(),
82-
justify_items: style.justify_items.into(),
83-
align_self: style.align_self.into(),
84-
justify_self: style.justify_self.into(),
85-
align_content: style.align_content.into(),
86-
justify_content: style.justify_content.into(),
74+
position: node.position_type.into(),
75+
flex_direction: node.flex_direction.into(),
76+
flex_wrap: node.flex_wrap.into(),
77+
align_items: node.align_items.into(),
78+
justify_items: node.justify_items.into(),
79+
align_self: node.align_self.into(),
80+
justify_self: node.justify_self.into(),
81+
align_content: node.align_content.into(),
82+
justify_content: node.justify_content.into(),
8783
inset: taffy::Rect {
88-
left: style.left.into_length_percentage_auto(context),
89-
right: style.right.into_length_percentage_auto(context),
90-
top: style.top.into_length_percentage_auto(context),
91-
bottom: style.bottom.into_length_percentage_auto(context),
84+
left: node.left.into_length_percentage_auto(context),
85+
right: node.right.into_length_percentage_auto(context),
86+
top: node.top.into_length_percentage_auto(context),
87+
bottom: node.bottom.into_length_percentage_auto(context),
9288
},
93-
margin: style
89+
margin: node
9490
.margin
9591
.map_to_taffy_rect(|m| m.into_length_percentage_auto(context)),
96-
padding: style
92+
padding: node
9793
.padding
9894
.map_to_taffy_rect(|m| m.into_length_percentage(context)),
9995
// Ignore border for leaf nodes as it isn't implemented in the rendering engine.
10096
// TODO: Implement rendering of border for leaf nodes
10197
border: if ignore_border {
10298
taffy::Rect::zero()
10399
} else {
104-
style
105-
.border
100+
node.border
106101
.map_to_taffy_rect(|m| m.into_length_percentage(context))
107102
},
108-
flex_grow: style.flex_grow,
109-
flex_shrink: style.flex_shrink,
110-
flex_basis: style.flex_basis.into_dimension(context),
103+
flex_grow: node.flex_grow,
104+
flex_shrink: node.flex_shrink,
105+
flex_basis: node.flex_basis.into_dimension(context),
111106
size: taffy::Size {
112-
width: style.width.into_dimension(context),
113-
height: style.height.into_dimension(context),
107+
width: node.width.into_dimension(context),
108+
height: node.height.into_dimension(context),
114109
},
115110
min_size: taffy::Size {
116-
width: style.min_width.into_dimension(context),
117-
height: style.min_height.into_dimension(context),
111+
width: node.min_width.into_dimension(context),
112+
height: node.min_height.into_dimension(context),
118113
},
119114
max_size: taffy::Size {
120-
width: style.max_width.into_dimension(context),
121-
height: style.max_height.into_dimension(context),
115+
width: node.max_width.into_dimension(context),
116+
height: node.max_height.into_dimension(context),
122117
},
123-
aspect_ratio: style.aspect_ratio,
118+
aspect_ratio: node.aspect_ratio,
124119
gap: taffy::Size {
125-
width: style.column_gap.into_length_percentage(context),
126-
height: style.row_gap.into_length_percentage(context),
120+
width: node.column_gap.into_length_percentage(context),
121+
height: node.row_gap.into_length_percentage(context),
127122
},
128-
grid_auto_flow: style.grid_auto_flow.into(),
129-
grid_template_rows: style
123+
grid_auto_flow: node.grid_auto_flow.into(),
124+
grid_template_rows: node
130125
.grid_template_rows
131126
.iter()
132127
.map(|track| track.clone_into_repeated_taffy_track(context))
133128
.collect::<Vec<_>>(),
134-
grid_template_columns: style
129+
grid_template_columns: node
135130
.grid_template_columns
136131
.iter()
137132
.map(|track| track.clone_into_repeated_taffy_track(context))
138133
.collect::<Vec<_>>(),
139-
grid_auto_rows: style
134+
grid_auto_rows: node
140135
.grid_auto_rows
141136
.iter()
142137
.map(|track| track.into_taffy_track(context))
143138
.collect::<Vec<_>>(),
144-
grid_auto_columns: style
139+
grid_auto_columns: node
145140
.grid_auto_columns
146141
.iter()
147142
.map(|track| track.into_taffy_track(context))
148143
.collect::<Vec<_>>(),
149-
grid_row: style.grid_row.into(),
150-
grid_column: style.grid_column.into(),
144+
grid_row: node.grid_row.into(),
145+
grid_column: node.grid_column.into(),
151146
}
152147
}
153148

@@ -448,7 +443,7 @@ mod tests {
448443
use sh::TaffyZero;
449444
use taffy::style_helpers as sh;
450445

451-
let bevy_style = Style {
446+
let node = Node {
452447
display: Display::Flex,
453448
position_type: PositionType::Absolute,
454449
left: Val::ZERO,
@@ -516,7 +511,7 @@ mod tests {
516511
grid_row: GridPlacement::span(3),
517512
};
518513
let viewport_values = LayoutContext::new(1.0, bevy_math::Vec2::new(800., 600.));
519-
let taffy_style = from_style(&viewport_values, &bevy_style, false);
514+
let taffy_style = from_node(&node, &viewport_values, false);
520515
assert_eq!(taffy_style.display, taffy::style::Display::Flex);
521516
assert_eq!(taffy_style.position, taffy::style::Position::Absolute);
522517
assert_eq!(

0 commit comments

Comments
 (0)