img.rs

  1use crate::{
  2    div, Active, Anonymous, AnyElement, BorrowWindow, Bounds, Click, Div, DivState, Element,
  3    ElementId, ElementIdentity, EventListeners, Hover, Identified, Interactive, IntoAnyElement,
  4    LayoutId, NonFocusable, Pixels, SharedString, StyleRefinement, Styled, ViewContext,
  5};
  6use futures::FutureExt;
  7use util::ResultExt;
  8
  9pub struct Img<V: 'static + Send + Sync, K: ElementIdentity = Anonymous> {
 10    base: Div<K, NonFocusable, V>,
 11    uri: Option<SharedString>,
 12    grayscale: bool,
 13}
 14
 15pub fn img<V>() -> Img<V, Anonymous>
 16where
 17    V: 'static + Send + Sync,
 18{
 19    Img {
 20        base: div(),
 21        uri: None,
 22        grayscale: false,
 23    }
 24}
 25
 26impl<V, K> Img<V, K>
 27where
 28    V: 'static + Send + Sync,
 29    K: ElementIdentity,
 30{
 31    pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
 32        self.uri = Some(uri.into());
 33        self
 34    }
 35
 36    pub fn grayscale(mut self, grayscale: bool) -> Self {
 37        self.grayscale = grayscale;
 38        self
 39    }
 40}
 41
 42impl<V: 'static + Send + Sync> Img<V, Anonymous> {
 43    pub fn id(self, id: impl Into<ElementId>) -> Img<V, Identified> {
 44        Img {
 45            base: self.base.id(id),
 46            uri: self.uri,
 47            grayscale: self.grayscale,
 48        }
 49    }
 50}
 51
 52impl<V, K> IntoAnyElement<V> for Img<V, K>
 53where
 54    V: 'static + Send + Sync,
 55    K: ElementIdentity,
 56{
 57    fn into_any(self) -> AnyElement<V> {
 58        AnyElement::new(self)
 59    }
 60}
 61
 62impl<V, K> Element for Img<V, K>
 63where
 64    V: Send + Sync + 'static,
 65    K: ElementIdentity,
 66{
 67    type ViewState = V;
 68    type ElementState = DivState;
 69
 70    fn id(&self) -> Option<crate::ElementId> {
 71        self.base.id()
 72    }
 73
 74    fn layout(
 75        &mut self,
 76        view_state: &mut Self::ViewState,
 77        element_state: Option<Self::ElementState>,
 78        cx: &mut ViewContext<Self::ViewState>,
 79    ) -> (LayoutId, Self::ElementState)
 80    where
 81        Self: Sized,
 82    {
 83        self.base.layout(view_state, element_state, cx)
 84    }
 85
 86    fn paint(
 87        &mut self,
 88        bounds: Bounds<Pixels>,
 89        view: &mut Self::ViewState,
 90        element_state: &mut Self::ElementState,
 91        cx: &mut ViewContext<Self::ViewState>,
 92    ) {
 93        cx.stack(0, |cx| {
 94            self.base.paint(bounds, view, element_state, cx);
 95        });
 96
 97        let style = self.base.compute_style(bounds, element_state, cx);
 98        let corner_radii = style.corner_radii;
 99
100        if let Some(uri) = self.uri.clone() {
101            let image_future = cx.image_cache.get(uri);
102            if let Some(data) = image_future
103                .clone()
104                .now_or_never()
105                .and_then(ResultExt::log_err)
106            {
107                let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
108                cx.stack(1, |cx| {
109                    cx.paint_image(bounds, corner_radii, data, self.grayscale)
110                        .log_err()
111                });
112            } else {
113                cx.spawn(|_, mut cx| async move {
114                    if image_future.await.log_err().is_some() {
115                        cx.on_next_frame(|cx| cx.notify());
116                    }
117                })
118                .detach()
119            }
120        }
121    }
122}
123
124impl<V, K> Styled for Img<V, K>
125where
126    V: 'static + Send + Sync,
127    K: ElementIdentity,
128{
129    fn style(&mut self) -> &mut StyleRefinement {
130        self.base.style()
131    }
132}
133
134impl<V, K> Interactive for Img<V, K>
135where
136    V: 'static + Send + Sync,
137    K: ElementIdentity,
138{
139    fn listeners(&mut self) -> &mut EventListeners<V> {
140        self.base.listeners()
141    }
142}
143
144impl<V, K> Hover for Img<V, K>
145where
146    V: 'static + Send + Sync,
147    K: ElementIdentity,
148{
149    fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
150        self.base.set_hover_style(group, style);
151    }
152}
153
154impl<V> Click for Img<V, Identified> where V: 'static + Send + Sync {}
155
156impl<V> Active for Img<V, Identified>
157where
158    V: 'static + Send + Sync,
159{
160    fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
161        self.base.set_active_style(group, style)
162    }
163}