img.rs

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