1use crate::{
2 BorrowWindow, Element, Layout, LayoutId, Result, SharedString, Style, StyleHelpers, 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 layout: Layout,
58 _: &mut Self::State,
59 _: &mut Self::FrameState,
60 cx: &mut ViewContext<Self::State>,
61 ) -> Result<()> {
62 let style = self.computed_style();
63 let order = layout.order;
64 let bounds = layout.bounds;
65
66 style.paint(order, bounds, cx);
67
68 if let Some(uri) = self.uri.clone() {
69 let image_future = cx.image_cache.get(uri);
70 if let Some(data) = image_future
71 .clone()
72 .now_or_never()
73 .and_then(ResultExt::log_err)
74 {
75 let corner_radii = style.corner_radii.to_pixels(bounds, cx.rem_size());
76 cx.paint_image(bounds, corner_radii, order, data, self.grayscale)?;
77 } else {
78 cx.spawn(|_, mut cx| async move {
79 if image_future.await.log_err().is_some() {
80 cx.on_next_frame(|cx| {
81 cx.notify();
82 });
83 }
84 })
85 .detach()
86 }
87 }
88 Ok(())
89 }
90}
91
92impl<S> Styled for Img<S> {
93 type Style = Style;
94
95 fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
96 &mut self.style
97 }
98
99 fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
100 self.style.base()
101 }
102}
103
104impl<S> StyleHelpers for Img<S> {}