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     /** Returns a new text style object with the specified `color`.
90 
91     # Example
92 
93     ```
94     use plotters::prelude::*;
95     let text_style = ("sans-serif", 20).into_font().color(&RED);
96     let drawing_area = SVGBackend::new("font_desc_color.svg", (200, 100)).into_drawing_area();
97     drawing_area.fill(&WHITE).unwrap();
98     drawing_area.draw_text("This is a big red label", &text_style, (10, 50));
99     ```
100 
101     The result is a text label colorized accordingly:
102 
103     ![](https://cdn.jsdelivr.net/gh/facorread/plotters-doc-data@f030ed3/apidoc/font_desc_color.svg)
104 
105     # See also
106 
107     [`IntoTextStyle::with_color()`](crate::style::IntoTextStyle::with_color)
108 
109     [`IntoTextStyle::into_text_style()`](crate::style::IntoTextStyle::into_text_style) for a more succinct example
110 
111     */
color<C: Color>(&self, color: &C) -> TextStyle<'a>112     pub fn color<C: Color>(&self, color: &C) -> TextStyle<'a> {
113         TextStyle {
114             font: self.clone(),
115             color: color.to_backend_color(),
116             pos: Pos::default(),
117         }
118     }
119 
120     /// Returns the font family
get_family(&self) -> FontFamily121     pub fn get_family(&self) -> FontFamily {
122         self.family
123     }
124 
125     /// Get the name of the font
get_name(&self) -> &str126     pub fn get_name(&self) -> &str {
127         self.family.as_str()
128     }
129 
130     /// Get the name of the style
get_style(&self) -> FontStyle131     pub fn get_style(&self) -> FontStyle {
132         self.style
133     }
134 
135     /// Get the size of font
get_size(&self) -> f64136     pub fn get_size(&self) -> f64 {
137         self.size
138     }
139 
140     /// Get the size of the text if rendered in this font
141     ///
142     /// For a TTF type, zero point of the layout box is the left most baseline char of the string
143     /// Thus the upper bound of the box is most likely be negative
layout_box(&self, text: &str) -> FontResult<((i32, i32), (i32, i32))>144     pub fn layout_box(&self, text: &str) -> FontResult<((i32, i32), (i32, i32))> {
145         match &self.data {
146             Ok(ref font) => font.estimate_layout(self.size, text),
147             Err(e) => Err(e.clone()),
148         }
149     }
150 
151     /// Get the size of the text if rendered in this font.
152     /// This is similar to `layout_box` function, but it apply the font transformation
153     /// and estimate the overall size of the font
box_size(&self, text: &str) -> FontResult<(u32, u32)>154     pub fn box_size(&self, text: &str) -> FontResult<(u32, u32)> {
155         let ((min_x, min_y), (max_x, max_y)) = self.layout_box(text)?;
156         let (w, h) = self.get_transform().transform(max_x - min_x, max_y - min_y);
157         Ok((w.unsigned_abs(), h.unsigned_abs()))
158     }
159 
160     /// 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>>161     pub fn draw<E, DrawFunc: FnMut(i32, i32, f32) -> Result<(), E>>(
162         &self,
163         text: &str,
164         (x, y): (i32, i32),
165         draw: DrawFunc,
166     ) -> FontResult<Result<(), E>> {
167         match &self.data {
168             Ok(ref font) => font.draw((x, y), self.size, text, draw),
169             Err(e) => Err(e.clone()),
170         }
171     }
172 }
173 
174 impl<'a> From<&'a str> for FontDesc<'a> {
from(from: &'a str) -> FontDesc<'a>175     fn from(from: &'a str) -> FontDesc<'a> {
176         FontDesc::new(from.into(), 12.0, FontStyle::Normal)
177     }
178 }
179 
180 impl<'a> From<FontFamily<'a>> for FontDesc<'a> {
from(family: FontFamily<'a>) -> FontDesc<'a>181     fn from(family: FontFamily<'a>) -> FontDesc<'a> {
182         FontDesc::new(family, 12.0, FontStyle::Normal)
183     }
184 }
185 
186 impl<'a, T: Into<f64>> From<(FontFamily<'a>, T)> for FontDesc<'a> {
from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a>187     fn from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a> {
188         FontDesc::new(family, size.into(), FontStyle::Normal)
189     }
190 }
191 
192 impl<'a, T: Into<f64>> From<(&'a str, T)> for FontDesc<'a> {
from((typeface, size): (&'a str, T)) -> FontDesc<'a>193     fn from((typeface, size): (&'a str, T)) -> FontDesc<'a> {
194         FontDesc::new(typeface.into(), size.into(), FontStyle::Normal)
195     }
196 }
197 
198 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>199     fn from((family, size, style): (FontFamily<'a>, T, S)) -> FontDesc<'a> {
200         FontDesc::new(family, size.into(), style.into())
201     }
202 }
203 
204 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>205     fn from((typeface, size, style): (&'a str, T, S)) -> FontDesc<'a> {
206         FontDesc::new(typeface.into(), size.into(), style.into())
207     }
208 }
209 
210 /// The trait that allows some type turns into a font description
211 pub trait IntoFont<'a> {
212     /// Make the font description from the source type
into_font(self) -> FontDesc<'a>213     fn into_font(self) -> FontDesc<'a>;
214 }
215 
216 impl<'a, T: Into<FontDesc<'a>>> IntoFont<'a> for T {
into_font(self) -> FontDesc<'a>217     fn into_font(self) -> FontDesc<'a> {
218         self.into()
219     }
220 }
221