use std::borrow;
use std::iter;
use crate::fonts;
use crate::Mm;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Color {
Rgb(u8, u8, u8),
Cmyk(u8, u8, u8, u8),
Greyscale(u8),
}
impl From<Color> for printpdf::Color {
fn from(color: Color) -> printpdf::Color {
match color {
Color::Rgb(r, g, b) => printpdf::Color::Rgb(printpdf::Rgb::new(
f64::from(r) / 255.0,
f64::from(g) / 255.0,
f64::from(b) / 255.0,
None,
)),
Color::Cmyk(c, m, y, k) => printpdf::Color::Cmyk(printpdf::Cmyk::new(
f64::from(c) / 255.0,
f64::from(m) / 255.0,
f64::from(y) / 255.0,
f64::from(k) / 255.0,
None,
)),
Color::Greyscale(val) => {
printpdf::Color::Greyscale(printpdf::Greyscale::new(f64::from(val) / 255.0, None))
}
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Effect {
Bold,
Italic,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Style {
font_family: Option<fonts::FontFamily<fonts::Font>>,
font_size: Option<u8>,
line_spacing: Option<f64>,
color: Option<Color>,
is_bold: bool,
is_italic: bool,
}
impl Style {
pub fn new() -> Style {
Style::default()
}
pub fn merge(&mut self, style: impl Into<Style>) {
let style = style.into();
if let Some(font_family) = style.font_family {
self.font_family = Some(font_family);
};
if let Some(font_size) = style.font_size {
self.font_size = Some(font_size);
}
if let Some(color) = style.color {
self.color = Some(color);
}
if style.is_bold {
self.is_bold = true;
}
if style.is_italic {
self.is_italic = true;
}
}
pub fn and(mut self, style: impl Into<Style>) -> Style {
self.merge(style);
self
}
pub fn combine(left: impl Into<Style>, right: impl Into<Style>) -> Style {
left.into().and(right)
}
pub fn color(&self) -> Option<Color> {
self.color
}
pub fn is_bold(&self) -> bool {
self.is_bold
}
pub fn is_italic(&self) -> bool {
self.is_italic
}
pub fn font_size(&self) -> u8 {
self.font_size.unwrap_or(12)
}
pub fn line_spacing(&self) -> f64 {
self.line_spacing.unwrap_or(1.0)
}
pub fn set_bold(&mut self) {
self.is_bold = true;
}
pub fn bold(mut self) -> Style {
self.set_bold();
self
}
pub fn set_italic(&mut self) {
self.is_italic = true;
}
pub fn italic(mut self) -> Style {
self.set_italic();
self
}
pub fn set_font_family(&mut self, font_family: fonts::FontFamily<fonts::Font>) {
self.font_family = Some(font_family);
}
pub fn with_font_family(mut self, font_family: fonts::FontFamily<fonts::Font>) -> Style {
self.set_font_family(font_family);
self
}
pub fn set_line_spacing(&mut self, line_spacing: f64) {
self.line_spacing = Some(line_spacing);
}
pub fn with_line_spacing(mut self, line_spacing: f64) -> Style {
self.set_line_spacing(line_spacing);
self
}
pub fn set_font_size(&mut self, font_size: u8) {
self.font_size = Some(font_size);
}
pub fn with_font_size(mut self, font_size: u8) -> Style {
self.set_font_size(font_size);
self
}
pub fn set_color(&mut self, color: Color) {
self.color = Some(color);
}
pub fn with_color(mut self, color: Color) -> Self {
self.set_color(color);
self
}
pub fn char_width(&self, font_cache: &fonts::FontCache, c: char) -> Mm {
self.font(font_cache)
.char_width(font_cache, c, self.font_size())
}
pub fn str_width(&self, font_cache: &fonts::FontCache, s: &str) -> Mm {
let font = self.font(font_cache);
font.str_width(font_cache, s, self.font_size())
}
pub fn font_family(&self, font_cache: &fonts::FontCache) -> fonts::FontFamily<fonts::Font> {
self.font_family
.unwrap_or_else(|| font_cache.default_font_family())
}
pub fn font(&self, font_cache: &fonts::FontCache) -> fonts::Font {
self.font_family(font_cache).get(*self)
}
pub fn line_height(&self, font_cache: &fonts::FontCache) -> Mm {
self.font(font_cache).get_line_height(self.font_size()) * self.line_spacing()
}
}
impl From<Color> for Style {
fn from(color: Color) -> Style {
Style::new().with_color(color)
}
}
impl From<Effect> for Style {
fn from(effect: Effect) -> Style {
let style = Style::new();
match effect {
Effect::Bold => style.bold(),
Effect::Italic => style.italic(),
}
}
}
impl From<fonts::FontFamily<fonts::Font>> for Style {
fn from(font_family: fonts::FontFamily<fonts::Font>) -> Style {
Style::new().with_font_family(font_family)
}
}
impl<T: Into<Style>> iter::Extend<T> for Style {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
for style in iter {
self.merge(style.into());
}
}
}
impl<T: Into<Style>> iter::FromIterator<T> for Style {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Style {
let mut style = Style::new();
style.extend(iter);
style
}
}
#[derive(Clone, Debug, Default)]
pub struct StyledString {
pub s: String,
pub style: Style,
}
impl StyledString {
pub fn new(s: impl Into<String>, style: impl Into<Style>) -> StyledString {
StyledString {
s: s.into(),
style: style.into(),
}
}
pub fn width(&self, font_cache: &fonts::FontCache) -> Mm {
self.style.str_width(font_cache, &self.s)
}
}
impl From<String> for StyledString {
fn from(s: String) -> StyledString {
StyledString::new(s, Style::new())
}
}
impl<'a> From<&'a String> for StyledString {
fn from(s: &'a String) -> StyledString {
StyledString::from(s.to_owned())
}
}
impl<'a> From<&'a str> for StyledString {
fn from(s: &'a str) -> StyledString {
StyledString::from(s.to_owned())
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct StyledStr<'s> {
pub s: &'s str,
pub style: Style,
}
impl<'s> StyledStr<'s> {
pub fn new(s: &'s str, style: impl Into<Style>) -> StyledStr<'s> {
StyledStr {
s,
style: style.into(),
}
}
pub fn width(&self, font_cache: &fonts::FontCache) -> Mm {
self.style.str_width(font_cache, &self.s)
}
}
impl<'s> From<&'s str> for StyledStr<'s> {
fn from(s: &'s str) -> StyledStr<'s> {
StyledStr::new(s, Style::new())
}
}
impl<'s> From<&'s String> for StyledStr<'s> {
fn from(s: &'s String) -> StyledStr<'s> {
StyledStr::new(s, Style::new())
}
}
impl<'s> From<&'s StyledString> for StyledStr<'s> {
fn from(s: &'s StyledString) -> StyledStr<'s> {
StyledStr::new(&s.s, s.style)
}
}
#[derive(Clone, Debug, Default)]
pub struct StyledCow<'s> {
pub s: borrow::Cow<'s, str>,
pub style: Style,
}
impl<'s> StyledCow<'s> {
pub fn new(s: impl Into<borrow::Cow<'s, str>>, style: impl Into<Style>) -> StyledCow<'s> {
StyledCow {
s: s.into(),
style: style.into(),
}
}
pub fn width(&self, font_cache: &fonts::FontCache) -> Mm {
self.style.str_width(font_cache, self.s.as_ref())
}
}
impl<'s> From<&'s str> for StyledCow<'s> {
fn from(s: &'s str) -> StyledCow<'s> {
StyledCow::new(s, Style::new())
}
}
impl<'s> From<&'s String> for StyledCow<'s> {
fn from(s: &'s String) -> StyledCow<'s> {
StyledCow::new(s, Style::new())
}
}
impl<'s> From<String> for StyledCow<'s> {
fn from(s: String) -> StyledCow<'s> {
StyledCow::new(s, Style::new())
}
}
impl<'s> From<StyledStr<'s>> for StyledCow<'s> {
fn from(s: StyledStr<'s>) -> StyledCow<'s> {
StyledCow::new(s.s, s.style)
}
}
impl<'s> From<&'s StyledString> for StyledCow<'s> {
fn from(s: &'s StyledString) -> StyledCow<'s> {
StyledCow::new(&s.s, s.style)
}
}
impl<'s> From<StyledString> for StyledCow<'s> {
fn from(s: StyledString) -> StyledCow<'s> {
StyledCow::new(s.s, s.style)
}
}