1use crate::{
2 div, AnyElement, Bounds, Div, DivState, Element, ElementFocus, ElementId, ElementInteraction,
3 FocusDisabled, FocusEnabled, FocusListeners, Focusable, IntoAnyElement, LayoutId, Pixels,
4 SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction,
5 StatelessInteractive, StyleRefinement, Styled, ViewContext,
6};
7use util::ResultExt;
8
9pub struct Svg<
10 V: 'static,
11 I: ElementInteraction<V> = StatelessInteraction<V>,
12 F: ElementFocus<V> = FocusDisabled,
13> {
14 base: Div<V, I, F>,
15 path: Option<SharedString>,
16}
17
18pub fn svg<V: 'static>() -> Svg<V, StatelessInteraction<V>, FocusDisabled> {
19 Svg {
20 base: div(),
21 path: None,
22 }
23}
24
25impl<V, I, F> Svg<V, I, F>
26where
27 I: ElementInteraction<V>,
28 F: ElementFocus<V>,
29{
30 pub fn path(mut self, path: impl Into<SharedString>) -> Self {
31 self.path = Some(path.into());
32 self
33 }
34}
35
36impl<V, F> Svg<V, StatelessInteraction<V>, F>
37where
38 F: ElementFocus<V>,
39{
40 pub fn id(self, id: impl Into<ElementId>) -> Svg<V, StatefulInteraction<V>, F> {
41 Svg {
42 base: self.base.id(id),
43 path: self.path,
44 }
45 }
46}
47
48impl<V, I, F> IntoAnyElement<V> for Svg<V, I, F>
49where
50 I: ElementInteraction<V>,
51 F: ElementFocus<V>,
52{
53 fn into_any(self) -> AnyElement<V> {
54 AnyElement::new(self)
55 }
56}
57
58impl<V, I, F> Element for Svg<V, I, F>
59where
60 I: ElementInteraction<V>,
61 F: ElementFocus<V>,
62{
63 type ViewState = V;
64 type ElementState = DivState;
65
66 fn id(&self) -> Option<crate::ElementId> {
67 self.base.id()
68 }
69
70 fn initialize(
71 &mut self,
72 view_state: &mut V,
73 element_state: Option<Self::ElementState>,
74 cx: &mut ViewContext<V>,
75 ) -> Self::ElementState {
76 self.base.initialize(view_state, element_state, cx)
77 }
78
79 fn layout(
80 &mut self,
81 view_state: &mut V,
82 element_state: &mut Self::ElementState,
83 cx: &mut ViewContext<Self::ViewState>,
84 ) -> LayoutId {
85 self.base.layout(view_state, element_state, cx)
86 }
87
88 fn paint(
89 &mut self,
90 bounds: Bounds<Pixels>,
91 view: &mut Self::ViewState,
92 element_state: &mut Self::ElementState,
93 cx: &mut ViewContext<V>,
94 ) where
95 Self: Sized,
96 {
97 self.base.paint(bounds, view, element_state, cx);
98 let color = self
99 .base
100 .compute_style(bounds, element_state, cx)
101 .text
102 .color;
103 if let Some((path, color)) = self.path.as_ref().zip(color) {
104 cx.paint_svg(bounds, path.clone(), color).log_err();
105 }
106 }
107}
108
109impl<V, I, F> Styled for Svg<V, I, F>
110where
111 I: ElementInteraction<V>,
112 F: ElementFocus<V>,
113{
114 fn style(&mut self) -> &mut StyleRefinement {
115 self.base.style()
116 }
117}
118
119impl<V, I, F> StatelessInteractive for Svg<V, I, F>
120where
121 I: ElementInteraction<V>,
122 F: ElementFocus<V>,
123{
124 fn stateless_interaction(&mut self) -> &mut StatelessInteraction<V> {
125 self.base.stateless_interaction()
126 }
127}
128
129impl<V, F> StatefulInteractive for Svg<V, StatefulInteraction<V>, F>
130where
131 V: 'static,
132 F: ElementFocus<V>,
133{
134 fn stateful_interaction(&mut self) -> &mut StatefulInteraction<Self::ViewState> {
135 self.base.stateful_interaction()
136 }
137}
138
139impl<V: 'static, I> Focusable for Svg<V, I, FocusEnabled<V>>
140where
141 I: ElementInteraction<V>,
142{
143 fn focus_listeners(&mut self) -> &mut FocusListeners<Self::ViewState> {
144 self.base.focus_listeners()
145 }
146
147 fn set_focus_style(&mut self, style: StyleRefinement) {
148 self.base.set_focus_style(style)
149 }
150
151 fn set_focus_in_style(&mut self, style: StyleRefinement) {
152 self.base.set_focus_in_style(style)
153 }
154
155 fn set_in_focus_style(&mut self, style: StyleRefinement) {
156 self.base.set_in_focus_style(style)
157 }
158}