svg.rs

 1use crate::{
 2    color::ColorU,
 3    geometry::{
 4        rect::RectF,
 5        vector::{vec2f, Vector2F},
 6    },
 7    scene, AfterLayoutContext, Element, Event, EventContext, LayoutContext, PaintContext,
 8    SizeConstraint,
 9};
10
11pub struct Svg {
12    path: String,
13    color: ColorU,
14}
15
16impl Svg {
17    pub fn new(path: String) -> Self {
18        Self {
19            path,
20            color: ColorU::black(),
21        }
22    }
23
24    pub fn with_color(mut self, color: ColorU) -> Self {
25        self.color = color;
26        self
27    }
28}
29
30impl Element for Svg {
31    type LayoutState = Option<usvg::Tree>;
32    type PaintState = ();
33
34    fn layout(
35        &mut self,
36        constraint: SizeConstraint,
37        ctx: &mut LayoutContext,
38    ) -> (Vector2F, Self::LayoutState) {
39        match ctx.asset_cache.svg(&self.path) {
40            Ok(tree) => {
41                let size = if constraint.max.x().is_infinite() && constraint.max.y().is_infinite() {
42                    let rect = from_usvg_rect(tree.svg_node().view_box.rect);
43                    rect.size()
44                } else {
45                    let max_size = constraint.max;
46                    let svg_size = from_usvg_rect(tree.svg_node().view_box.rect).size();
47
48                    if max_size.x().is_infinite()
49                        || max_size.x() / max_size.y() > svg_size.x() / svg_size.y()
50                    {
51                        vec2f(svg_size.x() * max_size.y() / svg_size.y(), max_size.y())
52                    } else {
53                        vec2f(max_size.x(), svg_size.y() * max_size.x() / svg_size.x())
54                    }
55                };
56                (size, Some(tree))
57            }
58            Err(error) => {
59                log::error!("{}", error);
60                (constraint.min, None)
61            }
62        }
63    }
64
65    fn after_layout(&mut self, _: Vector2F, _: &mut Self::LayoutState, _: &mut AfterLayoutContext) {
66    }
67
68    fn paint(&mut self, bounds: RectF, svg: &mut Self::LayoutState, ctx: &mut PaintContext) {
69        if let Some(svg) = svg.clone() {
70            ctx.scene.push_icon(scene::Icon {
71                bounds,
72                svg,
73                path: self.path.clone(),
74                color: self.color,
75            });
76        }
77    }
78
79    fn dispatch_event(
80        &mut self,
81        _: &Event,
82        _: RectF,
83        _: &mut Self::LayoutState,
84        _: &mut Self::PaintState,
85        _: &mut EventContext,
86    ) -> bool {
87        false
88    }
89}
90
91fn from_usvg_rect(rect: usvg::Rect) -> RectF {
92    RectF::new(
93        vec2f(rect.x() as f32, rect.y() as f32),
94        vec2f(rect.width() as f32, rect.height() as f32),
95    )
96}