plotters_unsable/style/font/
font_desc.rs

1use super::{FontData, FontDataInternal};
2use crate::style::{Color, LayoutBox, TextStyle};
3
4use std::convert::From;
5
6/// The error type for the font implementation
7pub type FontError = <FontDataInternal as FontData>::ErrorType;
8
9/// The type we used to represent a result of any font operations
10pub type FontResult<T> = Result<T, FontError>;
11
12/// Specifying text transformations
13#[derive(Clone)]
14pub enum FontTransform {
15    None,
16    Rotate90,
17    Rotate180,
18    Rotate270,
19}
20
21impl FontTransform {
22    /// Compute the offset of the "top-left" cornor of the text.
23    /// "Top-left" defined as the first char's top-left in reading orientation.
24    pub fn offset(&self, layout: LayoutBox) -> (i32, i32) {
25        match self {
26            FontTransform::None => (0, 0),
27            FontTransform::Rotate90 => ((layout.1).1 - (layout.0).1, 0),
28            FontTransform::Rotate180 => ((layout.1).0 - (layout.0).0, (layout.1).1 - (layout.0).1),
29            FontTransform::Rotate270 => (0, (layout.1).0 - (layout.0).0),
30        }
31    }
32
33    /// Transform the coordinate to performe the rotation
34    pub fn transform(&self, x: i32, y: i32) -> (i32, i32) {
35        match self {
36            FontTransform::None => (x, y),
37            FontTransform::Rotate90 => (-y, x),
38            FontTransform::Rotate180 => (-x, -y),
39            FontTransform::Rotate270 => (y, -x),
40        }
41    }
42}
43
44/// Describes a font
45pub struct FontDesc<'a> {
46    size: f64,
47    name: &'a str,
48    data: FontResult<FontDataInternal>,
49    transform: FontTransform,
50}
51
52impl<'a> From<&'a str> for FontDesc<'a> {
53    fn from(from: &'a str) -> FontDesc<'a> {
54        FontDesc::new(from, 1.0)
55    }
56}
57
58impl<'a, T: Into<f64>> From<(&'a str, T)> for FontDesc<'a> {
59    fn from((typeface, size): (&'a str, T)) -> FontDesc<'a> {
60        FontDesc::new(typeface, size.into())
61    }
62}
63
64pub trait IntoFont<'a> {
65    fn into_font(self) -> FontDesc<'a>;
66}
67
68impl<'a, T: Into<FontDesc<'a>>> IntoFont<'a> for T {
69    fn into_font(self) -> FontDesc<'a> {
70        self.into()
71    }
72}
73
74impl<'a> FontDesc<'a> {
75    /// Create a new font
76    pub fn new(typeface: &'a str, size: f64) -> Self {
77        Self {
78            size,
79            name: typeface,
80            data: FontDataInternal::new(typeface),
81            transform: FontTransform::None,
82        }
83    }
84
85    /// Create a new font desc with the same font but different size
86    pub fn resize(&self, size: f64) -> FontDesc<'a> {
87        Self {
88            size,
89            name: self.name,
90            data: self.data.clone(),
91            transform: self.transform.clone(),
92        }
93    }
94
95    /// Set the font transformation
96    pub fn transform(&self, trans: FontTransform) -> Self {
97        Self {
98            size: self.size,
99            name: self.name,
100            data: self.data.clone(),
101            transform: trans,
102        }
103    }
104
105    /// Get the font transformation description
106    pub fn get_transform(&self) -> FontTransform {
107        self.transform.clone()
108    }
109
110    /// Set the color of the font and return the result text style object
111    pub fn color<C: Color>(&'a self, color: &'a C) -> TextStyle<'a> {
112        TextStyle { font: self, color }
113    }
114
115    /// Get the name of the font
116    pub fn get_name(&self) -> &'a str {
117        self.name
118    }
119
120    /// Get the size of font
121    pub fn get_size(&self) -> f64 {
122        self.size
123    }
124
125    /// Get the size of the text if rendered in this font
126    pub fn layout_box(&self, text: &str) -> FontResult<((i32, i32), (i32, i32))> {
127        match &self.data {
128            Ok(ref font) => font.estimate_layout(self.size, text),
129            Err(e) => Err(e.clone()),
130        }
131    }
132
133    /// Get the size of the text if rendered in this font
134    pub fn box_size(&self, text: &str) -> FontResult<(u32, u32)> {
135        let ((min_x, min_y), (max_x, max_y)) = self.layout_box(text)?;
136        Ok(((max_x - min_x) as u32, (max_y - min_y) as u32))
137    }
138
139    /// Actually draws a font with a drawing function
140    pub fn draw<E, DrawFunc: FnMut(i32, i32, f32) -> Result<(), E>>(
141        &self,
142        text: &str,
143        (x, y): (i32, i32),
144        draw: DrawFunc,
145    ) -> FontResult<Result<(), E>> {
146        match &self.data {
147            Ok(ref font) => font.draw((x, y), self.size, text, self.get_transform(), draw),
148            Err(e) => Err(e.clone()),
149        }
150    }
151}