img.rs

  1use crate::{
  2    Bounds, Element, InteractiveElement, InteractiveElementState, Interactivity, LayoutId, Pixels,
  3    RenderOnce, SharedString, StyleRefinement, Styled, WindowContext,
  4};
  5use futures::FutureExt;
  6use util::ResultExt;
  7
  8pub struct Img {
  9    interactivity: Interactivity,
 10    uri: Option<SharedString>,
 11    grayscale: bool,
 12}
 13
 14pub fn img() -> Img {
 15    Img {
 16        interactivity: Interactivity::default(),
 17        uri: None,
 18        grayscale: false,
 19    }
 20}
 21
 22impl Img {
 23    pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
 24        self.uri = Some(uri.into());
 25        self
 26    }
 27
 28    pub fn grayscale(mut self, grayscale: bool) -> Self {
 29        self.grayscale = grayscale;
 30        self
 31    }
 32}
 33
 34impl Element for Img {
 35    type State = InteractiveElementState;
 36
 37    fn layout(
 38        &mut self,
 39        element_state: Option<Self::State>,
 40        cx: &mut WindowContext,
 41    ) -> (LayoutId, Self::State) {
 42        self.interactivity.layout(element_state, cx, |style, cx| {
 43            cx.request_layout(&style, None)
 44        })
 45    }
 46
 47    fn paint(
 48        self,
 49        bounds: Bounds<Pixels>,
 50        element_state: &mut Self::State,
 51        cx: &mut WindowContext,
 52    ) {
 53        self.interactivity.paint(
 54            bounds,
 55            bounds.size,
 56            element_state,
 57            cx,
 58            |style, _scroll_offset, cx| {
 59                let corner_radii = style.corner_radii;
 60
 61                if let Some(uri) = self.uri.clone() {
 62                    // eprintln!(">>> image_cache.get({uri}");
 63                    let image_future = cx.image_cache.get(uri.clone());
 64                    // eprintln!("<<< image_cache.get({uri}");
 65                    if let Some(data) = image_future
 66                        .clone()
 67                        .now_or_never()
 68                        .and_then(|result| result.ok())
 69                    {
 70                        let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
 71                        cx.with_z_index(1, |cx| {
 72                            cx.paint_image(bounds, corner_radii, data, self.grayscale)
 73                                .log_err()
 74                        });
 75                    } else {
 76                        cx.spawn(|mut cx| async move {
 77                            if image_future.await.ok().is_some() {
 78                                cx.on_next_frame(|cx| cx.notify());
 79                            }
 80                        })
 81                        .detach()
 82                    }
 83                }
 84            },
 85        )
 86    }
 87}
 88
 89impl RenderOnce for Img {
 90    type Element = Self;
 91
 92    fn element_id(&self) -> Option<crate::ElementId> {
 93        self.interactivity.element_id.clone()
 94    }
 95
 96    fn render_once(self) -> Self::Element {
 97        self
 98    }
 99}
100
101impl Styled for Img {
102    fn style(&mut self) -> &mut StyleRefinement {
103        &mut self.interactivity.base_style
104    }
105}
106
107impl InteractiveElement for Img {
108    fn interactivity(&mut self) -> &mut Interactivity {
109        &mut self.interactivity
110    }
111}