img.rs

  1use crate::{
  2    div, Active, AnyElement, BorrowWindow, Bounds, Div, DivState, Element, ElementFocusability,
  3    ElementId, ElementInteractivity, Focus, FocusListeners, Focusable, Hover, IntoAnyElement,
  4    LayoutId, NonFocusable, Pixels, SharedString, StatefulInteractivity, StatefullyInteractive,
  5    StatelessInteractivity, StatelesslyInteractive, StyleRefinement, Styled, ViewContext,
  6};
  7use futures::FutureExt;
  8use util::ResultExt;
  9
 10pub struct Img<
 11    V: 'static + Send + Sync,
 12    I: ElementInteractivity<V> = StatelessInteractivity<V>,
 13    F: ElementFocusability<V> = NonFocusable,
 14> {
 15    base: Div<V, I, F>,
 16    uri: Option<SharedString>,
 17    grayscale: bool,
 18}
 19
 20pub fn img<V>() -> Img<V, StatelessInteractivity<V>, NonFocusable>
 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: ElementInteractivity<V>,
 35    F: ElementFocusability<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, StatelessInteractivity<V>, F>
 49where
 50    V: 'static + Send + Sync,
 51    F: ElementFocusability<V>,
 52{
 53    pub fn id(self, id: impl Into<ElementId>) -> Img<V, StatefulInteractivity<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: ElementInteractivity<V>,
 66    F: ElementFocusability<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: ElementInteractivity<V>,
 77    F: ElementFocusability<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: ElementInteractivity<V>,
146    F: ElementFocusability<V>,
147{
148    fn style(&mut self) -> &mut StyleRefinement {
149        self.base.style()
150    }
151}
152
153impl<V, I, F> StatelesslyInteractive for Img<V, I, F>
154where
155    V: 'static + Send + Sync,
156    I: ElementInteractivity<V>,
157    F: ElementFocusability<V>,
158{
159    fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
160        self.base.stateless_interactivity()
161    }
162}
163
164impl<V, I, F> Hover for Img<V, I, F>
165where
166    V: 'static + Send + Sync,
167    I: ElementInteractivity<V>,
168    F: ElementFocusability<V>,
169{
170    fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
171        self.base.set_hover_style(group, style);
172    }
173}
174
175impl<V, F> StatefullyInteractive for Img<V, StatefulInteractivity<V>, F>
176where
177    V: 'static + Send + Sync,
178    F: ElementFocusability<V>,
179{
180    fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState> {
181        self.base.stateful_interactivity()
182    }
183}
184
185impl<V, F> Active for Img<V, StatefulInteractivity<V>, F>
186where
187    V: 'static + Send + Sync,
188    F: ElementFocusability<V>,
189{
190    fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
191        self.base.set_active_style(group, style)
192    }
193}
194
195impl<V, I> Focus for Img<V, I, Focusable<V>>
196where
197    V: 'static + Send + Sync,
198    I: ElementInteractivity<V>,
199{
200    fn focus_listeners(&mut self) -> &mut FocusListeners<Self::ViewState> {
201        self.base.focus_listeners()
202    }
203
204    fn set_focus_style(&mut self, style: StyleRefinement) {
205        self.base.set_focus_style(style)
206    }
207
208    fn set_focus_in_style(&mut self, style: StyleRefinement) {
209        self.base.set_focus_in_style(style)
210    }
211
212    fn set_in_focus_style(&mut self, style: StyleRefinement) {
213        self.base.set_in_focus_style(style)
214    }
215
216    fn handle(&self) -> &crate::FocusHandle {
217        self.base.handle()
218    }
219}