plotters/style/font/
font_desc.rs

1use super::{FontData, FontDataInternal};
2use crate::style::text_anchor::Pos;
3use crate::style::{Color, TextStyle};
4
5use std::convert::From;
6
7pub use plotters_backend::{FontFamily, FontStyle, FontTransform};
8
9/// The error type for the font implementation
10pub type FontError = <FontDataInternal as FontData>::ErrorType;
11
12/// The type we used to represent a result of any font operations
13pub type FontResult<T> = Result<T, FontError>;
14
15/// Describes a font
16#[derive(Clone)]
17pub struct FontDesc<'a> {
18    size: f64,
19    family: FontFamily<'a>,
20    data: FontResult<FontDataInternal>,
21    transform: FontTransform,
22    style: FontStyle,
23}
24
25impl<'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
32    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
46    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
60    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
74    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
85    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
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
98    pub fn get_family(&self) -> FontFamily {
99        self.family
100    }
101
102    /// Get the name of the font
103    pub fn get_name(&self) -> &str {
104        self.family.as_str()
105    }
106
107    /// Get the name of the style
108    pub fn get_style(&self) -> FontStyle {
109        self.style
110    }
111
112    /// Get the size of font
113    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
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
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
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
151impl<'a> From<&'a str> for FontDesc<'a> {
152    fn from(from: &'a str) -> FontDesc<'a> {
153        FontDesc::new(from.into(), 12.0, FontStyle::Normal)
154    }
155}
156
157impl<'a> From<FontFamily<'a>> for FontDesc<'a> {
158    fn from(family: FontFamily<'a>) -> FontDesc<'a> {
159        FontDesc::new(family, 12.0, FontStyle::Normal)
160    }
161}
162
163impl<'a, T: Into<f64>> From<(FontFamily<'a>, T)> for FontDesc<'a> {
164    fn from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a> {
165        FontDesc::new(family, size.into(), FontStyle::Normal)
166    }
167}
168
169impl<'a, T: Into<f64>> From<(&'a str, T)> for FontDesc<'a> {
170    fn from((typeface, size): (&'a str, T)) -> FontDesc<'a> {
171        FontDesc::new(typeface.into(), size.into(), FontStyle::Normal)
172    }
173}
174
175impl<'a, T: Into<f64>, S: Into<FontStyle>> From<(FontFamily<'a>, T, S)> for 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
181impl<'a, T: Into<f64>, S: Into<FontStyle>> From<(&'a str, T, S)> for 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
188pub trait IntoFont<'a> {
189    /// Make the font description from the source type
190    fn into_font(self) -> FontDesc<'a>;
191}
192
193impl<'a, T: Into<FontDesc<'a>>> IntoFont<'a> for T {
194    fn into_font(self) -> FontDesc<'a> {
195        self.into()
196    }
197}