1use crate::{
2 AnyElement, BorrowWindow, Bounds, Element, IntoAnyElement, LayoutId, Pixels, SharedString,
3 Style, Styled, ViewContext,
4};
5use futures::FutureExt;
6use refineable::Cascade;
7use std::marker::PhantomData;
8use util::ResultExt;
9
10pub struct Img<S> {
11 style: Cascade<Style>,
12 uri: Option<SharedString>,
13 grayscale: bool,
14 state_type: PhantomData<S>,
15}
16
17pub fn img<S>() -> Img<S> {
18 Img {
19 style: Cascade::default(),
20 uri: None,
21 grayscale: false,
22 state_type: PhantomData,
23 }
24}
25
26impl<S> Img<S> {
27 pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
28 self.uri = Some(uri.into());
29 self
30 }
31
32 pub fn grayscale(mut self, grayscale: bool) -> Self {
33 self.grayscale = grayscale;
34 self
35 }
36}
37
38impl<S> IntoAnyElement<S> for Img<S>
39where
40 S: 'static + Send + Sync,
41{
42 fn into_any(self) -> AnyElement<S> {
43 AnyElement::new(self)
44 }
45}
46
47impl<S: Send + Sync + 'static> Element for Img<S> {
48 type ViewState = S;
49 type ElementState = ();
50
51 fn element_id(&self) -> Option<crate::ElementId> {
52 None
53 }
54
55 fn layout(
56 &mut self,
57 _: &mut Self::ViewState,
58 _: Option<Self::ElementState>,
59 cx: &mut ViewContext<Self::ViewState>,
60 ) -> (LayoutId, Self::ElementState)
61 where
62 Self: Sized,
63 {
64 let style = self.computed_style();
65 let layout_id = cx.request_layout(style, []);
66 (layout_id, ())
67 }
68
69 fn paint(
70 &mut self,
71 bounds: Bounds<Pixels>,
72 _: &mut Self::ViewState,
73 _: &mut Self::ElementState,
74 cx: &mut ViewContext<Self::ViewState>,
75 ) {
76 let style = self.computed_style();
77
78 style.paint(bounds, cx);
79
80 if let Some(uri) = self.uri.clone() {
81 let image_future = cx.image_cache.get(uri);
82 if let Some(data) = image_future
83 .clone()
84 .now_or_never()
85 .and_then(ResultExt::log_err)
86 {
87 let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
88 cx.stack(1, |cx| {
89 cx.paint_image(bounds, corner_radii, data, self.grayscale)
90 .log_err()
91 });
92 } else {
93 cx.spawn(|_, mut cx| async move {
94 if image_future.await.log_err().is_some() {
95 cx.on_next_frame(|cx| cx.notify());
96 }
97 })
98 .detach()
99 }
100 }
101 }
102}
103
104impl<S> Styled for Img<S> {
105 type Style = Style;
106
107 fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
108 &mut self.style
109 }
110
111 fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
112 self.style.base()
113 }
114}