Skip to content

Remove the style component from ui widgets #6886

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
10 changes: 10 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1463,6 +1463,16 @@ description = "Illustrates how FontAtlases are populated (used to optimize text
category = "UI (User Interface)"
wasm = true

[[example]]
name = "layout"
path = "examples/ui/layout.rs"

[package.metadata.example.layout]
name = "Layout"
description = "Creates a more complex UI layout and demonstrates how the different JustifyContent and AlignItems variants compose."
category = "UI (User Interface)"
wasm = false

[[example]]
name = "text"
path = "examples/ui/text.rs"
Expand Down
105 changes: 78 additions & 27 deletions crates/bevy_ui/src/flex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{CalculatedSize, Node, Style, UiScale};
use bevy_ecs::{
entity::Entity,
event::EventReader,
query::{Changed, ReadOnlyWorldQuery, With, Without},
query::{Changed, With, Without},
system::{Query, RemovedComponents, Res, ResMut, Resource},
};
use bevy_hierarchy::{Children, Parent};
Expand Down Expand Up @@ -86,11 +86,15 @@ impl FlexSurface {
match (constraints.width, constraints.height) {
(Number::Undefined, Number::Undefined) => {}
(Number::Defined(width), Number::Undefined) => {
size.height = width * size.height / size.width;
if calculated_size.preserve_aspect_ratio {
size.height = width * size.height / size.width;
}
size.width = width;
}
(Number::Undefined, Number::Defined(height)) => {
size.width = height * size.width / size.height;
if calculated_size.preserve_aspect_ratio {
size.width = height * size.width / size.height;
}
size.height = height;
}
(Number::Defined(width), Number::Defined(height)) => {
Expand All @@ -111,6 +115,52 @@ impl FlexSurface {
}
}

fn upsert_widget(
&mut self,
entity: Entity,
calculated_size: CalculatedSize,
scale_factor: f64,
) {
let taffy = &mut self.taffy;
let measure = taffy::node::MeasureFunc::Boxed(Box::new(
move |constraints: taffy::geometry::Size<Number>| {
let mut size = convert::from_f32_size(scale_factor, calculated_size.size);
match (constraints.width, constraints.height) {
(Number::Undefined, Number::Undefined) => {}
(Number::Defined(width), Number::Undefined) => {
if calculated_size.preserve_aspect_ratio {
size.height = width * size.height / size.width;
}
size.width = width;
}
(Number::Undefined, Number::Defined(height)) => {
if calculated_size.preserve_aspect_ratio {
size.width = height * size.width / size.height;
}
size.height = height;
}
(Number::Defined(width), Number::Defined(height)) => {
size.width = width;
size.height = height;
}
}
size
},
));

if let Some(taffy_node) = self.entity_to_taffy.get(&entity) {
self.taffy
.set_style(*taffy_node, taffy::style::Style::default())
.unwrap();
self.taffy.set_measure(*taffy_node, Some(measure)).unwrap();
} else {
let taffy_node = taffy
.new_leaf(taffy::style::Style::default(), measure)
.unwrap();
self.entity_to_taffy.insert(entity, taffy_node);
}
}

pub fn update_children(&mut self, entity: Entity, children: &Children) {
let mut taffy_children = Vec::with_capacity(children.len());
for child in children {
Expand Down Expand Up @@ -216,13 +266,18 @@ pub fn flex_node_system(
mut scale_factor_events: EventReader<WindowScaleFactorChanged>,
mut flex_surface: ResMut<FlexSurface>,
root_node_query: Query<Entity, (With<Node>, Without<Parent>)>,
node_query: Query<(Entity, &Style, Option<&CalculatedSize>), (With<Node>, Changed<Style>)>,
full_node_query: Query<(Entity, &Style, Option<&CalculatedSize>), With<Node>>,
changed_size_query: Query<
(Entity, &Style, &CalculatedSize),
(With<Node>, Changed<CalculatedSize>),
node_query: Query<(Entity, &Style), (With<Node>, With<Style>)>,
full_node_query: Query<(Entity, &Style), With<Node>>,
widget_query: Query<(Entity, &CalculatedSize), (With<Node>, Without<Style>)>,
changed_widget_query: Query<
(Entity, &CalculatedSize),
(With<Node>, With<CalculatedSize>, Without<Style>),
>,
children_query: Query<(Entity, &Children), (With<Node>, Changed<Children>)>,
// changed_size_query: Query<
// (Entity, &Style, &CalculatedSize),
// (With<Node>, Changed<CalculatedSize>),
// >,
children_query: Query<(Entity, &Children), (With<Node>, With<Children>)>,
removed_children: RemovedComponents<Children>,
mut node_transform_query: Query<(Entity, &mut Node, &mut Transform, Option<&Parent>)>,
removed_nodes: RemovedComponents<Node>,
Expand All @@ -237,29 +292,25 @@ pub fn flex_node_system(
let scale_factor = logical_to_physical_factor * ui_scale.scale;

if scale_factor_events.iter().next_back().is_some() || ui_scale.is_changed() {
update_changed(&mut flex_surface, scale_factor, full_node_query);
for (entity, style) in &full_node_query {
flex_surface.upsert_node(entity, style, scale_factor);
}

for (entity, calculated_size) in &widget_query {
flex_surface.upsert_widget(entity, *calculated_size, scale_factor);
}
} else {
update_changed(&mut flex_surface, scale_factor, node_query);
}
for (entity, style) in &node_query {
flex_surface.upsert_node(entity, style, scale_factor);
}

fn update_changed<F: ReadOnlyWorldQuery>(
flex_surface: &mut FlexSurface,
scaling_factor: f64,
query: Query<(Entity, &Style, Option<&CalculatedSize>), F>,
) {
// update changed nodes
for (entity, style, calculated_size) in &query {
// TODO: remove node from old hierarchy if its root has changed
if let Some(calculated_size) = calculated_size {
flex_surface.upsert_leaf(entity, style, *calculated_size, scaling_factor);
} else {
flex_surface.upsert_node(entity, style, scaling_factor);
}
for (entity, calculated_size) in &changed_widget_query {
flex_surface.upsert_widget(entity, *calculated_size, scale_factor);
}
}

for (entity, style, calculated_size) in &changed_size_query {
flex_surface.upsert_leaf(entity, style, *calculated_size, scale_factor);
for (entity, calculated_size) in &changed_widget_query {
flex_surface.upsert_widget(entity, *calculated_size, scale_factor);
}

// clean up removed nodes
Expand Down
15 changes: 1 addition & 14 deletions crates/bevy_ui/src/node_bundles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ impl Default for NodeBundle {
pub struct ImageBundle {
/// Describes the size of the node
pub node: Node,
/// Describes the style including flexbox settings
pub style: Style,

/// The calculated size based on the given image
pub calculated_size: CalculatedSize,
/// The background color, which serves as a "fill" for this node
Expand Down Expand Up @@ -100,8 +99,6 @@ pub struct ImageBundle {
pub struct TextBundle {
/// Describes the size of the node
pub node: Node,
/// Describes the style including flexbox settings
pub style: Style,
/// Contains the text of the node
pub text: Text,
/// The calculated size based on the given image
Expand Down Expand Up @@ -152,12 +149,6 @@ impl TextBundle {
self.text.alignment = alignment;
self
}

/// Returns this [`TextBundle`] with a new [`Style`].
pub const fn with_style(mut self, style: Style) -> Self {
self.style = style;
self
}
}

impl Default for TextBundle {
Expand All @@ -167,7 +158,6 @@ impl Default for TextBundle {
text: Default::default(),
node: Default::default(),
calculated_size: Default::default(),
style: Default::default(),
transform: Default::default(),
global_transform: Default::default(),
visibility: Default::default(),
Expand All @@ -184,8 +174,6 @@ pub struct ButtonBundle {
pub node: Node,
/// Marker component that signals this node is a button
pub button: Button,
/// Describes the style including flexbox settings
pub style: Style,
/// Describes whether and how the button has been interacted with by the input
pub interaction: Interaction,
/// Whether this node should block interaction with lower nodes
Expand Down Expand Up @@ -221,7 +209,6 @@ impl Default for ButtonBundle {
interaction: Default::default(),
focus_policy: Default::default(),
node: Default::default(),
style: Default::default(),
background_color: Default::default(),
image: Default::default(),
transform: Default::default(),
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_ui/src/ui_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@ pub enum FlexWrap {
pub struct CalculatedSize {
/// The size of the node
pub size: Size,
/// Whether to attempt to preserve the aspect ratio when determing the layout for this item
pub preserve_aspect_ratio: bool,
}

/// The background color of the node
Expand Down
34 changes: 24 additions & 10 deletions crates/bevy_ui/src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@ use bevy_transform::components::GlobalTransform;
pub fn update_clipping_system(
mut commands: Commands,
root_node_query: Query<Entity, (With<Node>, Without<Parent>)>,
mut node_query: Query<(&Node, &GlobalTransform, &Style, Option<&mut CalculatedClip>)>,
mut node_query: Query<(
&Node,
&GlobalTransform,
Option<&Style>,
Option<&mut CalculatedClip>,
)>,

children_query: Query<&Children>,
) {
for root_node in &root_node_query {
Expand All @@ -33,7 +39,12 @@ pub fn update_clipping_system(
fn update_clipping(
commands: &mut Commands,
children_query: &Query<&Children>,
node_query: &mut Query<(&Node, &GlobalTransform, &Style, Option<&mut CalculatedClip>)>,
node_query: &mut Query<(
&Node,
&GlobalTransform,
Option<&Style>,
Option<&mut CalculatedClip>,
)>,
entity: Entity,
clip: Option<Rect>,
) {
Expand All @@ -53,15 +64,18 @@ fn update_clipping(
}
}
}

// Calculate new clip for its children
let children_clip = match style.overflow {
Overflow::Visible => clip,
Overflow::Hidden => {
let node_center = global_transform.translation().truncate();
let node_rect = Rect::from_center_size(node_center, node.calculated_size);
Some(clip.map_or(node_rect, |c| c.intersect(node_rect)))
let children_clip = if let Some(style) = style {
// Calculate new clip for its children
match style.overflow {
Overflow::Visible => clip,
Overflow::Hidden => {
let node_center = global_transform.translation().truncate();
let node_rect = Rect::from_center_size(node_center, node.calculated_size);
Some(clip.map_or(node_rect, |c| c.intersect(node_rect)))
}
}
} else {
clip
};

if let Ok(children) = children_query.get(entity) {
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_ui/src/widget/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub fn update_image_calculated_size_system(
// Update only if size has changed to avoid needless layout calculations
if size != calculated_size.size {
calculated_size.size = size;
calculated_size.preserve_aspect_ratio = true;
}
}
}
Expand Down
Loading