use anyhow::bail;
use quick_xml::events::{BytesStart, Event};
use std::io::Read;
use crate::excel::XmlReader;
use crate::helper::string_to_unsignedint;
use crate::raw::drawing::st_types::{STPositiveAngle, STPositivePercentage};
use crate::{helper::string_to_bool, raw::drawing::color::XlsxColorEnum};
use super::fill_rectangle::{XlsxFillToRectangle, XlsxTileRectangle};
#[derive(Debug, Clone, PartialEq)]
pub struct XlsxGradientFill {
pub gs_lst: Option<Vec<XlsxGradientStop>>,
pub lin: Option<XlsxLinearGradientFill>,
pub path: Option<XlsxPathGradientFill>,
pub tile_rect: Option<XlsxTileRectangle>,
pub flip: Option<String>,
pub rotate_with_shape: Option<bool>,
}
impl XlsxGradientFill {
pub(crate) fn load(reader: &mut XmlReader<impl Read>, e: &BytesStart) -> anyhow::Result<Self> {
let attributes = e.attributes();
let mut fill = Self {
path: None,
gs_lst: None,
lin: None,
tile_rect: None,
flip: None,
rotate_with_shape: None,
};
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"flip" => {
fill.flip = Some(string_value);
}
b"rotWithShape" => {
fill.rotate_with_shape = string_to_bool(&string_value);
}
_ => {}
}
}
Err(error) => {
bail!(error.to_string())
}
}
}
let mut buf = Vec::new();
loop {
buf.clear();
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"gsLst" => {
fill.gs_lst = Some(load_gradient_stops(reader)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"lin" => {
fill.lin = Some(XlsxLinearGradientFill::load(e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"path" => {
fill.path = Some(XlsxPathGradientFill::load(reader, e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"tileRect" => {
fill.tile_rect = Some(XlsxTileRectangle::load(e)?);
}
Ok(Event::End(ref e)) if e.local_name().as_ref() == b"gradFill" => break,
Ok(Event::Eof) => bail!("unexpected end of file."),
Err(e) => bail!(e.to_string()),
_ => (),
}
}
Ok(fill)
}
}
pub(crate) fn load_gradient_stops(
reader: &mut XmlReader<impl Read>,
) -> anyhow::Result<Vec<XlsxGradientStop>> {
let mut gs_list: Vec<XlsxGradientStop> = vec![];
let mut buf = Vec::new();
loop {
buf.clear();
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"gs" => {
let gs = XlsxGradientStop::load(reader, e)?;
gs_list.push(gs);
}
Ok(Event::End(ref e)) if e.local_name().as_ref() == b"gsLst" => break,
Ok(Event::Eof) => bail!("unexpected end of file."),
Err(e) => bail!(e.to_string()),
_ => (),
}
}
Ok(gs_list)
}
#[derive(Debug, Clone, PartialEq)]
pub struct XlsxGradientStop {
pub color: Option<XlsxColorEnum>,
pub pos: Option<STPositivePercentage>,
}
impl XlsxGradientStop {
pub(crate) fn load(reader: &mut XmlReader<impl Read>, e: &BytesStart) -> anyhow::Result<Self> {
let attributes = e.attributes();
let mut stop = Self {
color: None,
pos: None,
};
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"pos" => {
stop.pos = string_to_unsignedint(&string_value);
break;
}
_ => {}
}
}
Err(error) => {
bail!(error.to_string())
}
}
}
stop.color = XlsxColorEnum::load(reader, b"gs")?;
Ok(stop)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct XlsxLinearGradientFill {
pub ang: Option<STPositiveAngle>,
pub scaled: Option<bool>,
}
impl XlsxLinearGradientFill {
pub(crate) fn load(e: &BytesStart) -> anyhow::Result<Self> {
let attributes = e.attributes();
let mut fill = Self {
ang: None,
scaled: None,
};
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"ang" => {
fill.ang = string_to_unsignedint(&string_value);
}
b"scaled" => {
fill.scaled = string_to_bool(&string_value);
}
_ => {}
}
}
Err(error) => {
bail!(error.to_string())
}
}
}
Ok(fill)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct XlsxPathGradientFill {
pub fill_to_rect: Option<XlsxFillToRectangle>,
pub path: Option<String>,
}
impl XlsxPathGradientFill {
pub(crate) fn load(reader: &mut XmlReader<impl Read>, e: &BytesStart) -> anyhow::Result<Self> {
let attributes = e.attributes();
let mut fill = Self {
fill_to_rect: None,
path: None,
};
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"path" => {
fill.path = Some(string_value);
break;
}
_ => {}
}
}
Err(error) => {
bail!(error.to_string())
}
}
}
let mut buf = Vec::new();
loop {
buf.clear();
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"fillToRect" => {
fill.fill_to_rect = Some(XlsxFillToRectangle::load(e)?);
}
Ok(Event::End(ref e)) if e.local_name().as_ref() == b"path" => break,
Ok(Event::Eof) => bail!("unexpected end of file."),
Err(e) => bail!(e.to_string()),
_ => (),
}
}
Ok(fill)
}
}