img.rs

  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 {}