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();
    }
}
```
This commit is contained in:
Carter Anderson 2024-10-18 17:25:33 -05:00 committed by GitHub
parent 624f573443
commit 015f2c69ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
149 changed files with 1258 additions and 1616 deletions

View file

@ -15,10 +15,9 @@ use bevy_ecs::{
use bevy_hierarchy::{BuildChildren, ChildBuild}; use bevy_hierarchy::{BuildChildren, ChildBuild};
use bevy_render::view::Visibility; use bevy_render::view::Visibility;
use bevy_text::{Font, TextColor, TextFont, TextSpan}; use bevy_text::{Font, TextColor, TextFont, TextSpan};
use bevy_ui::Node;
use bevy_ui::{ use bevy_ui::{
widget::{Text, TextUiWriter}, widget::{Text, TextUiWriter},
GlobalZIndex, PositionType, Style, GlobalZIndex, Node, PositionType,
}; };
use bevy_utils::default; use bevy_utils::default;
@ -89,8 +88,7 @@ struct FpsText;
fn setup(mut commands: Commands, overlay_config: Res<FpsOverlayConfig>) { fn setup(mut commands: Commands, overlay_config: Res<FpsOverlayConfig>) {
commands commands
.spawn(( .spawn((
Node::default(), Node {
Style {
// We need to make sure the overlay doesn't affect the position of other UI nodes // We need to make sure the overlay doesn't affect the position of other UI nodes
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
..default() ..default()

View file

@ -15,7 +15,7 @@ use bevy_render::{
view::{RenderLayers, VisibilitySystems}, view::{RenderLayers, VisibilitySystems},
}; };
use bevy_transform::{prelude::GlobalTransform, TransformSystem}; 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_utils::{default, warn_once};
use bevy_window::{PrimaryWindow, Window, WindowRef}; use bevy_window::{PrimaryWindow, Window, WindowRef};
@ -37,7 +37,7 @@ struct LayoutRect {
} }
impl 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 { let mut this = Self {
pos: trans.translation().xy() * scale, pos: trans.translation().xy() * scale,
size: node.size() * scale, size: node.size() * scale,
@ -123,8 +123,8 @@ fn outline_nodes(outline: &OutlineParam, draw: &mut InsetGizmo, this_entity: Ent
return; return;
}; };
for (entity, trans, node, style, children) in outline.nodes.iter_many(to_iter) { for (entity, trans, node, computed_node, children) in outline.nodes.iter_many(to_iter) {
if style.is_none() || style.is_some_and(|s| matches!(s.display, Display::None)) { if matches!(node.display, Display::None) {
continue; continue;
} }
@ -133,7 +133,7 @@ fn outline_nodes(outline: &OutlineParam, draw: &mut InsetGizmo, this_entity: Ent
continue; continue;
} }
} }
let rect = LayoutRect::new(trans, node, scale); let rect = LayoutRect::new(trans, computed_node, scale);
outline_node(entity, rect, draw); outline_node(entity, rect, draw);
if children.is_some() { if children.is_some() {
outline_nodes(outline, draw, entity, scale); outline_nodes(outline, draw, entity, scale);
@ -146,7 +146,7 @@ type NodesQuery = (
Entity, Entity,
&'static GlobalTransform, &'static GlobalTransform,
&'static Node, &'static Node,
Option<&'static Style>, &'static ComputedNode,
Option<&'static Children>, Option<&'static Children>,
); );
@ -178,7 +178,7 @@ fn outline_roots(
( (
Entity, Entity,
&GlobalTransform, &GlobalTransform,
&Node, &ComputedNode,
Option<&ViewVisibility>, Option<&ViewVisibility>,
Option<&TargetCamera>, Option<&TargetCamera>,
), ),

View file

@ -352,9 +352,9 @@ unsafe impl<T: Component> QueryFilter for Without<T> {
/// # #[derive(Component, Debug)] /// # #[derive(Component, Debug)]
/// # struct Color {}; /// # struct Color {};
/// # #[derive(Component)] /// # #[derive(Component)]
/// # struct Style {}; /// # struct Node {};
/// # /// #
/// fn print_cool_entity_system(query: Query<Entity, Or<(Changed<Color>, Changed<Style>)>>) { /// fn print_cool_entity_system(query: Query<Entity, Or<(Changed<Color>, Changed<Node>)>>) {
/// for entity in &query { /// for entity in &query {
/// println!("Entity {:?} got a new style or color", entity); /// println!("Entity {:?} got a new style or color", entity);
/// } /// }

View file

@ -171,11 +171,11 @@ impl<'a, R: TextRoot> Iterator for TextSpanIter<'a, R> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
// Root // Root
if let Some(root_entity) = self.root_entity.take() { if let Some(root_entity) = self.root_entity.take() {
if let Ok((text, style, color, maybe_children)) = self.roots.get(root_entity) { if let Ok((text, text_font, color, maybe_children)) = self.roots.get(root_entity) {
if let Some(children) = maybe_children { if let Some(children) = maybe_children {
self.stack.push((children, 0)); self.stack.push((children, 0));
} }
return Some((root_entity, 0, text.read_span(), style, color.0)); return Some((root_entity, 0, text.read_span(), text_font, color.0));
} }
return None; return None;
} }
@ -193,7 +193,7 @@ impl<'a, R: TextRoot> Iterator for TextSpanIter<'a, R> {
*idx += 1; *idx += 1;
let entity = *child; let entity = *child;
let Ok((span, style, color, maybe_children)) = self.spans.get(entity) else { let Ok((span, text_font, color, maybe_children)) = self.spans.get(entity) else {
continue; continue;
}; };
@ -201,7 +201,7 @@ impl<'a, R: TextRoot> Iterator for TextSpanIter<'a, R> {
if let Some(children) = maybe_children { if let Some(children) = maybe_children {
self.stack.push((children, 0)); self.stack.push((children, 0));
} }
return Some((entity, depth, span.read_span(), style, color.0)); return Some((entity, depth, span.read_span(), text_font, color.0));
} }
// All children at this stack entry have been iterated. // All children at this stack entry have been iterated.

View file

@ -2,7 +2,7 @@ use crate::{
experimental::UiChildren, experimental::UiChildren,
prelude::{Button, Label}, prelude::{Button, Label},
widget::TextUiReader, widget::TextUiReader,
Node, UiImage, ComputedNode, UiImage,
}; };
use bevy_a11y::{ use bevy_a11y::{
accesskit::{NodeBuilder, Rect, Role}, accesskit::{NodeBuilder, Rect, Role},
@ -38,7 +38,11 @@ fn calc_name(
fn calc_bounds( fn calc_bounds(
camera: Query<(&Camera, &GlobalTransform)>, camera: Query<(&Camera, &GlobalTransform)>,
mut nodes: Query<(&mut AccessibilityNode, Ref<Node>, Ref<GlobalTransform>)>, mut nodes: Query<(
&mut AccessibilityNode,
Ref<ComputedNode>,
Ref<GlobalTransform>,
)>,
) { ) {
if let Ok((camera, camera_transform)) = camera.get_single() { if let Ok((camera, camera_transform)) = camera.get_single() {
for (mut accessible, node, transform) in &mut nodes { for (mut accessible, node, transform) in &mut nodes {

View file

@ -1,5 +1,6 @@
use crate::{ use crate::{
CalculatedClip, DefaultUiCamera, Node, ResolvedBorderRadius, TargetCamera, UiScale, UiStack, CalculatedClip, ComputedNode, DefaultUiCamera, ResolvedBorderRadius, TargetCamera, UiScale,
UiStack,
}; };
use bevy_ecs::{ use bevy_ecs::{
change_detection::DetectChangesMut, change_detection::DetectChangesMut,
@ -74,7 +75,7 @@ impl Default for Interaction {
/// ///
/// It can be used alongside [`Interaction`] to get the position of the press. /// It can be used alongside [`Interaction`] to get the position of the press.
/// ///
/// The component is updated when it is in the same entity with [`Node`]. /// The component is updated when it is in the same entity with [`Node`](crate::Node).
#[derive(Component, Copy, Clone, Default, PartialEq, Debug, Reflect)] #[derive(Component, Copy, Clone, Default, PartialEq, Debug, Reflect)]
#[reflect(Component, Default, PartialEq, Debug)] #[reflect(Component, Default, PartialEq, Debug)]
#[cfg_attr( #[cfg_attr(
@ -135,7 +136,7 @@ pub struct State {
#[query_data(mutable)] #[query_data(mutable)]
pub struct NodeQuery { pub struct NodeQuery {
entity: Entity, entity: Entity,
node: &'static Node, node: &'static ComputedNode,
global_transform: &'static GlobalTransform, global_transform: &'static GlobalTransform,
interaction: Option<&'static mut Interaction>, interaction: Option<&'static mut Interaction>,
relative_cursor_position: Option<&'static mut RelativeCursorPosition>, relative_cursor_position: Option<&'static mut RelativeCursorPosition>,

View file

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

View file

@ -3,8 +3,8 @@ use taffy::style_helpers;
use crate::{ use crate::{
AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, GridAutoFlow, AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, GridAutoFlow,
GridPlacement, GridTrack, GridTrackRepetition, JustifyContent, JustifyItems, JustifySelf, GridPlacement, GridTrack, GridTrackRepetition, JustifyContent, JustifyItems, JustifySelf,
MaxTrackSizingFunction, MinTrackSizingFunction, OverflowAxis, PositionType, RepeatedGridTrack, MaxTrackSizingFunction, MinTrackSizingFunction, Node, OverflowAxis, PositionType,
Style, UiRect, Val, RepeatedGridTrack, UiRect, Val,
}; };
use super::LayoutContext; use super::LayoutContext;
@ -63,37 +63,33 @@ impl UiRect {
} }
} }
pub fn from_style( pub fn from_node(node: &Node, context: &LayoutContext, ignore_border: bool) -> taffy::style::Style {
context: &LayoutContext,
style: &Style,
ignore_border: bool,
) -> taffy::style::Style {
taffy::style::Style { taffy::style::Style {
display: style.display.into(), display: node.display.into(),
overflow: taffy::Point { overflow: taffy::Point {
x: style.overflow.x.into(), x: node.overflow.x.into(),
y: style.overflow.y.into(), y: node.overflow.y.into(),
}, },
scrollbar_width: 0.0, scrollbar_width: 0.0,
position: style.position_type.into(), position: node.position_type.into(),
flex_direction: style.flex_direction.into(), flex_direction: node.flex_direction.into(),
flex_wrap: style.flex_wrap.into(), flex_wrap: node.flex_wrap.into(),
align_items: style.align_items.into(), align_items: node.align_items.into(),
justify_items: style.justify_items.into(), justify_items: node.justify_items.into(),
align_self: style.align_self.into(), align_self: node.align_self.into(),
justify_self: style.justify_self.into(), justify_self: node.justify_self.into(),
align_content: style.align_content.into(), align_content: node.align_content.into(),
justify_content: style.justify_content.into(), justify_content: node.justify_content.into(),
inset: taffy::Rect { inset: taffy::Rect {
left: style.left.into_length_percentage_auto(context), left: node.left.into_length_percentage_auto(context),
right: style.right.into_length_percentage_auto(context), right: node.right.into_length_percentage_auto(context),
top: style.top.into_length_percentage_auto(context), top: node.top.into_length_percentage_auto(context),
bottom: style.bottom.into_length_percentage_auto(context), bottom: node.bottom.into_length_percentage_auto(context),
}, },
margin: style margin: node
.margin .margin
.map_to_taffy_rect(|m| m.into_length_percentage_auto(context)), .map_to_taffy_rect(|m| m.into_length_percentage_auto(context)),
padding: style padding: node
.padding .padding
.map_to_taffy_rect(|m| m.into_length_percentage(context)), .map_to_taffy_rect(|m| m.into_length_percentage(context)),
// Ignore border for leaf nodes as it isn't implemented in the rendering engine. // Ignore border for leaf nodes as it isn't implemented in the rendering engine.
@ -101,53 +97,52 @@ pub fn from_style(
border: if ignore_border { border: if ignore_border {
taffy::Rect::zero() taffy::Rect::zero()
} else { } else {
style node.border
.border
.map_to_taffy_rect(|m| m.into_length_percentage(context)) .map_to_taffy_rect(|m| m.into_length_percentage(context))
}, },
flex_grow: style.flex_grow, flex_grow: node.flex_grow,
flex_shrink: style.flex_shrink, flex_shrink: node.flex_shrink,
flex_basis: style.flex_basis.into_dimension(context), flex_basis: node.flex_basis.into_dimension(context),
size: taffy::Size { size: taffy::Size {
width: style.width.into_dimension(context), width: node.width.into_dimension(context),
height: style.height.into_dimension(context), height: node.height.into_dimension(context),
}, },
min_size: taffy::Size { min_size: taffy::Size {
width: style.min_width.into_dimension(context), width: node.min_width.into_dimension(context),
height: style.min_height.into_dimension(context), height: node.min_height.into_dimension(context),
}, },
max_size: taffy::Size { max_size: taffy::Size {
width: style.max_width.into_dimension(context), width: node.max_width.into_dimension(context),
height: style.max_height.into_dimension(context), height: node.max_height.into_dimension(context),
}, },
aspect_ratio: style.aspect_ratio, aspect_ratio: node.aspect_ratio,
gap: taffy::Size { gap: taffy::Size {
width: style.column_gap.into_length_percentage(context), width: node.column_gap.into_length_percentage(context),
height: style.row_gap.into_length_percentage(context), height: node.row_gap.into_length_percentage(context),
}, },
grid_auto_flow: style.grid_auto_flow.into(), grid_auto_flow: node.grid_auto_flow.into(),
grid_template_rows: style grid_template_rows: node
.grid_template_rows .grid_template_rows
.iter() .iter()
.map(|track| track.clone_into_repeated_taffy_track(context)) .map(|track| track.clone_into_repeated_taffy_track(context))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
grid_template_columns: style grid_template_columns: node
.grid_template_columns .grid_template_columns
.iter() .iter()
.map(|track| track.clone_into_repeated_taffy_track(context)) .map(|track| track.clone_into_repeated_taffy_track(context))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
grid_auto_rows: style grid_auto_rows: node
.grid_auto_rows .grid_auto_rows
.iter() .iter()
.map(|track| track.into_taffy_track(context)) .map(|track| track.into_taffy_track(context))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
grid_auto_columns: style grid_auto_columns: node
.grid_auto_columns .grid_auto_columns
.iter() .iter()
.map(|track| track.into_taffy_track(context)) .map(|track| track.into_taffy_track(context))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
grid_row: style.grid_row.into(), grid_row: node.grid_row.into(),
grid_column: style.grid_column.into(), grid_column: node.grid_column.into(),
} }
} }
@ -448,7 +443,7 @@ mod tests {
use sh::TaffyZero; use sh::TaffyZero;
use taffy::style_helpers as sh; use taffy::style_helpers as sh;
let bevy_style = Style { let node = Node {
display: Display::Flex, display: Display::Flex,
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
left: Val::ZERO, left: Val::ZERO,
@ -516,7 +511,7 @@ mod tests {
grid_row: GridPlacement::span(3), grid_row: GridPlacement::span(3),
}; };
let viewport_values = LayoutContext::new(1.0, bevy_math::Vec2::new(800., 600.)); let viewport_values = LayoutContext::new(1.0, bevy_math::Vec2::new(800., 600.));
let taffy_style = from_style(&viewport_values, &bevy_style, false); let taffy_style = from_node(&node, &viewport_values, false);
assert_eq!(taffy_style.display, taffy::style::Display::Flex); assert_eq!(taffy_style.display, taffy::style::Display::Flex);
assert_eq!(taffy_style.position, taffy::style::Position::Absolute); assert_eq!(taffy_style.position, taffy::style::Position::Absolute);
assert_eq!( assert_eq!(

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
experimental::{UiChildren, UiRootNodes}, experimental::{UiChildren, UiRootNodes},
BorderRadius, ContentSize, DefaultUiCamera, Display, Node, Outline, OverflowAxis, BorderRadius, ComputedNode, ContentSize, DefaultUiCamera, Display, Node, Outline, OverflowAxis,
ScrollPosition, Style, TargetCamera, UiScale, ScrollPosition, TargetCamera, UiScale,
}; };
use bevy_ecs::{ use bevy_ecs::{
change_detection::{DetectChanges, DetectChangesMut}, change_detection::{DetectChanges, DetectChangesMut},
@ -115,22 +115,19 @@ pub fn ui_layout_system(
mut resize_events: EventReader<bevy_window::WindowResized>, mut resize_events: EventReader<bevy_window::WindowResized>,
mut ui_surface: ResMut<UiSurface>, mut ui_surface: ResMut<UiSurface>,
root_nodes: UiRootNodes, root_nodes: UiRootNodes,
mut style_query: Query< mut node_query: Query<(
( Entity,
Entity, Ref<Node>,
Ref<Style>, Option<&mut ContentSize>,
Option<&mut ContentSize>, Option<&TargetCamera>,
Option<&TargetCamera>, )>,
), computed_node_query: Query<(Entity, Option<Ref<Parent>>), With<ComputedNode>>,
With<Node>,
>,
node_query: Query<(Entity, Option<Ref<Parent>>), With<Node>>,
ui_children: UiChildren, ui_children: UiChildren,
mut removed_components: UiLayoutSystemRemovedComponentParam, mut removed_components: UiLayoutSystemRemovedComponentParam,
mut node_transform_query: Query<( mut node_transform_query: Query<(
&mut Node, &mut ComputedNode,
&mut Transform, &mut Transform,
&Style, &Node,
Option<&BorderRadius>, Option<&BorderRadius>,
Option<&Outline>, Option<&Outline>,
Option<&ScrollPosition>, Option<&ScrollPosition>,
@ -173,7 +170,7 @@ pub fn ui_layout_system(
// Precalculate the layout info for each camera, so we have fast access to it for each node // Precalculate the layout info for each camera, so we have fast access to it for each node
camera_layout_info.clear(); camera_layout_info.clear();
style_query node_query
.iter_many(root_nodes.iter()) .iter_many(root_nodes.iter())
.for_each(|(entity, _, _, target_camera)| { .for_each(|(entity, _, _, target_camera)| {
match camera_with_default(target_camera) { match camera_with_default(target_camera) {
@ -211,17 +208,17 @@ pub fn ui_layout_system(
ui_surface.try_remove_node_context(entity); ui_surface.try_remove_node_context(entity);
} }
// Sync Style and ContentSize to Taffy for all nodes // Sync Node and ContentSize to Taffy for all nodes
style_query node_query
.iter_mut() .iter_mut()
.for_each(|(entity, style, content_size, target_camera)| { .for_each(|(entity, node, content_size, target_camera)| {
if let Some(camera) = if let Some(camera) =
camera_with_default(target_camera).and_then(|c| camera_layout_info.get(&c)) camera_with_default(target_camera).and_then(|c| camera_layout_info.get(&c))
{ {
if camera.resized if camera.resized
|| !scale_factor_events.is_empty() || !scale_factor_events.is_empty()
|| ui_scale.is_changed() || ui_scale.is_changed()
|| style.is_changed() || node.is_changed()
|| content_size || content_size
.as_ref() .as_ref()
.map(|c| c.measure.is_some()) .map(|c| c.measure.is_some())
@ -232,10 +229,10 @@ pub fn ui_layout_system(
[camera.size.x as f32, camera.size.y as f32].into(), [camera.size.x as f32, camera.size.y as f32].into(),
); );
let measure = content_size.and_then(|mut c| c.measure.take()); let measure = content_size.and_then(|mut c| c.measure.take());
ui_surface.upsert_node(&layout_context, entity, &style, measure); ui_surface.upsert_node(&layout_context, entity, &node, measure);
} }
} else { } else {
ui_surface.upsert_node(&LayoutContext::DEFAULT, entity, &Style::default(), None); ui_surface.upsert_node(&LayoutContext::DEFAULT, entity, &Node::default(), None);
} }
}); });
scale_factor_events.clear(); scale_factor_events.clear();
@ -259,30 +256,32 @@ pub fn ui_layout_system(
ui_surface.try_remove_children(entity); ui_surface.try_remove_children(entity);
} }
node_query.iter().for_each(|(entity, maybe_parent)| { computed_node_query
if let Some(parent) = maybe_parent { .iter()
// Note: This does not cover the case where a parent's Node component was removed. .for_each(|(entity, maybe_parent)| {
// Users are responsible for fixing hierarchies if they do that (it is not recommended). if let Some(parent) = maybe_parent {
// Detecting it here would be a permanent perf burden on the hot path. // Note: This does not cover the case where a parent's Node component was removed.
if parent.is_changed() && !ui_children.is_ui_node(parent.get()) { // Users are responsible for fixing hierarchies if they do that (it is not recommended).
warn!( // Detecting it here would be a permanent perf burden on the hot path.
"Styled child ({entity}) in a non-UI entity hierarchy. You are using an entity \ if parent.is_changed() && !ui_children.is_ui_node(parent.get()) {
warn!(
"Node ({entity}) is in a non-UI entity hierarchy. You are using an entity \
with UI components as a child of an entity without UI components, your UI layout may be broken." with UI components as a child of an entity without UI components, your UI layout may be broken."
); );
}
} }
}
if ui_children.is_changed(entity) { if ui_children.is_changed(entity) {
ui_surface.update_children(entity, ui_children.iter_ui_children(entity)); ui_surface.update_children(entity, ui_children.iter_ui_children(entity));
} }
}); });
let text_buffers = &mut buffer_query; let text_buffers = &mut buffer_query;
// clean up removed nodes after syncing children to avoid potential panic (invalid SlotMap key used) // clean up removed nodes after syncing children to avoid potential panic (invalid SlotMap key used)
ui_surface.remove_entities(removed_components.removed_nodes.read()); ui_surface.remove_entities(removed_components.removed_nodes.read());
// Re-sync changed children: avoid layout glitches caused by removed nodes that are still set as a child of another node // Re-sync changed children: avoid layout glitches caused by removed nodes that are still set as a child of another node
node_query.iter().for_each(|(entity, _)| { computed_node_query.iter().for_each(|(entity, _)| {
if ui_children.is_changed(entity) { if ui_children.is_changed(entity) {
ui_surface.update_children(entity, ui_children.iter_ui_children(entity)); ui_surface.update_children(entity, ui_children.iter_ui_children(entity));
} }
@ -319,9 +318,9 @@ with UI components as a child of an entity without UI components, your UI layout
ui_surface: &UiSurface, ui_surface: &UiSurface,
root_size: Option<Vec2>, root_size: Option<Vec2>,
node_transform_query: &mut Query<( node_transform_query: &mut Query<(
&mut Node, &mut ComputedNode,
&mut Transform, &mut Transform,
&Style, &Node,
Option<&BorderRadius>, Option<&BorderRadius>,
Option<&Outline>, Option<&Outline>,
Option<&ScrollPosition>, Option<&ScrollPosition>,
@ -581,25 +580,19 @@ mod tests {
// spawn a root entity with width and height set to fill 100% of its parent // spawn a root entity with width and height set to fill 100% of its parent
let ui_root = world let ui_root = world
.spawn(( .spawn(Node {
Node::default(), width: Val::Percent(100.),
Style { height: Val::Percent(100.),
width: Val::Percent(100.), ..default()
height: Val::Percent(100.), })
..default()
},
))
.id(); .id();
let ui_child = world let ui_child = world
.spawn(( .spawn(Node {
Node::default(), width: Val::Percent(100.),
Style { height: Val::Percent(100.),
width: Val::Percent(100.), ..default()
height: Val::Percent(100.), })
..default()
},
))
.id(); .id();
world.entity_mut(ui_root).add_child(ui_child); world.entity_mut(ui_root).add_child(ui_child);
@ -828,45 +821,36 @@ mod tests {
let mut size = 150.; let mut size = 150.;
world.spawn(( world.spawn(Node {
Node::default(), // test should pass without explicitly requiring position_type to be set to Absolute
Style { // position_type: PositionType::Absolute,
// test should pass without explicitly requiring position_type to be set to Absolute width: Val::Px(size),
// position_type: PositionType::Absolute, height: Val::Px(size),
width: Val::Px(size), ..default()
height: Val::Px(size), });
..default()
},
));
size -= 50.; size -= 50.;
world.spawn(( world.spawn(Node {
Node::default(), // position_type: PositionType::Absolute,
Style { width: Val::Px(size),
// position_type: PositionType::Absolute, height: Val::Px(size),
width: Val::Px(size), ..default()
height: Val::Px(size), });
..default()
},
));
size -= 50.; size -= 50.;
world.spawn(( world.spawn(Node {
Node::default(), // position_type: PositionType::Absolute,
Style { width: Val::Px(size),
// position_type: PositionType::Absolute, height: Val::Px(size),
width: Val::Px(size), ..default()
height: Val::Px(size), });
..default()
},
));
ui_schedule.run(&mut world); ui_schedule.run(&mut world);
let overlap_check = world let overlap_check = world
.query_filtered::<(Entity, &Node, &GlobalTransform), Without<Parent>>() .query_filtered::<(Entity, &ComputedNode, &GlobalTransform), Without<Parent>>()
.iter(&world) .iter(&world)
.fold( .fold(
Option::<(Rect, bool)>::None, Option::<(Rect, bool)>::None,
@ -949,7 +933,7 @@ mod tests {
commands commands
.entity(moving_ui_entity) .entity(moving_ui_entity)
.insert(TargetCamera(target_camera_entity)) .insert(TargetCamera(target_camera_entity))
.insert(Style { .insert(Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(pos.y), top: Val::Px(pos.y),
left: Val::Px(pos.x), left: Val::Px(pos.x),
@ -996,8 +980,7 @@ mod tests {
)); ));
world.spawn(( world.spawn((
Node::default(), Node {
Style {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(0.), top: Val::Px(0.),
left: Val::Px(0.), left: Val::Px(0.),
@ -1050,8 +1033,7 @@ mod tests {
let ui_entity = world let ui_entity = world
.spawn(( .spawn((
Node::default(), Node {
Style {
align_self: AlignSelf::Start, align_self: AlignSelf::Start,
..default() ..default()
}, },
@ -1076,8 +1058,7 @@ mod tests {
let content_size = Vec2::new(50., 25.); let content_size = Vec2::new(50., 25.);
let ui_entity = world let ui_entity = world
.spawn(( .spawn((
Node::default(), Node {
Style {
align_self: AlignSelf::Start, align_self: AlignSelf::Start,
..Default::default() ..Default::default()
}, },
@ -1115,26 +1096,20 @@ mod tests {
let (mut world, mut ui_schedule) = setup_ui_test_world(); let (mut world, mut ui_schedule) = setup_ui_test_world();
let parent = world let parent = world
.spawn(( .spawn(Node {
Node::default(), display: Display::Grid,
Style { grid_template_columns: RepeatedGridTrack::min_content(2),
display: Display::Grid, margin: UiRect::all(Val::Px(4.0)),
grid_template_columns: RepeatedGridTrack::min_content(2), ..default()
margin: UiRect::all(Val::Px(4.0)), })
..default()
},
))
.with_children(|commands| { .with_children(|commands| {
for _ in 0..2 { for _ in 0..2 {
commands.spawn(( commands.spawn(Node {
Node::default(), display: Display::Grid,
Style { width: Val::Px(160.),
display: Display::Grid, height: Val::Px(160.),
width: Val::Px(160.), ..default()
height: Val::Px(160.), });
..default()
},
));
} }
}) })
.id(); .id();
@ -1154,9 +1129,9 @@ mod tests {
ui_schedule.run(&mut world); ui_schedule.run(&mut world);
let width_sum: f32 = children let width_sum: f32 = children
.iter() .iter()
.map(|child| world.get::<Node>(*child).unwrap().calculated_size.x) .map(|child| world.get::<ComputedNode>(*child).unwrap().calculated_size.x)
.sum(); .sum();
let parent_width = world.get::<Node>(parent).unwrap().calculated_size.x; let parent_width = world.get::<ComputedNode>(parent).unwrap().calculated_size.x;
assert!((width_sum - parent_width).abs() < 0.001); assert!((width_sum - parent_width).abs() < 0.001);
assert!((width_sum - 320.).abs() <= 1.); assert!((width_sum - 320.).abs() <= 1.);
s += r; s += r;
@ -1205,25 +1180,19 @@ mod tests {
); );
let ui_root = world let ui_root = world
.spawn(( .spawn(Node {
Node::default(), width: Val::Percent(100.),
Style { height: Val::Percent(100.),
width: Val::Percent(100.), ..default()
height: Val::Percent(100.), })
..default()
},
))
.id(); .id();
let ui_child = world let ui_child = world
.spawn(( .spawn(Node {
Node::default(), width: Val::Percent(100.),
Style { height: Val::Percent(100.),
width: Val::Percent(100.), ..default()
height: Val::Percent(100.), })
..default()
},
))
.id(); .id();
world.entity_mut(ui_root).add_child(ui_child); world.entity_mut(ui_root).add_child(ui_child);
@ -1254,7 +1223,7 @@ mod tests {
ui_surface.upsert_node( ui_surface.upsert_node(
&LayoutContext::TEST_CONTEXT, &LayoutContext::TEST_CONTEXT,
params.root_node_entity, params.root_node_entity,
&Style::default(), &Node::default(),
None, None,
); );

View file

@ -9,9 +9,7 @@ use bevy_ecs::{
use bevy_math::UVec2; use bevy_math::UVec2;
use bevy_utils::default; use bevy_utils::default;
use crate::{ use crate::{layout::convert, LayoutContext, LayoutError, Measure, MeasureArgs, Node, NodeMeasure};
layout::convert, LayoutContext, LayoutError, Measure, MeasureArgs, NodeMeasure, Style,
};
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct RootNodePair { pub struct RootNodePair {
@ -71,7 +69,7 @@ impl UiSurface {
&mut self, &mut self,
layout_context: &LayoutContext, layout_context: &LayoutContext,
entity: Entity, entity: Entity,
style: &Style, node: &Node,
mut new_node_context: Option<NodeMeasure>, mut new_node_context: Option<NodeMeasure>,
) { ) {
let taffy = &mut self.taffy; let taffy = &mut self.taffy;
@ -81,14 +79,11 @@ impl UiSurface {
added = true; added = true;
if let Some(measure) = new_node_context.take() { if let Some(measure) = new_node_context.take() {
taffy taffy
.new_leaf_with_context( .new_leaf_with_context(convert::from_node(node, layout_context, true), measure)
convert::from_style(layout_context, style, true),
measure,
)
.unwrap() .unwrap()
} else { } else {
taffy taffy
.new_leaf(convert::from_style(layout_context, style, false)) .new_leaf(convert::from_node(node, layout_context, false))
.unwrap() .unwrap()
} }
}); });
@ -106,7 +101,7 @@ impl UiSurface {
taffy taffy
.set_style( .set_style(
taffy_node_id, taffy_node_id,
convert::from_style(layout_context, style, has_measure), convert::from_node(node, layout_context, has_measure),
) )
.unwrap(); .unwrap();
} }
@ -353,17 +348,17 @@ mod tests {
let mut ui_surface = UiSurface::default(); let mut ui_surface = UiSurface::default();
let camera_entity = Entity::from_raw(0); let camera_entity = Entity::from_raw(0);
let root_node_entity = Entity::from_raw(1); let root_node_entity = Entity::from_raw(1);
let style = Style::default(); let node = Node::default();
// standard upsert // standard upsert
ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &style, None); ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &node, None);
// should be inserted into taffy // should be inserted into taffy
assert_eq!(ui_surface.taffy.total_node_count(), 1); assert_eq!(ui_surface.taffy.total_node_count(), 1);
assert!(ui_surface.entity_to_taffy.contains_key(&root_node_entity)); assert!(ui_surface.entity_to_taffy.contains_key(&root_node_entity));
// test duplicate insert 1 // test duplicate insert 1
ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &style, None); ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &node, None);
// node count should not have increased // node count should not have increased
assert_eq!(ui_surface.taffy.total_node_count(), 1); assert_eq!(ui_surface.taffy.total_node_count(), 1);
@ -380,7 +375,7 @@ mod tests {
assert!(is_root_node_pair_valid(&ui_surface.taffy, root_node_pair)); assert!(is_root_node_pair_valid(&ui_surface.taffy, root_node_pair));
// test duplicate insert 2 // test duplicate insert 2
ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &style, None); ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &node, None);
// node count should not have increased // node count should not have increased
assert_eq!(ui_surface.taffy.total_node_count(), 2); assert_eq!(ui_surface.taffy.total_node_count(), 2);
@ -418,9 +413,9 @@ mod tests {
let mut ui_surface = UiSurface::default(); let mut ui_surface = UiSurface::default();
let camera_entity = Entity::from_raw(0); let camera_entity = Entity::from_raw(0);
let root_node_entity = Entity::from_raw(1); let root_node_entity = Entity::from_raw(1);
let style = Style::default(); let node = Node::default();
ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &style, None); ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &node, None);
// assign root node to camera // assign root node to camera
ui_surface.set_camera_children(camera_entity, [root_node_entity].into_iter()); ui_surface.set_camera_children(camera_entity, [root_node_entity].into_iter());
@ -453,9 +448,9 @@ mod tests {
let mut ui_surface = UiSurface::default(); let mut ui_surface = UiSurface::default();
let camera_entity = Entity::from_raw(0); let camera_entity = Entity::from_raw(0);
let root_node_entity = Entity::from_raw(1); let root_node_entity = Entity::from_raw(1);
let style = Style::default(); let node = Node::default();
ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &style, None); ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &node, None);
// assign root node to camera // assign root node to camera
ui_surface.set_camera_children(camera_entity, [root_node_entity].into_iter()); ui_surface.set_camera_children(camera_entity, [root_node_entity].into_iter());
@ -502,9 +497,9 @@ mod tests {
let mut ui_surface = UiSurface::default(); let mut ui_surface = UiSurface::default();
let camera_entity = Entity::from_raw(0); let camera_entity = Entity::from_raw(0);
let root_node_entity = Entity::from_raw(1); let root_node_entity = Entity::from_raw(1);
let style = Style::default(); let node = Node::default();
ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &style, None); ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &node, None);
ui_surface.set_camera_children(camera_entity, [root_node_entity].into_iter()); ui_surface.set_camera_children(camera_entity, [root_node_entity].into_iter());
@ -548,9 +543,9 @@ mod tests {
fn test_try_update_measure() { fn test_try_update_measure() {
let mut ui_surface = UiSurface::default(); let mut ui_surface = UiSurface::default();
let root_node_entity = Entity::from_raw(1); let root_node_entity = Entity::from_raw(1);
let style = Style::default(); let node = Node::default();
ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &style, None); ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &node, None);
let mut content_size = ContentSize::default(); let mut content_size = ContentSize::default();
content_size.set(NodeMeasure::Fixed(FixedMeasure { size: Vec2::ONE })); content_size.set(NodeMeasure::Fixed(FixedMeasure { size: Vec2::ONE }));
let measure_func = content_size.measure.take().unwrap(); let measure_func = content_size.measure.take().unwrap();
@ -564,10 +559,10 @@ mod tests {
let mut ui_surface = UiSurface::default(); let mut ui_surface = UiSurface::default();
let root_node_entity = Entity::from_raw(1); let root_node_entity = Entity::from_raw(1);
let child_entity = Entity::from_raw(2); let child_entity = Entity::from_raw(2);
let style = Style::default(); let node = Node::default();
ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &style, None); ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &node, None);
ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, child_entity, &style, None); ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, child_entity, &node, None);
ui_surface.update_children(root_node_entity, vec![child_entity].into_iter()); ui_surface.update_children(root_node_entity, vec![child_entity].into_iter());
@ -583,10 +578,10 @@ mod tests {
let camera_entity = Entity::from_raw(0); let camera_entity = Entity::from_raw(0);
let root_node_entity = Entity::from_raw(1); let root_node_entity = Entity::from_raw(1);
let child_entity = Entity::from_raw(2); let child_entity = Entity::from_raw(2);
let style = Style::default(); let node = Node::default();
ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &style, None); ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, root_node_entity, &node, None);
ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, child_entity, &style, None); ui_surface.upsert_node(&LayoutContext::TEST_CONTEXT, child_entity, &node, None);
let root_taffy_node = *ui_surface.entity_to_taffy.get(&root_node_entity).unwrap(); let root_taffy_node = *ui_surface.entity_to_taffy.get(&root_node_entity).unwrap();
let child_taffy = *ui_surface.entity_to_taffy.get(&child_entity).unwrap(); let child_taffy = *ui_surface.entity_to_taffy.get(&child_entity).unwrap();

View file

@ -129,10 +129,6 @@ struct AmbiguousWithTextSystem;
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)] #[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
struct AmbiguousWithUpdateText2DLayout; struct AmbiguousWithUpdateText2DLayout;
/// A convenient alias for `With<Node>`, for use with
/// [`bevy_render::view::VisibleEntities`].
pub type WithNode = With<Node>;
impl Plugin for UiPlugin { impl Plugin for UiPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.init_resource::<UiSurface>() app.init_resource::<UiSurface>()
@ -140,13 +136,13 @@ impl Plugin for UiPlugin {
.init_resource::<UiStack>() .init_resource::<UiStack>()
.register_type::<BackgroundColor>() .register_type::<BackgroundColor>()
.register_type::<CalculatedClip>() .register_type::<CalculatedClip>()
.register_type::<ComputedNode>()
.register_type::<ContentSize>() .register_type::<ContentSize>()
.register_type::<FocusPolicy>() .register_type::<FocusPolicy>()
.register_type::<Interaction>() .register_type::<Interaction>()
.register_type::<Node>() .register_type::<Node>()
.register_type::<RelativeCursorPosition>() .register_type::<RelativeCursorPosition>()
.register_type::<ScrollPosition>() .register_type::<ScrollPosition>()
.register_type::<Style>()
.register_type::<TargetCamera>() .register_type::<TargetCamera>()
.register_type::<UiImage>() .register_type::<UiImage>()
.register_type::<UiImageSize>() .register_type::<UiImageSize>()
@ -189,7 +185,7 @@ impl Plugin for UiPlugin {
app.add_systems( app.add_systems(
PostUpdate, PostUpdate,
( (
check_visibility::<WithNode>.in_set(VisibilitySystems::CheckVisibility), check_visibility::<With<Node>>.in_set(VisibilitySystems::CheckVisibility),
update_target_camera_system.in_set(UiSystem::Prepare), update_target_camera_system.in_set(UiSystem::Prepare),
ui_layout_system_config, ui_layout_system_config,
ui_stack_system ui_stack_system

View file

@ -3,8 +3,8 @@
use crate::{ use crate::{
widget::{Button, UiImageSize}, widget::{Button, UiImageSize},
BackgroundColor, BorderColor, BorderRadius, ContentSize, FocusPolicy, Interaction, BackgroundColor, BorderColor, BorderRadius, ComputedNode, ContentSize, FocusPolicy,
MaterialNode, Node, ScrollPosition, Style, UiImage, UiMaterial, ZIndex, Interaction, MaterialNode, Node, ScrollPosition, UiImage, UiMaterial, ZIndex,
}; };
use bevy_ecs::bundle::Bundle; use bevy_ecs::bundle::Bundle;
use bevy_render::view::{InheritedVisibility, ViewVisibility, Visibility}; use bevy_render::view::{InheritedVisibility, ViewVisibility, Visibility};
@ -21,11 +21,11 @@ use bevy_transform::prelude::{GlobalTransform, Transform};
note = "Use the `Node` component instead. Inserting `Node` will also insert the other components required automatically." note = "Use the `Node` component instead. Inserting `Node` will also insert the other components required automatically."
)] )]
pub struct NodeBundle { pub struct NodeBundle {
/// Describes the logical size of the node /// Controls the layout (size and position) of the node and its children
/// This also affect how the node is drawn/painted.
pub node: Node, pub node: Node,
/// Styles which control the layout (size and position) of the node and its children /// Describes the logical size of the node
/// In some cases these styles also affect how the node drawn/painted. pub computed_node: ComputedNode,
pub style: Style,
/// The background color, which serves as a "fill" for this node /// The background color, which serves as a "fill" for this node
pub background_color: BackgroundColor, pub background_color: BackgroundColor,
/// The color of the Node's border /// The color of the Node's border
@ -39,12 +39,12 @@ pub struct NodeBundle {
/// The transform of the node /// The transform of the node
/// ///
/// This component is automatically managed by the UI layout system. /// This component is automatically managed by the UI layout system.
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component. /// To alter the position of the `NodeBundle`, use the properties of the [`Node`] component.
pub transform: Transform, pub transform: Transform,
/// The global transform of the node /// The global transform of the node
/// ///
/// This component is automatically updated by the [`TransformPropagate`](`bevy_transform::TransformSystem::TransformPropagate`) systems. /// This component is automatically updated by the [`TransformPropagate`](`bevy_transform::TransformSystem::TransformPropagate`) systems.
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component. /// To alter the position of the `NodeBundle`, use the properties of the [`Node`] component.
pub global_transform: GlobalTransform, pub global_transform: GlobalTransform,
/// Describes the visibility properties of the node /// Describes the visibility properties of the node
pub visibility: Visibility, pub visibility: Visibility,
@ -70,10 +70,10 @@ pub struct NodeBundle {
)] )]
pub struct ImageBundle { pub struct ImageBundle {
/// Describes the logical size of the node /// Describes the logical size of the node
pub computed_node: ComputedNode,
/// Controls the layout (size and position) of the node and its children
/// This also affects how the node is drawn/painted.
pub node: Node, pub node: Node,
/// Styles which control the layout (size and position) of the node and its children
/// In some cases these styles also affect how the node drawn/painted.
pub style: Style,
/// The calculated size based on the given image /// The calculated size based on the given image
pub calculated_size: ContentSize, pub calculated_size: ContentSize,
/// The image of the node. /// The image of the node.
@ -93,7 +93,7 @@ pub struct ImageBundle {
/// The transform of the node /// The transform of the node
/// ///
/// This component is automatically managed by the UI layout system. /// This component is automatically managed by the UI layout system.
/// To alter the position of the `ImageBundle`, use the properties of the [`Style`] component. /// To alter the position of the `ImageBundle`, use the properties of the [`Node`] component.
pub transform: Transform, pub transform: Transform,
/// The global transform of the node /// The global transform of the node
/// ///
@ -123,12 +123,12 @@ pub struct ImageBundle {
)] )]
pub struct ButtonBundle { pub struct ButtonBundle {
/// Describes the logical size of the node /// Describes the logical size of the node
pub node: Node, pub computed_node: ComputedNode,
/// Marker component that signals this node is a button /// Marker component that signals this node is a button
pub button: Button, pub button: Button,
/// Styles which control the layout (size and position) of the node and its children /// Controls the layout (size and position) of the node and its children
/// In some cases these styles also affect how the node drawn/painted. /// Also affect how the node is drawn/painted.
pub style: Style, pub node: Node,
/// Describes whether and how the button has been interacted with by the input /// Describes whether and how the button has been interacted with by the input
pub interaction: Interaction, pub interaction: Interaction,
/// Whether this node should block interaction with lower nodes /// Whether this node should block interaction with lower nodes
@ -144,7 +144,7 @@ pub struct ButtonBundle {
/// The transform of the node /// The transform of the node
/// ///
/// This component is automatically managed by the UI layout system. /// This component is automatically managed by the UI layout system.
/// To alter the position of the `ButtonBundle`, use the properties of the [`Style`] component. /// To alter the position of the `ButtonBundle`, use the properties of the [`Node`] component.
pub transform: Transform, pub transform: Transform,
/// The global transform of the node /// The global transform of the node
/// ///
@ -164,8 +164,8 @@ impl Default for ButtonBundle {
fn default() -> Self { fn default() -> Self {
Self { Self {
node: Default::default(), node: Default::default(),
computed_node: Default::default(),
button: Default::default(), button: Default::default(),
style: Default::default(),
interaction: Default::default(), interaction: Default::default(),
focus_policy: FocusPolicy::Block, focus_policy: FocusPolicy::Block,
border_color: Default::default(), border_color: Default::default(),
@ -193,10 +193,10 @@ impl Default for ButtonBundle {
)] )]
pub struct MaterialNodeBundle<M: UiMaterial> { pub struct MaterialNodeBundle<M: UiMaterial> {
/// Describes the logical size of the node /// Describes the logical size of the node
pub computed_node: ComputedNode,
/// Controls the layout (size and position) of the node and its children
/// Also affects how the node is drawn/painted.
pub node: Node, pub node: Node,
/// Styles which control the layout (size and position) of the node and its children
/// In some cases these styles also affect how the node drawn/painted.
pub style: Style,
/// The [`UiMaterial`] used to render the node. /// The [`UiMaterial`] used to render the node.
pub material: MaterialNode<M>, pub material: MaterialNode<M>,
/// Whether this node should block interaction with lower nodes /// Whether this node should block interaction with lower nodes
@ -204,12 +204,12 @@ pub struct MaterialNodeBundle<M: UiMaterial> {
/// The transform of the node /// The transform of the node
/// ///
/// This field is automatically managed by the UI layout system. /// This field is automatically managed by the UI layout system.
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component. /// To alter the position of the `NodeBundle`, use the properties of the [`Node`] component.
pub transform: Transform, pub transform: Transform,
/// The global transform of the node /// The global transform of the node
/// ///
/// This field is automatically managed by the UI layout system. /// This field is automatically managed by the UI layout system.
/// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component. /// To alter the position of the `NodeBundle`, use the properties of the [`Node`] component.
pub global_transform: GlobalTransform, pub global_transform: GlobalTransform,
/// Describes the visibility properties of the node /// Describes the visibility properties of the node
pub visibility: Visibility, pub visibility: Visibility,
@ -225,7 +225,7 @@ impl<M: UiMaterial> Default for MaterialNodeBundle<M> {
fn default() -> Self { fn default() -> Self {
Self { Self {
node: Default::default(), node: Default::default(),
style: Default::default(), computed_node: Default::default(),
material: Default::default(), material: Default::default(),
focus_policy: Default::default(), focus_policy: Default::default(),
transform: Default::default(), transform: Default::default(),

View file

@ -48,7 +48,7 @@ impl Plugin for UiPickingBackendPlugin {
#[query_data(mutable)] #[query_data(mutable)]
pub struct NodeQuery { pub struct NodeQuery {
entity: Entity, entity: Entity,
node: &'static Node, node: &'static ComputedNode,
global_transform: &'static GlobalTransform, global_transform: &'static GlobalTransform,
picking_behavior: Option<&'static PickingBehavior>, picking_behavior: Option<&'static PickingBehavior>,
calculated_clip: Option<&'static CalculatedClip>, calculated_clip: Option<&'static CalculatedClip>,

View file

@ -1,7 +1,7 @@
use core::{hash::Hash, ops::Range}; use core::{hash::Hash, ops::Range};
use crate::{ use crate::{
BoxShadow, CalculatedClip, DefaultUiCamera, Node, RenderUiSystem, ResolvedBorderRadius, BoxShadow, CalculatedClip, ComputedNode, DefaultUiCamera, RenderUiSystem, ResolvedBorderRadius,
TargetCamera, TransparentUi, UiBoxShadowSamples, UiScale, Val, TargetCamera, TransparentUi, UiBoxShadowSamples, UiScale, Val,
}; };
use bevy_app::prelude::*; use bevy_app::prelude::*;
@ -239,7 +239,7 @@ pub fn extract_shadows(
box_shadow_query: Extract< box_shadow_query: Extract<
Query<( Query<(
Entity, Entity,
&Node, &ComputedNode,
&GlobalTransform, &GlobalTransform,
&ViewVisibility, &ViewVisibility,
&BoxShadow, &BoxShadow,

View file

@ -5,7 +5,7 @@ mod ui_material_pipeline;
pub mod ui_texture_slice_pipeline; pub mod ui_texture_slice_pipeline;
use crate::{ use crate::{
BackgroundColor, BorderColor, CalculatedClip, DefaultUiCamera, Node, Outline, BackgroundColor, BorderColor, CalculatedClip, ComputedNode, DefaultUiCamera, Outline,
ResolvedBorderRadius, TargetCamera, UiAntiAlias, UiBoxShadowSamples, UiImage, UiScale, ResolvedBorderRadius, TargetCamera, UiAntiAlias, UiBoxShadowSamples, UiImage, UiScale,
}; };
use bevy_app::prelude::*; use bevy_app::prelude::*;
@ -245,7 +245,7 @@ pub fn extract_uinode_background_colors(
uinode_query: Extract< uinode_query: Extract<
Query<( Query<(
Entity, Entity,
&Node, &ComputedNode,
&GlobalTransform, &GlobalTransform,
&ViewVisibility, &ViewVisibility,
Option<&CalculatedClip>, Option<&CalculatedClip>,
@ -309,7 +309,7 @@ pub fn extract_uinode_images(
Query< Query<
( (
Entity, Entity,
&Node, &ComputedNode,
&GlobalTransform, &GlobalTransform,
&ViewVisibility, &ViewVisibility,
Option<&CalculatedClip>, Option<&CalculatedClip>,
@ -398,7 +398,7 @@ pub fn extract_uinode_borders(
uinode_query: Extract< uinode_query: Extract<
Query<( Query<(
Entity, Entity,
&Node, &ComputedNode,
&GlobalTransform, &GlobalTransform,
&ViewVisibility, &ViewVisibility,
Option<&CalculatedClip>, Option<&CalculatedClip>,
@ -613,7 +613,7 @@ pub fn extract_text_sections(
uinode_query: Extract< uinode_query: Extract<
Query<( Query<(
Entity, Entity,
&Node, &ComputedNode,
&GlobalTransform, &GlobalTransform,
&ViewVisibility, &ViewVisibility,
Option<&CalculatedClip>, Option<&CalculatedClip>,

View file

@ -365,7 +365,7 @@ pub fn extract_ui_material_nodes<M: UiMaterial>(
uinode_query: Extract< uinode_query: Extract<
Query<( Query<(
Entity, Entity,
&Node, &ComputedNode,
&GlobalTransform, &GlobalTransform,
&MaterialNode<M>, &MaterialNode<M>,
&ViewVisibility, &ViewVisibility,

View file

@ -251,7 +251,7 @@ pub fn extract_ui_texture_slices(
slicers_query: Extract< slicers_query: Extract<
Query<( Query<(
Entity, Entity,
&Node, &ComputedNode,
&GlobalTransform, &GlobalTransform,
&ViewVisibility, &ViewVisibility,
Option<&CalculatedClip>, Option<&CalculatedClip>,

View file

@ -5,7 +5,7 @@ use bevy_utils::HashSet;
use crate::{ use crate::{
experimental::{UiChildren, UiRootNodes}, experimental::{UiChildren, UiRootNodes},
GlobalZIndex, Node, ZIndex, ComputedNode, GlobalZIndex, ZIndex,
}; };
/// The current UI stack, which contains all UI nodes ordered by their depth (back-to-front). /// The current UI stack, which contains all UI nodes ordered by their depth (back-to-front).
@ -46,10 +46,10 @@ pub fn ui_stack_system(
mut ui_stack: ResMut<UiStack>, mut ui_stack: ResMut<UiStack>,
ui_root_nodes: UiRootNodes, ui_root_nodes: UiRootNodes,
root_node_query: Query<(Entity, Option<&GlobalZIndex>, Option<&ZIndex>)>, root_node_query: Query<(Entity, Option<&GlobalZIndex>, Option<&ZIndex>)>,
zindex_global_node_query: Query<(Entity, &GlobalZIndex, Option<&ZIndex>), With<Node>>, zindex_global_node_query: Query<(Entity, &GlobalZIndex, Option<&ZIndex>), With<ComputedNode>>,
ui_children: UiChildren, ui_children: UiChildren,
zindex_query: Query<Option<&ZIndex>, (With<Node>, Without<GlobalZIndex>)>, zindex_query: Query<Option<&ZIndex>, (With<ComputedNode>, Without<GlobalZIndex>)>,
mut update_query: Query<&mut Node>, mut update_query: Query<&mut ComputedNode>,
) { ) {
ui_stack.uinodes.clear(); ui_stack.uinodes.clear();
visited_root_nodes.clear(); visited_root_nodes.clear();
@ -102,7 +102,7 @@ fn update_uistack_recursive(
cache: &mut ChildBufferCache, cache: &mut ChildBufferCache,
node_entity: Entity, node_entity: Entity,
ui_children: &UiChildren, ui_children: &UiChildren,
zindex_query: &Query<Option<&ZIndex>, (With<Node>, Without<GlobalZIndex>)>, zindex_query: &Query<Option<&ZIndex>, (With<ComputedNode>, Without<GlobalZIndex>)>,
ui_stack: &mut Vec<Entity>, ui_stack: &mut Vec<Entity>,
) { ) {
ui_stack.push(node_entity); ui_stack.push(node_entity);

View file

@ -1,5 +1,3 @@
use core::hash::Hash;
use crate::Node; use crate::Node;
use bevy_asset::{Asset, AssetId, Handle}; use bevy_asset::{Asset, AssetId, Handle};
use bevy_derive::{Deref, DerefMut}; use bevy_derive::{Deref, DerefMut};
@ -9,6 +7,7 @@ use bevy_render::{
extract_component::ExtractComponent, extract_component::ExtractComponent,
render_resource::{AsBindGroup, RenderPipelineDescriptor, ShaderRef}, render_resource::{AsBindGroup, RenderPipelineDescriptor, ShaderRef},
}; };
use core::hash::Hash;
use derive_more::derive::From; use derive_more::derive::From;
/// Materials are used alongside [`UiMaterialPlugin`](crate::UiMaterialPlugin) and [`MaterialNode`] /// Materials are used alongside [`UiMaterialPlugin`](crate::UiMaterialPlugin) and [`MaterialNode`]
@ -64,7 +63,7 @@ use derive_more::derive::From;
/// color: LinearRgba::RED, /// color: LinearRgba::RED,
/// color_texture: asset_server.load("some_image.png"), /// color_texture: asset_server.load("some_image.png"),
/// })), /// })),
/// Style { /// Node {
/// width: Val::Percent(100.0), /// width: Val::Percent(100.0),
/// ..Default::default() /// ..Default::default()
/// }, /// },

View file

@ -17,29 +17,10 @@ use core::num::NonZero;
use derive_more::derive::{Display, Error, From}; use derive_more::derive::{Display, Error, From};
use smallvec::SmallVec; use smallvec::SmallVec;
/// Base component for a UI node, which also provides the computed size of the node. /// Provides the computed size and layout properties of the node.
///
/// # See also
///
/// - [`node_bundles`](crate::node_bundles) for the list of built-in bundles that set up UI node
/// - [`RelativeCursorPosition`](crate::RelativeCursorPosition)
/// to obtain the cursor position relative to this node
/// - [`Interaction`](crate::Interaction) to obtain the interaction state of this node
#[derive(Component, Debug, Copy, Clone, PartialEq, Reflect)] #[derive(Component, Debug, Copy, Clone, PartialEq, Reflect)]
#[reflect(Component, Default, Debug)] #[reflect(Component, Default, Debug)]
#[require( pub struct ComputedNode {
Style,
BackgroundColor,
BorderColor,
BorderRadius,
ContentSize,
FocusPolicy,
ScrollPosition,
Transform,
Visibility,
ZIndex
)]
pub struct Node {
/// The order of the node in the UI layout. /// The order of the node in the UI layout.
/// Nodes with a higher stack index are drawn on top of and receive interactions before nodes with lower stack indices. /// Nodes with a higher stack index are drawn on top of and receive interactions before nodes with lower stack indices.
pub(crate) stack_index: u32, pub(crate) stack_index: u32,
@ -79,7 +60,7 @@ pub struct Node {
pub(crate) padding: BorderRect, pub(crate) padding: BorderRect,
} }
impl Node { impl ComputedNode {
/// The calculated node size as width and height in logical pixels. /// The calculated node size as width and height in logical pixels.
/// ///
/// Automatically calculated by [`super::layout::ui_layout_system`]. /// Automatically calculated by [`super::layout::ui_layout_system`].
@ -215,7 +196,7 @@ impl Node {
} }
} }
impl Node { impl ComputedNode {
pub const DEFAULT: Self = Self { pub const DEFAULT: Self = Self {
stack_index: 0, stack_index: 0,
calculated_size: Vec2::ZERO, calculated_size: Vec2::ZERO,
@ -228,7 +209,7 @@ impl Node {
}; };
} }
impl Default for Node { impl Default for ComputedNode {
fn default() -> Self { fn default() -> Self {
Self::DEFAULT Self::DEFAULT
} }
@ -238,7 +219,7 @@ impl Default for Node {
/// ///
/// Updating the values of `ScrollPosition` will reposition the children of the node by the offset amount. /// Updating the values of `ScrollPosition` will reposition the children of the node by the offset amount.
/// `ScrollPosition` may be updated by the layout system when a layout change makes a previously valid `ScrollPosition` invalid. /// `ScrollPosition` may be updated by the layout system when a layout change makes a previously valid `ScrollPosition` invalid.
/// Changing this does nothing on a `Node` without a `Style` setting at least one `OverflowAxis` to `OverflowAxis::Scroll`. /// Changing this does nothing on a `Node` without setting at least one `OverflowAxis` to `OverflowAxis::Scroll`.
#[derive(Component, Debug, Clone, Reflect)] #[derive(Component, Debug, Clone, Reflect)]
#[reflect(Component, Default)] #[reflect(Component, Default)]
pub struct ScrollPosition { pub struct ScrollPosition {
@ -276,7 +257,9 @@ impl From<&Vec2> for ScrollPosition {
} }
} }
/// Describes the style of a UI container node /// The base component for UI entities. It describes UI layout and style properties.
///
/// When defining new types of UI entities, require [`Node`] to make them behave like UI nodes.
/// ///
/// Nodes can be laid out using either Flexbox or CSS Grid Layout. /// Nodes can be laid out using either Flexbox or CSS Grid Layout.
/// ///
@ -293,15 +276,32 @@ impl From<&Vec2> for ScrollPosition {
/// - [MDN: Basic Concepts of Grid Layout](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout) /// - [MDN: Basic Concepts of Grid Layout](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout)
/// - [A Complete Guide To CSS Grid](https://css-tricks.com/snippets/css/complete-guide-grid/) by CSS Tricks. This is detailed guide with illustrations and comprehensive written explanation of the different CSS Grid properties and how they work. /// - [A Complete Guide To CSS Grid](https://css-tricks.com/snippets/css/complete-guide-grid/) by CSS Tricks. This is detailed guide with illustrations and comprehensive written explanation of the different CSS Grid properties and how they work.
/// - [CSS Grid Garden](https://cssgridgarden.com/). An interactive tutorial/game that teaches the essential parts of CSS Grid in a fun engaging way. /// - [CSS Grid Garden](https://cssgridgarden.com/). An interactive tutorial/game that teaches the essential parts of CSS Grid in a fun engaging way.
///
/// # See also
///
/// - [`RelativeCursorPosition`](crate::RelativeCursorPosition) to obtain the cursor position relative to this node
/// - [`Interaction`](crate::Interaction) to obtain the interaction state of this node
#[derive(Component, Clone, PartialEq, Debug, Reflect)] #[derive(Component, Clone, PartialEq, Debug, Reflect)]
#[require(
ComputedNode,
BackgroundColor,
BorderColor,
BorderRadius,
ContentSize,
FocusPolicy,
ScrollPosition,
Transform,
Visibility,
ZIndex
)]
#[reflect(Component, Default, PartialEq, Debug)] #[reflect(Component, Default, PartialEq, Debug)]
#[cfg_attr( #[cfg_attr(
feature = "serialize", feature = "serialize",
derive(serde::Serialize, serde::Deserialize), derive(serde::Serialize, serde::Deserialize),
reflect(Serialize, Deserialize) reflect(Serialize, Deserialize)
)] )]
pub struct Style { pub struct Node {
/// Which layout algorithm to use when laying out this node's contents: /// Which layout algorithm to use when laying out this node's contents:
/// - [`Display::Flex`]: Use the Flexbox layout algorithm /// - [`Display::Flex`]: Use the Flexbox layout algorithm
/// - [`Display::Grid`]: Use the CSS Grid layout algorithm /// - [`Display::Grid`]: Use the CSS Grid layout algorithm
@ -446,8 +446,8 @@ pub struct Style {
/// ///
/// # Example /// # Example
/// ``` /// ```
/// # use bevy_ui::{Style, UiRect, Val}; /// # use bevy_ui::{Node, UiRect, Val};
/// let style = Style { /// let node = Node {
/// margin: UiRect { /// margin: UiRect {
/// left: Val::Percent(10.), /// left: Val::Percent(10.),
/// right: Val::Percent(10.), /// right: Val::Percent(10.),
@ -468,8 +468,8 @@ pub struct Style {
/// ///
/// # Example /// # Example
/// ``` /// ```
/// # use bevy_ui::{Style, UiRect, Val}; /// # use bevy_ui::{Node, UiRect, Val};
/// let style = Style { /// let node = Node {
/// padding: UiRect { /// padding: UiRect {
/// left: Val::Percent(1.), /// left: Val::Percent(1.),
/// right: Val::Percent(2.), /// right: Val::Percent(2.),
@ -574,7 +574,7 @@ pub struct Style {
pub grid_column: GridPlacement, pub grid_column: GridPlacement,
} }
impl Style { impl Node {
pub const DEFAULT: Self = Self { pub const DEFAULT: Self = Self {
display: Display::DEFAULT, display: Display::DEFAULT,
position_type: PositionType::DEFAULT, position_type: PositionType::DEFAULT,
@ -617,7 +617,7 @@ impl Style {
}; };
} }
impl Default for Style { impl Default for Node {
fn default() -> Self { fn default() -> Self {
Self::DEFAULT Self::DEFAULT
} }
@ -879,7 +879,7 @@ impl Default for JustifyContent {
/// Defines the layout model used by this node. /// Defines the layout model used by this node.
/// ///
/// Part of the [`Style`] component. /// Part of the [`Node`] component.
#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
#[reflect(Default, PartialEq)] #[reflect(Default, PartialEq)]
#[cfg_attr( #[cfg_attr(
@ -1976,8 +1976,7 @@ impl Default for BorderColor {
/// # use bevy_color::palettes::basic::{RED, BLUE}; /// # use bevy_color::palettes::basic::{RED, BLUE};
/// fn setup_ui(mut commands: Commands) { /// fn setup_ui(mut commands: Commands) {
/// commands.spawn(( /// commands.spawn((
/// Node::default(), /// Node {
/// Style {
/// width: Val::Px(100.), /// width: Val::Px(100.),
/// height: Val::Px(100.), /// height: Val::Px(100.),
/// ..Default::default() /// ..Default::default()
@ -2192,8 +2191,7 @@ pub struct GlobalZIndex(pub i32);
/// # use bevy_color::palettes::basic::{BLUE}; /// # use bevy_color::palettes::basic::{BLUE};
/// fn setup_ui(mut commands: Commands) { /// fn setup_ui(mut commands: Commands) {
/// commands.spawn(( /// commands.spawn((
/// Node::default(), /// Node {
/// Style {
/// width: Val::Px(100.), /// width: Val::Px(100.),
/// height: Val::Px(100.), /// height: Val::Px(100.),
/// border: UiRect::all(Val::Px(2.)), /// border: UiRect::all(Val::Px(2.)),

View file

@ -2,10 +2,10 @@
use crate::{ use crate::{
experimental::{UiChildren, UiRootNodes}, experimental::{UiChildren, UiRootNodes},
CalculatedClip, Display, OverflowAxis, Style, TargetCamera, CalculatedClip, Display, Node, OverflowAxis, TargetCamera,
}; };
use super::Node; use super::ComputedNode;
use bevy_ecs::{ use bevy_ecs::{
entity::Entity, entity::Entity,
query::{Changed, With}, query::{Changed, With},
@ -20,7 +20,12 @@ use bevy_utils::HashSet;
pub fn update_clipping_system( pub fn update_clipping_system(
mut commands: Commands, mut commands: Commands,
root_nodes: UiRootNodes, root_nodes: UiRootNodes,
mut node_query: Query<(&Node, &GlobalTransform, &Style, Option<&mut CalculatedClip>)>, mut node_query: Query<(
&Node,
&ComputedNode,
&GlobalTransform,
Option<&mut CalculatedClip>,
)>,
ui_children: UiChildren, ui_children: UiChildren,
) { ) {
for root_node in root_nodes.iter() { for root_node in root_nodes.iter() {
@ -37,17 +42,23 @@ pub fn update_clipping_system(
fn update_clipping( fn update_clipping(
commands: &mut Commands, commands: &mut Commands,
ui_children: &UiChildren, ui_children: &UiChildren,
node_query: &mut Query<(&Node, &GlobalTransform, &Style, Option<&mut CalculatedClip>)>, node_query: &mut Query<(
&Node,
&ComputedNode,
&GlobalTransform,
Option<&mut CalculatedClip>,
)>,
entity: Entity, entity: Entity,
mut maybe_inherited_clip: Option<Rect>, mut maybe_inherited_clip: Option<Rect>,
) { ) {
let Ok((node, global_transform, style, maybe_calculated_clip)) = node_query.get_mut(entity) let Ok((node, computed_node, global_transform, maybe_calculated_clip)) =
node_query.get_mut(entity)
else { else {
return; return;
}; };
// If `display` is None, clip the entire node and all its descendants by replacing the inherited clip with a default rect (which is empty) // If `display` is None, clip the entire node and all its descendants by replacing the inherited clip with a default rect (which is empty)
if style.display == Display::None { if node.display == Display::None {
maybe_inherited_clip = Some(Rect::default()); maybe_inherited_clip = Some(Rect::default());
} }
@ -72,7 +83,7 @@ fn update_clipping(
} }
// Calculate new clip rectangle for children nodes // Calculate new clip rectangle for children nodes
let children_clip = if style.overflow.is_visible() { let children_clip = if node.overflow.is_visible() {
// When `Visible`, children might be visible even when they are outside // When `Visible`, children might be visible even when they are outside
// the current node's boundaries. In this case they inherit the current // the current node's boundaries. In this case they inherit the current
// node's parent clip. If an ancestor is set as `Hidden`, that clip will // node's parent clip. If an ancestor is set as `Hidden`, that clip will
@ -84,17 +95,19 @@ fn update_clipping(
// of nested `Overflow::Hidden` nodes. If parent `clip` is not // of nested `Overflow::Hidden` nodes. If parent `clip` is not
// defined, use the current node's clip. // defined, use the current node's clip.
let mut clip_rect = let mut clip_rect = Rect::from_center_size(
Rect::from_center_size(global_transform.translation().truncate(), node.size()); global_transform.translation().truncate(),
computed_node.size(),
);
// Content isn't clipped at the edges of the node but at the edges of the region specified by [`Style::overflow_clip_margin`]. // Content isn't clipped at the edges of the node but at the edges of the region specified by [`Node::overflow_clip_margin`].
// //
// `clip_inset` should always fit inside `node_rect`. // `clip_inset` should always fit inside `node_rect`.
// Even if `clip_inset` were to overflow, we won't return a degenerate result as `Rect::intersect` will clamp the intersection, leaving it empty. // Even if `clip_inset` were to overflow, we won't return a degenerate result as `Rect::intersect` will clamp the intersection, leaving it empty.
let clip_inset = match style.overflow_clip_margin.visual_box { let clip_inset = match node.overflow_clip_margin.visual_box {
crate::OverflowClipBox::BorderBox => BorderRect::ZERO, crate::OverflowClipBox::BorderBox => BorderRect::ZERO,
crate::OverflowClipBox::ContentBox => node.content_inset(), crate::OverflowClipBox::ContentBox => computed_node.content_inset(),
crate::OverflowClipBox::PaddingBox => node.border(), crate::OverflowClipBox::PaddingBox => computed_node.border(),
}; };
clip_rect.min.x += clip_inset.left; clip_rect.min.x += clip_inset.left;
@ -102,13 +115,13 @@ fn update_clipping(
clip_rect.max.x -= clip_inset.right; clip_rect.max.x -= clip_inset.right;
clip_rect.max.y -= clip_inset.bottom; clip_rect.max.y -= clip_inset.bottom;
clip_rect = clip_rect.inflate(style.overflow_clip_margin.margin.max(0.)); clip_rect = clip_rect.inflate(node.overflow_clip_margin.margin.max(0.));
if style.overflow.x == OverflowAxis::Visible { if node.overflow.x == OverflowAxis::Visible {
clip_rect.min.x = -f32::INFINITY; clip_rect.min.x = -f32::INFINITY;
clip_rect.max.x = f32::INFINITY; clip_rect.max.x = f32::INFINITY;
} }
if style.overflow.y == OverflowAxis::Visible { if node.overflow.y == OverflowAxis::Visible {
clip_rect.min.y = -f32::INFINITY; clip_rect.min.y = -f32::INFINITY;
clip_rect.max.y = f32::INFINITY; clip_rect.max.y = f32::INFINITY;
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
ContentSize, DefaultUiCamera, FixedMeasure, Measure, MeasureArgs, Node, NodeMeasure, ComputedNode, ContentSize, DefaultUiCamera, FixedMeasure, Measure, MeasureArgs, Node,
TargetCamera, UiScale, NodeMeasure, TargetCamera, UiScale,
}; };
use bevy_asset::Assets; use bevy_asset::Assets;
use bevy_color::Color; use bevy_color::Color;
@ -102,7 +102,7 @@ pub struct TextBundle {}
/// ``` /// ```
#[derive(Component, Debug, Default, Clone, Deref, DerefMut, Reflect)] #[derive(Component, Debug, Default, Clone, Deref, DerefMut, Reflect)]
#[reflect(Component, Default, Debug)] #[reflect(Component, Default, Debug)]
#[require(TextLayout, TextFont, TextColor, TextNodeFlags, Node)] #[require(Node, TextLayout, TextFont, TextColor, TextNodeFlags)]
pub struct Text(pub String); pub struct Text(pub String);
impl Text { impl Text {
@ -331,7 +331,7 @@ fn queue_text(
scale_factor: f32, scale_factor: f32,
inverse_scale_factor: f32, inverse_scale_factor: f32,
block: &TextLayout, block: &TextLayout,
node: Ref<Node>, node: Ref<ComputedNode>,
mut text_flags: Mut<TextNodeFlags>, mut text_flags: Mut<TextNodeFlags>,
text_layout_info: Mut<TextLayoutInfo>, text_layout_info: Mut<TextLayoutInfo>,
computed: &mut ComputedTextBlock, computed: &mut ComputedTextBlock,
@ -408,7 +408,7 @@ pub fn text_system(
mut text_pipeline: ResMut<TextPipeline>, mut text_pipeline: ResMut<TextPipeline>,
mut text_query: Query<( mut text_query: Query<(
Entity, Entity,
Ref<Node>, Ref<ComputedNode>,
&TextLayout, &TextLayout,
&mut TextLayoutInfo, &mut TextLayoutInfo,
&mut TextNodeFlags, &mut TextNodeFlags,

View file

@ -66,7 +66,7 @@ fn setup(
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
commands.spawn(( commands.spawn((
Text::new("Press space to toggle wireframes"), Text::new("Press space to toggle wireframes"),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -59,7 +59,7 @@ fn setup(
// UI // UI
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -254,7 +254,7 @@ fn setup(mut commands: Commands) {
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -135,7 +135,7 @@ fn setup(
// create a minimal UI explaining how to interact with the example // create a minimal UI explaining how to interact with the example
commands.spawn(( commands.spawn((
Text::new("Left Arrow Key: Animate Left Sprite\nRight Arrow Key: Animate Right Sprite"), Text::new("Left Arrow Key: Animate Left Sprite\nRight Arrow Key: Animate Right Sprite"),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -90,7 +90,7 @@ fn setup(
// Text used to show controls // Text used to show controls
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -135,7 +135,7 @@ fn setup(
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
commands.spawn(( commands.spawn((
Text::new("Press space to toggle wireframes"), Text::new("Press space to toggle wireframes"),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -83,7 +83,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, app_status: Res
fn spawn_text(commands: &mut Commands, app_status: &AppStatus) { fn spawn_text(commands: &mut Commands, app_status: &AppStatus) {
commands.spawn(( commands.spawn((
app_status.create_help_text(), app_status.create_help_text(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -328,7 +328,7 @@ fn setup(
// example instructions // example instructions
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -86,7 +86,7 @@ fn setup_terrain_scene(
fn setup_instructions(mut commands: Commands) { fn setup_instructions(mut commands: Commands) {
commands.spawn((Text::new("Press Spacebar to Toggle Atmospheric Fog.\nPress S to Toggle Directional Light Fog Influence."), commands.spawn((Text::new("Press Spacebar to Toggle Atmospheric Fog.\nPress S to Toggle Directional Light Fog Influence."),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -119,17 +119,17 @@ fn setup(
texture: metering_mask, texture: metering_mask,
..default() ..default()
}, },
Style { Node {
width: Val::Percent(100.0), width: Val::Percent(100.0),
height: Val::Percent(100.0), height: Val::Percent(100.0),
..default() ..default()
}, },
)); ));
let text_style = TextFont::default(); let text_font = TextFont::default();
commands.spawn((Text::new("Left / Right - Rotate Camera\nC - Toggle Compensation Curve\nM - Toggle Metering Mask\nV - Visualize Metering Mask"), commands.spawn((Text::new("Left / Right - Rotate Camera\nC - Toggle Compensation Curve\nM - Toggle Metering Mask\nV - Visualize Metering Mask"),
text_style.clone(), Style { text_font.clone(), Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),
@ -139,8 +139,8 @@ fn setup(
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
text_style, text_font,
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
right: Val::Px(12.0), right: Val::Px(12.0),
@ -162,7 +162,7 @@ struct ExampleResources {
fn example_control_system( fn example_control_system(
camera: Single<(&mut Transform, &mut AutoExposure), With<Camera3d>>, camera: Single<(&mut Transform, &mut AutoExposure), With<Camera3d>>,
mut display: Single<&mut Text, With<ExampleDisplay>>, mut display: Single<&mut Text, With<ExampleDisplay>>,
mut mask_image: Single<&mut Style, With<UiImage>>, mut mask_image: Single<&mut Node, With<UiImage>>,
time: Res<Time>, time: Res<Time>,
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
resources: Res<ExampleResources>, resources: Res<ExampleResources>,

View file

@ -169,7 +169,7 @@ fn setup(
commands.spawn((Text::new("Up / Down — Increase / Decrease Alpha\nLeft / Right — Rotate Camera\nH - Toggle HDR\nSpacebar — Toggle Unlit\nC — Randomize Colors"), commands.spawn((Text::new("Up / Down — Increase / Decrease Alpha\nLeft / Right — Rotate Camera\nH - Toggle HDR\nSpacebar — Toggle Unlit\nC — Randomize Colors"),
text_style.clone(), text_style.clone(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),
@ -180,7 +180,7 @@ fn setup(
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
text_style, text_style,
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
right: Val::Px(12.0), right: Val::Px(12.0),
@ -192,8 +192,7 @@ fn setup(
let mut label = |entity: Entity, label: &str| { let mut label = |entity: Entity, label: &str| {
commands commands
.spawn(( .spawn((
Node::default(), Node {
Style {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
..default() ..default()
}, },
@ -203,7 +202,7 @@ fn setup(
parent.spawn(( parent.spawn((
Text::new(label), Text::new(label),
label_text_style.clone(), label_text_style.clone(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::ZERO, bottom: Val::ZERO,
..default() ..default()
@ -253,7 +252,7 @@ fn example_control_system(
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
controllable: Query<(&MeshMaterial3d<StandardMaterial>, &ExampleControls)>, controllable: Query<(&MeshMaterial3d<StandardMaterial>, &ExampleControls)>,
camera: Single<(&mut Camera, &mut Transform, &GlobalTransform), With<Camera3d>>, camera: Single<(&mut Camera, &mut Transform, &GlobalTransform), With<Camera3d>>,
mut labels: Query<(&mut Style, &ExampleLabel)>, mut labels: Query<(&mut Node, &ExampleLabel)>,
mut display: Single<&mut Text, With<ExampleDisplay>>, mut display: Single<&mut Text, With<ExampleDisplay>>,
labelled: Query<&GlobalTransform>, labelled: Query<&GlobalTransform>,
mut state: Local<ExampleState>, mut state: Local<ExampleState>,
@ -308,15 +307,15 @@ fn example_control_system(
camera_transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(rotation)); camera_transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(rotation));
for (mut style, label) in &mut labels { for (mut node, label) in &mut labels {
let world_position = labelled.get(label.entity).unwrap().translation() + Vec3::Y; let world_position = labelled.get(label.entity).unwrap().translation() + Vec3::Y;
let viewport_position = camera let viewport_position = camera
.world_to_viewport(camera_global_transform, world_position) .world_to_viewport(camera_global_transform, world_position)
.unwrap(); .unwrap();
style.top = Val::Px(viewport_position.y); node.top = Val::Px(viewport_position.y);
style.left = Val::Px(viewport_position.x); node.left = Val::Px(viewport_position.x);
} }
display.0 = format!( display.0 = format!(

View file

@ -86,7 +86,7 @@ fn setup_scene(
// example instructions // example instructions
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -219,7 +219,7 @@ fn spawn_camera(commands: &mut Commands, asset_server: &AssetServer) {
fn spawn_text(commands: &mut Commands, light_mode: &LightMode) { fn spawn_text(commands: &mut Commands, light_mode: &LightMode) {
commands.spawn(( commands.spawn((
light_mode.create_help_text(), light_mode.create_help_text(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -138,17 +138,14 @@ fn setup(
fn add_buttons(commands: &mut Commands, font: &Handle<Font>, color_grading: &ColorGrading) { fn add_buttons(commands: &mut Commands, font: &Handle<Font>, color_grading: &ColorGrading) {
// Spawn the parent node that contains all the buttons. // Spawn the parent node that contains all the buttons.
commands commands
.spawn(( .spawn(Node {
Node::default(), flex_direction: FlexDirection::Column,
Style { position_type: PositionType::Absolute,
flex_direction: FlexDirection::Column, row_gap: Val::Px(6.0),
position_type: PositionType::Absolute, left: Val::Px(12.0),
row_gap: Val::Px(6.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), ..default()
bottom: Val::Px(12.0), })
..default()
},
))
.with_children(|parent| { .with_children(|parent| {
// Create the first row, which contains the global controls. // Create the first row, which contains the global controls.
add_buttons_for_global_controls(parent, color_grading, font); add_buttons_for_global_controls(parent, color_grading, font);
@ -174,13 +171,10 @@ fn add_buttons_for_global_controls(
// Add the parent node for the row. // Add the parent node for the row.
parent.spawn(Node::default()).with_children(|parent| { parent.spawn(Node::default()).with_children(|parent| {
// Add some placeholder text to fill this column. // Add some placeholder text to fill this column.
parent.spawn(( parent.spawn(Node {
Node::default(), width: Val::Px(125.0),
Style { ..default()
width: Val::Px(125.0), });
..default()
},
));
// Add each global color grading option button. // Add each global color grading option button.
for option in [ for option in [
@ -209,16 +203,13 @@ fn add_buttons_for_section(
) { ) {
// Spawn the row container. // Spawn the row container.
parent parent
.spawn(( .spawn(Node {
Node::default(), align_items: AlignItems::Center,
Style { ..default()
align_items: AlignItems::Center, })
..default()
},
))
.with_children(|parent| { .with_children(|parent| {
// Spawn the label ("Highlights", etc.) // Spawn the label ("Highlights", etc.)
add_text(parent, &section.to_string(), font, Color::WHITE).insert(Style { add_text(parent, &section.to_string(), font, Color::WHITE).insert(Node {
width: Val::Px(125.0), width: Val::Px(125.0),
..default() ..default()
}); });
@ -252,7 +243,7 @@ fn add_button_for_value(
parent parent
.spawn(( .spawn((
Button, Button,
Style { Node {
border: UiRect::all(Val::Px(1.0)), border: UiRect::all(Val::Px(1.0)),
width: Val::Px(200.0), width: Val::Px(200.0),
justify_content: JustifyContent::Center, justify_content: JustifyContent::Center,
@ -281,13 +272,10 @@ fn add_button_for_value(
}); });
// Add a spacer. // Add a spacer.
parent.spawn(( parent.spawn(Node {
Node::default(), flex_grow: 1.0,
Style { ..default()
flex_grow: 1.0, });
..default()
},
));
// Add the value text. // Add the value text.
add_text( add_text(
@ -315,7 +303,7 @@ fn add_help_text(
font: font.clone(), font: font.clone(),
..default() ..default()
}, },
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
left: Val::Px(12.0), left: Val::Px(12.0),
top: Val::Px(12.0), top: Val::Px(12.0),

View file

@ -190,7 +190,7 @@ fn setup(
// Example instructions // Example instructions
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -94,7 +94,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, app_settings: R
// Spawn the help text. // Spawn the help text.
commands.spawn(( commands.spawn((
create_text(&app_settings), create_text(&app_settings),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -118,7 +118,7 @@ fn setup_pyramid_scene(
fn setup_instructions(mut commands: Commands) { fn setup_instructions(mut commands: Commands) {
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -59,7 +59,7 @@ fn setup(
// Text to describe the controls. // Text to describe the controls.
commands.spawn(( commands.spawn((
Text::new("Controls:\nSpace: Change UVs\nX/Y/Z: Rotate\nR: Reset orientation"), Text::new("Controls:\nSpace: Change UVs\nX/Y/Z: Rotate\nR: Reset orientation"),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -290,7 +290,7 @@ fn spawn_fox(commands: &mut Commands, assets: &ExampleAssets) {
fn spawn_text(commands: &mut Commands, app_status: &AppStatus) { fn spawn_text(commands: &mut Commands, app_status: &AppStatus) {
commands.spawn(( commands.spawn((
app_status.create_text(), app_status.create_text(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -211,7 +211,7 @@ fn setup(
commands commands
.spawn(( .spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -39,7 +39,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
font_size: 15., font_size: 15.,
..default() ..default()
}, },
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -234,7 +234,7 @@ fn setup_ui(mut commands: Commands) {
commands commands
.spawn(( .spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -53,7 +53,7 @@ fn setup(
commands commands
.spawn(( .spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -298,7 +298,7 @@ fn setup(
commands commands
.spawn(( .spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -65,7 +65,7 @@ fn setup(
font_size: 30.0, font_size: 30.0,
..default() ..default()
}, },
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(20.0), top: Val::Px(20.0),
left: Val::Px(100.0), left: Val::Px(100.0),
@ -79,7 +79,7 @@ fn setup(
font_size: 30.0, font_size: 30.0,
..default() ..default()
}, },
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(130.0), top: Val::Px(130.0),
right: Val::ZERO, right: Val::ZERO,
@ -97,7 +97,7 @@ fn setup(
font_size: 30.0, font_size: 30.0,
..default() ..default()
}, },
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(20.0), bottom: Val::Px(20.0),
right: Val::Px(20.0), right: Val::Px(20.0),

View file

@ -209,7 +209,7 @@ fn spawn_gltf_scene(commands: &mut Commands, asset_server: &AssetServer) {
/// Spawns all the buttons at the bottom of the screen. /// Spawns all the buttons at the bottom of the screen.
fn spawn_buttons(commands: &mut Commands) { fn spawn_buttons(commands: &mut Commands) {
commands commands
.spawn((Node::default(), widgets::main_ui_style())) .spawn(widgets::main_ui_node())
.with_children(|parent| { .with_children(|parent| {
widgets::spawn_option_buttons( widgets::spawn_option_buttons(
parent, parent,

View file

@ -124,7 +124,7 @@ fn spawn_scene(commands: &mut Commands, asset_server: &AssetServer) {
fn spawn_text(commands: &mut Commands, app_settings: &AppSettings) { fn spawn_text(commands: &mut Commands, app_settings: &AppSettings) {
commands.spawn(( commands.spawn((
create_help_text(app_settings), create_help_text(app_settings),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -154,7 +154,7 @@ fn spawn_text(commands: &mut Commands, app_status: &AppStatus) {
// Create the text. // Create the text.
commands.spawn(( commands.spawn((
app_status.create_text(), app_status.create_text(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -98,8 +98,7 @@ fn setup(
commands commands
.spawn(( .spawn((
Node::default(), Node {
Style {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
padding: UiRect::all(Val::Px(5.0)), padding: UiRect::all(Val::Px(5.0)),
..default() ..default()

View file

@ -85,8 +85,7 @@ fn setup(
commands commands
.spawn(( .spawn((
TargetCamera(camera), TargetCamera(camera),
Node::default(), Node {
Style {
width: Val::Percent(100.), width: Val::Percent(100.),
height: Val::Percent(100.), height: Val::Percent(100.),
..default() ..default()
@ -95,7 +94,7 @@ fn setup(
.with_children(|parent| { .with_children(|parent| {
parent.spawn(( parent.spawn((
Text::new(*camera_name), Text::new(*camera_name),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.), top: Val::Px(12.),
left: Val::Px(12.), left: Val::Px(12.),
@ -108,20 +107,17 @@ fn setup(
fn buttons_panel(parent: &mut ChildBuilder) { fn buttons_panel(parent: &mut ChildBuilder) {
parent parent
.spawn(( .spawn(Node {
Node::default(), position_type: PositionType::Absolute,
Style { width: Val::Percent(100.),
position_type: PositionType::Absolute, height: Val::Percent(100.),
width: Val::Percent(100.), display: Display::Flex,
height: Val::Percent(100.), flex_direction: FlexDirection::Row,
display: Display::Flex, justify_content: JustifyContent::SpaceBetween,
flex_direction: FlexDirection::Row, align_items: AlignItems::Center,
justify_content: JustifyContent::SpaceBetween, padding: UiRect::all(Val::Px(20.)),
align_items: AlignItems::Center, ..default()
padding: UiRect::all(Val::Px(20.)), })
..default()
},
))
.with_children(|parent| { .with_children(|parent| {
rotate_button(parent, "<", Direction::Left); rotate_button(parent, "<", Direction::Left);
rotate_button(parent, ">", Direction::Right); rotate_button(parent, ">", Direction::Right);
@ -133,7 +129,7 @@ fn setup(
.spawn(( .spawn((
RotateCamera(direction), RotateCamera(direction),
Button, Button,
Style { Node {
width: Val::Px(40.), width: Val::Px(40.),
height: Val::Px(40.), height: Val::Px(40.),
border: UiRect::all(Val::Px(2.)), border: UiRect::all(Val::Px(2.)),

View file

@ -128,7 +128,7 @@ fn setup(
commands.spawn(( commands.spawn((
Text::new(INSTRUCTIONS), Text::new(INSTRUCTIONS),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -80,7 +80,7 @@ fn setup(
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -253,7 +253,7 @@ fn spawn_camera(commands: &mut Commands, asset_server: &AssetServer) {
fn spawn_text(commands: &mut Commands, app_settings: &AppSettings) { fn spawn_text(commands: &mut Commands, app_settings: &AppSettings) {
commands.spawn(( commands.spawn((
create_text(app_settings), create_text(app_settings),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -83,7 +83,7 @@ fn setup(
// ui // ui
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),
@ -178,7 +178,7 @@ fn setup_image_viewer_scene(
}, },
TextColor(Color::BLACK), TextColor(Color::BLACK),
TextLayout::new_with_justify(JustifyText::Center), TextLayout::new_with_justify(JustifyText::Center),
Style { Node {
align_self: AlignSelf::Center, align_self: AlignSelf::Center,
margin: UiRect::all(Val::Auto), margin: UiRect::all(Val::Auto),
..default() ..default()

View file

@ -333,7 +333,7 @@ fn setup(
// Controls Text // Controls Text
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -151,7 +151,7 @@ fn setup(
// Create the text. // Create the text.
commands.spawn(( commands.spawn((
app_status.create_text(), app_status.create_text(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -125,7 +125,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, app_settings: R
// Add the help text. // Add the help text.
commands.spawn(( commands.spawn((
create_text(&app_settings), create_text(&app_settings),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -101,7 +101,7 @@ fn setup(
// Text used to show controls // Text used to show controls
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -151,9 +151,8 @@ fn setup(
// text to be animated. // text to be animated.
commands commands
.spawn(( .spawn((
Node::default(),
// Cover the whole screen, and center contents. // Cover the whole screen, and center contents.
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(0.0), top: Val::Px(0.0),
left: Val::Px(0.0), left: Val::Px(0.0),
@ -163,9 +162,9 @@ fn setup(
align_items: AlignItems::Center, align_items: AlignItems::Center,
..default() ..default()
}, },
animation_player,
AnimationGraphHandle(animation_graph),
)) ))
.insert(animation_player)
.insert(AnimationGraphHandle(animation_graph))
.with_children(|builder| { .with_children(|builder| {
// Build the text node. // Build the text node.
let player = builder.parent_entity(); let player = builder.parent_entity();

View file

@ -252,7 +252,7 @@ fn setup_scene(
fn setup_help_text(commands: &mut Commands) { fn setup_help_text(commands: &mut Commands) {
commands.spawn(( commands.spawn((
Text::new(HELP_TEXT), Text::new(HELP_TEXT),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),
@ -283,8 +283,7 @@ fn setup_node_rects(commands: &mut Commands) {
let container = { let container = {
let mut container = commands.spawn(( let mut container = commands.spawn((
Node::default(), Node {
Style {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(node_rect.bottom), bottom: Val::Px(node_rect.bottom),
left: Val::Px(node_rect.left), left: Val::Px(node_rect.left),
@ -315,8 +314,7 @@ fn setup_node_rects(commands: &mut Commands) {
if let NodeType::Clip(_) = node_type { if let NodeType::Clip(_) = node_type {
let background = commands let background = commands
.spawn(( .spawn((
Node::default(), Node {
Style {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(0.), top: Val::Px(0.),
left: Val::Px(0.), left: Val::Px(0.),
@ -342,8 +340,7 @@ fn setup_node_rects(commands: &mut Commands) {
fn setup_node_lines(commands: &mut Commands) { fn setup_node_lines(commands: &mut Commands) {
for line in &HORIZONTAL_LINES { for line in &HORIZONTAL_LINES {
commands.spawn(( commands.spawn((
Node::default(), Node {
Style {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(line.bottom), bottom: Val::Px(line.bottom),
left: Val::Px(line.left), left: Val::Px(line.left),
@ -358,8 +355,7 @@ fn setup_node_lines(commands: &mut Commands) {
for line in &VERTICAL_LINES { for line in &VERTICAL_LINES {
commands.spawn(( commands.spawn((
Node::default(), Node {
Style {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(line.bottom), bottom: Val::Px(line.bottom),
left: Val::Px(line.left), left: Val::Px(line.left),
@ -421,7 +417,7 @@ fn handle_weight_drag(
// Updates the UI based on the weights that the user has chosen. // Updates the UI based on the weights that the user has chosen.
fn update_ui( fn update_ui(
mut text_query: Query<&mut Text>, mut text_query: Query<&mut Text>,
mut background_query: Query<&mut Style, Without<Text>>, mut background_query: Query<&mut Node, Without<Text>>,
container_query: Query<(&Children, &ClipNode)>, container_query: Query<(&Children, &ClipNode)>,
animation_weights_query: Query<&ExampleAnimationWeights, Changed<ExampleAnimationWeights>>, animation_weights_query: Query<&ExampleAnimationWeights, Changed<ExampleAnimationWeights>>,
) { ) {
@ -429,9 +425,9 @@ fn update_ui(
for (children, clip_node) in &container_query { for (children, clip_node) in &container_query {
// Draw the green background color to visually indicate the weight. // Draw the green background color to visually indicate the weight.
let mut bg_iter = background_query.iter_many_mut(children); let mut bg_iter = background_query.iter_many_mut(children);
if let Some(mut style) = bg_iter.fetch_next() { if let Some(mut node) = bg_iter.fetch_next() {
// All nodes are the same width, so `NODE_RECTS[0]` is as good as any other. // All nodes are the same width, so `NODE_RECTS[0]` is as good as any other.
style.width = node.width =
Val::Px(NODE_RECTS[0].width * animation_weights.weights[clip_node.index]); Val::Px(NODE_RECTS[0].width * animation_weights.weights[clip_node.index]);
} }

View file

@ -158,7 +158,7 @@ fn setup_ui(mut commands: Commands) {
// Add help text. // Add help text.
commands.spawn(( commands.spawn((
Text::new("Click on a button to toggle animations for its associated bones"), Text::new("Click on a button to toggle animations for its associated bones"),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
left: Val::Px(12.0), left: Val::Px(12.0),
top: Val::Px(12.0), top: Val::Px(12.0),
@ -168,19 +168,16 @@ fn setup_ui(mut commands: Commands) {
// Add the buttons that allow the user to toggle mask groups on and off. // Add the buttons that allow the user to toggle mask groups on and off.
commands commands
.spawn(( .spawn(Node {
Node::default(), flex_direction: FlexDirection::Column,
Style { position_type: PositionType::Absolute,
flex_direction: FlexDirection::Column, row_gap: Val::Px(6.0),
position_type: PositionType::Absolute, left: Val::Px(12.0),
row_gap: Val::Px(6.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), ..default()
bottom: Val::Px(12.0), })
..default()
},
))
.with_children(|parent| { .with_children(|parent| {
let row_style = Style { let row_node = Node {
flex_direction: FlexDirection::Row, flex_direction: FlexDirection::Row,
column_gap: Val::Px(6.0), column_gap: Val::Px(6.0),
..default() ..default()
@ -188,39 +185,35 @@ fn setup_ui(mut commands: Commands) {
add_mask_group_control(parent, "Head", Val::Auto, MASK_GROUP_HEAD); add_mask_group_control(parent, "Head", Val::Auto, MASK_GROUP_HEAD);
parent parent.spawn(row_node.clone()).with_children(|parent| {
.spawn((Node::default(), row_style.clone())) add_mask_group_control(
.with_children(|parent| { parent,
add_mask_group_control( "Left Front Leg",
parent, Val::Px(MASK_GROUP_BUTTON_WIDTH),
"Left Front Leg", MASK_GROUP_LEFT_FRONT_LEG,
Val::Px(MASK_GROUP_BUTTON_WIDTH), );
MASK_GROUP_LEFT_FRONT_LEG, add_mask_group_control(
); parent,
add_mask_group_control( "Right Front Leg",
parent, Val::Px(MASK_GROUP_BUTTON_WIDTH),
"Right Front Leg", MASK_GROUP_RIGHT_FRONT_LEG,
Val::Px(MASK_GROUP_BUTTON_WIDTH), );
MASK_GROUP_RIGHT_FRONT_LEG, });
);
});
parent parent.spawn(row_node).with_children(|parent| {
.spawn((Node::default(), row_style)) add_mask_group_control(
.with_children(|parent| { parent,
add_mask_group_control( "Left Hind Leg",
parent, Val::Px(MASK_GROUP_BUTTON_WIDTH),
"Left Hind Leg", MASK_GROUP_LEFT_HIND_LEG,
Val::Px(MASK_GROUP_BUTTON_WIDTH), );
MASK_GROUP_LEFT_HIND_LEG, add_mask_group_control(
); parent,
add_mask_group_control( "Right Hind Leg",
parent, Val::Px(MASK_GROUP_BUTTON_WIDTH),
"Right Hind Leg", MASK_GROUP_RIGHT_HIND_LEG,
Val::Px(MASK_GROUP_BUTTON_WIDTH), );
MASK_GROUP_RIGHT_HIND_LEG, });
);
});
add_mask_group_control(parent, "Tail", Val::Auto, MASK_GROUP_TAIL); add_mask_group_control(parent, "Tail", Val::Auto, MASK_GROUP_TAIL);
}); });
@ -246,8 +239,7 @@ fn add_mask_group_control(parent: &mut ChildBuilder, label: &str, width: Val, ma
parent parent
.spawn(( .spawn((
Node::default(), Node {
Style {
border: UiRect::all(Val::Px(1.0)), border: UiRect::all(Val::Px(1.0)),
width, width,
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,
@ -264,8 +256,7 @@ fn add_mask_group_control(parent: &mut ChildBuilder, label: &str, width: Val, ma
.with_children(|builder| { .with_children(|builder| {
builder builder
.spawn(( .spawn((
Node::default(), Node {
Style {
border: UiRect::ZERO, border: UiRect::ZERO,
width: Val::Percent(100.0), width: Val::Percent(100.0),
justify_content: JustifyContent::Center, justify_content: JustifyContent::Center,
@ -279,7 +270,7 @@ fn add_mask_group_control(parent: &mut ChildBuilder, label: &str, width: Val, ma
.with_child(( .with_child((
Text::new(label), Text::new(label),
label_text_style.clone(), label_text_style.clone(),
Style { Node {
margin: UiRect::vertical(Val::Px(3.0)), margin: UiRect::vertical(Val::Px(3.0)),
..default() ..default()
}, },
@ -287,8 +278,7 @@ fn add_mask_group_control(parent: &mut ChildBuilder, label: &str, width: Val, ma
builder builder
.spawn(( .spawn((
Node::default(), Node {
Style {
width: Val::Percent(100.0), width: Val::Percent(100.0),
flex_direction: FlexDirection::Row, flex_direction: FlexDirection::Row,
justify_content: JustifyContent::Center, justify_content: JustifyContent::Center,
@ -316,7 +306,7 @@ fn add_mask_group_control(parent: &mut ChildBuilder, label: &str, width: Val, ma
} else { } else {
Color::WHITE Color::WHITE
}), }),
Style { Node {
flex_grow: 1.0, flex_grow: 1.0,
border: if index > 0 { border: if index > 0 {
UiRect::left(Val::Px(1.0)) UiRect::left(Val::Px(1.0))
@ -335,7 +325,7 @@ fn add_mask_group_control(parent: &mut ChildBuilder, label: &str, width: Val, ma
selected_button_text_style.clone() selected_button_text_style.clone()
}, },
TextLayout::new_with_justify(JustifyText::Center), TextLayout::new_with_justify(JustifyText::Center),
Style { Node {
flex_grow: 1.0, flex_grow: 1.0,
margin: UiRect::vertical(Val::Px(3.0)), margin: UiRect::vertical(Val::Px(3.0)),
..default() ..default()

View file

@ -88,7 +88,7 @@ fn setup(mut commands: Commands) {
} }
commands.spawn(( commands.spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -126,8 +126,7 @@ fn setup(mut commands: Commands) {
commands.spawn(Camera2d); commands.spawn(Camera2d);
commands.spawn(( commands.spawn((
Node::default(), Node {
Style {
width: Val::Vw(100.0), width: Val::Vw(100.0),
height: Val::Vh(100.0), height: Val::Vh(100.0),
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,

View file

@ -21,7 +21,7 @@ fn setup(mut commands: Commands) {
commands.spawn(Camera2d); commands.spawn(Camera2d);
commands.spawn(( commands.spawn((
Text::new("Press P to panic"), Text::new("Press P to panic"),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -138,7 +138,7 @@ fn spawn_text(mut commands: Commands) {
"Space: swap meshes by mutating a Handle<Mesh>\n\ "Space: swap meshes by mutating a Handle<Mesh>\n\
Return: mutate the mesh itself, changing all copies of it", Return: mutate the mesh itself, changing all copies of it",
), ),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.), top: Val::Px(12.),
left: Val::Px(12.), left: Val::Px(12.),

View file

@ -96,7 +96,7 @@ fn spawn_text(mut commands: Commands) {
"Space: swap the right sprite's image handle\n\ "Space: swap the right sprite's image handle\n\
Return: modify the image Asset of the left sprite, affecting all uses of it", Return: modify the image Asset of the left sprite, affecting all uses of it",
), ),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.), top: Val::Px(12.),
left: Val::Px(12.), left: Val::Px(12.),

View file

@ -172,7 +172,7 @@ fn setup_ui(mut commands: Commands) {
commands.spawn(( commands.spawn((
LoadingText, LoadingText,
Text::new("Loading...".to_owned()), Text::new("Loading...".to_owned()),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
left: Val::Px(12.0), left: Val::Px(12.0),
top: Val::Px(12.0), top: Val::Px(12.0),

View file

@ -66,7 +66,7 @@ fn setup(
// example instructions // example instructions
commands.spawn(( commands.spawn((
Text::new("Up/Down/Left/Right: Move Listener\nSpace: Toggle Emitter Movement"), Text::new("Up/Down/Left/Right: Move Listener\nSpace: Toggle Emitter Movement"),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -65,7 +65,7 @@ fn setup(
// example instructions // example instructions
commands.spawn(( commands.spawn((
Text::new("Up/Down/Left/Right: Move Listener\nSpace: Toggle Emitter Movement"), Text::new("Up/Down/Left/Right: Move Listener\nSpace: Toggle Emitter Movement"),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -65,7 +65,7 @@ fn setup_scene(
fn setup_instructions(mut commands: Commands) { fn setup_instructions(mut commands: Commands) {
commands.spawn(( commands.spawn((
Text::new("Hold space to trigger a screen shake"), Text::new("Hold space to trigger a screen shake"),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -51,7 +51,7 @@ fn setup_scene(
fn setup_instructions(mut commands: Commands) { fn setup_instructions(mut commands: Commands) {
commands.spawn(( commands.spawn((
Text::new("Move the light with WASD.\nThe camera will smoothly track the light."), Text::new("Move the light with WASD.\nThe camera will smoothly track the light."),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -87,7 +87,7 @@ fn instructions(mut commands: Commands) {
Mouse left or right: yaw\n\ Mouse left or right: yaw\n\
Mouse buttons: roll", Mouse buttons: roll",
), ),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.), top: Val::Px(12.),
left: Val::Px(12.), left: Val::Px(12.),

View file

@ -192,15 +192,12 @@ fn spawn_lights(mut commands: Commands) {
fn spawn_text(mut commands: Commands) { fn spawn_text(mut commands: Commands) {
commands commands
.spawn(( .spawn(Node {
Node::default(), position_type: PositionType::Absolute,
Style { bottom: Val::Px(12.0),
position_type: PositionType::Absolute, left: Val::Px(12.0),
bottom: Val::Px(12.0), ..default()
left: Val::Px(12.0), })
..default()
},
))
.with_child(Text::new(concat!( .with_child(Text::new(concat!(
"Move the camera with your mouse.\n", "Move the camera with your mouse.\n",
"Press arrow up to decrease the FOV of the world model.\n", "Press arrow up to decrease the FOV of the world model.\n",

View file

@ -99,7 +99,7 @@ fn instructions(mut commands: Commands) {
"Scroll mouse wheel to zoom in/out\n\ "Scroll mouse wheel to zoom in/out\n\
Space: switch between orthographic and perspective projections", Space: switch between orthographic and perspective projections",
), ),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.), top: Val::Px(12.),
left: Val::Px(12.), left: Val::Px(12.),

View file

@ -51,7 +51,7 @@ fn setup(mut commands: Commands) {
"Press 3 to increase the overlay size.\n", "Press 3 to increase the overlay size.\n",
"Press 4 to toggle the overlay visibility." "Press 4 to toggle the overlay visibility."
)), )),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.), bottom: Val::Px(12.),
left: Val::Px(12.), left: Val::Px(12.),

View file

@ -76,7 +76,7 @@ fn setup(mut commands: Commands) {
"Click on a \"Mine\" to trigger it.\n\ "Click on a \"Mine\" to trigger it.\n\
When it explodes it will trigger all overlapping mines.", When it explodes it will trigger all overlapping mines.",
), ),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.), top: Val::Px(12.),
left: Val::Px(12.), left: Val::Px(12.),

View file

@ -95,7 +95,7 @@ fn setup_ui(mut commands: Commands) {
.spawn(( .spawn((
Text::default(), Text::default(),
TextLayout::new_with_justify(JustifyText::Center), TextLayout::new_with_justify(JustifyText::Center),
Style { Node {
align_self: AlignSelf::Center, align_self: AlignSelf::Center,
justify_self: JustifySelf::Center, justify_self: JustifySelf::Center,
..default() ..default()

View file

@ -182,7 +182,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut game: ResMu
..default() ..default()
}, },
TextColor(Color::srgb(0.5, 0.5, 1.0)), TextColor(Color::srgb(0.5, 0.5, 1.0)),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(5.0), top: Val::Px(5.0),
left: Val::Px(5.0), left: Val::Px(5.0),
@ -393,15 +393,12 @@ fn gameover_keyboard(
// display the number of cake eaten before losing // display the number of cake eaten before losing
fn display_score(mut commands: Commands, game: Res<Game>) { fn display_score(mut commands: Commands, game: Res<Game>) {
commands commands
.spawn(( .spawn(Node {
Node::default(), width: Val::Percent(100.),
Style { align_items: AlignItems::Center,
width: Val::Percent(100.), justify_content: JustifyContent::Center,
align_items: AlignItems::Center, ..default()
justify_content: JustifyContent::Center, })
..default()
},
))
.with_child(( .with_child((
Text::new(format!("Cake eaten: {}", game.cake_eaten)), Text::new(format!("Cake eaten: {}", game.cake_eaten)),
TextFont { TextFont {

View file

@ -225,7 +225,7 @@ fn setup(
}, },
TextColor(TEXT_COLOR), TextColor(TEXT_COLOR),
ScoreboardUi, ScoreboardUi,
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: SCOREBOARD_TEXT_PADDING, top: SCOREBOARD_TEXT_PADDING,
left: SCOREBOARD_TEXT_PADDING, left: SCOREBOARD_TEXT_PADDING,

View file

@ -148,7 +148,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
Text::new("Contributor showcase"), Text::new("Contributor showcase"),
text_style.clone(), text_style.clone(),
ContributorDisplay, ContributorDisplay,
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.), top: Val::Px(12.),
left: Val::Px(12.), left: Val::Px(12.),

View file

@ -75,8 +75,7 @@ mod splash {
// Display the logo // Display the logo
commands commands
.spawn(( .spawn((
Node::default(), Node {
Style {
align_items: AlignItems::Center, align_items: AlignItems::Center,
justify_content: JustifyContent::Center, justify_content: JustifyContent::Center,
width: Val::Percent(100.0), width: Val::Percent(100.0),
@ -88,7 +87,7 @@ mod splash {
.with_children(|parent| { .with_children(|parent| {
parent.spawn(( parent.spawn((
UiImage::new(icon), UiImage::new(icon),
Style { Node {
// This will set the logo to be 200px wide, and auto adjust its height // This will set the logo to be 200px wide, and auto adjust its height
width: Val::Px(200.0), width: Val::Px(200.0),
..default() ..default()
@ -141,8 +140,7 @@ mod game {
) { ) {
commands commands
.spawn(( .spawn((
Node::default(), Node {
Style {
width: Val::Percent(100.0), width: Val::Percent(100.0),
height: Val::Percent(100.0), height: Val::Percent(100.0),
// center children // center children
@ -153,11 +151,10 @@ mod game {
OnGameScreen, OnGameScreen,
)) ))
.with_children(|parent| { .with_children(|parent| {
// First create a `Node` and `Style` for centering what we want to display // First create a `Node` for centering what we want to display
parent parent
.spawn(( .spawn((
Node::default(), Node {
Style {
// This will display its children in a column, from top to bottom // This will display its children in a column, from top to bottom
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,
// `align_items` will align children on the cross axis. Here the main axis is // `align_items` will align children on the cross axis. Here the main axis is
@ -176,14 +173,14 @@ mod game {
..default() ..default()
}, },
TextColor(TEXT_COLOR), TextColor(TEXT_COLOR),
Style { Node {
margin: UiRect::all(Val::Px(50.0)), margin: UiRect::all(Val::Px(50.0)),
..default() ..default()
}, },
)); ));
p.spawn(( p.spawn((
Text::default(), Text::default(),
Style { Node {
margin: UiRect::all(Val::Px(50.0)), margin: UiRect::all(Val::Px(50.0)),
..default() ..default()
}, },
@ -377,7 +374,7 @@ mod menu {
fn main_menu_setup(mut commands: Commands, asset_server: Res<AssetServer>) { fn main_menu_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// Common style for all buttons on the screen // Common style for all buttons on the screen
let button_style = Style { let button_node = Node {
width: Val::Px(300.0), width: Val::Px(300.0),
height: Val::Px(65.0), height: Val::Px(65.0),
margin: UiRect::all(Val::Px(20.0)), margin: UiRect::all(Val::Px(20.0)),
@ -385,7 +382,7 @@ mod menu {
align_items: AlignItems::Center, align_items: AlignItems::Center,
..default() ..default()
}; };
let button_icon_style = Style { let button_icon_node = Node {
width: Val::Px(30.0), width: Val::Px(30.0),
// This takes the icons out of the flexbox flow, to be positioned exactly // This takes the icons out of the flexbox flow, to be positioned exactly
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
@ -400,8 +397,7 @@ mod menu {
commands commands
.spawn(( .spawn((
Node::default(), Node {
Style {
width: Val::Percent(100.0), width: Val::Percent(100.0),
height: Val::Percent(100.0), height: Val::Percent(100.0),
align_items: AlignItems::Center, align_items: AlignItems::Center,
@ -413,8 +409,7 @@ mod menu {
.with_children(|parent| { .with_children(|parent| {
parent parent
.spawn(( .spawn((
Node::default(), Node {
Style {
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,
align_items: AlignItems::Center, align_items: AlignItems::Center,
..default() ..default()
@ -430,7 +425,7 @@ mod menu {
..default() ..default()
}, },
TextColor(TEXT_COLOR), TextColor(TEXT_COLOR),
Style { Node {
margin: UiRect::all(Val::Px(50.0)), margin: UiRect::all(Val::Px(50.0)),
..default() ..default()
}, },
@ -443,13 +438,13 @@ mod menu {
parent parent
.spawn(( .spawn((
Button, Button,
button_style.clone(), button_node.clone(),
BackgroundColor(NORMAL_BUTTON), BackgroundColor(NORMAL_BUTTON),
MenuButtonAction::Play, MenuButtonAction::Play,
)) ))
.with_children(|parent| { .with_children(|parent| {
let icon = asset_server.load("textures/Game Icons/right.png"); let icon = asset_server.load("textures/Game Icons/right.png");
parent.spawn((UiImage::new(icon), button_icon_style.clone())); parent.spawn((UiImage::new(icon), button_icon_node.clone()));
parent.spawn(( parent.spawn((
Text::new("New Game"), Text::new("New Game"),
button_text_font.clone(), button_text_font.clone(),
@ -459,13 +454,13 @@ mod menu {
parent parent
.spawn(( .spawn((
Button, Button,
button_style.clone(), button_node.clone(),
BackgroundColor(NORMAL_BUTTON), BackgroundColor(NORMAL_BUTTON),
MenuButtonAction::Settings, MenuButtonAction::Settings,
)) ))
.with_children(|parent| { .with_children(|parent| {
let icon = asset_server.load("textures/Game Icons/wrench.png"); let icon = asset_server.load("textures/Game Icons/wrench.png");
parent.spawn((UiImage::new(icon), button_icon_style.clone())); parent.spawn((UiImage::new(icon), button_icon_node.clone()));
parent.spawn(( parent.spawn((
Text::new("Settings"), Text::new("Settings"),
button_text_font.clone(), button_text_font.clone(),
@ -475,13 +470,13 @@ mod menu {
parent parent
.spawn(( .spawn((
Button, Button,
button_style, button_node,
BackgroundColor(NORMAL_BUTTON), BackgroundColor(NORMAL_BUTTON),
MenuButtonAction::Quit, MenuButtonAction::Quit,
)) ))
.with_children(|parent| { .with_children(|parent| {
let icon = asset_server.load("textures/Game Icons/exitRight.png"); let icon = asset_server.load("textures/Game Icons/exitRight.png");
parent.spawn((UiImage::new(icon), button_icon_style)); parent.spawn((UiImage::new(icon), button_icon_node));
parent.spawn(( parent.spawn((
Text::new("Quit"), Text::new("Quit"),
button_text_font, button_text_font,
@ -493,7 +488,7 @@ mod menu {
} }
fn settings_menu_setup(mut commands: Commands) { fn settings_menu_setup(mut commands: Commands) {
let button_style = Style { let button_node = Node {
width: Val::Px(200.0), width: Val::Px(200.0),
height: Val::Px(65.0), height: Val::Px(65.0),
margin: UiRect::all(Val::Px(20.0)), margin: UiRect::all(Val::Px(20.0)),
@ -512,8 +507,7 @@ mod menu {
commands commands
.spawn(( .spawn((
Node::default(), Node {
Style {
width: Val::Percent(100.0), width: Val::Percent(100.0),
height: Val::Percent(100.0), height: Val::Percent(100.0),
align_items: AlignItems::Center, align_items: AlignItems::Center,
@ -525,8 +519,7 @@ mod menu {
.with_children(|parent| { .with_children(|parent| {
parent parent
.spawn(( .spawn((
Node::default(), Node {
Style {
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,
align_items: AlignItems::Center, align_items: AlignItems::Center,
..default() ..default()
@ -542,7 +535,7 @@ mod menu {
parent parent
.spawn(( .spawn((
Button, Button,
button_style.clone(), button_node.clone(),
BackgroundColor(NORMAL_BUTTON), BackgroundColor(NORMAL_BUTTON),
action, action,
)) ))
@ -555,7 +548,7 @@ mod menu {
} }
fn display_settings_menu_setup(mut commands: Commands, display_quality: Res<DisplayQuality>) { fn display_settings_menu_setup(mut commands: Commands, display_quality: Res<DisplayQuality>) {
let button_style = Style { let button_node = Node {
width: Val::Px(200.0), width: Val::Px(200.0),
height: Val::Px(65.0), height: Val::Px(65.0),
margin: UiRect::all(Val::Px(20.0)), margin: UiRect::all(Val::Px(20.0)),
@ -573,8 +566,7 @@ mod menu {
commands commands
.spawn(( .spawn((
Node::default(), Node {
Style {
width: Val::Percent(100.0), width: Val::Percent(100.0),
height: Val::Percent(100.0), height: Val::Percent(100.0),
align_items: AlignItems::Center, align_items: AlignItems::Center,
@ -586,8 +578,7 @@ mod menu {
.with_children(|parent| { .with_children(|parent| {
parent parent
.spawn(( .spawn((
Node::default(), Node {
Style {
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,
align_items: AlignItems::Center, align_items: AlignItems::Center,
..default() ..default()
@ -595,12 +586,11 @@ mod menu {
BackgroundColor(CRIMSON.into()), BackgroundColor(CRIMSON.into()),
)) ))
.with_children(|parent| { .with_children(|parent| {
// Create a new `Node` and `Style` , this time not setting its `flex_direction`. It will // Create a new `Node`, this time not setting its `flex_direction`. It will
// use the default value, `FlexDirection::Row`, from left to right. // use the default value, `FlexDirection::Row`, from left to right.
parent parent
.spawn(( .spawn((
Node::default(), Node {
Style {
align_items: AlignItems::Center, align_items: AlignItems::Center,
..default() ..default()
}, },
@ -620,10 +610,10 @@ mod menu {
] { ] {
let mut entity = parent.spawn(( let mut entity = parent.spawn((
Button, Button,
Style { Node {
width: Val::Px(150.0), width: Val::Px(150.0),
height: Val::Px(65.0), height: Val::Px(65.0),
..button_style.clone() ..button_node.clone()
}, },
BackgroundColor(NORMAL_BUTTON), BackgroundColor(NORMAL_BUTTON),
quality_setting, quality_setting,
@ -643,7 +633,7 @@ mod menu {
parent parent
.spawn(( .spawn((
Button, Button,
button_style, button_node,
BackgroundColor(NORMAL_BUTTON), BackgroundColor(NORMAL_BUTTON),
MenuButtonAction::BackToSettings, MenuButtonAction::BackToSettings,
)) ))
@ -655,7 +645,7 @@ mod menu {
} }
fn sound_settings_menu_setup(mut commands: Commands, volume: Res<Volume>) { fn sound_settings_menu_setup(mut commands: Commands, volume: Res<Volume>) {
let button_style = Style { let button_node = Node {
width: Val::Px(200.0), width: Val::Px(200.0),
height: Val::Px(65.0), height: Val::Px(65.0),
margin: UiRect::all(Val::Px(20.0)), margin: UiRect::all(Val::Px(20.0)),
@ -673,8 +663,7 @@ mod menu {
commands commands
.spawn(( .spawn((
Node::default(), Node {
Style {
width: Val::Percent(100.0), width: Val::Percent(100.0),
height: Val::Percent(100.0), height: Val::Percent(100.0),
align_items: AlignItems::Center, align_items: AlignItems::Center,
@ -686,8 +675,7 @@ mod menu {
.with_children(|parent| { .with_children(|parent| {
parent parent
.spawn(( .spawn((
Node::default(), Node {
Style {
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,
align_items: AlignItems::Center, align_items: AlignItems::Center,
..default() ..default()
@ -697,8 +685,7 @@ mod menu {
.with_children(|parent| { .with_children(|parent| {
parent parent
.spawn(( .spawn((
Node::default(), Node {
Style {
align_items: AlignItems::Center, align_items: AlignItems::Center,
..default() ..default()
}, },
@ -709,10 +696,10 @@ mod menu {
for volume_setting in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] { for volume_setting in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] {
let mut entity = parent.spawn(( let mut entity = parent.spawn((
Button, Button,
Style { Node {
width: Val::Px(30.0), width: Val::Px(30.0),
height: Val::Px(65.0), height: Val::Px(65.0),
..button_style.clone() ..button_node.clone()
}, },
BackgroundColor(NORMAL_BUTTON), BackgroundColor(NORMAL_BUTTON),
Volume(volume_setting), Volume(volume_setting),
@ -725,7 +712,7 @@ mod menu {
parent parent
.spawn(( .spawn((
Button, Button,
button_style, button_node,
BackgroundColor(NORMAL_BUTTON), BackgroundColor(NORMAL_BUTTON),
MenuButtonAction::BackToSettings, MenuButtonAction::BackToSettings,
)) ))

View file

@ -83,13 +83,12 @@ fn setup(mut commands: Commands) {
}; };
commands commands
.spawn(( .spawn((
Node::default(), Node {
BackgroundColor(Color::NONE),
Style {
justify_self: JustifySelf::Center, justify_self: JustifySelf::Center,
align_self: AlignSelf::FlexEnd, align_self: AlignSelf::FlexEnd,
..default() ..default()
}, },
BackgroundColor(Color::NONE),
)) ))
.with_child((Text::new("Press 1 or 2 to load a new scene."), text_style)); .with_child((Text::new("Press 1 or 2 to load a new scene."), text_style));
} }
@ -257,15 +256,14 @@ fn load_loading_screen(mut commands: Commands) {
// Spawn the UI that will make up the loading screen. // Spawn the UI that will make up the loading screen.
commands commands
.spawn(( .spawn((
Node::default(), Node {
BackgroundColor(Color::BLACK),
Style {
height: Val::Percent(100.0), height: Val::Percent(100.0),
width: Val::Percent(100.0), width: Val::Percent(100.0),
justify_content: JustifyContent::Center, justify_content: JustifyContent::Center,
align_items: AlignItems::Center, align_items: AlignItems::Center,
..default() ..default()
}, },
BackgroundColor(Color::BLACK),
LoadingScreen, LoadingScreen,
)) ))
.with_child((Text::new("Loading..."), text_style.clone())); .with_child((Text::new("Loading..."), text_style.clone()));

View file

@ -165,7 +165,7 @@ fn build_ui(
.spawn(( .spawn((
Text::default(), Text::default(),
SteppingUi, SteppingUi,
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: state.ui_top, top: state.ui_top,
left: state.ui_left, left: state.ui_left,
@ -197,7 +197,7 @@ fn build_stepping_hint(mut commands: Commands) {
..default() ..default()
}, },
TextColor(FONT_COLOR), TextColor(FONT_COLOR),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(5.0), bottom: Val::Px(5.0),
left: Val::Px(5.0), left: Val::Px(5.0),

View file

@ -28,7 +28,7 @@ fn setup(mut commands: Commands) {
Press 'U' / 'I' to cycle through line styles\n\ Press 'U' / 'I' to cycle through line styles\n\
Press 'J' / 'K' to cycle through line joins", Press 'J' / 'K' to cycle through line joins",
), ),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.), top: Val::Px(12.),
left: Val::Px(12.), left: Val::Px(12.),

View file

@ -62,7 +62,7 @@ fn setup(
Press 'U' or 'I' to cycle through line styles for straight or round gizmos\n\ Press 'U' or 'I' to cycle through line styles for straight or round gizmos\n\
Press 'J' or 'K' to cycle through line joins for straight or round gizmos", Press 'J' or 'K' to cycle through line joins for straight or round gizmos",
), ),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -109,7 +109,7 @@ fn setup(
Press 'A' to toggle drawing of the light gizmos\n\ Press 'A' to toggle drawing of the light gizmos\n\
Press 'C' to cycle between the light gizmos coloring modes", Press 'C' to cycle between the light gizmos coloring modes",
), ),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),
@ -125,7 +125,7 @@ fn setup(
.spawn(( .spawn((
Text::new("Gizmo color mode: "), Text::new("Gizmo color mode: "),
GizmoColorText, GizmoColorText,
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
bottom: Val::Px(12.0), bottom: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -22,11 +22,11 @@ pub struct RadioButton;
#[derive(Clone, Copy, Component)] #[derive(Clone, Copy, Component)]
pub struct RadioButtonText; pub struct RadioButtonText;
/// Returns a [`Style`] appropriate for the outer main UI node. /// Returns a [`Node`] appropriate for the outer main UI node.
/// ///
/// This UI is in the bottom left corner and has flex column support /// This UI is in the bottom left corner and has flex column support
pub fn main_ui_style() -> Style { pub fn main_ui_node() -> Node {
Style { Node {
flex_direction: FlexDirection::Column, flex_direction: FlexDirection::Column,
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
row_gap: Val::Px(6.0), row_gap: Val::Px(6.0),
@ -60,7 +60,7 @@ pub fn spawn_option_button<T>(
parent parent
.spawn(( .spawn((
Button, Button,
Style { Node {
border: UiRect::all(Val::Px(1.0)).with_left(if is_first { border: UiRect::all(Val::Px(1.0)).with_left(if is_first {
Val::Px(1.0) Val::Px(1.0)
} else { } else {
@ -97,15 +97,12 @@ where
{ {
// Add the parent node for the row. // Add the parent node for the row.
parent parent
.spawn(( .spawn(Node {
Node::default(), align_items: AlignItems::Center,
Style { ..default()
align_items: AlignItems::Center, })
..default()
},
))
.with_children(|parent| { .with_children(|parent| {
spawn_ui_text(parent, title, Color::BLACK).insert(Style { spawn_ui_text(parent, title, Color::BLACK).insert(Node {
width: Val::Px(125.0), width: Val::Px(125.0),
..default() ..default()
}); });

View file

@ -37,7 +37,7 @@ fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
commands commands
.spawn(( .spawn((
Text::default(), Text::default(),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -78,17 +78,14 @@ fn setup(mut commands: Commands) {
let style = TextFont::default(); let style = TextFont::default();
commands commands
.spawn(( .spawn(Node {
Node::default(), position_type: PositionType::Absolute,
Style { top: Val::Px(12.0),
position_type: PositionType::Absolute, left: Val::Px(12.0),
top: Val::Px(12.0), flex_direction: FlexDirection::Column,
left: Val::Px(12.0), row_gap: Val::Px(20.0),
flex_direction: FlexDirection::Column, ..default()
row_gap: Val::Px(20.0), })
..default()
},
))
.with_children(|parent| { .with_children(|parent| {
parent.spawn((Text::new(instructions_text), style.clone())); parent.spawn((Text::new(instructions_text), style.clone()));
parent.spawn((SplineModeText, Text(spline_mode_text), style.clone())); parent.spawn((SplineModeText, Text(spline_mode_text), style.clone()));

View file

@ -157,14 +157,16 @@ fn setup(
)); ));
// Example instructions // Example instructions
commands.spawn((Text::new("Press 'B' to toggle between no bounding shapes, bounding boxes (AABBs) and bounding spheres / circles\n\ commands.spawn((
Text::new("Press 'B' to toggle between no bounding shapes, bounding boxes (AABBs) and bounding spheres / circles\n\
Press 'Space' to switch between 3D and 2D"), Press 'Space' to switch between 3D and 2D"),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),
..default() ..default()
})); },
));
} }
// Rotate the 2D shapes. // Rotate the 2D shapes.

View file

@ -118,7 +118,7 @@ fn setup(
D: Add 100 random samples.\n\ D: Add 100 random samples.\n\
Rotate camera by holding left mouse and panning left/right.", Rotate camera by holding left mouse and panning left/right.",
), ),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -370,8 +370,7 @@ fn setup_text(mut commands: Commands, cameras: Query<(Entity, &Camera)>) {
commands commands
.spawn(( .spawn((
HeaderNode, HeaderNode,
Node::default(), Node {
Style {
justify_self: JustifySelf::Center, justify_self: JustifySelf::Center,
top: Val::Px(5.0), top: Val::Px(5.0),
..Default::default() ..Default::default()

View file

@ -388,7 +388,7 @@ fn setup(
Move camera by L/R arrow keys.\n\ Move camera by L/R arrow keys.\n\
Tab: Toggle this text", Tab: Toggle this text",
), ),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -116,7 +116,7 @@ fn setup_scene(
commands commands
.spawn(( .spawn((
Button, Button,
Style { Node {
justify_content: JustifyContent::Center, justify_content: JustifyContent::Center,
align_items: AlignItems::Center, align_items: AlignItems::Center,
position_type: PositionType::Absolute, position_type: PositionType::Absolute,

View file

@ -145,15 +145,12 @@ fn spawn_player(mut commands: Commands, asset_server: Res<AssetServer>) {
/// Spawn a bit of UI text to explain how to move the player. /// Spawn a bit of UI text to explain how to move the player.
fn spawn_text(mut commands: Commands) { fn spawn_text(mut commands: Commands) {
commands commands
.spawn(( .spawn(Node {
Node::default(), position_type: PositionType::Absolute,
Style { bottom: Val::Px(12.0),
position_type: PositionType::Absolute, left: Val::Px(12.0),
bottom: Val::Px(12.0), ..default()
left: Val::Px(12.0), })
..default()
},
))
.with_child(( .with_child((
Text::new("Move the player with WASD"), Text::new("Move the player with WASD"),
TextFont { TextFont {

View file

@ -149,7 +149,7 @@ fn setup(
// Instructions // Instructions
commands.spawn(( commands.spawn((
Text::new("Hover over the shapes to pick them"), Text::new("Hover over the shapes to pick them"),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Px(12.0), top: Val::Px(12.0),
left: Val::Px(12.0), left: Val::Px(12.0),

View file

@ -20,7 +20,7 @@ fn setup(
commands commands
.spawn(( .spawn((
Text::new("Click Me to get a box"), Text::new("Click Me to get a box"),
Style { Node {
position_type: PositionType::Absolute, position_type: PositionType::Absolute,
top: Val::Percent(12.0), top: Val::Percent(12.0),
left: Val::Percent(12.0), left: Val::Percent(12.0),

View file

@ -152,7 +152,7 @@ fn infotext_system(mut commands: Commands) {
font_size: 42.0, font_size: 42.0,
..default() ..default()
}, },
Style { Node {
align_self: AlignSelf::FlexEnd, align_self: AlignSelf::FlexEnd,
..default() ..default()
}, },

Some files were not shown because too many files have changed in this diff Show more