use std::rc::Rc;
use svg::{self, node::element as svg_element};
use super::ShapeDefinition;
use crate::{
color::Color,
draw::{StrokeDefinition, TextDefinition},
geometry::{Insets, Point, Size},
};
#[derive(Debug, Clone)]
pub struct ActorDefinition {
fill_color: Option<Color>,
stroke: Rc<StrokeDefinition>,
text: Rc<TextDefinition>,
}
impl ActorDefinition {
pub fn new() -> Self {
Self::default()
}
fn fill_color(&self) -> Option<Color> {
self.fill_color
}
}
impl Default for ActorDefinition {
fn default() -> Self {
Self {
fill_color: Some(Color::new("white").expect("Failed to create white color")),
stroke: Rc::new(StrokeDefinition::default_solid()),
text: Rc::new(TextDefinition::default()),
}
}
}
impl ShapeDefinition for ActorDefinition {
fn calculate_inner_size(&self, _content_size: Size, _padding: Insets) -> Size {
Size::new(24.0, 54.0)
}
fn clone_box(&self) -> Box<dyn ShapeDefinition> {
Box::new(self.clone())
}
fn stroke(&self) -> &Rc<StrokeDefinition> {
&self.stroke
}
fn set_fill_color(&mut self, color: Option<Color>) -> Result<(), &'static str> {
self.fill_color = color;
Ok(())
}
fn text(&self) -> &Rc<TextDefinition> {
&self.text
}
fn set_text(&mut self, text: Rc<TextDefinition>) {
self.text = text;
}
fn set_stroke(&mut self, stroke: Rc<StrokeDefinition>) {
self.stroke = stroke;
}
fn render_to_svg(&self, _size: Size, position: Point) -> Box<dyn svg::Node> {
let mut group = svg_element::Group::new().set("id", "actor-group");
let head_radius = 8.0;
let body_length = 20.0;
let arm_length = 12.0;
let leg_length = 18.0;
let head_center = position.with_y(position.y() - 22.0);
let head = svg_element::Circle::new()
.set("cx", head_center.x())
.set("cy", head_center.y())
.set("r", head_radius)
.set("fill", "white");
let mut head = crate::apply_stroke!(head, &self.stroke);
if let Some(fill_color) = self.fill_color() {
head = head
.set("fill", fill_color.to_string())
.set("fill-opacity", fill_color.alpha());
}
group = group.add(head);
let body_top = position.with_y(head_center.y() + head_radius);
let body_bottom = position.with_y(body_top.y() + body_length);
let body = crate::apply_stroke!(
svg_element::Line::new()
.set("x1", body_top.x())
.set("y1", body_top.y())
.set("x2", body_bottom.x())
.set("y2", body_bottom.y()),
&self.stroke
);
group = group.add(body);
let arm_center = position.with_y(body_top.y() + 6.0);
let left_arm = crate::apply_stroke!(
svg_element::Line::new()
.set("x1", arm_center.x())
.set("y1", arm_center.y())
.set("x2", arm_center.x() - arm_length)
.set("y2", arm_center.y() + 8.0),
&self.stroke
);
group = group.add(left_arm);
let right_arm = crate::apply_stroke!(
svg_element::Line::new()
.set("x1", arm_center.x())
.set("y1", arm_center.y())
.set("x2", arm_center.x() + arm_length)
.set("y2", arm_center.y() + 8.0),
&self.stroke
);
group = group.add(right_arm);
let left_leg = crate::apply_stroke!(
svg_element::Line::new()
.set("x1", body_bottom.x())
.set("y1", body_bottom.y())
.set("x2", body_bottom.x() - 10.0)
.set("y2", body_bottom.y() + leg_length),
&self.stroke
);
group = group.add(left_leg);
let right_leg = crate::apply_stroke!(
svg_element::Line::new()
.set("x1", body_bottom.x())
.set("y1", body_bottom.y())
.set("x2", body_bottom.x() + 10.0)
.set("y2", body_bottom.y() + leg_length),
&self.stroke
);
group = group.add(right_leg);
group.into()
}
}