1use crate::{
2 div, Active, AnyElement, BorrowWindow, Bounds, Div, Element, ElementFocusability, ElementId,
3 ElementInteractivity, Focus, FocusListeners, Focusable, Hover, InteractiveElementState,
4 IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString, StatefulInteractivity,
5 StatefullyInteractive, StatelessInteractivity, StatelesslyInteractive, StyleRefinement, Styled,
6 ViewContext,
7};
8use futures::FutureExt;
9use util::ResultExt;
10
11pub struct Img<
12 V: 'static + Send + Sync,
13 I: ElementInteractivity<V> = StatelessInteractivity<V>,
14 F: ElementFocusability<V> = NonFocusable,
15> {
16 base: Div<V, I, F>,
17 uri: Option<SharedString>,
18 grayscale: bool,
19}
20
21pub fn img<V>() -> Img<V, StatelessInteractivity<V>, NonFocusable>
22where
23 V: 'static + Send + Sync,
24{
25 Img {
26 base: div(),
27 uri: None,
28 grayscale: false,
29 }
30}
31
32impl<V, I, F> Img<V, I, F>
33where
34 V: 'static + Send + Sync,
35 I: ElementInteractivity<V>,
36 F: ElementFocusability<V>,
37{
38 pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
39 self.uri = Some(uri.into());
40 self
41 }
42
43 pub fn grayscale(mut self, grayscale: bool) -> Self {
44 self.grayscale = grayscale;
45 self
46 }
47}
48
49impl<V, F> Img<V, StatelessInteractivity<V>, F>
50where
51 V: 'static + Send + Sync,
52 F: ElementFocusability<V>,
53{
54 pub fn id(self, id: impl Into<ElementId>) -> Img<V, StatefulInteractivity<V>, F> {
55 Img {
56 base: self.base.id(id),
57 uri: self.uri,
58 grayscale: self.grayscale,
59 }
60 }
61}
62
63impl<V, I, F> IntoAnyElement<V> for Img<V, I, F>
64where
65 V: 'static + Send + Sync,
66 I: ElementInteractivity<V>,
67 F: ElementFocusability<V>,
68{
69 fn into_any(self) -> AnyElement<V> {
70 AnyElement::new(self)
71 }
72}
73
74impl<V, I, F> Element for Img<V, I, F>
75where
76 V: Send + Sync + 'static,
77 I: ElementInteractivity<V>,
78 F: ElementFocusability<V>,
79{
80 type ViewState = V;
81 type ElementState = InteractiveElementState;
82
83 fn id(&self) -> Option<crate::ElementId> {
84 self.base.id()
85 }
86
87 fn initialize(
88 &mut self,
89 view_state: &mut V,
90 element_state: Option<Self::ElementState>,
91 cx: &mut ViewContext<V>,
92 ) -> Self::ElementState {
93 self.base.initialize(view_state, element_state, cx)
94 }
95
96 fn layout(
97 &mut self,
98 view_state: &mut V,
99 element_state: &mut Self::ElementState,
100 cx: &mut ViewContext<Self::ViewState>,
101 ) -> LayoutId {
102 self.base.layout(view_state, element_state, cx)
103 }
104
105 fn paint(
106 &mut self,
107 bounds: Bounds<Pixels>,
108 view: &mut V,
109 element_state: &mut Self::ElementState,
110 cx: &mut ViewContext<V>,
111 ) {
112 cx.stack(0, |cx| {
113 self.base.paint(bounds, view, element_state, cx);
114 });
115
116 let style = self.base.compute_style(bounds, element_state, cx);
117 let corner_radii = style.corner_radii;
118
119 if let Some(uri) = self.uri.clone() {
120 let image_future = cx.image_cache.get(uri);
121 if let Some(data) = image_future
122 .clone()
123 .now_or_never()
124 .and_then(ResultExt::log_err)
125 {
126 let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
127 cx.stack(1, |cx| {
128 cx.paint_image(bounds, corner_radii, data, self.grayscale)
129 .log_err()
130 });
131 } else {
132 cx.spawn(|_, mut cx| async move {
133 if image_future.await.log_err().is_some() {
134 cx.on_next_frame(|cx| cx.notify());
135 }
136 })
137 .detach()
138 }
139 }
140 }
141}
142
143impl<V, I, F> Styled for Img<V, I, F>
144where
145 V: 'static + Send + Sync,
146 I: ElementInteractivity<V>,
147 F: ElementFocusability<V>,
148{
149 fn style(&mut self) -> &mut StyleRefinement {
150 self.base.style()
151 }
152}
153
154impl<V, I, F> StatelesslyInteractive for Img<V, I, F>
155where
156 V: 'static + Send + Sync,
157 I: ElementInteractivity<V>,
158 F: ElementFocusability<V>,
159{
160 fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
161 self.base.stateless_interactivity()
162 }
163}
164
165impl<V, I, F> Hover for Img<V, I, F>
166where
167 V: 'static + Send + Sync,
168 I: ElementInteractivity<V>,
169 F: ElementFocusability<V>,
170{
171 fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
172 self.base.set_hover_style(group, style);
173 }
174}
175
176impl<V, F> StatefullyInteractive for Img<V, StatefulInteractivity<V>, F>
177where
178 V: 'static + Send + Sync,
179 F: ElementFocusability<V>,
180{
181 fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState> {
182 self.base.stateful_interactivity()
183 }
184}
185
186impl<V, F> Active for Img<V, StatefulInteractivity<V>, F>
187where
188 V: 'static + Send + Sync,
189 F: ElementFocusability<V>,
190{
191 fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
192 self.base.set_active_style(group, style)
193 }
194}
195
196impl<V, I> Focus for Img<V, I, Focusable<V>>
197where
198 V: 'static + Send + Sync,
199 I: ElementInteractivity<V>,
200{
201 fn focus_listeners(&mut self) -> &mut FocusListeners<Self::ViewState> {
202 self.base.focus_listeners()
203 }
204
205 fn set_focus_style(&mut self, style: StyleRefinement) {
206 self.base.set_focus_style(style)
207 }
208
209 fn set_focus_in_style(&mut self, style: StyleRefinement) {
210 self.base.set_focus_in_style(style)
211 }
212
213 fn set_in_focus_style(&mut self, style: StyleRefinement) {
214 self.base.set_in_focus_style(style)
215 }
216
217 fn handle(&self) -> &crate::FocusHandle {
218 self.base.handle()
219 }
220}