edit-xlsx 0.4.4

A quick and easy-to-use Rust library for Excel file editing.
Documentation
use serde::{Deserialize, Serialize};
use crate::xml::common::{Element, FromFormat};
use crate::xml::style::color::Color;
use crate::api::format::FormatFont;
use crate::RichText;

#[derive(Debug, Clone, Deserialize, Serialize)]
pub(crate) struct Fonts {
    #[serde(rename = "@count", default)]
    count: u32,
    #[serde(rename(serialize = "@x14ac:knownFonts", deserialize = "@knownFonts"), skip_serializing_if = "Option::is_none")]
    x14ac_known_fonts: Option<u32>,
    #[serde(rename = "font", default)]
    fonts: Vec<Font>,
}

impl Default for Fonts {
    fn default() -> Self {
        Fonts {
            count: 1,
            x14ac_known_fonts: Some(1),
            fonts: vec![Default::default()],
        }
    }
}

impl Fonts {
    pub(crate) fn add_font(&mut self, font: &Font) -> u32 {
        for i in 0..self.fonts.len() {
            if self.fonts[i] == *font {
                return i as u32;
            }
        }
        self.count += 1;
        self.fonts.push(font.clone());
        self.fonts.len() as u32 - 1
    }
    
    pub(crate) fn get_font(&self, id: u32) -> Option<&Font> {
        self.fonts.get(id as usize)
    }
}

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
pub(crate) struct Font {
    #[serde(rename = "b", skip_serializing_if = "Option::is_none")]
    pub(crate) bold: Option<Bold>,
    #[serde(rename = "i", skip_serializing_if = "Option::is_none")]
    pub(crate) italic: Option<Italic>,
    #[serde(skip_serializing_if = "Option::is_none")]
    strike: Option<Element<u8>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    condense: Option<Element<u8>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    extend: Option<Element<u8>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    outline: Option<Element<u8>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    shadow: Option<Element<u8>>,
    #[serde(rename = "u", skip_serializing_if = "Option::is_none")]
    pub(crate) underline: Option<Underline>,
    #[serde(rename = "vertAlign", skip_serializing_if = "Option::is_none")]
    vert_align: Option<Element<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub(crate) sz: Option<Element<f64>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub(crate) color: Option<Color>,
    #[serde(rename = "name", default, skip_serializing_if = "Option::is_none")]
    pub(crate) name: Option<Element<String>>,
    #[serde(rename = "rFont", default, skip_serializing_if = "Option::is_none")]
    pub(crate) rich_font_name: Option<Element<String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    family: Option<Element<u8>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    charset: Option<Element<u8>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    scheme: Option<Element<String>>,
}

impl Default for Font {
    fn default() -> Font {
        Font {
            sz: Some(Element::from_val(11.0)),
            color: None,
            name: Some(Element::from_val("Calibri".to_string())),
            rich_font_name: None,
            family: None,
            charset: None,
            scheme: None,
            bold: None,
            italic: None,
            strike: None,
            condense: None,
            extend: None,
            outline: None,
            shadow: None,
            underline: None,
            vert_align: None,
        }
    }
}

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
pub(crate) struct Bold {

}

impl Bold {
    pub(crate) fn default() -> Bold {
        Bold {}
    }
}

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
pub(crate) struct Italic {

}

impl Italic {
    pub(crate) fn default() -> Italic {
        Italic {}
    }
}

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
pub(crate) struct Underline {

}

impl Underline {
    pub(crate) fn default() -> Underline {
        Underline {}
    }
}

impl FromFormat<FormatFont> for Font {
    fn set_attrs_by_format(&mut self, format: &FormatFont) {
        self.color = Some(Color::from_format(&format.color));
        self.name = Some(Element::from_val(format.name.to_string()));
        self.sz = Some(Element::from_val(format.size));
        self.bold = if format.bold { Some(Bold::default()) } else { None };
        self.underline = if format.underline { Some(Underline::default()) } else { None };
        self.italic = if format.italic { Some(Italic::default()) } else { None };
    }

    fn set_format(&self, format: &mut FormatFont) {
        format.bold = self.bold.is_some();
        format.italic = self.italic.is_some();
        format.underline = self.underline.is_some();
        if let Some(size) = &self.sz {
            format.size = size.get_format();
        }
        if let Some(name) = &self.name {
            format.name = name.val.to_string();
        }
        format.color = self.color.as_ref().get_format();
    }
}

impl Font {
    pub(crate) fn from_rich_font_format(rich_font: &FormatFont) -> Font {
        let mut font = Font::from_format(rich_font);
        font.rich_font_name = font.name;
        font.name = None;
        font
    }

    pub(crate) fn get_rich_font_format(&self) -> FormatFont {
        let mut rich_font = self.get_format();
        if let Some(rich_font_name) = &self.rich_font_name {
            rich_font.name = rich_font_name.val.to_string();
        }
        rich_font
    }
}