1use crate::{
2 self as gpui2, scene,
3 style::{Style, StyleHelpers, Styleable},
4 Element, IntoElement, Layout, LayoutId, Rgba,
5};
6use gpui::geometry::vector::Vector2F;
7use refineable::RefinementCascade;
8use std::borrow::Cow;
9use util::ResultExt;
10
11#[derive(IntoElement)]
12pub struct Svg {
13 path: Option<Cow<'static, str>>,
14 style: RefinementCascade<Style>,
15}
16
17pub fn svg() -> Svg {
18 Svg {
19 path: None,
20 style: RefinementCascade::<Style>::default(),
21 }
22}
23
24impl Svg {
25 pub fn path(mut self, path: impl Into<Cow<'static, str>>) -> Self {
26 self.path = Some(path.into());
27 self
28 }
29}
30
31impl<V: 'static> Element<V> for Svg {
32 type PaintState = ();
33
34 fn layout(
35 &mut self,
36 _: &mut V,
37 cx: &mut crate::ViewContext<V>,
38 ) -> anyhow::Result<(LayoutId, Self::PaintState)>
39 where
40 Self: Sized,
41 {
42 let style = self.computed_style();
43 Ok((cx.add_layout_node(style, [])?, ()))
44 }
45
46 fn paint(
47 &mut self,
48 _: &mut V,
49 parent_origin: Vector2F,
50 layout: &Layout,
51 _: &mut Self::PaintState,
52 cx: &mut crate::ViewContext<V>,
53 ) where
54 Self: Sized,
55 {
56 let fill_color = self.computed_style().fill.and_then(|fill| fill.color());
57 if let Some((path, fill_color)) = self.path.as_ref().zip(fill_color) {
58 if let Some(svg_tree) = cx.asset_cache.svg(path).log_err() {
59 let icon = scene::Icon {
60 bounds: layout.bounds + parent_origin,
61 svg: svg_tree,
62 path: path.clone(),
63 color: Rgba::from(fill_color).into(),
64 };
65
66 cx.scene().push_icon(icon);
67 }
68 }
69 }
70}
71
72impl Styleable for Svg {
73 type Style = Style;
74
75 fn style_cascade(&mut self) -> &mut refineable::RefinementCascade<Self::Style> {
76 &mut self.style
77 }
78
79 fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
80 self.style.base()
81 }
82}
83
84impl StyleHelpers for Svg {}