use super::DoubleValue;
use super::StringValue;
use super::UInt32Value;
use md5::Digest;
use quick_xml::events::{BytesStart, Event};
use quick_xml::Reader;
use quick_xml::Writer;
use reader::driver::*;
use std::borrow::Cow;
use std::io::Cursor;
use structs::drawing::Theme;
use writer::driver::*;
const INDEXED_COLORS: &[&str] = &[
"FF000000", "FFFFFFFF", "FFFF0000", "FF00FF00", "FF0000FF", "FFFFFF00", "FFFF00FF", "FF00FFFF", "FF800000", "FF008000", "FF000080", "FF808000", "FF800080", "FF008080", "FFC0C0C0", "FF808080", "FF9999FF", "FF993366", "FFFFFFCC", "FFCCFFFF", "FF660066", "FFFF8080", "FF0066CC", "FFCCCCFF", "FF000080", "FFFF00FF", "FFFFFF00", "FF00FFFF", "FF800080", "FF800000", "FF008080", "FF0000FF", "FF00CCFF", "FFCCFFFF", "FFCCFFCC", "FFFFFF99", "FF99CCFF", "FFFF99CC", "FFCC99FF", "FFFFCC99", "FF3366FF", "FF33CCCC", "FF99CC00", "FFFFCC00", "FFFF9900", "FFFF6600", "FF666699", "FF969696", "FF003366", "FF339966", "FF003300", "FF333300", "FF993300", "FF993366", "FF333399", "FF333333", ];
#[derive(Default, Debug, Clone, PartialEq, PartialOrd)]
pub struct Color {
indexed: UInt32Value,
theme_index: UInt32Value,
argb: StringValue,
tint: DoubleValue,
}
impl Color {
pub const NAMED_COLORS: &'static [&'static str] = &[
"Black", "White", "Red", "Green", "Blue", "Yellow", "Magenta", "Cyan",
];
pub const COLOR_BLACK: &'static str = "FF000000";
pub const COLOR_WHITE: &'static str = "FFFFFFFF";
pub const COLOR_RED: &'static str = "FFFF0000";
pub const COLOR_DARKRED: &'static str = "FF800000";
pub const COLOR_BLUE: &'static str = "FF0000FF";
pub const COLOR_DARKBLUE: &'static str = "FF000080";
pub const COLOR_GREEN: &'static str = "FF00FF00";
pub const COLOR_DARKGREEN: &'static str = "FF008000";
pub const COLOR_YELLOW: &'static str = "FFFFFF00";
pub const COLOR_DARKYELLOW: &'static str = "FF808000";
pub fn get_argb(&self) -> &str {
if self.indexed.has_value() {
match INDEXED_COLORS.get(self.indexed.get_value().clone() as usize) {
Some(v) => return v,
None => {}
}
}
self.argb.get_value_str()
}
pub fn get_argb_with_theme(&self, theme: &Theme) -> Cow<'static, str> {
if self.indexed.has_value() {
return self.get_argb().to_owned().into();
}
if self.theme_index.has_value() {
match theme
.get_theme_elements()
.get_color_scheme()
.get_color_map()
.get(*self.theme_index.get_value() as usize)
{
Some(v) => return v.to_string().into(),
None => {}
}
}
self.argb.get_value_str().to_string().into()
}
pub fn set_argb<S: Into<String>>(&mut self, value: S) -> &mut Self {
let argb = value.into();
let indexed = INDEXED_COLORS.iter().position(|&r| r == argb);
match indexed {
Some(v) => {
self.indexed.set_value(v as u32);
self.argb.remove_value();
}
None => {
self.indexed.remove_value();
self.argb.set_value(argb);
}
}
self.theme_index.remove_value();
self
}
pub fn get_indexed(&self) -> &u32 {
self.indexed.get_value()
}
pub fn set_indexed(&mut self, index: u32) -> &mut Self {
self.indexed.set_value(index);
self.theme_index.remove_value();
self.argb.remove_value();
self
}
pub fn get_theme_index(&self) -> &u32 {
self.theme_index.get_value()
}
pub fn set_theme_index(&mut self, index: u32) -> &mut Self {
self.indexed.remove_value();
self.theme_index.set_value(index);
self.argb.remove_value();
self
}
pub fn get_tint(&self) -> &f64 {
self.tint.get_value()
}
pub fn set_tint(&mut self, value: f64) -> &mut Color {
self.tint.set_value(value);
self
}
pub(crate) fn has_value(&self) -> bool {
self.theme_index.has_value()
|| self.indexed.has_value()
|| self.argb.has_value()
|| self.tint.has_value()
}
pub(crate) fn get_hash_code(&self) -> String {
format!(
"{:x}",
md5::Md5::digest(format!(
"{}{}{}{}",
&self.indexed.get_hash_string(),
&self.theme_index.get_hash_string(),
&self.argb.get_hash_string(),
&self.tint.get_hash_string()
))
)
}
pub(crate) fn set_attributes<R: std::io::BufRead>(
&mut self,
reader: &mut Reader<R>,
e: &BytesStart,
empty_flg: bool,
) {
for a in e.attributes().with_checks(false) {
match a {
Ok(ref attr) => match attr.key.0 {
b"indexed" => {
self.indexed
.set_value_string(get_attribute_value(attr).unwrap());
}
b"theme" => {
self.theme_index
.set_value_string(get_attribute_value(attr).unwrap());
}
b"rgb" => {
self.argb
.set_value_string(get_attribute_value(attr).unwrap());
}
b"tint" => {
self.tint
.set_value_string(get_attribute_value(attr).unwrap());
}
_ => {}
},
Err(_) => {}
}
}
if empty_flg {
return;
}
let mut buf = Vec::new();
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::End(ref e)) => match e.name().into_inner() {
b"color" => return,
b"fgColor" => return,
b"bgColor" => return,
b"tabColor" => return,
_ => (),
},
Ok(Event::Eof) => panic!(
"Error not find {} end element",
"color,fgColor,bgColor,tabColor"
),
Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
_ => (),
}
buf.clear();
}
}
pub(crate) fn write_to_color(&self, writer: &mut Writer<Cursor<Vec<u8>>>) {
self.write_to(writer, "color");
}
pub(crate) fn write_to_fg_color(&self, writer: &mut Writer<Cursor<Vec<u8>>>) {
self.write_to(writer, "fgColor");
}
pub(crate) fn write_to_bg_color(&self, writer: &mut Writer<Cursor<Vec<u8>>>) {
self.write_to(writer, "bgColor");
}
pub(crate) fn write_to_tab_color(&self, writer: &mut Writer<Cursor<Vec<u8>>>) {
self.write_to(writer, "tabColor");
}
fn write_to(&self, writer: &mut Writer<Cursor<Vec<u8>>>, tag_name: &str) {
let mut attributes: Vec<(&str, &str)> = Vec::new();
let theme_index = self.theme_index.get_value_string();
let indexed = self.indexed.get_value_string();
if self.theme_index.has_value() {
attributes.push(("theme", &theme_index));
} else if self.indexed.has_value() {
attributes.push(("indexed", &indexed));
} else if self.argb.has_value() {
attributes.push(("rgb", self.argb.get_value_str()));
}
let tint = self.tint.get_value_string();
if self.tint.has_value() {
attributes.push(("tint", &tint));
}
if !attributes.is_empty() {
write_start_tag(writer, tag_name, attributes, true);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn set_value() {
let mut obj = Color::default();
obj.set_argb("F34F8080");
assert_eq!(obj.get_argb(), "F34F8080");
let mut obj = Color::default();
obj.set_argb("FFFF8080");
assert_eq!(obj.get_indexed(), &21);
assert_eq!(obj.get_argb(), "FFFF8080");
let mut obj = Color::default();
let theme = Theme::get_default_value();
obj.set_theme_index(1);
assert_eq!(obj.get_argb_with_theme(&theme), "FFFFFF");
}
}