From ca1fcdaf1454fd3febae8e6864c9a7dec04f41b1 Mon Sep 17 00:00:00 2001 From: Emi Simpson Date: Sat, 22 Jan 2022 20:09:35 -0500 Subject: Add support for `ContentFit` for `Image` --- native/src/widget/image.rs | 66 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 16 deletions(-) (limited to 'native/src/widget/image.rs') diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs index b8fb662e..5ddc3642 100644 --- a/native/src/widget/image.rs +++ b/native/src/widget/image.rs @@ -5,7 +5,9 @@ pub use viewer::Viewer; use crate::image; use crate::layout; use crate::renderer; -use crate::{Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget}; +use crate::{ + ContentFit, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget, +}; use std::hash::Hash; @@ -26,6 +28,7 @@ pub struct Image { handle: Handle, width: Length, height: Length, + fit: ContentFit, } impl Image { @@ -35,6 +38,7 @@ impl Image { handle: handle.into(), width: Length::Shrink, height: Length::Shrink, + fit: ContentFit::Contain, } } @@ -49,6 +53,13 @@ impl Image { self.height = height; self } + + /// Sets the image fit + /// + /// Defaults to [`ContentFit::Contain`] + pub fn fit(self, fit: ContentFit) -> Self { + Self { fit, ..self } + } } impl Widget for Image @@ -69,24 +80,32 @@ where renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { + // The raw w/h of the underlying image let (width, height) = renderer.dimensions(&self.handle); + let image_size = Size::new(width as f32, height as f32); - let aspect_ratio = width as f32 / height as f32; - - let mut size = limits + // The size to be available to the widget prior to `Shrink`ing + let raw_size = limits .width(self.width) .height(self.height) - .resolve(Size::new(width as f32, height as f32)); - - let viewport_aspect_ratio = size.width / size.height; - - if viewport_aspect_ratio > aspect_ratio { - size.width = width as f32 * size.height / height as f32; - } else { - size.height = height as f32 * size.width / width as f32; - } - - layout::Node::new(size) + .resolve(image_size); + + // The uncropped size of the image when fit to the bounds above + let full_size = self.fit.fit(image_size, raw_size); + + // Shrink the widget to fit the resized image, if requested + let final_size = Size { + width: match self.width { + Length::Shrink => f32::min(raw_size.width, full_size.width), + _ => raw_size.width, + }, + height: match self.height { + Length::Shrink => f32::min(raw_size.height, full_size.height), + _ => raw_size.height, + }, + }; + + layout::Node::new(final_size) } fn draw( @@ -97,7 +116,22 @@ where _cursor_position: Point, _viewport: &Rectangle, ) { - renderer.draw(self.handle.clone(), layout.bounds()); + // The raw w/h of the underlying image + let (width, height) = renderer.dimensions(&self.handle); + let image_size = Size::new(width as f32, height as f32); + + let adjusted_fit = self.fit.fit(image_size, layout.bounds().size()); + + renderer.with_layer(layout.bounds(), |renderer| { + renderer.draw( + self.handle.clone(), + Rectangle { + width: adjusted_fit.width, + height: adjusted_fit.height, + ..layout.bounds() + }, + ) + }) } fn hash_layout(&self, state: &mut Hasher) { -- cgit