img.rs

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