diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a16f32..b44e7c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,6 +88,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 evaluation. - `Graphics::set_font_family` now clears the cached font family list, ensuring that the next call to apply_current_font_settings works correctly. +- `Image` now returns the correct size from `layout()` when in aspect scaling + modes. Previously, it reported back the minimum size, since it's scale was + considered flexible. This new behavior ensures that it always requests a size + that is scaled with the aspect ratio. + + The rendering behavior remains unchanged, and the image will scale correctly + within whatever bounds it is given. ### Changed diff --git a/src/widgets/image.rs b/src/widgets/image.rs index 5353769..dbdde77 100644 --- a/src/widgets/image.rs +++ b/src/widgets/image.rs @@ -1,7 +1,7 @@ //! A widget that displays an image/texture. -use figures::units::UPx; -use figures::{FloatConversion, IntoSigned, Point, Rect, Size, Zero}; +use figures::units::{Px, UPx}; +use figures::{FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, Size, Zero}; use kludgine::{AnyTexture, CollectedTexture, LazyTexture, SharedTexture, Texture, TextureRegion}; use crate::animation::ZeroToOne; @@ -109,37 +109,44 @@ impl Image { Value::Dynamic(amount) => Value::Dynamic(amount.map_each_cloned(ImageScaling::Scale)), }) } + + fn calculate_image_rect( + &self, + texture: &AnyTexture, + within_size: Size, + context: &mut crate::context::GraphicsContext<'_, '_, '_, '_>, + ) -> Rect { + let within_size = within_size.into_signed(); + let size = texture.size().into_signed(); + match self.scaling.get_tracking_invalidate(context) { + ImageScaling::Aspect { mode, orientation } => { + let scale_width = within_size.width.into_float() / size.width.into_float(); + let scale_height = within_size.height.into_float() / size.height.into_float(); + + let effective_scale = match mode { + Aspect::Fill => scale_width.max(scale_height), + Aspect::Fit => scale_width.min(scale_height), + }; + let scaled = size * effective_scale; + + let x = (within_size.width - scaled.width) * *orientation.width; + let y = (within_size.height - scaled.height) * *orientation.height; + + Rect::new(Point::new(x, y), scaled) + } + ImageScaling::Stretch => within_size.into(), + ImageScaling::Scale(factor) => { + let size = size.map(|px| px * factor); + size.into() + } + } + } } impl Widget for Image { fn redraw(&mut self, context: &mut crate::context::GraphicsContext<'_, '_, '_, '_>) { self.contents.map(|texture| { - let size = texture.size().into_signed(); - let rect = match self.scaling.get() { - ImageScaling::Aspect { mode, orientation } => { - let scale_width = - context.gfx.region().size.width.into_float() / size.width.into_float(); - let scale_height = - context.gfx.region().size.height.into_float() / size.height.into_float(); - - let effective_scale = match mode { - Aspect::Fill => scale_width.max(scale_height), - Aspect::Fit => scale_width.min(scale_height), - }; - let scaled = size * effective_scale; - - let x = (context.gfx.region().size.width - scaled.width) * *orientation.width; - let y = - (context.gfx.region().size.height - scaled.height) * *orientation.height; - - Rect::new(Point::new(x, y), scaled) - } - ImageScaling::Stretch => context.gfx.region().size.into(), - ImageScaling::Scale(factor) => { - let size = size.map(|px| px * factor); - size.into() - } - }; + let rect = self.calculate_image_rect(texture, context.gfx.size(), context); context.gfx.draw_texture(texture, rect); }); } @@ -149,15 +156,10 @@ impl Widget for Image { available_space: Size, context: &mut LayoutContext<'_, '_, '_, '_>, ) -> Size { - match self.scaling.get_tracking_invalidate(context) { - ImageScaling::Aspect { .. } | ImageScaling::Stretch => { - available_space.map(ConstraintLimit::min) - } - ImageScaling::Scale(factor) => self - .contents - .map_tracking_invalidate(context, AnyTexture::size) - .map(|px| px * factor), - } + let rect = self.contents.map(|texture| { + self.calculate_image_rect(texture, available_space.map(ConstraintLimit::max), context) + }); + rect.size.into_unsigned() } }