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            // eprintln!(">>> image_cache.get({uri}");
113            let image_future = cx.image_cache.get(uri.clone());
114            // eprintln!("<<< image_cache.get({uri}");
115            if let Some(data) = image_future
116                .clone()
117                .now_or_never()
118                .and_then(ResultExt::log_err)
119            {
120                let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
121                cx.stack(1, |cx| {
122                    cx.paint_image(bounds, corner_radii, data, self.grayscale)
123                        .log_err()
124                });
125            } else {
126                cx.spawn(|_, mut cx| async move {
127                    if image_future.await.log_err().is_some() {
128                        cx.on_next_frame(|cx| cx.notify());
129                    }
130                })
131                .detach()
132            }
133        }
134    }
135}
136
137impl<V, I, F> Styled for Img<V, I, F>
138where
139    I: ElementInteraction<V>,
140    F: ElementFocus<V>,
141{
142    fn style(&mut self) -> &mut StyleRefinement {
143        self.base.style()
144    }
145}
146
147impl<V, I, F> StatelessInteractive<V> for Img<V, I, F>
148where
149    I: ElementInteraction<V>,
150    F: ElementFocus<V>,
151{
152    fn stateless_interaction(&mut self) -> &mut StatelessInteraction<V> {
153        self.base.stateless_interaction()
154    }
155}
156
157impl<V, F> StatefulInteractive<V> for Img<V, StatefulInteraction<V>, F>
158where
159    F: ElementFocus<V>,
160{
161    fn stateful_interaction(&mut self) -> &mut StatefulInteraction<V> {
162        self.base.stateful_interaction()
163    }
164}
165
166impl<V, I> Focusable<V> for Img<V, I, FocusEnabled<V>>
167where
168    V: 'static,
169    I: ElementInteraction<V>,
170{
171    fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
172        self.base.focus_listeners()
173    }
174
175    fn set_focus_style(&mut self, style: StyleRefinement) {
176        self.base.set_focus_style(style)
177    }
178
179    fn set_focus_in_style(&mut self, style: StyleRefinement) {
180        self.base.set_focus_in_style(style)
181    }
182
183    fn set_in_focus_style(&mut self, style: StyleRefinement) {
184        self.base.set_in_focus_style(style)
185    }
186}