1 use super::{FontData, FontDataInternal};
2 use crate::style::text_anchor::Pos;
3 use crate::style::{Color, TextStyle};
4 
5 use std::convert::From;
6 
7 pub use plotters_backend::{FontFamily, FontStyle, FontTransform};
8 
9 /// The error type for the font implementation
10 pub type FontError = <FontDataInternal as FontData>::ErrorType;
11 
12 /// The type we used to represent a result of any font operations
13 pub type FontResult<T> = Result<T, FontError>;
14 
15 /// Describes a font
16 #[derive(Clone)]
17 pub struct FontDesc<'a> {
18     size: f64,
19     family: FontFamily<'a>,
20     data: FontResult<FontDataInternal>,
21     transform: FontTransform,
22     style: FontStyle,
23 }
24 
25 impl<'a> From<&'a str> for FontDesc<'a> {
from(from: &'a str) -> FontDesc<'a>26     fn from(from: &'a str) -> FontDesc<'a> {
27         FontDesc::new(from.into(), 1.0, FontStyle::Normal)
28     }
29 }
30 
31 impl<'a> From<FontFamily<'a>> for FontDesc<'a> {
from(family: FontFamily<'a>) -> FontDesc<'a>32     fn from(family: FontFamily<'a>) -> FontDesc<'a> {
33         FontDesc::new(family, 1.0, FontStyle::Normal)
34     }
35 }
36 
37 impl<'a, T: Into<f64>> From<(FontFamily<'a>, T)> for FontDesc<'a> {
from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a>38     fn from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a> {
39         FontDesc::new(family, size.into(), FontStyle::Normal)
40     }
41 }
42 
43 impl<'a, T: Into<f64>> From<(&'a str, T)> for FontDesc<'a> {
from((typeface, size): (&'a str, T)) -> FontDesc<'a>44     fn from((typeface, size): (&'a str, T)) -> FontDesc<'a> {
45         FontDesc::new(typeface.into(), size.into(), FontStyle::Normal)
46     }
47 }
48 
49 impl<'a, T: Into<f64>, S: Into<FontStyle>> From<(FontFamily<'a>, T, S)> for FontDesc<'a> {
from((family, size, style): (FontFamily<'a>, T, S)) -> FontDesc<'a>50     fn from((family, size, style): (FontFamily<'a>, T, S)) -> FontDesc<'a> {
51         FontDesc::new(family, size.into(), style.into())
52     }
53 }
54 
55 impl<'a, T: Into<f64>, S: Into<FontStyle>> From<(&'a str, T, S)> for FontDesc<'a> {
from((typeface, size, style): (&'a str, T, S)) -> FontDesc<'a>56     fn from((typeface, size, style): (&'a str, T, S)) -> FontDesc<'a> {
57         FontDesc::new(typeface.into(), size.into(), style.into())
58     }
59 }
60 
61 /// The trait that allows some type turns into a font description
62 pub trait IntoFont<'a> {
63     /// Make the font description from the source type
into_font(self) -> FontDesc<'a>64     fn into_font(self) -> FontDesc<'a>;
65 }
66 
67 impl<'a, T: Into<FontDesc<'a>>> IntoFont<'a> for T {
into_font(self) -> FontDesc<'a>68     fn into_font(self) -> FontDesc<'a> {
69         self.into()
70     }
71 }
72 
73 impl<'a> FontDesc<'a> {
74     /// Create a new font
75     ///
76     /// - `family`: The font family name
77     /// - `size`: The size of the font
78     /// - `style`: The font variations
79     /// - **returns** The newly created font description
new(family: FontFamily<'a>, size: f64, style: FontStyle) -> Self80     pub fn new(family: FontFamily<'a>, size: f64, style: FontStyle) -> Self {
81         Self {
82             size,
83             family,
84             data: FontDataInternal::new(family, style),
85             transform: FontTransform::None,
86             style,
87         }
88     }
89 
90     /// Create a new font desc with the same font but different size
91     ///
92     /// - `size`: The new size to set
93     /// - **returns** The newly created font descriptor with a new size
resize(&self, size: f64) -> FontDesc<'a>94     pub fn resize(&self, size: f64) -> FontDesc<'a> {
95         Self {
96             size,
97             family: self.family,
98             data: self.data.clone(),
99             transform: self.transform.clone(),
100             style: self.style,
101         }
102     }
103 
104     /// Set the style of the font
105     ///
106     /// - `style`: The new style
107     /// - **returns** The new font description with this style applied
style(&self, style: FontStyle) -> Self108     pub fn style(&self, style: FontStyle) -> Self {
109         Self {
110             size: self.size,
111             family: self.family,
112             data: self.data.clone(),
113             transform: self.transform.clone(),
114             style,
115         }
116     }
117 
118     /// Set the font transformation
119     ///
120     /// - `trans`: The new transformation
121     /// - **returns** The new font description with this font transformation applied
transform(&self, trans: FontTransform) -> Self122     pub fn transform(&self, trans: FontTransform) -> Self {
123         Self {
124             size: self.size,
125             family: self.family,
126             data: self.data.clone(),
127             transform: trans,
128             style: self.style,
129         }
130     }
131 
132     /// Get the font transformation description
get_transform(&self) -> FontTransform133     pub fn get_transform(&self) -> FontTransform {
134         self.transform.clone()
135     }
136 
137     /// Set the color of the font and return the result text style object
color<C: Color>(&self, color: &C) -> TextStyle<'a>138     pub fn color<C: Color>(&self, color: &C) -> TextStyle<'a> {
139         TextStyle {
140             font: self.clone(),
141             color: color.color(),
142             pos: Pos::default(),
143         }
144     }
145 
get_family(&self) -> FontFamily146     pub fn get_family(&self) -> FontFamily {
147         self.family
148     }
149 
150     /// Get the name of the font
get_name(&self) -> &str151     pub fn get_name(&self) -> &str {
152         self.family.as_str()
153     }
154 
155     /// Get the name of the style
get_style(&self) -> FontStyle156     pub fn get_style(&self) -> FontStyle {
157         self.style
158     }
159 
160     /// Get the size of font
get_size(&self) -> f64161     pub fn get_size(&self) -> f64 {
162         self.size
163     }
164 
165     /// Get the size of the text if rendered in this font
166     ///
167     /// For a TTF type, zero point of the layout box is the left most baseline char of the string
168     /// Thus the upper bound of the box is most likely be negative
layout_box(&self, text: &str) -> FontResult<((i32, i32), (i32, i32))>169     pub fn layout_box(&self, text: &str) -> FontResult<((i32, i32), (i32, i32))> {
170         match &self.data {
171             Ok(ref font) => font.estimate_layout(self.size, text),
172             Err(e) => Err(e.clone()),
173         }
174     }
175 
176     /// Get the size of the text if rendered in this font.
177     /// This is similar to `layout_box` function, but it apply the font transformation
178     /// and estimate the overall size of the font
box_size(&self, text: &str) -> FontResult<(u32, u32)>179     pub fn box_size(&self, text: &str) -> FontResult<(u32, u32)> {
180         let ((min_x, min_y), (max_x, max_y)) = self.layout_box(text)?;
181         let (w, h) = self.get_transform().transform(max_x - min_x, max_y - min_y);
182         Ok((w.abs() as u32, h.abs() as u32))
183     }
184 
185     /// Actually draws a font with a drawing function
draw<E, DrawFunc: FnMut(i32, i32, f32) -> Result<(), E>>( &self, text: &str, (x, y): (i32, i32), draw: DrawFunc, ) -> FontResult<Result<(), E>>186     pub fn draw<E, DrawFunc: FnMut(i32, i32, f32) -> Result<(), E>>(
187         &self,
188         text: &str,
189         (x, y): (i32, i32),
190         draw: DrawFunc,
191     ) -> FontResult<Result<(), E>> {
192         match &self.data {
193             Ok(ref font) => font.draw((x, y), self.size, text, draw),
194             Err(e) => Err(e.clone()),
195         }
196     }
197 }
198