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> FontDesc<'a> {
26     /// Create a new font
27     ///
28     /// - `family`: The font family name
29     /// - `size`: The size of the font
30     /// - `style`: The font variations
31     /// - **returns** The newly created font description
new(family: FontFamily<'a>, size: f64, style: FontStyle) -> Self32     pub fn new(family: FontFamily<'a>, size: f64, style: FontStyle) -> Self {
33         Self {
34             size,
35             family,
36             data: FontDataInternal::new(family, style),
37             transform: FontTransform::None,
38             style,
39         }
40     }
41 
42     /// Create a new font desc with the same font but different size
43     ///
44     /// - `size`: The new size to set
45     /// - **returns** The newly created font descriptor with a new size
resize(&self, size: f64) -> Self46     pub fn resize(&self, size: f64) -> Self {
47         Self {
48             size,
49             family: self.family,
50             data: self.data.clone(),
51             transform: self.transform.clone(),
52             style: self.style,
53         }
54     }
55 
56     /// Set the style of the font
57     ///
58     /// - `style`: The new style
59     /// - **returns** The new font description with this style applied
style(&self, style: FontStyle) -> Self60     pub fn style(&self, style: FontStyle) -> Self {
61         Self {
62             size: self.size,
63             family: self.family,
64             data: self.data.clone(),
65             transform: self.transform.clone(),
66             style,
67         }
68     }
69 
70     /// Set the font transformation
71     ///
72     /// - `trans`: The new transformation
73     /// - **returns** The new font description with this font transformation applied
transform(&self, trans: FontTransform) -> Self74     pub fn transform(&self, trans: FontTransform) -> Self {
75         Self {
76             size: self.size,
77             family: self.family,
78             data: self.data.clone(),
79             transform: trans,
80             style: self.style,
81         }
82     }
83 
84     /// Get the font transformation description
get_transform(&self) -> FontTransform85     pub fn get_transform(&self) -> FontTransform {
86         self.transform.clone()
87     }
88 
89     /// Set the color of the font and return the result text style object
color<C: Color>(&self, color: &C) -> TextStyle<'a>90     pub fn color<C: Color>(&self, color: &C) -> TextStyle<'a> {
91         TextStyle {
92             font: self.clone(),
93             color: color.to_backend_color(),
94             pos: Pos::default(),
95         }
96     }
97 
get_family(&self) -> FontFamily98     pub fn get_family(&self) -> FontFamily {
99         self.family
100     }
101 
102     /// Get the name of the font
get_name(&self) -> &str103     pub fn get_name(&self) -> &str {
104         self.family.as_str()
105     }
106 
107     /// Get the name of the style
get_style(&self) -> FontStyle108     pub fn get_style(&self) -> FontStyle {
109         self.style
110     }
111 
112     /// Get the size of font
get_size(&self) -> f64113     pub fn get_size(&self) -> f64 {
114         self.size
115     }
116 
117     /// Get the size of the text if rendered in this font
118     ///
119     /// For a TTF type, zero point of the layout box is the left most baseline char of the string
120     /// Thus the upper bound of the box is most likely be negative
layout_box(&self, text: &str) -> FontResult<((i32, i32), (i32, i32))>121     pub fn layout_box(&self, text: &str) -> FontResult<((i32, i32), (i32, i32))> {
122         match &self.data {
123             Ok(ref font) => font.estimate_layout(self.size, text),
124             Err(e) => Err(e.clone()),
125         }
126     }
127 
128     /// Get the size of the text if rendered in this font.
129     /// This is similar to `layout_box` function, but it apply the font transformation
130     /// and estimate the overall size of the font
box_size(&self, text: &str) -> FontResult<(u32, u32)>131     pub fn box_size(&self, text: &str) -> FontResult<(u32, u32)> {
132         let ((min_x, min_y), (max_x, max_y)) = self.layout_box(text)?;
133         let (w, h) = self.get_transform().transform(max_x - min_x, max_y - min_y);
134         Ok((w.abs() as u32, h.abs() as u32))
135     }
136 
137     /// 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>>138     pub fn draw<E, DrawFunc: FnMut(i32, i32, f32) -> Result<(), E>>(
139         &self,
140         text: &str,
141         (x, y): (i32, i32),
142         draw: DrawFunc,
143     ) -> FontResult<Result<(), E>> {
144         match &self.data {
145             Ok(ref font) => font.draw((x, y), self.size, text, draw),
146             Err(e) => Err(e.clone()),
147         }
148     }
149 }
150 
151 impl<'a> From<&'a str> for FontDesc<'a> {
from(from: &'a str) -> FontDesc<'a>152     fn from(from: &'a str) -> FontDesc<'a> {
153         FontDesc::new(from.into(), 12.0, FontStyle::Normal)
154     }
155 }
156 
157 impl<'a> From<FontFamily<'a>> for FontDesc<'a> {
from(family: FontFamily<'a>) -> FontDesc<'a>158     fn from(family: FontFamily<'a>) -> FontDesc<'a> {
159         FontDesc::new(family, 12.0, FontStyle::Normal)
160     }
161 }
162 
163 impl<'a, T: Into<f64>> From<(FontFamily<'a>, T)> for FontDesc<'a> {
from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a>164     fn from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a> {
165         FontDesc::new(family, size.into(), FontStyle::Normal)
166     }
167 }
168 
169 impl<'a, T: Into<f64>> From<(&'a str, T)> for FontDesc<'a> {
from((typeface, size): (&'a str, T)) -> FontDesc<'a>170     fn from((typeface, size): (&'a str, T)) -> FontDesc<'a> {
171         FontDesc::new(typeface.into(), size.into(), FontStyle::Normal)
172     }
173 }
174 
175 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>176     fn from((family, size, style): (FontFamily<'a>, T, S)) -> FontDesc<'a> {
177         FontDesc::new(family, size.into(), style.into())
178     }
179 }
180 
181 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>182     fn from((typeface, size, style): (&'a str, T, S)) -> FontDesc<'a> {
183         FontDesc::new(typeface.into(), size.into(), style.into())
184     }
185 }
186 
187 /// The trait that allows some type turns into a font description
188 pub trait IntoFont<'a> {
189     /// Make the font description from the source type
into_font(self) -> FontDesc<'a>190     fn into_font(self) -> FontDesc<'a>;
191 }
192 
193 impl<'a, T: Into<FontDesc<'a>>> IntoFont<'a> for T {
into_font(self) -> FontDesc<'a>194     fn into_font(self) -> FontDesc<'a> {
195         self.into()
196     }
197 }
198