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 From 395eacfc103e3123a10bebe4a9330f7c126650a4 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 16 Feb 2022 17:35:28 +0700 Subject: Use a new clipping layer only when necessary in `Image::draw` --- native/src/widget/image.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'native/src/widget/image.rs') diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs index 5ddc3642..b253b1b8 100644 --- a/native/src/widget/image.rs +++ b/native/src/widget/image.rs @@ -121,8 +121,9 @@ where let image_size = Size::new(width as f32, height as f32); let adjusted_fit = self.fit.fit(image_size, layout.bounds().size()); + let bounds = layout.bounds(); - renderer.with_layer(layout.bounds(), |renderer| { + let render = |renderer: &mut Renderer| { renderer.draw( self.handle.clone(), Rectangle { @@ -131,7 +132,15 @@ where ..layout.bounds() }, ) - }) + }; + + if adjusted_fit.width > bounds.width + || adjusted_fit.height > bounds.height + { + renderer.with_layer(layout.bounds(), render); + } else { + render(renderer) + } } fn hash_layout(&self, state: &mut Hasher) { -- cgit From 8b5c9dfa71f770281ca277163c320571c39ee572 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 16 Feb 2022 17:37:24 +0700 Subject: Make documentation of `Image::fit` consistent --- native/src/widget/image.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'native/src/widget/image.rs') diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs index b253b1b8..f2b8ef2f 100644 --- a/native/src/widget/image.rs +++ b/native/src/widget/image.rs @@ -54,7 +54,7 @@ impl Image { self } - /// Sets the image fit + /// Sets the [`ContentFit`] of the [`Image`]. /// /// Defaults to [`ContentFit::Contain`] pub fn fit(self, fit: ContentFit) -> Self { -- cgit From 0aff444941f8b44b5a996dde4810ba6313f43a7e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 16 Feb 2022 17:51:03 +0700 Subject: Rename `Image::fit` to `content_fit` ... just for consistency! --- native/src/widget/image.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'native/src/widget/image.rs') diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs index f2b8ef2f..d83230f2 100644 --- a/native/src/widget/image.rs +++ b/native/src/widget/image.rs @@ -28,7 +28,7 @@ pub struct Image { handle: Handle, width: Length, height: Length, - fit: ContentFit, + content_fit: ContentFit, } impl Image { @@ -38,7 +38,7 @@ impl Image { handle: handle.into(), width: Length::Shrink, height: Length::Shrink, - fit: ContentFit::Contain, + content_fit: ContentFit::Contain, } } @@ -57,8 +57,11 @@ impl Image { /// Sets the [`ContentFit`] of the [`Image`]. /// /// Defaults to [`ContentFit::Contain`] - pub fn fit(self, fit: ContentFit) -> Self { - Self { fit, ..self } + pub fn content_fit(self, content_fit: ContentFit) -> Self { + Self { + content_fit, + ..self + } } } @@ -91,7 +94,7 @@ where .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); + let full_size = self.content_fit.fit(image_size, raw_size); // Shrink the widget to fit the resized image, if requested let final_size = Size { @@ -120,7 +123,8 @@ where 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()); + let adjusted_fit = + self.content_fit.fit(image_size, layout.bounds().size()); let bounds = layout.bounds(); let render = |renderer: &mut Renderer| { -- cgit From 6822d1d9f2c5b4fcbf65763c8edd091ac18a657e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 16 Feb 2022 17:52:57 +0700 Subject: Center `Image` inside available bounds when possible --- native/src/widget/image.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'native/src/widget/image.rs') diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs index d83230f2..a2e7f765 100644 --- a/native/src/widget/image.rs +++ b/native/src/widget/image.rs @@ -6,7 +6,8 @@ use crate::image; use crate::layout; use crate::renderer; use crate::{ - ContentFit, Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget, + ContentFit, Element, Hasher, Layout, Length, Point, Rectangle, Size, + Vector, Widget, }; use std::hash::Hash; @@ -128,14 +129,18 @@ where let bounds = layout.bounds(); let render = |renderer: &mut Renderer| { - renderer.draw( - self.handle.clone(), - Rectangle { - width: adjusted_fit.width, - height: adjusted_fit.height, - ..layout.bounds() - }, - ) + let offset = Vector::new( + (bounds.width - adjusted_fit.width).max(0.0) / 2.0, + (bounds.height - adjusted_fit.height).max(0.0) / 2.0, + ); + + let bounds = Rectangle { + width: adjusted_fit.width, + height: adjusted_fit.height, + ..layout.bounds() + }; + + renderer.draw(self.handle.clone(), bounds + offset) }; if adjusted_fit.width > bounds.width -- cgit From 83c0e0f7a862ddcefedfb4ef11a11f9bd5245605 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 16 Feb 2022 17:59:39 +0700 Subject: Add `ContentFit` support to `Svg` widget --- native/src/widget/image.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'native/src/widget/image.rs') diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs index a2e7f765..8ccc7856 100644 --- a/native/src/widget/image.rs +++ b/native/src/widget/image.rs @@ -120,7 +120,6 @@ where _cursor_position: Point, _viewport: &Rectangle, ) { - // 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); -- cgit From 8d94cd4c5c9e33965c24e59fd4710218e346be24 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 16 Feb 2022 18:09:22 +0700 Subject: Remove redundant `layout.bounds()` calls in `Image` and `Svg` --- native/src/widget/image.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'native/src/widget/image.rs') diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs index 8ccc7856..6aab76e4 100644 --- a/native/src/widget/image.rs +++ b/native/src/widget/image.rs @@ -123,9 +123,8 @@ where let (width, height) = renderer.dimensions(&self.handle); let image_size = Size::new(width as f32, height as f32); - let adjusted_fit = - self.content_fit.fit(image_size, layout.bounds().size()); let bounds = layout.bounds(); + let adjusted_fit = self.content_fit.fit(image_size, bounds.size()); let render = |renderer: &mut Renderer| { let offset = Vector::new( @@ -133,19 +132,19 @@ where (bounds.height - adjusted_fit.height).max(0.0) / 2.0, ); - let bounds = Rectangle { + let drawing_bounds = Rectangle { width: adjusted_fit.width, height: adjusted_fit.height, - ..layout.bounds() + ..bounds }; - renderer.draw(self.handle.clone(), bounds + offset) + renderer.draw(self.handle.clone(), drawing_bounds + offset) }; if adjusted_fit.width > bounds.width || adjusted_fit.height > bounds.height { - renderer.with_layer(layout.bounds(), render); + renderer.with_layer(bounds, render); } else { render(renderer) } -- cgit From 15b4bbd49dfb4f70e1e73699958a764c0568b452 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 16 Feb 2022 18:16:09 +0700 Subject: Hash `content_fit` in `hash_layout` of `Image` and `Svg` --- native/src/widget/image.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'native/src/widget/image.rs') diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs index 6aab76e4..83c24ee5 100644 --- a/native/src/widget/image.rs +++ b/native/src/widget/image.rs @@ -157,6 +157,7 @@ where self.handle.hash(state); self.width.hash(state); self.height.hash(state); + self.content_fit.hash(state); } } -- cgit From 1313c94e3bb206f064462bc521f78dbffc2a6cd6 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 22 Feb 2022 14:10:49 +0700 Subject: Remove `hash_layout` method from `Widget` trait --- native/src/widget/image.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'native/src/widget/image.rs') diff --git a/native/src/widget/image.rs b/native/src/widget/image.rs index 83c24ee5..de0ffbc0 100644 --- a/native/src/widget/image.rs +++ b/native/src/widget/image.rs @@ -6,8 +6,7 @@ use crate::image; use crate::layout; use crate::renderer; use crate::{ - ContentFit, Element, Hasher, Layout, Length, Point, Rectangle, Size, - Vector, Widget, + ContentFit, Element, Layout, Length, Point, Rectangle, Size, Vector, Widget, }; use std::hash::Hash; @@ -149,16 +148,6 @@ where render(renderer) } } - - fn hash_layout(&self, state: &mut Hasher) { - struct Marker; - std::any::TypeId::of::().hash(state); - - self.handle.hash(state); - self.width.hash(state); - self.height.hash(state); - self.content_fit.hash(state); - } } impl<'a, Message, Renderer, Handle> From> -- cgit