svg.rs

  1use crate::{
  2    div, Active, AnyElement, Bounds, Div, Element, ElementFocusability, ElementId,
  3    ElementInteractivity, Focus, FocusListeners, Focusable, Hover, InteractiveElementState,
  4    IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString, StatefulInteractivity,
  5    StatefullyInteractive, StatelessInteractivity, StatelesslyInteractive, StyleRefinement, Styled,
  6    ViewContext,
  7};
  8use util::ResultExt;
  9
 10pub struct Svg<
 11    V: 'static + Send + Sync,
 12    I: ElementInteractivity<V> = StatelessInteractivity<V>,
 13    F: ElementFocusability<V> = NonFocusable,
 14> {
 15    base: Div<V, I, F>,
 16    path: Option<SharedString>,
 17}
 18
 19pub fn svg<V>() -> Svg<V, StatelessInteractivity<V>, NonFocusable>
 20where
 21    V: 'static + Send + Sync,
 22{
 23    Svg {
 24        base: div(),
 25        path: None,
 26    }
 27}
 28
 29impl<V, I, F> Svg<V, I, F>
 30where
 31    V: 'static + Send + Sync,
 32    I: ElementInteractivity<V>,
 33    F: ElementFocusability<V>,
 34{
 35    pub fn path(mut self, path: impl Into<SharedString>) -> Self {
 36        self.path = Some(path.into());
 37        self
 38    }
 39}
 40
 41impl<V, F> Svg<V, StatelessInteractivity<V>, F>
 42where
 43    V: 'static + Send + Sync,
 44    F: ElementFocusability<V>,
 45{
 46    pub fn id(self, id: impl Into<ElementId>) -> Svg<V, StatefulInteractivity<V>, F> {
 47        Svg {
 48            base: self.base.id(id),
 49            path: self.path,
 50        }
 51    }
 52}
 53
 54impl<V, I, F> IntoAnyElement<V> for Svg<V, I, F>
 55where
 56    V: 'static + Send + Sync,
 57    I: ElementInteractivity<V>,
 58    F: ElementFocusability<V>,
 59{
 60    fn into_any(self) -> AnyElement<V> {
 61        AnyElement::new(self)
 62    }
 63}
 64
 65impl<V, I, F> Element for Svg<V, I, F>
 66where
 67    V: 'static + Send + Sync,
 68    I: ElementInteractivity<V>,
 69    F: ElementFocusability<V>,
 70{
 71    type ViewState = V;
 72    type ElementState = InteractiveElementState;
 73
 74    fn id(&self) -> Option<crate::ElementId> {
 75        self.base.id()
 76    }
 77
 78    fn initialize(
 79        &mut self,
 80        view_state: &mut V,
 81        element_state: Option<Self::ElementState>,
 82        cx: &mut ViewContext<V>,
 83    ) -> Self::ElementState {
 84        self.base.initialize(view_state, element_state, cx)
 85    }
 86
 87    fn layout(
 88        &mut self,
 89        view_state: &mut V,
 90        element_state: &mut Self::ElementState,
 91        cx: &mut ViewContext<Self::ViewState>,
 92    ) -> LayoutId {
 93        self.base.layout(view_state, element_state, cx)
 94    }
 95
 96    fn paint(
 97        &mut self,
 98        bounds: Bounds<Pixels>,
 99        view: &mut Self::ViewState,
100        element_state: &mut Self::ElementState,
101        cx: &mut ViewContext<V>,
102    ) where
103        Self: Sized,
104    {
105        self.base.paint(bounds, view, element_state, cx);
106        let color = self
107            .base
108            .compute_style(bounds, element_state, cx)
109            .text
110            .color;
111        if let Some((path, color)) = self.path.as_ref().zip(color) {
112            cx.paint_svg(bounds, path.clone(), color).log_err();
113        }
114    }
115}
116
117impl<V, I, F> Styled for Svg<V, I, F>
118where
119    V: 'static + Send + Sync,
120    I: ElementInteractivity<V>,
121    F: ElementFocusability<V>,
122{
123    fn style(&mut self) -> &mut StyleRefinement {
124        self.base.style()
125    }
126}
127
128impl<V, I, F> StatelesslyInteractive for Svg<V, I, F>
129where
130    V: 'static + Send + Sync,
131    I: ElementInteractivity<V>,
132    F: ElementFocusability<V>,
133{
134    fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
135        self.base.stateless_interactivity()
136    }
137}
138
139impl<V, I, F> Hover for Svg<V, I, F>
140where
141    V: 'static + Send + Sync,
142    I: ElementInteractivity<V>,
143    F: ElementFocusability<V>,
144{
145    fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
146        self.base.set_hover_style(group, style);
147    }
148}
149
150impl<V, F> StatefullyInteractive for Svg<V, StatefulInteractivity<V>, F>
151where
152    V: 'static + Send + Sync,
153    F: ElementFocusability<V>,
154{
155    fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState> {
156        self.base.stateful_interactivity()
157    }
158}
159
160impl<V, F> Active for Svg<V, StatefulInteractivity<V>, F>
161where
162    V: 'static + Send + Sync,
163    F: ElementFocusability<V>,
164{
165    fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
166        self.base.set_active_style(group, style)
167    }
168}
169
170impl<V, I> Focus for Svg<V, I, Focusable<V>>
171where
172    V: 'static + Send + Sync,
173    I: ElementInteractivity<V>,
174{
175    fn focus_listeners(&mut self) -> &mut FocusListeners<Self::ViewState> {
176        self.base.focus_listeners()
177    }
178
179    fn set_focus_style(&mut self, style: StyleRefinement) {
180        self.base.set_focus_style(style)
181    }
182
183    fn set_focus_in_style(&mut self, style: StyleRefinement) {
184        self.base.set_focus_in_style(style)
185    }
186
187    fn set_in_focus_style(&mut self, style: StyleRefinement) {
188        self.base.set_in_focus_style(style)
189    }
190
191    fn handle(&self) -> &crate::FocusHandle {
192        self.base.handle()
193    }
194}