img.rs

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