use std::marker::PhantomData;
use crate::colors::Color;
use crate::debugger::SourceLocation;
use crate::image::{ObjectFit, SvgData, SvgStyle};
use crate::ui::event::EventResult;
use crate::ui::{Event, View};
use crate::{Context, Node};
pub struct Svg<Msg> {
pub(crate) data: SvgData,
pub(crate) fit: ObjectFit,
pub(crate) style_opts: SvgStyle,
pub(crate) source_loc: Option<SourceLocation>,
_marker: PhantomData<Msg>,
}
#[track_caller]
pub fn svg<Msg>(data: SvgData) -> Svg<Msg> {
Svg {
data,
fit: ObjectFit::default(),
style_opts: SvgStyle::default(),
source_loc: Some(SourceLocation::here("Svg")),
_marker: PhantomData,
}
}
impl<Msg> Svg<Msg> {
pub fn fit(mut self, fit: ObjectFit) -> Self {
self.fit = fit;
self
}
pub fn color(mut self, color: Color) -> Self {
self.style_opts.color = Some(color);
self
}
pub fn fill(mut self, fill: Color) -> Self {
self.style_opts.fill = Some(fill);
self
}
pub fn stroke(mut self, stroke: Color) -> Self {
self.style_opts.stroke = Some(stroke);
self
}
pub fn stroke_width(mut self, width: f32) -> Self {
self.style_opts.stroke_width = Some(width);
self
}
pub fn custom_css(mut self, css: impl Into<String>) -> Self {
self.style_opts.custom_css = Some(css.into());
self
}
pub fn svg_style(mut self, style: SvgStyle) -> Self {
self.style_opts = style;
self
}
}
pub struct SvgElement {
pub(crate) node: Node,
}
impl<State, Msg> View<State> for Svg<Msg> {
type Element = SvgElement;
type Message = Msg;
fn build(&self, ctx: &mut Context) -> Self::Element {
let node = ctx.create_node();
if let Some(loc) = self.source_loc {
ctx.set_node_source(node, loc);
}
if self.data.height > 0.0 && self.data.width > 0.0 {
let intrinsic_ar = self.data.width / self.data.height;
node.update_constraints(ctx, |c| {
if c.aspect_ratio == 0.0 {
c.aspect_ratio = intrinsic_ar;
}
});
}
let data = if self.style_opts != SvgStyle::default() {
self.data
.with_style(&self.style_opts)
.unwrap_or_else(|_| self.data.clone())
} else {
self.data.clone()
};
ctx.svgs.borrow_mut().insert(node, (data, self.fit));
SvgElement { node }
}
fn rebuild(&self, prev: &Self, ctx: &mut Context, element: &mut Self::Element) {
let data = if self.style_opts != SvgStyle::default() {
self.data
.with_style(&self.style_opts)
.unwrap_or_else(|_| self.data.clone())
} else {
self.data.clone()
};
if self.data.id != prev.data.id
|| self.fit != prev.fit
|| self.style_opts != prev.style_opts
{
ctx.svgs.borrow_mut().insert(element.node, (data, self.fit));
element.node.set_dirty(ctx);
}
if self.data.height > 0.0 && self.data.width > 0.0 {
let intrinsic_ar = self.data.width / self.data.height;
element.node.update_constraints(ctx, |c| {
if c.aspect_ratio == 0.0 {
c.aspect_ratio = intrinsic_ar;
}
});
}
}
fn teardown(&self, ctx: &mut Context, element: &mut Self::Element) {
ctx.svgs.borrow_mut().remove(&element.node);
element.node.remove(ctx);
ctx.destroy_node(element.node);
}
fn get_node(&self, element: &Self::Element) -> Node {
element.node
}
fn handle_event(
&self,
_element: &mut Self::Element,
_state: &State,
_event: Event,
_ctx: &mut Context,
) -> (EventResult, Option<Self::Message>) {
(EventResult::Ignored, None)
}
}