use crate::{
excel::XmlReader, helper::string_to_unsignedint, raw::drawing::st_types::STPositiveCoordinate,
};
use anyhow::bail;
use std::io::Read;
use arc_to::XlsxArcTo;
use close_shape_path::XlsxCloseShapePath;
use cubic_bezier_curve_to::XlsxCubicBezierCurveTo;
use line_to::XlsxLineTo;
use move_to::XlsxMoveTo;
use quad_bezier_curve_to::XlsxQuadraticBezierCurveTo;
use quick_xml::events::{BytesStart, Event};
use crate::helper::string_to_bool;
pub mod arc_to;
pub mod close_shape_path;
pub mod cubic_bezier_curve_to;
pub mod line_to;
pub mod move_to;
pub mod path_list;
pub mod path_point;
pub mod quad_bezier_curve_to;
#[derive(Debug, Clone, PartialEq)]
pub struct XlsxPath {
pub paths: Option<Vec<XlsxPathTypeEnum>>,
pub extrusion_allowed: Option<bool>,
pub fill: Option<String>,
pub height: Option<STPositiveCoordinate>,
pub stroke: Option<bool>,
pub width: Option<STPositiveCoordinate>,
}
impl XlsxPath {
pub(crate) fn load(reader: &mut XmlReader<impl Read>, e: &BytesStart) -> anyhow::Result<Self> {
let mut path = Self {
paths: Some(XlsxPathTypeEnum::load_list(reader, b"path")?),
extrusion_allowed: None,
fill: None,
height: None,
stroke: None,
width: None,
};
let attributes = e.attributes();
for a in attributes {
match a {
Ok(a) => {
let string_value = String::from_utf8(a.value.to_vec())?;
match a.key.local_name().as_ref() {
b"extrusionOk" => path.extrusion_allowed = string_to_bool(&string_value),
b"fill" => path.fill = Some(string_value),
b"h" => path.height = string_to_unsignedint(&string_value),
b"stroke" => path.stroke = string_to_bool(&string_value),
b"w" => path.width = string_to_unsignedint(&string_value),
_ => {}
}
}
Err(error) => {
bail!(error.to_string())
}
}
}
Ok(path)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum XlsxPathTypeEnum {
Arc(XlsxArcTo),
Close(XlsxCloseShapePath),
CubicBezier(XlsxCubicBezierCurveTo),
Line(XlsxLineTo),
Move(XlsxMoveTo),
QuadBezier(XlsxQuadraticBezierCurveTo),
}
impl XlsxPathTypeEnum {
pub(crate) fn load_list(
reader: &mut XmlReader<impl Read>,
tag: &[u8],
) -> anyhow::Result<Vec<Self>> {
let mut paths: Vec<XlsxPathTypeEnum> = vec![];
let mut buf = Vec::new();
loop {
buf.clear();
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) => {
if let Some(fill) = XlsxPathTypeEnum::load_helper(reader, e)? {
paths.push(fill);
}
}
Ok(Event::End(ref e)) if e.local_name().as_ref() == tag => break,
Ok(Event::Eof) => bail!("unexpected end of file."),
Err(e) => bail!(e.to_string()),
_ => (),
}
}
Ok(paths)
}
fn load_helper(
reader: &mut XmlReader<impl Read>,
e: &BytesStart,
) -> anyhow::Result<Option<Self>> {
match e.local_name().as_ref() {
b"arcTo" => {
return Ok(Some(XlsxPathTypeEnum::Arc(XlsxArcTo::load(e)?)));
}
b"close" => {
return Ok(Some(XlsxPathTypeEnum::Close(true)));
}
b"cubicBezTo" => {
return Ok(Some(XlsxPathTypeEnum::CubicBezier(
XlsxCubicBezierCurveTo::load(reader)?,
)));
}
b"lnTo" => {
return Ok(Some(XlsxPathTypeEnum::Line(XlsxLineTo::load(reader)?)));
}
b"moveTo" => {
return Ok(Some(XlsxPathTypeEnum::Move(XlsxMoveTo::load(reader)?)));
}
b"quadBezTo" => {
return Ok(Some(XlsxPathTypeEnum::QuadBezier(
XlsxQuadraticBezierCurveTo::load(reader)?,
)));
}
_ => return Ok(None),
}
}
}