img.rs

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