1use crate as gpui2;
2use crate::style::{StyleHelpers, Styleable};
3use crate::{style::Style, Element};
4use futures::FutureExt;
5use gpui::scene;
6use gpui2_macros::IntoElement;
7use refineable::RefinementCascade;
8use util::arc_cow::ArcCow;
9use util::ResultExt;
10
11#[derive(IntoElement)]
12pub struct Img {
13 style: RefinementCascade<Style>,
14 uri: Option<ArcCow<'static, str>>,
15}
16
17pub fn img() -> Img {
18 Img {
19 style: RefinementCascade::default(),
20 uri: None,
21 }
22}
23
24impl Img {
25 pub fn uri(mut self, uri: impl Into<ArcCow<'static, str>>) -> Self {
26 self.uri = Some(uri.into());
27 self
28 }
29}
30
31impl<V: 'static> Element<V> for Img {
32 type PaintState = ();
33
34 fn layout(
35 &mut self,
36 _: &mut V,
37 cx: &mut crate::LayoutContext<V>,
38 ) -> anyhow::Result<(gpui::LayoutId, Self::PaintState)>
39 where
40 Self: Sized,
41 {
42 let style = self.computed_style();
43 let layout_id = cx.add_layout_node(style, [])?;
44 Ok((layout_id, ()))
45 }
46
47 fn paint(
48 &mut self,
49 _: &mut V,
50 layout: &gpui::Layout,
51 _: &mut Self::PaintState,
52 cx: &mut crate::paint_context::PaintContext<V>,
53 ) where
54 Self: Sized,
55 {
56 let style = self.computed_style();
57
58 style.paint_background(layout.bounds, cx);
59
60 if let Some(uri) = &self.uri {
61 let image_future = cx.image_cache.get(uri.clone());
62 if let Some(data) = image_future
63 .clone()
64 .now_or_never()
65 .and_then(ResultExt::log_err)
66 {
67 let rem_size = cx.rem_size();
68 cx.scene.push_image(scene::Image {
69 bounds: layout.bounds,
70 border: gpui::Border {
71 color: style.border_color.unwrap_or_default().into(),
72 top: style.border_widths.top.to_pixels(rem_size),
73 right: style.border_widths.right.to_pixels(rem_size),
74 bottom: style.border_widths.bottom.to_pixels(rem_size),
75 left: style.border_widths.left.to_pixels(rem_size),
76 },
77 corner_radii: style.corner_radii.to_gpui(layout.bounds.size(), rem_size),
78 grayscale: false,
79 data,
80 })
81 } else {
82 cx.spawn(|this, mut cx| async move {
83 if image_future.await.log_err().is_some() {
84 this.update(&mut cx, |_, cx| cx.notify()).ok();
85 }
86 })
87 .detach();
88 }
89 }
90 }
91}
92
93impl Styleable for Img {
94 type Style = Style;
95
96 fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
97 &mut self.style
98 }
99
100 fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
101 self.style.base()
102 }
103}
104
105impl StyleHelpers for Img {}