1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use minidom::Element;

use super::make_svg::NAMESPACE;
use super::{MakeSvgError, StoneColor};

#[derive(Debug, Clone, serde::Deserialize)]
pub struct GobanStyle {
    line_color: String,
    line_width: f64,
    hoshi_radius: f64,
    background_fill: String,
    label_color: String,
    black_stone_fill: Option<String>,
    white_stone_fill: Option<String>,
    black_stone_stroke: Option<String>,
    white_stone_stroke: Option<String>,
    markup_stroke_width: f64,
    black_stone_markup_color: String,
    white_stone_markup_color: String,
    empty_markup_color: String,
    black_stone_selected_color: String,
    white_stone_selected_color: String,
    empty_selected_color: String,
    defs: Option<String>,
}

impl GobanStyle {
    pub fn line_color(&self) -> &str {
        &self.line_color
    }

    pub fn line_width(&self) -> f64 {
        self.line_width
    }

    pub fn hoshi_radius(&self) -> f64 {
        self.hoshi_radius
    }

    pub fn background_fill(&self) -> &str {
        &self.background_fill
    }

    pub fn label_color(&self) -> &str {
        &self.label_color
    }

    pub fn stone_fill(&self, color: StoneColor) -> Option<&str> {
        match color {
            StoneColor::Black => self.black_stone_fill.as_deref(),
            StoneColor::White => self.white_stone_fill.as_deref(),
        }
    }

    pub fn stone_stroke(&self, color: StoneColor) -> Option<&str> {
        match color {
            StoneColor::Black => self.black_stone_stroke.as_deref(),
            StoneColor::White => self.white_stone_stroke.as_deref(),
        }
    }

    pub fn markup_color(&self, color: Option<StoneColor>) -> &str {
        match color {
            Some(StoneColor::Black) => &self.black_stone_markup_color,
            Some(StoneColor::White) => &self.white_stone_markup_color,
            None => &self.empty_markup_color,
        }
    }

    pub fn markup_stroke_width(&self) -> f64 {
        self.markup_stroke_width
    }

    pub fn selected_color(&self, color: Option<StoneColor>) -> &str {
        match color {
            Some(StoneColor::Black) => &self.black_stone_selected_color,
            Some(StoneColor::White) => &self.white_stone_selected_color,
            None => &self.empty_selected_color,
        }
    }

    pub fn defs(&self) -> Result<Vec<Element>, MakeSvgError> {
        let linehead = Element::builder("marker", NAMESPACE)
            .attr("id", "linehead")
            .attr("markerWidth", "4")
            .attr("markerHeight", "4")
            .attr("refX", "2")
            .attr("refY", "2")
            .append(
                Element::builder("circle", NAMESPACE)
                    .attr("cx", "2")
                    .attr("cy", "2")
                    .attr("r", "2")
                    .build(),
            )
            .build();
        let arrowhead = Element::builder("marker", NAMESPACE)
            .attr("id", "arrowhead")
            .attr("markerWidth", "7")
            .attr("markerHeight", "5")
            .attr("refX", "7")
            .attr("refY", "2.5")
            .attr("orient", "auto")
            .append(
                Element::builder("polygon", NAMESPACE)
                    .attr("points", "0 0, 7 2.5, 0 5")
                    .build(),
            )
            .build();
        let mut defs = vec![linehead, arrowhead];
        if let Some(s) = &self.defs {
            // Wrap
            let wrapped = format!("<svg xmlns=\"{}\">{}</svg>", NAMESPACE, s);
            let wrapper: Element = wrapped.parse().map_err(MakeSvgError::StyleDefError)?;
            for child in wrapper.children() {
                defs.push(child.clone());
            }
        }
        Ok(defs)
    }
}