svg.rs

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