1use crate::{
2 div, Active, Anonymous, AnyElement, BorrowWindow, Bounds, Click, Div, DivState, Element,
3 ElementId, ElementIdentity, EventListeners, Hover, Identified, Interactive, IntoAnyElement,
4 LayoutId, NonFocusable, Pixels, SharedString, StyleRefinement, Styled, ViewContext,
5};
6use futures::FutureExt;
7use util::ResultExt;
8
9pub struct Img<V: 'static + Send + Sync, K: ElementIdentity = Anonymous> {
10 base: Div<K, NonFocusable, V>,
11 uri: Option<SharedString>,
12 grayscale: bool,
13}
14
15pub fn img<V>() -> Img<V, Anonymous>
16where
17 V: 'static + Send + Sync,
18{
19 Img {
20 base: div(),
21 uri: None,
22 grayscale: false,
23 }
24}
25
26impl<V, K> Img<V, K>
27where
28 V: 'static + Send + Sync,
29 K: ElementIdentity,
30{
31 pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
32 self.uri = Some(uri.into());
33 self
34 }
35
36 pub fn grayscale(mut self, grayscale: bool) -> Self {
37 self.grayscale = grayscale;
38 self
39 }
40}
41
42impl<V: 'static + Send + Sync> Img<V, Anonymous> {
43 pub fn id(self, id: impl Into<ElementId>) -> Img<V, Identified> {
44 Img {
45 base: self.base.id(id),
46 uri: self.uri,
47 grayscale: self.grayscale,
48 }
49 }
50}
51
52impl<V, K> IntoAnyElement<V> for Img<V, K>
53where
54 V: 'static + Send + Sync,
55 K: ElementIdentity,
56{
57 fn into_any(self) -> AnyElement<V> {
58 AnyElement::new(self)
59 }
60}
61
62impl<V, K> Element for Img<V, K>
63where
64 V: Send + Sync + 'static,
65 K: ElementIdentity,
66{
67 type ViewState = V;
68 type ElementState = DivState;
69
70 fn id(&self) -> Option<crate::ElementId> {
71 self.base.id()
72 }
73
74 fn initialize(
75 &mut self,
76 view_state: &mut V,
77 element_state: Option<Self::ElementState>,
78 cx: &mut ViewContext<V>,
79 ) -> Self::ElementState {
80 self.base.initialize(view_state, element_state, cx)
81 }
82
83 fn layout(
84 &mut self,
85 view_state: &mut V,
86 element_state: &mut Self::ElementState,
87 cx: &mut ViewContext<Self::ViewState>,
88 ) -> LayoutId {
89 self.base.layout(view_state, element_state, cx)
90 }
91
92 fn paint(
93 &mut self,
94 bounds: Bounds<Pixels>,
95 view: &mut V,
96 element_state: &mut Self::ElementState,
97 cx: &mut ViewContext<V>,
98 ) {
99 cx.stack(0, |cx| {
100 self.base.paint(bounds, view, element_state, cx);
101 });
102
103 let style = self.base.compute_style(bounds, element_state, cx);
104 let corner_radii = style.corner_radii;
105
106 if let Some(uri) = self.uri.clone() {
107 let image_future = cx.image_cache.get(uri);
108 if let Some(data) = image_future
109 .clone()
110 .now_or_never()
111 .and_then(ResultExt::log_err)
112 {
113 let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
114 cx.stack(1, |cx| {
115 cx.paint_image(bounds, corner_radii, data, self.grayscale)
116 .log_err()
117 });
118 } else {
119 cx.spawn(|_, mut cx| async move {
120 if image_future.await.log_err().is_some() {
121 cx.on_next_frame(|cx| cx.notify());
122 }
123 })
124 .detach()
125 }
126 }
127 }
128}
129
130impl<V, K> Styled for Img<V, K>
131where
132 V: 'static + Send + Sync,
133 K: ElementIdentity,
134{
135 fn style(&mut self) -> &mut StyleRefinement {
136 self.base.style()
137 }
138}
139
140impl<V, K> Interactive for Img<V, K>
141where
142 V: 'static + Send + Sync,
143 K: ElementIdentity,
144{
145 fn listeners(&mut self) -> &mut EventListeners<V> {
146 self.base.listeners()
147 }
148}
149
150impl<V, K> Hover for Img<V, K>
151where
152 V: 'static + Send + Sync,
153 K: ElementIdentity,
154{
155 fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
156 self.base.set_hover_style(group, style);
157 }
158}
159
160impl<V> Click for Img<V, Identified> where V: 'static + Send + Sync {}
161
162impl<V> Active for Img<V, Identified>
163where
164 V: 'static + Send + Sync,
165{
166 fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
167 self.base.set_active_style(group, style)
168 }
169}