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 initialize(
 75        &mut self,
 76        view_state: &mut V,
 77        element_state: Option<Self::ElementState>,
 78        cx: &mut ViewContext<V>,
 79    ) -> Self::ElementState {
 80        self.base.initialize(view_state, element_state, cx)
 81    }
 82
 83    fn layout(
 84        &mut self,
 85        view_state: &mut V,
 86        element_state: &mut Self::ElementState,
 87        cx: &mut ViewContext<Self::ViewState>,
 88    ) -> LayoutId {
 89        self.base.layout(view_state, element_state, cx)
 90    }
 91
 92    fn paint(
 93        &mut self,
 94        bounds: Bounds<Pixels>,
 95        view: &mut V,
 96        element_state: &mut Self::ElementState,
 97        cx: &mut ViewContext<V>,
 98    ) {
 99        cx.stack(0, |cx| {
100            self.base.paint(bounds, view, element_state, cx);
101        });
102
103        let style = self.base.compute_style(bounds, element_state, cx);
104        let corner_radii = style.corner_radii;
105
106        if let Some(uri) = self.uri.clone() {
107            let image_future = cx.image_cache.get(uri);
108            if let Some(data) = image_future
109                .clone()
110                .now_or_never()
111                .and_then(ResultExt::log_err)
112            {
113                let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
114                cx.stack(1, |cx| {
115                    cx.paint_image(bounds, corner_radii, data, self.grayscale)
116                        .log_err()
117                });
118            } else {
119                cx.spawn(|_, mut cx| async move {
120                    if image_future.await.log_err().is_some() {
121                        cx.on_next_frame(|cx| cx.notify());
122                    }
123                })
124                .detach()
125            }
126        }
127    }
128}
129
130impl<V, K> Styled for Img<V, K>
131where
132    V: 'static + Send + Sync,
133    K: ElementIdentity,
134{
135    fn style(&mut self) -> &mut StyleRefinement {
136        self.base.style()
137    }
138}
139
140impl<V, K> Interactive for Img<V, K>
141where
142    V: 'static + Send + Sync,
143    K: ElementIdentity,
144{
145    fn listeners(&mut self) -> &mut EventListeners<V> {
146        self.base.listeners()
147    }
148}
149
150impl<V, K> Hover for Img<V, K>
151where
152    V: 'static + Send + Sync,
153    K: ElementIdentity,
154{
155    fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
156        self.base.set_hover_style(group, style);
157    }
158}
159
160impl<V> Click for Img<V, Identified> where V: 'static + Send + Sync {}
161
162impl<V> Active for Img<V, Identified>
163where
164    V: 'static + Send + Sync,
165{
166    fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
167        self.base.set_active_style(group, style)
168    }
169}