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/svg.rs | 83 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 16 deletions(-) (limited to 'native/src/widget/svg.rs') diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs index f212dfcb..9e3639db 100644 --- a/native/src/widget/svg.rs +++ b/native/src/widget/svg.rs @@ -2,7 +2,10 @@ use crate::layout; use crate::renderer; use crate::svg::{self, Handle}; -use crate::{Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget}; +use crate::{ + ContentFit, Element, Hasher, Layout, Length, Point, Rectangle, Size, + Vector, Widget, +}; use std::hash::Hash; use std::path::PathBuf; @@ -18,6 +21,7 @@ pub struct Svg { handle: Handle, width: Length, height: Length, + content_fit: ContentFit, } impl Svg { @@ -27,6 +31,7 @@ impl Svg { handle: handle.into(), width: Length::Fill, height: Length::Shrink, + content_fit: ContentFit::Contain, } } @@ -47,6 +52,16 @@ impl Svg { self.height = height; self } + + /// Sets the [`ContentFit`] of the [`Svg`]. + /// + /// Defaults to [`ContentFit::Contain`] + pub fn content_fit(self, content_fit: ContentFit) -> Self { + Self { + content_fit, + ..self + } + } } impl Widget for Svg @@ -66,24 +81,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.content_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( @@ -94,7 +117,35 @@ where _cursor_position: Point, _viewport: &Rectangle, ) { - renderer.draw(self.handle.clone(), layout.bounds()) + 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 render = |renderer: &mut Renderer| { + 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 + || adjusted_fit.height > bounds.height + { + renderer.with_layer(layout.bounds(), render); + } else { + render(renderer) + } } fn hash_layout(&self, state: &mut Hasher) { -- 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/svg.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'native/src/widget/svg.rs') diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs index 9e3639db..5ce8d25b 100644 --- a/native/src/widget/svg.rs +++ b/native/src/widget/svg.rs @@ -120,9 +120,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( @@ -130,19 +129,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/svg.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'native/src/widget/svg.rs') diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs index 5ce8d25b..22aac331 100644 --- a/native/src/widget/svg.rs +++ b/native/src/widget/svg.rs @@ -153,6 +153,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/svg.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'native/src/widget/svg.rs') diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs index 22aac331..008ab356 100644 --- a/native/src/widget/svg.rs +++ b/native/src/widget/svg.rs @@ -3,11 +3,9 @@ use crate::layout; use crate::renderer; use crate::svg::{self, Handle}; 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; use std::path::PathBuf; /// A vector graphics image. @@ -146,15 +144,6 @@ where render(renderer) } } - - fn hash_layout(&self, state: &mut Hasher) { - 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> From for Element<'a, Message, Renderer> -- cgit