1use crate::{
2 div, AnyElement, BorrowWindow, Bounds, Div, DivState, Element, ElementFocus, ElementId,
3 ElementInteraction, FocusDisabled, FocusEnabled, FocusListeners, Focusable, IntoAnyElement,
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 + Send + Sync,
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>() -> Img<V, StatelessInteraction<V>, FocusDisabled>
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: ElementInteraction<V>,
35 F: ElementFocus<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, StatelessInteraction<V>, F>
49where
50 V: 'static + Send + Sync,
51 F: ElementFocus<V>,
52{
53 pub fn id(self, id: impl Into<ElementId>) -> Img<V, StatefulInteraction<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: ElementInteraction<V>,
66 F: ElementFocus<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: ElementInteraction<V>,
77 F: ElementFocus<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: ElementInteraction<V>,
146 F: ElementFocus<V>,
147{
148 fn style(&mut self) -> &mut StyleRefinement {
149 self.base.style()
150 }
151}
152
153impl<V, I, F> StatelessInteractive for Img<V, I, F>
154where
155 V: 'static + Send + Sync,
156 I: ElementInteraction<V>,
157 F: ElementFocus<V>,
158{
159 fn stateless_interactivity(&mut self) -> &mut StatelessInteraction<V> {
160 self.base.stateless_interactivity()
161 }
162}
163
164impl<V, F> StatefulInteractive for Img<V, StatefulInteraction<V>, F>
165where
166 V: 'static + Send + Sync,
167 F: ElementFocus<V>,
168{
169 fn stateful_interaction(&mut self) -> &mut StatefulInteraction<Self::ViewState> {
170 self.base.stateful_interaction()
171 }
172}
173
174impl<V, I> Focusable for Img<V, I, FocusEnabled<V>>
175where
176 V: 'static + Send + Sync,
177 I: ElementInteraction<V>,
178{
179 fn focus_listeners(&mut self) -> &mut FocusListeners<Self::ViewState> {
180 self.base.focus_listeners()
181 }
182
183 fn set_focus_style(&mut self, style: StyleRefinement) {
184 self.base.set_focus_style(style)
185 }
186
187 fn set_focus_in_style(&mut self, style: StyleRefinement) {
188 self.base.set_focus_in_style(style)
189 }
190
191 fn set_in_focus_style(&mut self, style: StyleRefinement) {
192 self.base.set_in_focus_style(style)
193 }
194}