use crate::color::Color;
use crate::geom::{Point, Rect};
use crate::layer::Layer;
use crate::path::PathData;
use crate::style::{DashPattern, Fill, FontStyle, Stroke};
#[derive(Clone, Debug)]
pub struct DrawElement {
pub kind: Element,
pub layer: Layer,
}
#[derive(Clone, Debug)]
pub enum Element {
Line {
start: Point,
end: Point,
stroke: Stroke,
},
Polyline {
points: Vec<Point>,
stroke: Stroke,
fill: Fill,
},
Rect {
rect: Rect,
fill: Fill,
stroke: Option<Stroke>,
rx: f64,
},
Circle {
center: Point,
radius: f64,
fill: Fill,
stroke: Option<Stroke>,
},
Path {
data: PathData,
fill: Fill,
stroke: Option<Stroke>,
},
Text {
position: Point,
content: String,
font: FontStyle,
rotation: Option<f64>,
},
Group {
children: Vec<DrawElement>,
clip: Option<Rect>,
},
}
#[derive(Clone, Debug)]
pub struct LinearGradient {
pub id: String,
pub x1: f64,
pub y1: f64,
pub x2: f64,
pub y2: f64,
pub stops: Vec<(f64, Color)>,
}
#[derive(Clone, Debug)]
pub struct ClipDef {
pub id: String,
pub rect: Rect,
}
impl DrawElement {
pub fn new(kind: Element, layer: Layer) -> Self {
Self { kind, layer }
}
}
impl Element {
pub fn line(x1: f64, y1: f64, x2: f64, y2: f64, stroke: Stroke) -> Self {
Self::Line {
start: Point::new(x1, y1),
end: Point::new(x2, y2),
stroke,
}
}
pub fn filled_rect(rect: Rect, fill: Fill) -> Self {
Self::Rect {
rect,
fill,
stroke: None,
rx: 0.0,
}
}
pub fn circle(cx: f64, cy: f64, r: f64, fill: Fill) -> Self {
Self::Circle {
center: Point::new(cx, cy),
radius: r,
fill,
stroke: None,
}
}
pub fn text(x: f64, y: f64, content: impl Into<String>, font: FontStyle) -> Self {
Self::Text {
position: Point::new(x, y),
content: content.into(),
font,
rotation: None,
}
}
pub fn polyline(points: Vec<Point>, stroke: Stroke) -> Self {
Self::Polyline {
points,
stroke,
fill: Fill::None,
}
}
}
impl DrawElement {
pub fn line(x1: f64, y1: f64, x2: f64, y2: f64, stroke: Stroke, layer: Layer) -> Self {
Self::new(Element::line(x1, y1, x2, y2, stroke), layer)
}
pub fn filled_rect(rect: Rect, fill: Fill, layer: Layer) -> Self {
Self::new(Element::filled_rect(rect, fill), layer)
}
pub fn circle(cx: f64, cy: f64, r: f64, fill: Fill, layer: Layer) -> Self {
Self::new(Element::circle(cx, cy, r, fill), layer)
}
pub fn text(x: f64, y: f64, content: impl Into<String>, font: FontStyle, layer: Layer) -> Self {
Self::new(Element::text(x, y, content, font), layer)
}
}
pub fn escape_xml(s: &str) -> String {
let mut out = String::with_capacity(s.len());
for c in s.chars() {
match c {
'&' => out.push_str("&"),
'<' => out.push_str("<"),
'>' => out.push_str(">"),
'"' => out.push_str("""),
'\'' => out.push_str("'"),
_ => out.push(c),
}
}
out
}
pub fn stroke_dash_attrs(dash: &Option<DashPattern>) -> String {
match dash {
Some(dp) => format!(" stroke-dasharray=\"{}\"", dp.to_svg_string()),
None => String::new(),
}
}