use crate::{AsPaletteColor, Result, XmlWritable, XmlWriter};
use indexmap::{indexmap, IndexSet};
use rgb::RGB8;
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Default, Clone, Debug, Hash, Eq, PartialEq)]
pub struct Fill {
pub fg_color: Option<RGB8>,
pub bg_color: Option<RGB8>,
pub pattern: Option<Pattern>,
}
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub enum Pattern {
Solid,
MediumGray,
DarkGray,
LightGray,
DarkHorizontal,
DarkVertical,
DarkDown,
DarkUp,
DarkGrid,
DarkTrellis,
LightHorizontal,
LightVertical,
LightDown,
LightUp,
LightGrid,
LightTrellis,
Gray125,
Gray0625,
}
impl Pattern {
fn xml_string(&self) -> &'static str {
match self {
Pattern::Solid => "solid",
Pattern::MediumGray => "mediumGray",
Pattern::DarkGray => "darkGray",
Pattern::LightGray => "lightGray",
Pattern::DarkHorizontal => "darkHorizontal",
Pattern::DarkVertical => "darkVertical",
Pattern::DarkDown => "darkDown",
Pattern::DarkUp => "darkUp",
Pattern::DarkGrid => "darkGrid",
Pattern::DarkTrellis => "darkTrellis",
Pattern::LightHorizontal => "lightHorizontal",
Pattern::LightVertical => "lightVertical",
Pattern::LightDown => "lightDown",
Pattern::LightUp => "lightUp",
Pattern::LightGrid => "lightGrid",
Pattern::LightTrellis => "lightTrellis",
Pattern::Gray125 => "gray125",
Pattern::Gray0625 => "gray0625",
}
}
}
#[derive(Default, Debug)]
struct Inner {
fills: IndexSet<Fill>,
}
#[derive(Clone, Debug)]
pub(crate) struct Fills {
inner: Rc<RefCell<Inner>>,
}
impl Default for Fills {
fn default() -> Self {
let mut inner = Inner::default();
inner.fills.insert(Fill::default());
inner.fills.insert(Fill {
fg_color: None,
bg_color: None,
pattern: Some(Pattern::Gray125),
});
Fills {
inner: Rc::new(RefCell::new(inner)),
}
}
}
impl Fills {
pub fn create_or_get_index(
&mut self,
fill: Option<&Fill>,
) -> Option<usize> {
let mut inner = self.inner.borrow_mut();
fill.map(|f| inner.fills.insert_full(f.clone()).0)
}
}
impl XmlWritable for Fills {
fn write_xml<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
self.inner.borrow().write_xml(w)
}
}
impl XmlWritable for Inner {
fn write_xml<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
if !self.fills.is_empty() {
let tag = "fills";
let attrs = indexmap! {
"count" => format!("{}", self.fills.len()),
};
w.start_tag_with_attrs(tag, attrs)?;
for font in self.fills.iter() {
font.write_xml(w)?;
}
w.end_tag(tag)?;
}
Ok(())
}
}
impl XmlWritable for Fill {
fn write_xml<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
let tag = "fill";
w.start_tag(tag)?;
self.write_pattern_fill(w)?;
w.end_tag(tag)?;
Ok(())
}
}
impl Fill {
fn write_pattern_fill<W: XmlWriter>(&self, w: &mut W) -> Result<()> {
let tag = "patternFill";
let pattern = self
.pattern
.map(|p| p.xml_string())
.unwrap_or_else(|| "none");
let attrs = indexmap! {
"patternType" => pattern
};
match (self.bg_color, self.fg_color) {
(Some(bg_color), Some(fg_color)) => {
w.start_tag_with_attrs(tag, attrs)?;
Self::write_color(w, "bgColor", bg_color)?;
Self::write_color(w, "fgColor", fg_color)?;
w.end_tag(tag)?;
}
(Some(bg_color), None) => {
w.start_tag_with_attrs(tag, attrs)?;
Self::write_color(w, "bgColor", bg_color)?;
w.end_tag(tag)?;
}
(None, Some(fg_color)) => {
w.start_tag_with_attrs(tag, attrs)?;
Self::write_color(w, "fgColor", fg_color)?;
w.end_tag(tag)?;
}
(None, None) => {
w.empty_tag_with_attrs(tag, attrs)?;
}
}
Ok(())
}
fn write_color<W: XmlWriter>(
w: &mut W,
tag: &str,
color: RGB8,
) -> Result<()> {
let attrs = indexmap! { "rgb" => color.as_palette_color(), };
w.empty_tag_with_attrs(tag, attrs)
}
}