1use crate::{
2 div, AnyElement, Bounds, Component, Div, DivState, Element, ElementFocus, ElementId,
3 ElementInteraction, FocusDisabled, FocusEnabled, FocusListeners, Focusable, 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> Component<V> for Svg<V, I, F>
49where
50 I: ElementInteraction<V>,
51 F: ElementFocus<V>,
52{
53 fn render(self) -> AnyElement<V> {
54 AnyElement::new(self)
55 }
56}
57
58impl<V, I, F> Element<V> for Svg<V, I, F>
59where
60 I: ElementInteraction<V>,
61 F: ElementFocus<V>,
62{
63 type ElementState = DivState;
64
65 fn id(&self) -> Option<crate::ElementId> {
66 self.base.id()
67 }
68
69 fn initialize(
70 &mut self,
71 view_state: &mut V,
72 element_state: Option<Self::ElementState>,
73 cx: &mut ViewContext<V>,
74 ) -> Self::ElementState {
75 self.base.initialize(view_state, element_state, cx)
76 }
77
78 fn layout(
79 &mut self,
80 view_state: &mut V,
81 element_state: &mut Self::ElementState,
82 cx: &mut ViewContext<V>,
83 ) -> LayoutId {
84 self.base.layout(view_state, element_state, cx)
85 }
86
87 fn paint(
88 &mut self,
89 bounds: Bounds<Pixels>,
90 view: &mut V,
91 element_state: &mut Self::ElementState,
92 cx: &mut ViewContext<V>,
93 ) where
94 Self: Sized,
95 {
96 self.base.paint(bounds, view, element_state, cx);
97 let color = self
98 .base
99 .compute_style(bounds, element_state, cx)
100 .text
101 .color;
102 if let Some((path, color)) = self.path.as_ref().zip(color) {
103 cx.paint_svg(bounds, path.clone(), color).log_err();
104 }
105 }
106}
107
108impl<V, I, F> Styled for Svg<V, I, F>
109where
110 I: ElementInteraction<V>,
111 F: ElementFocus<V>,
112{
113 fn style(&mut self) -> &mut StyleRefinement {
114 self.base.style()
115 }
116}
117
118impl<V, I, F> StatelessInteractive<V> for Svg<V, I, F>
119where
120 I: ElementInteraction<V>,
121 F: ElementFocus<V>,
122{
123 fn stateless_interaction(&mut self) -> &mut StatelessInteraction<V> {
124 self.base.stateless_interaction()
125 }
126}
127
128impl<V, F> StatefulInteractive<V> for Svg<V, StatefulInteraction<V>, F>
129where
130 V: 'static,
131 F: ElementFocus<V>,
132{
133 fn stateful_interaction(&mut self) -> &mut StatefulInteraction<V> {
134 self.base.stateful_interaction()
135 }
136}
137
138impl<V: 'static, I> Focusable<V> for Svg<V, I, FocusEnabled<V>>
139where
140 I: ElementInteraction<V>,
141{
142 fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
143 self.base.focus_listeners()
144 }
145
146 fn set_focus_style(&mut self, style: StyleRefinement) {
147 self.base.set_focus_style(style)
148 }
149
150 fn set_focus_in_style(&mut self, style: StyleRefinement) {
151 self.base.set_focus_in_style(style)
152 }
153
154 fn set_in_focus_style(&mut self, style: StyleRefinement) {
155 self.base.set_in_focus_style(style)
156 }
157}