1use crate::{
2 BorrowWindow, Bounds, Element, LayoutId, Pixels, Result, SharedString, Style, Styled,
3 ViewContext,
4};
5use futures::FutureExt;
6use refineable::RefinementCascade;
7use std::marker::PhantomData;
8use util::ResultExt;
9
10pub struct Img<S> {
11 style: RefinementCascade<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: RefinementCascade::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: Send + Sync + 'static> Element for Img<S> {
39 type State = S;
40 type FrameState = ();
41
42 fn layout(
43 &mut self,
44 _: &mut Self::State,
45 cx: &mut ViewContext<Self::State>,
46 ) -> anyhow::Result<(LayoutId, Self::FrameState)>
47 where
48 Self: Sized,
49 {
50 let style = self.computed_style();
51 let layout_id = cx.request_layout(style, [])?;
52 Ok((layout_id, ()))
53 }
54
55 fn paint(
56 &mut self,
57 bounds: Bounds<Pixels>,
58 _: &mut Self::State,
59 _: &mut Self::FrameState,
60 cx: &mut ViewContext<Self::State>,
61 ) -> Result<()> {
62 let style = self.computed_style();
63
64 style.paint(bounds, cx);
65
66 if let Some(uri) = self.uri.clone() {
67 let image_future = cx.image_cache.get(uri);
68 if let Some(data) = image_future
69 .clone()
70 .now_or_never()
71 .and_then(ResultExt::log_err)
72 {
73 let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
74 cx.stack(1, |cx| {
75 cx.paint_image(bounds, corner_radii, data, self.grayscale)
76 })?;
77 } else {
78 cx.spawn(|_, mut cx| async move {
79 if image_future.await.log_err().is_some() {
80 cx.on_next_frame(|cx| cx.notify());
81 }
82 })
83 .detach()
84 }
85 }
86 Ok(())
87 }
88}
89
90impl<S> Styled for Img<S> {
91 type Style = Style;
92
93 fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
94 &mut self.style
95 }
96
97 fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
98 self.style.base()
99 }
100}