1use crate::{
2 Bounds, Element, ElementContext, Hitbox, InteractiveElement, Interactivity, IntoElement,
3 LayoutId, Pixels, SharedString, StyleRefinement, Styled,
4};
5use util::ResultExt;
6
7/// An SVG element.
8pub struct Svg {
9 interactivity: Interactivity,
10 path: Option<SharedString>,
11}
12
13/// Create a new SVG element.
14pub fn svg() -> Svg {
15 Svg {
16 interactivity: Interactivity::default(),
17 path: None,
18 }
19}
20
21impl Svg {
22 /// Set the path to the SVG file for this element.
23 pub fn path(mut self, path: impl Into<SharedString>) -> Self {
24 self.path = Some(path.into());
25 self
26 }
27}
28
29impl Element for Svg {
30 type BeforeLayout = ();
31 type AfterLayout = Option<Hitbox>;
32
33 fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
34 let layout_id = self
35 .interactivity
36 .before_layout(cx, |style, cx| cx.request_layout(&style, None));
37 (layout_id, ())
38 }
39
40 fn after_layout(
41 &mut self,
42 bounds: Bounds<Pixels>,
43 _before_layout: &mut Self::BeforeLayout,
44 cx: &mut ElementContext,
45 ) -> Option<Hitbox> {
46 self.interactivity
47 .after_layout(bounds, bounds.size, cx, |_, _, hitbox, _| hitbox)
48 }
49
50 fn paint(
51 &mut self,
52 bounds: Bounds<Pixels>,
53 _before_layout: &mut Self::BeforeLayout,
54 hitbox: &mut Option<Hitbox>,
55 cx: &mut ElementContext,
56 ) where
57 Self: Sized,
58 {
59 self.interactivity
60 .paint(bounds, hitbox.as_ref(), cx, |style, cx| {
61 if let Some((path, color)) = self.path.as_ref().zip(style.text.color) {
62 cx.paint_svg(bounds, path.clone(), color).log_err();
63 }
64 })
65 }
66}
67
68impl IntoElement for Svg {
69 type Element = Self;
70
71 fn into_element(self) -> Self::Element {
72 self
73 }
74}
75
76impl Styled for Svg {
77 fn style(&mut self) -> &mut StyleRefinement {
78 &mut self.interactivity.base_style
79 }
80}
81
82impl InteractiveElement for Svg {
83 fn interactivity(&mut self) -> &mut Interactivity {
84 &mut self.interactivity
85 }
86}