From 3ac545088ac41e7b27ed855de84ba9cfafdceaf9 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 28 Nov 2023 17:32:27 +0100 Subject: [PATCH] WIP: preserve aspect ratio of images --- crates/call2/src/shared_screen.rs | 2 +- crates/gpui2/src/elements/img.rs | 134 ++++++++++++++++------------ crates/gpui2/src/geometry.rs | 6 ++ crates/ui2/src/components/avatar.rs | 5 +- 4 files changed, 88 insertions(+), 59 deletions(-) diff --git a/crates/call2/src/shared_screen.rs b/crates/call2/src/shared_screen.rs index 14b997af3b4f7221ff6a2acded9af516d7773310..58d8445f8f0ef242ba563eeca76d2c3da5d78030 100644 --- a/crates/call2/src/shared_screen.rs +++ b/crates/call2/src/shared_screen.rs @@ -72,7 +72,7 @@ impl Render for SharedScreen { // self.current_frame_id = self.current_frame_id.wrapping_add(1); div() .size_full() - .children(frame.map(|frame| img().size_full().surface(frame.image()))) + .children(frame.map(|frame| img(frame.image()).w_full())) } } // impl View for SharedScreen { diff --git a/crates/gpui2/src/elements/img.rs b/crates/gpui2/src/elements/img.rs index 1c1fbd0961fb0a86a1c407d803245d11ce1c72d6..87a7cda07fe11d9f9da0fee9c33a76551b3b8347 100644 --- a/crates/gpui2/src/elements/img.rs +++ b/crates/gpui2/src/elements/img.rs @@ -1,8 +1,8 @@ use std::sync::Arc; use crate::{ - Bounds, Element, ImageData, InteractiveElement, InteractiveElementState, Interactivity, - IntoElement, LayoutId, Pixels, SharedString, StyleRefinement, Styled, WindowContext, + size, Bounds, Element, ImageData, InteractiveElement, InteractiveElementState, Interactivity, + IntoElement, LayoutId, Pixels, SharedString, Size, StyleRefinement, Styled, WindowContext, }; use futures::FutureExt; use media::core_video::CVImageBuffer; @@ -36,38 +36,19 @@ impl From for ImageSource { pub struct Img { interactivity: Interactivity, - source: Option, + source: ImageSource, grayscale: bool, } -pub fn img() -> Img { +pub fn img(source: impl Into) -> Img { Img { interactivity: Interactivity::default(), - source: None, + source: source.into(), grayscale: false, } } impl Img { - pub fn uri(mut self, uri: impl Into) -> Self { - self.source = Some(ImageSource::from(uri.into())); - self - } - - pub fn data(mut self, data: Arc) -> Self { - self.source = Some(ImageSource::from(data)); - self - } - - pub fn surface(mut self, data: CVImageBuffer) -> Self { - self.source = Some(ImageSource::from(data)); - self - } - - pub fn source(mut self, source: impl Into) -> Self { - self.source = Some(source.into()); - self - } pub fn grayscale(mut self, grayscale: bool) -> Self { self.grayscale = grayscale; self @@ -83,7 +64,52 @@ impl Element for Img { cx: &mut WindowContext, ) -> (LayoutId, Self::State) { self.interactivity.layout(element_state, cx, |style, cx| { - cx.request_layout(&style, None) + let image_size = match &self.source { + ImageSource::Uri(uri) => { + let image_future = cx.image_cache.get(uri.clone()); + if let Some(data) = image_future + .clone() + .now_or_never() + .and_then(|result| result.ok()) + { + data.size().map(|pixels| Pixels::from(u32::from(pixels))) + } else { + Size::default() + } + } + + ImageSource::Data(data) => { + data.size().map(|pixels| Pixels::from(u32::from(pixels))) + } + + ImageSource::Surface(surface) => { + size(surface.width().into(), surface.height().into()) + } + }; + dbg!(image_size); + + cx.request_measured_layout( + style, + cx.rem_size(), + move |known_dimensions, available_space| match dbg!( + known_dimensions.width, + known_dimensions.height, + ) { + (None, None) => image_size, + + (None, Some(height)) => { + let aspect_ratio = height / image_size.height; + size(image_size.width * aspect_ratio, height) + } + + (Some(width), None) => { + let aspect_ratio = width / image_size.width; + size(width, image_size.height * aspect_ratio) + } + + (Some(width), Some(height)) => size(width, height), + }, + ) }) } @@ -101,38 +127,36 @@ impl Element for Img { |style, _scroll_offset, cx| { let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size()); cx.with_z_index(1, |cx| { - if let Some(source) = self.source { - match source { - ImageSource::Uri(uri) => { - let image_future = cx.image_cache.get(uri.clone()); - if let Some(data) = image_future - .clone() - .now_or_never() - .and_then(|result| result.ok()) - { - cx.paint_image(bounds, corner_radii, data, self.grayscale) - .log_err(); - } else { - cx.spawn(|mut cx| async move { - if image_future.await.ok().is_some() { - cx.on_next_frame(|cx| cx.notify()); - } - }) - .detach(); - } - } - - ImageSource::Data(image) => { - cx.paint_image(bounds, corner_radii, image, self.grayscale) + match self.source { + ImageSource::Uri(uri) => { + let image_future = cx.image_cache.get(uri.clone()); + if let Some(data) = image_future + .clone() + .now_or_never() + .and_then(|result| result.ok()) + { + cx.paint_image(bounds, corner_radii, data, self.grayscale) .log_err(); + } else { + cx.spawn(|mut cx| async move { + if image_future.await.ok().is_some() { + cx.on_next_frame(|cx| cx.notify()); + } + }) + .detach(); } - - ImageSource::Surface(surface) => { - // TODO: Add support for corner_radii and grayscale. - cx.paint_surface(bounds, surface); - } - }; - } + } + + ImageSource::Data(image) => { + cx.paint_image(bounds, corner_radii, image, self.grayscale) + .log_err(); + } + + ImageSource::Surface(surface) => { + // TODO: Add support for corner_radii and grayscale. + cx.paint_surface(bounds, surface); + } + }; }); }, ) diff --git a/crates/gpui2/src/geometry.rs b/crates/gpui2/src/geometry.rs index e1f039e309466bcd07e867551b2e082b27c6a186..5ade68663c6ea4a379663044027bd0dbef9061ae 100644 --- a/crates/gpui2/src/geometry.rs +++ b/crates/gpui2/src/geometry.rs @@ -905,6 +905,12 @@ impl From for usize { } } +impl From for Pixels { + fn from(pixels: usize) -> Self { + Pixels(pixels as f32) + } +} + #[derive( Add, AddAssign, Clone, Copy, Default, Div, Eq, Hash, Ord, PartialEq, PartialOrd, Sub, SubAssign, )] diff --git a/crates/ui2/src/components/avatar.rs b/crates/ui2/src/components/avatar.rs index d358b221da9287f488bd68dd95bcff659191b5a5..f74a7d02eadfa5a076ce07c219983f4e60853551 100644 --- a/crates/ui2/src/components/avatar.rs +++ b/crates/ui2/src/components/avatar.rs @@ -20,7 +20,7 @@ impl RenderOnce for Avatar { type Rendered = Img; fn render(self, _: &mut WindowContext) -> Self::Rendered { - let mut img = img(); + let mut img = img(self.src); if self.shape == Shape::Circle { img = img.rounded_full(); @@ -28,8 +28,7 @@ impl RenderOnce for Avatar { img = img.rounded_md(); } - img.source(self.src.clone()) - .size_4() + img.size_4() // todo!(Pull the avatar fallback background from the theme.) .bg(gpui::red()) }