Skip to content

Update ImageMeasure to apply aspect ratio to min/max height/width #19577

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 71 additions & 12 deletions crates/bevy_ui/src/widget/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,24 +220,81 @@ impl Measure for ImageMeasure {
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));
// Determine width and height from styles and known sizes (if a size is available
// from any of these sources).
let mut width = width.or(s_width).maybe_clamp(s_min_width, s_max_width);
let height = height.or(s_height).maybe_clamp(s_min_height, s_max_height);

// If there is no width/height then fall back to the image's size.
if width.is_none() && height.is_none() {
width = Some(self.size.x).maybe_clamp(s_min_width, s_max_width);
}

// 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));
let aspect_applied =
(width.is_some() && height.is_none()) || (width.is_none() && height.is_some());
let mut taffy_size =
taffy::Size { width, height }.maybe_apply_aspect_ratio(Some(aspect_ratio));
tracing::info!("{taffy_size:?} {aspect_applied} {s_min_width:?} {s_max_width:?} {s_min_height:?} {s_max_height:?}");

// Pull back if applying aspect ratio violated a min/max.
if aspect_applied {
// Check max violation.
if taffy_size
.width
.map(|w| w > s_max_width.unwrap_or(f32::MAX))
.unwrap_or(false)
{
taffy_size = taffy::Size {
width: s_max_width,
height: None,
}
.maybe_apply_aspect_ratio(Some(aspect_ratio));
}
if taffy_size
.height
.map(|h| h > s_max_height.unwrap_or(f32::MAX))
.unwrap_or(false)
{
taffy_size = taffy::Size {
width: None,
height: s_max_height,
}
.maybe_apply_aspect_ratio(Some(aspect_ratio));
}

// Use computed sizes or fall back to image's inherent size
Vec2 {
// Check min violation.
if taffy_size
.width
.map(|w| w < s_min_width.unwrap_or(0.))
.unwrap_or(false)
{
taffy_size = taffy::Size {
width: s_min_width,
height: None,
}
.maybe_apply_aspect_ratio(Some(aspect_ratio));
}
if taffy_size
.height
.map(|h| h < s_min_height.unwrap_or(0.))
.unwrap_or(false)
{
taffy_size = taffy::Size {
width: None,
height: s_min_height,
}
.maybe_apply_aspect_ratio(Some(aspect_ratio));
}
}
tracing::info!("{taffy_size:?}");
// Use computed sizes or fall back to image's inherent size.
// Note that clamping to min/max is allowed to stretch the image at this point.
let res = Vec2 {
x: taffy_size
.width
.unwrap_or(self.size.x)
Expand All @@ -246,7 +303,9 @@ impl Measure for ImageMeasure {
.height
.unwrap_or(self.size.y)
.maybe_clamp(s_min_height, s_max_height),
}
};
tracing::info!("{res:?}");
res
}
}

Expand Down
4 changes: 2 additions & 2 deletions examples/ui/ui_scaling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
parent.spawn((
ImageNode::new(asset_server.load("branding/icon.png")),
Node {
width: Val::Px(30.0),
height: Val::Px(30.0),
height: Val::Percent(50.0),
max_width: Val::Px(50.0),
..default()
},
));
Expand Down
Loading