img.rs

  1use crate::{
  2    BorrowWindow, ContentMask, Element, IsZero, Layout, LayoutId, Result, SharedString, Style,
  3    StyleHelpers, Styled, ViewContext,
  4};
  5use futures::FutureExt;
  6use refineable::RefinementCascade;
  7use std::marker::PhantomData;
  8use util::ResultExt;
  9
 10pub struct Img<S> {
 11    style: RefinementCascade<Style>,
 12    uri: Option<SharedString>,
 13    grayscale: bool,
 14    state_type: PhantomData<S>,
 15}
 16
 17pub fn img<S>() -> Img<S> {
 18    Img {
 19        style: RefinementCascade::default(),
 20        uri: None,
 21        grayscale: false,
 22        state_type: PhantomData,
 23    }
 24}
 25
 26impl<S> Img<S> {
 27    pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
 28        self.uri = Some(uri.into());
 29        self
 30    }
 31
 32    pub fn grayscale(mut self, grayscale: bool) -> Self {
 33        self.grayscale = grayscale;
 34        self
 35    }
 36}
 37
 38impl<S: 'static> Element for Img<S> {
 39    type State = S;
 40    type FrameState = ();
 41
 42    fn layout(
 43        &mut self,
 44        _: &mut Self::State,
 45        cx: &mut ViewContext<Self::State>,
 46    ) -> anyhow::Result<(LayoutId, Self::FrameState)>
 47    where
 48        Self: Sized,
 49    {
 50        let style = self.computed_style();
 51        let layout_id = cx.request_layout(style, [])?;
 52        Ok((layout_id, ()))
 53    }
 54
 55    fn paint(
 56        &mut self,
 57        layout: Layout,
 58        _: &mut Self::State,
 59        _: &mut Self::FrameState,
 60        cx: &mut ViewContext<Self::State>,
 61    ) -> Result<()> {
 62        let style = self.computed_style();
 63        let order = layout.order;
 64        let bounds = layout.bounds;
 65
 66        style.paint(order, bounds, cx);
 67
 68        if let Some(uri) = self.uri.clone() {
 69            let image_future = cx.image_cache.get(uri);
 70            if let Some(data) = image_future
 71                .clone()
 72                .now_or_never()
 73                .and_then(ResultExt::log_err)
 74            {
 75                let corner_radii = style.corner_radii.to_pixels(bounds, cx.rem_size());
 76                if corner_radii.is_zero() {
 77                    cx.paint_image(bounds, order, data, self.grayscale)?;
 78                } else {
 79                    cx.with_content_mask(
 80                        ContentMask {
 81                            bounds,
 82                            corner_radii,
 83                        },
 84                        |cx| cx.paint_image(bounds, order, data, self.grayscale),
 85                    )?;
 86                }
 87            } else {
 88                log::warn!("image not loaded yet");
 89                // cx.spawn(|this, mut cx| async move {
 90                //     if image_future.await.log_err().is_some() {
 91                //         this.update(&mut cx, |_, cx| cx.notify()).ok();
 92                //     }
 93                // })
 94                // .detach();
 95            }
 96        }
 97        Ok(())
 98    }
 99}
100
101impl<S> Styled for Img<S> {
102    type Style = Style;
103
104    fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
105        &mut self.style
106    }
107
108    fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
109        self.style.base()
110    }
111}
112
113impl<S> StyleHelpers for Img<S> {}