1use std::borrow::Cow;
2
3use serde_json::json;
4
5use crate::{
6 color::Color,
7 geometry::{
8 rect::RectF,
9 vector::{vec2f, Vector2F},
10 },
11 scene, DebugContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
12};
13
14pub struct Svg {
15 path: Cow<'static, str>,
16 color: Color,
17}
18
19impl Svg {
20 pub fn new(path: impl Into<Cow<'static, str>>) -> Self {
21 Self {
22 path: path.into(),
23 color: Color::black(),
24 }
25 }
26
27 pub fn with_color(mut self, color: Color) -> Self {
28 self.color = color;
29 self
30 }
31}
32
33impl Element for Svg {
34 type LayoutState = Option<usvg::Tree>;
35 type PaintState = ();
36
37 fn layout(
38 &mut self,
39 constraint: SizeConstraint,
40 cx: &mut LayoutContext,
41 ) -> (Vector2F, Self::LayoutState) {
42 match cx.asset_cache.svg(&self.path) {
43 Ok(tree) => {
44 let size = constrain_size_preserving_aspect_ratio(
45 constraint.max,
46 from_usvg_rect(tree.svg_node().view_box.rect).size(),
47 );
48 (size, Some(tree))
49 }
50 Err(_error) => {
51 #[cfg(not(any(test, feature = "test-support")))]
52 log::error!("{}", _error);
53 (constraint.min, None)
54 }
55 }
56 }
57
58 fn paint(
59 &mut self,
60 bounds: RectF,
61 _visible_bounds: RectF,
62 svg: &mut Self::LayoutState,
63 cx: &mut PaintContext,
64 ) {
65 if let Some(svg) = svg.clone() {
66 cx.scene.push_icon(scene::Icon {
67 bounds,
68 svg,
69 path: self.path.clone(),
70 color: self.color,
71 });
72 }
73 }
74
75 fn dispatch_event(
76 &mut self,
77 _: &Event,
78 _: RectF,
79 _: &mut Self::LayoutState,
80 _: &mut Self::PaintState,
81 _: &mut EventContext,
82 ) -> bool {
83 false
84 }
85
86 fn debug(
87 &self,
88 bounds: RectF,
89 _: &Self::LayoutState,
90 _: &Self::PaintState,
91 _: &DebugContext,
92 ) -> serde_json::Value {
93 json!({
94 "type": "Svg",
95 "bounds": bounds.to_json(),
96 "path": self.path,
97 "color": self.color.to_json(),
98 })
99 }
100}
101
102use crate::json::ToJson;
103
104use super::constrain_size_preserving_aspect_ratio;
105
106fn from_usvg_rect(rect: usvg::Rect) -> RectF {
107 RectF::new(
108 vec2f(rect.x() as f32, rect.y() as f32),
109 vec2f(rect.width() as f32, rect.height() as f32),
110 )
111}