diff --git a/crates/bevy_ui/Cargo.toml b/crates/bevy_ui/Cargo.toml index 4e47819a6da6c..759b895b471ab 100644 --- a/crates/bevy_ui/Cargo.toml +++ b/crates/bevy_ui/Cargo.toml @@ -31,7 +31,7 @@ bevy_window = { path = "../bevy_window", version = "0.14.0-dev" } bevy_utils = { path = "../bevy_utils", version = "0.14.0-dev" } # other -taffy = { version = "0.4" } +taffy = { version = "0.5" } serde = { version = "1", features = ["derive"], optional = true } bytemuck = { version = "1.5", features = ["derive"] } thiserror = "1.0.0" diff --git a/crates/bevy_ui/src/layout/ui_surface.rs b/crates/bevy_ui/src/layout/ui_surface.rs index 2ba6eed374383..8bb13d83bcf70 100644 --- a/crates/bevy_ui/src/layout/ui_surface.rs +++ b/crates/bevy_ui/src/layout/ui_surface.rs @@ -213,7 +213,8 @@ without UI components as a child of an entity with UI components, results may be |known_dimensions: taffy::Size>, available_space: taffy::Size, _node_id: taffy::NodeId, - context: Option<&mut NodeMeasure>| + context: Option<&mut NodeMeasure>, + style: &taffy::Style| -> taffy::Size { context .map(|ctx| { @@ -222,6 +223,7 @@ without UI components as a child of an entity with UI components, results may be known_dimensions.height, available_space.width, available_space.height, + style, ); taffy::Size { width: size.x, diff --git a/crates/bevy_ui/src/measurement.rs b/crates/bevy_ui/src/measurement.rs index b482bd01aa759..f84391896e426 100644 --- a/crates/bevy_ui/src/measurement.rs +++ b/crates/bevy_ui/src/measurement.rs @@ -26,6 +26,7 @@ pub trait Measure: Send + Sync + 'static { height: Option, available_width: AvailableSpace, available_height: AvailableSpace, + style: &taffy::Style, ) -> Vec2; } @@ -48,20 +49,21 @@ impl Measure for NodeMeasure { height: Option, available_width: AvailableSpace, available_height: AvailableSpace, + style: &taffy::Style, ) -> Vec2 { match self { NodeMeasure::Fixed(fixed) => { - fixed.measure(width, height, available_width, available_height) + fixed.measure(width, height, available_width, available_height, style) } #[cfg(feature = "bevy_text")] NodeMeasure::Text(text) => { - text.measure(width, height, available_width, available_height) + text.measure(width, height, available_width, available_height, style) } NodeMeasure::Image(image) => { - image.measure(width, height, available_width, available_height) + image.measure(width, height, available_width, available_height, style) } NodeMeasure::Custom(custom) => { - custom.measure(width, height, available_width, available_height) + custom.measure(width, height, available_width, available_height, style) } } } @@ -81,6 +83,7 @@ impl Measure for FixedMeasure { _: Option, _: AvailableSpace, _: AvailableSpace, + _: &taffy::Style, ) -> Vec2 { self.size } diff --git a/crates/bevy_ui/src/widget/image.rs b/crates/bevy_ui/src/widget/image.rs index b78515c68d2ff..28b50be15c455 100644 --- a/crates/bevy_ui/src/widget/image.rs +++ b/crates/bevy_ui/src/widget/image.rs @@ -8,6 +8,7 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_render::texture::Image; use bevy_sprite::{TextureAtlas, TextureAtlasLayout}; use bevy_window::{PrimaryWindow, Window}; +use taffy::{MaybeMath, MaybeResolve}; /// The size of the image's texture /// @@ -40,26 +41,50 @@ impl Measure for ImageMeasure { &self, width: Option, height: Option, - _: AvailableSpace, - _: AvailableSpace, + available_width: AvailableSpace, + available_height: AvailableSpace, + style: &taffy::Style, ) -> Vec2 { - let mut size = self.size; - match (width, height) { - (None, None) => {} - (Some(width), None) => { - size.y = width * size.y / size.x; - size.x = width; - } - (None, Some(height)) => { - size.x = height * size.x / size.y; - size.y = height; - } - (Some(width), Some(height)) => { - size.x = width; - size.y = height; - } + // Convert available width/height into an option + let parent_width = available_width.into_option(); + let parent_height = available_height.into_option(); + + // Resolve styles + let s_aspect_ratio = style.aspect_ratio; + let s_width = style.size.width.maybe_resolve(parent_width); + let s_min_width = style.min_size.width.maybe_resolve(parent_width); + let s_max_width = style.max_size.width.maybe_resolve(parent_width); + let s_height = style.size.height.maybe_resolve(parent_height); + let s_min_height = style.min_size.height.maybe_resolve(parent_height); + let s_max_height = style.max_size.height.maybe_resolve(parent_height); + + // Determine width and height from styles and known_sizes (if a size is available + // from any of these sources) + let width = width.or(s_width + .or(s_min_width) + .maybe_clamp(s_min_width, s_max_width)); + let height = height.or(s_height + .or(s_min_height) + .maybe_clamp(s_min_height, s_max_height)); + + // Use aspect_ratio from style, fall back to inherent aspect ratio + let aspect_ratio = s_aspect_ratio.unwrap_or_else(|| self.size.x / self.size.y); + + // Apply aspect ratio + // If only one of width or height was determined at this point, then the other is set beyond this point using the aspect ratio. + let taffy_size = taffy::Size { width, height }.maybe_apply_aspect_ratio(Some(aspect_ratio)); + + // Use computed sizes or fall back to image's inherent size + Vec2 { + x: taffy_size + .width + .unwrap_or(self.size.x) + .maybe_clamp(s_min_width, s_max_width), + y: taffy_size + .height + .unwrap_or(self.size.y) + .maybe_clamp(s_min_height, s_max_height), } - size } } diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index 5aa6b44ed6f57..6d044596a2c79 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -51,6 +51,7 @@ impl Measure for TextMeasure { height: Option, available_width: AvailableSpace, _available_height: AvailableSpace, + _style: &taffy::Style, ) -> Vec2 { let x = width.unwrap_or_else(|| match available_width { AvailableSpace::Definite(x) => {