1use crate::{
2 BorrowWindow, ContentMask, Element, IsZero, Layout, LayoutId, Result, SharedString, Style,
3 StyleHelpers, Styled, 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: '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 if corner_radii.is_zero() {
77 cx.paint_image(bounds, order, data, self.grayscale)?;
78 } else {
79 cx.with_content_mask(
80 ContentMask {
81 bounds,
82 corner_radii,
83 },
84 |cx| cx.paint_image(bounds, order, data, self.grayscale),
85 )?;
86 }
87 } else {
88 log::warn!("image not loaded yet");
89 // cx.spawn(|this, mut cx| async move {
90 // if image_future.await.log_err().is_some() {
91 // this.update(&mut cx, |_, cx| cx.notify()).ok();
92 // }
93 // })
94 // .detach();
95 }
96 }
97 Ok(())
98 }
99}
100
101impl<S> Styled for Img<S> {
102 type Style = Style;
103
104 fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
105 &mut self.style
106 }
107
108 fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
109 self.style.base()
110 }
111}
112
113impl<S> StyleHelpers for Img<S> {}