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}