From 015f2c69ca2a2c009fd04eadada282482deaf469 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Fri, 18 Oct 2024 17:25:33 -0500 Subject: [PATCH] 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](https://github.com/bevyengine/bevy/discussions/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(); } } ``` --- crates/bevy_dev_tools/src/fps_overlay.rs | 6 +- .../src/ui_debug_overlay/mod.rs | 14 +- crates/bevy_ecs/src/query/filter.rs | 4 +- crates/bevy_text/src/text_access.rs | 8 +- crates/bevy_ui/src/accessibility.rs | 8 +- crates/bevy_ui/src/focus.rs | 7 +- crates/bevy_ui/src/geometry.rs | 6 +- crates/bevy_ui/src/layout/convert.rs | 91 +++--- crates/bevy_ui/src/layout/mod.rs | 223 +++++++------- crates/bevy_ui/src/layout/ui_surface.rs | 51 ++-- crates/bevy_ui/src/lib.rs | 8 +- crates/bevy_ui/src/node_bundles.rs | 48 ++-- crates/bevy_ui/src/picking_backend.rs | 2 +- crates/bevy_ui/src/render/box_shadow.rs | 4 +- crates/bevy_ui/src/render/mod.rs | 10 +- .../src/render/ui_material_pipeline.rs | 2 +- .../src/render/ui_texture_slice_pipeline.rs | 2 +- crates/bevy_ui/src/stack.rs | 10 +- crates/bevy_ui/src/ui_material.rs | 5 +- crates/bevy_ui/src/ui_node.rs | 74 +++-- crates/bevy_ui/src/update.rs | 45 +-- crates/bevy_ui/src/widget/text.rs | 10 +- examples/2d/2d_shapes.rs | 2 +- examples/2d/bloom_2d.rs | 2 +- examples/2d/bounding_2d.rs | 2 +- examples/2d/sprite_animation.rs | 2 +- examples/2d/wireframe_2d.rs | 2 +- examples/3d/3d_shapes.rs | 2 +- examples/3d/anisotropy.rs | 2 +- examples/3d/anti_aliasing.rs | 2 +- examples/3d/atmospheric_fog.rs | 2 +- examples/3d/auto_exposure.rs | 12 +- examples/3d/blend_modes.rs | 17 +- examples/3d/bloom_3d.rs | 2 +- examples/3d/clearcoat.rs | 2 +- examples/3d/color_grading.rs | 58 ++-- examples/3d/deferred_rendering.rs | 2 +- examples/3d/depth_of_field.rs | 2 +- examples/3d/fog.rs | 2 +- examples/3d/generate_custom_mesh.rs | 2 +- examples/3d/irradiance_volumes.rs | 2 +- examples/3d/lighting.rs | 2 +- examples/3d/load_gltf_extras.rs | 2 +- examples/3d/motion_blur.rs | 2 +- examples/3d/order_independent_transparency.rs | 2 +- examples/3d/parallax_mapping.rs | 2 +- examples/3d/pbr.rs | 6 +- examples/3d/pcss.rs | 2 +- examples/3d/post_processing.rs | 2 +- examples/3d/reflection_probes.rs | 2 +- examples/3d/shadow_biases.rs | 3 +- examples/3d/split_screen.rs | 32 +-- examples/3d/spotlight.rs | 2 +- examples/3d/ssao.rs | 2 +- examples/3d/ssr.rs | 2 +- examples/3d/tonemapping.rs | 4 +- examples/3d/transmission.rs | 2 +- examples/3d/visibility_range.rs | 2 +- examples/3d/volumetric_fog.rs | 2 +- examples/3d/wireframe.rs | 2 +- examples/animation/animated_ui.rs | 7 +- examples/animation/animation_graph.rs | 20 +- examples/animation/animation_masks.rs | 98 +++---- examples/animation/easing_functions.rs | 2 +- examples/app/log_layers_ecs.rs | 3 +- examples/app/logs.rs | 2 +- examples/asset/alter_mesh.rs | 2 +- examples/asset/alter_sprite.rs | 2 +- examples/asset/multi_asset_sync.rs | 2 +- examples/audio/spatial_audio_2d.rs | 2 +- examples/audio/spatial_audio_3d.rs | 2 +- examples/camera/2d_screen_shake.rs | 2 +- examples/camera/2d_top_down_camera.rs | 2 +- examples/camera/camera_orbit.rs | 2 +- examples/camera/first_person_view_model.rs | 15 +- examples/camera/projection_zoom.rs | 2 +- examples/dev_tools/fps_overlay.rs | 2 +- examples/ecs/observers.rs | 2 +- examples/ecs/one_shot_systems.rs | 2 +- examples/games/alien_cake_addict.rs | 17 +- examples/games/breakout.rs | 2 +- examples/games/contributors.rs | 2 +- examples/games/game_menu.rs | 87 +++--- examples/games/loading_screen.rs | 10 +- examples/games/stepping.rs | 4 +- examples/gizmos/2d_gizmos.rs | 2 +- examples/gizmos/3d_gizmos.rs | 2 +- examples/gizmos/light_gizmos.rs | 4 +- examples/helpers/widgets.rs | 21 +- examples/input/text_input.rs | 2 +- examples/math/cubic_splines.rs | 19 +- examples/math/custom_primitives.rs | 8 +- examples/math/random_sampling.rs | 2 +- examples/math/render_primitives.rs | 3 +- examples/math/sampling_primitives.rs | 2 +- examples/mobile/src/lib.rs | 2 +- .../movement/physics_in_fixed_timestep.rs | 15 +- examples/picking/mesh_picking.rs | 2 +- examples/picking/simple_picking.rs | 2 +- examples/scene/scene.rs | 2 +- examples/shader/shader_prepass.rs | 2 +- examples/state/computed_states.rs | 42 ++- examples/state/custom_transitions.rs | 21 +- examples/state/states.rs | 21 +- examples/state/sub_states.rs | 27 +- examples/stress_tests/bevymark.rs | 3 +- examples/stress_tests/many_buttons.rs | 46 ++- examples/stress_tests/many_gizmos.rs | 2 +- examples/stress_tests/many_glyphs.rs | 26 +- examples/time/virtual_time.rs | 21 +- examples/tools/gamepad_viewer.rs | 2 +- .../tools/scene_viewer/morph_viewer_plugin.rs | 2 +- examples/transforms/align.rs | 2 +- examples/ui/borders.rs | 53 ++-- examples/ui/box_shadow.rs | 6 +- examples/ui/button.rs | 19 +- examples/ui/display_and_visibility.rs | 220 +++++++------- examples/ui/flex_layout.rs | 54 ++-- examples/ui/font_atlas_debug.rs | 7 +- examples/ui/ghost_nodes.rs | 19 +- examples/ui/grid.rs | 27 +- examples/ui/overflow.rs | 26 +- examples/ui/overflow_clip_margin.rs | 27 +- examples/ui/overflow_debug.rs | 70 ++--- examples/ui/relative_cursor_position.rs | 22 +- examples/ui/render_ui_to_texture.rs | 3 +- examples/ui/scroll.rs | 139 ++++----- examples/ui/size_constraints.rs | 79 +++-- examples/ui/text.rs | 6 +- examples/ui/text_debug.rs | 271 +++++++++--------- examples/ui/text_wrap_debug.rs | 25 +- examples/ui/transparency_ui.rs | 21 +- examples/ui/ui.rs | 103 +++---- examples/ui/ui_material.rs | 19 +- examples/ui/ui_scaling.rs | 11 +- examples/ui/ui_texture_atlas.rs | 23 +- examples/ui/ui_texture_atlas_slice.rs | 19 +- examples/ui/ui_texture_slice.rs | 19 +- examples/ui/ui_texture_slice_flip_and_tile.rs | 25 +- examples/ui/viewport_debug.rs | 48 ++-- examples/ui/window_fallthrough.rs | 2 +- examples/ui/z_index.rs | 35 +-- examples/window/low_power.rs | 2 +- examples/window/monitor_info.rs | 2 +- examples/window/multiple_windows.rs | 6 +- examples/window/scale_factor_override.rs | 20 +- examples/window/screenshot.rs | 2 +- examples/window/window_drag_move.rs | 3 +- examples/window/window_resizing.rs | 11 +- 149 files changed, 1258 insertions(+), 1616 deletions(-) diff --git a/crates/bevy_dev_tools/src/fps_overlay.rs b/crates/bevy_dev_tools/src/fps_overlay.rs index efba70a210..f970fc8f43 100644 --- a/crates/bevy_dev_tools/src/fps_overlay.rs +++ b/crates/bevy_dev_tools/src/fps_overlay.rs @@ -15,10 +15,9 @@ use bevy_ecs::{ use bevy_hierarchy::{BuildChildren, ChildBuild}; use bevy_render::view::Visibility; use bevy_text::{Font, TextColor, TextFont, TextSpan}; -use bevy_ui::Node; use bevy_ui::{ widget::{Text, TextUiWriter}, - GlobalZIndex, PositionType, Style, + GlobalZIndex, Node, PositionType, }; use bevy_utils::default; @@ -89,8 +88,7 @@ struct FpsText; fn setup(mut commands: Commands, overlay_config: Res) { commands .spawn(( - Node::default(), - Style { + Node { // We need to make sure the overlay doesn't affect the position of other UI nodes position_type: PositionType::Absolute, ..default() diff --git a/crates/bevy_dev_tools/src/ui_debug_overlay/mod.rs b/crates/bevy_dev_tools/src/ui_debug_overlay/mod.rs index 550cd1c29d..4e72778f15 100644 --- a/crates/bevy_dev_tools/src/ui_debug_overlay/mod.rs +++ b/crates/bevy_dev_tools/src/ui_debug_overlay/mod.rs @@ -15,7 +15,7 @@ use bevy_render::{ view::{RenderLayers, VisibilitySystems}, }; use bevy_transform::{prelude::GlobalTransform, TransformSystem}; -use bevy_ui::{DefaultUiCamera, Display, Node, Style, TargetCamera, UiScale}; +use bevy_ui::{ComputedNode, DefaultUiCamera, Display, Node, TargetCamera, UiScale}; use bevy_utils::{default, warn_once}; use bevy_window::{PrimaryWindow, Window, WindowRef}; @@ -37,7 +37,7 @@ struct LayoutRect { } impl LayoutRect { - fn new(trans: &GlobalTransform, node: &Node, scale: f32) -> Self { + fn new(trans: &GlobalTransform, node: &ComputedNode, scale: f32) -> Self { let mut this = Self { pos: trans.translation().xy() * scale, size: node.size() * scale, @@ -123,8 +123,8 @@ fn outline_nodes(outline: &OutlineParam, draw: &mut InsetGizmo, this_entity: Ent return; }; - for (entity, trans, node, style, children) in outline.nodes.iter_many(to_iter) { - if style.is_none() || style.is_some_and(|s| matches!(s.display, Display::None)) { + for (entity, trans, node, computed_node, children) in outline.nodes.iter_many(to_iter) { + if matches!(node.display, Display::None) { continue; } @@ -133,7 +133,7 @@ fn outline_nodes(outline: &OutlineParam, draw: &mut InsetGizmo, this_entity: Ent continue; } } - let rect = LayoutRect::new(trans, node, scale); + let rect = LayoutRect::new(trans, computed_node, scale); outline_node(entity, rect, draw); if children.is_some() { outline_nodes(outline, draw, entity, scale); @@ -146,7 +146,7 @@ type NodesQuery = ( Entity, &'static GlobalTransform, &'static Node, - Option<&'static Style>, + &'static ComputedNode, Option<&'static Children>, ); @@ -178,7 +178,7 @@ fn outline_roots( ( Entity, &GlobalTransform, - &Node, + &ComputedNode, Option<&ViewVisibility>, Option<&TargetCamera>, ), diff --git a/crates/bevy_ecs/src/query/filter.rs b/crates/bevy_ecs/src/query/filter.rs index e75f506039..024332b914 100644 --- a/crates/bevy_ecs/src/query/filter.rs +++ b/crates/bevy_ecs/src/query/filter.rs @@ -352,9 +352,9 @@ unsafe impl QueryFilter for Without { /// # #[derive(Component, Debug)] /// # struct Color {}; /// # #[derive(Component)] -/// # struct Style {}; +/// # struct Node {}; /// # -/// fn print_cool_entity_system(query: Query, Changed