img.rs

  1use crate::{
  2    AnyElement, BorrowWindow, Bounds, Element, IntoAnyElement, LayoutId, Pixels, SharedString,
  3    Style, Styled, ViewContext,
  4};
  5use futures::FutureExt;
  6use refineable::Cascade;
  7use std::marker::PhantomData;
  8use util::ResultExt;
  9
 10pub struct Img<S> {
 11    style: Cascade<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: Cascade::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> IntoAnyElement<S> for Img<S>
 39where
 40    S: 'static + Send + Sync,
 41{
 42    fn into_any(self) -> AnyElement<S> {
 43        AnyElement::new(self)
 44    }
 45}
 46
 47impl<S: Send + Sync + 'static> Element for Img<S> {
 48    type ViewState = S;
 49    type ElementState = ();
 50
 51    fn element_id(&self) -> Option<crate::ElementId> {
 52        None
 53    }
 54
 55    fn layout(
 56        &mut self,
 57        _: &mut Self::ViewState,
 58        _: Option<Self::ElementState>,
 59        cx: &mut ViewContext<Self::ViewState>,
 60    ) -> (LayoutId, Self::ElementState)
 61    where
 62        Self: Sized,
 63    {
 64        let style = self.computed_style();
 65        let layout_id = cx.request_layout(style, []);
 66        (layout_id, ())
 67    }
 68
 69    fn paint(
 70        &mut self,
 71        bounds: Bounds<Pixels>,
 72        _: &mut Self::ViewState,
 73        _: &mut Self::ElementState,
 74        cx: &mut ViewContext<Self::ViewState>,
 75    ) {
 76        let style = self.computed_style();
 77
 78        style.paint(bounds, cx);
 79
 80        if let Some(uri) = self.uri.clone() {
 81            let image_future = cx.image_cache.get(uri);
 82            if let Some(data) = image_future
 83                .clone()
 84                .now_or_never()
 85                .and_then(ResultExt::log_err)
 86            {
 87                let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
 88                cx.stack(1, |cx| {
 89                    cx.paint_image(bounds, corner_radii, data, self.grayscale)
 90                        .log_err()
 91                });
 92            } else {
 93                cx.spawn(|_, mut cx| async move {
 94                    if image_future.await.log_err().is_some() {
 95                        cx.on_next_frame(|cx| cx.notify());
 96                    }
 97                })
 98                .detach()
 99            }
100        }
101    }
102}
103
104impl<S> Styled for Img<S> {
105    type Style = Style;
106
107    fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
108        &mut self.style
109    }
110
111    fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
112        self.style.base()
113    }
114}