1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use crate::{
    Bounds, Element, InteractiveElement, InteractiveElementState, Interactivity, LayoutId, Pixels,
    RenderOnce, SharedString, StyleRefinement, Styled, WindowContext,
};
use futures::FutureExt;
use util::ResultExt;

pub struct Img {
    interactivity: Interactivity,
    uri: Option<SharedString>,
    grayscale: bool,
}

pub fn img() -> Img {
    Img {
        interactivity: Interactivity::default(),
        uri: None,
        grayscale: false,
    }
}

impl Img {
    pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
        self.uri = Some(uri.into());
        self
    }

    pub fn grayscale(mut self, grayscale: bool) -> Self {
        self.grayscale = grayscale;
        self
    }
}

impl Element for Img {
    type State = InteractiveElementState;

    fn layout(
        &mut self,
        element_state: Option<Self::State>,
        cx: &mut WindowContext,
    ) -> (LayoutId, Self::State) {
        self.interactivity.layout(element_state, cx, |style, cx| {
            cx.request_layout(&style, None)
        })
    }

    fn paint(
        self,
        bounds: Bounds<Pixels>,
        element_state: &mut Self::State,
        cx: &mut WindowContext,
    ) {
        self.interactivity.paint(
            bounds,
            bounds.size,
            element_state,
            cx,
            |style, _scroll_offset, cx| {
                let corner_radii = style.corner_radii;

                if let Some(uri) = self.uri.clone() {
                    // eprintln!(">>> image_cache.get({uri}");
                    let image_future = cx.image_cache.get(uri.clone());
                    // eprintln!("<<< image_cache.get({uri}");
                    if let Some(data) = image_future
                        .clone()
                        .now_or_never()
                        .and_then(|result| result.ok())
                    {
                        let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
                        cx.with_z_index(1, |cx| {
                            cx.paint_image(bounds, corner_radii, data, self.grayscale)
                                .log_err()
                        });
                    } else {
                        cx.spawn(|mut cx| async move {
                            if image_future.await.ok().is_some() {
                                cx.on_next_frame(|cx| cx.notify());
                            }
                        })
                        .detach()
                    }
                }
            },
        )
    }
}

impl RenderOnce for Img {
    type Element = Self;

    fn element_id(&self) -> Option<crate::ElementId> {
        self.interactivity.element_id.clone()
    }

    fn render_once(self) -> Self::Element {
        self
    }
}

impl Styled for Img {
    fn style(&mut self) -> &mut StyleRefinement {
        &mut self.interactivity.base_style
    }
}

impl InteractiveElement for Img {
    fn interactivity(&mut self) -> &mut Interactivity {
        &mut self.interactivity
    }
}