plotters_unstable/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> From<&'a str> for FontDesc<'a> {
26    fn from(from: &'a str) -> FontDesc<'a> {
27        FontDesc::new(from.into(), 1.0, FontStyle::Normal)
28    }
29}
30
31impl<'a> From<FontFamily<'a>> for FontDesc<'a> {
32    fn from(family: FontFamily<'a>) -> FontDesc<'a> {
33        FontDesc::new(family, 1.0, FontStyle::Normal)
34    }
35}
36
37impl<'a, T: Into<f64>> From<(FontFamily<'a>, T)> for FontDesc<'a> {
38    fn from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a> {
39        FontDesc::new(family, size.into(), FontStyle::Normal)
40    }
41}
42
43impl<'a, T: Into<f64>> From<(&'a str, T)> for FontDesc<'a> {
44    fn from((typeface, size): (&'a str, T)) -> FontDesc<'a> {
45        FontDesc::new(typeface.into(), size.into(), FontStyle::Normal)
46    }
47}
48
49impl<'a, T: Into<f64>, S: Into<FontStyle>> From<(FontFamily<'a>, T, S)> for 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
55impl<'a, T: Into<f64>, S: Into<FontStyle>> From<(&'a str, T, S)> for 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
62pub trait IntoFont<'a> {
63    /// Make the font description from the source type
64    fn into_font(self) -> FontDesc<'a>;
65}
66
67impl<'a, T: Into<FontDesc<'a>>> IntoFont<'a> for T {
68    fn into_font(self) -> FontDesc<'a> {
69        self.into()
70    }
71}
72
73impl<'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
80    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
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
108    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
122    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
133    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
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
146    pub fn get_family(&self) -> FontFamily {
147        self.family
148    }
149
150    /// Get the name of the font
151    pub fn get_name(&self) -> &str {
152        self.family.as_str()
153    }
154
155    /// Get the name of the style
156    pub fn get_style(&self) -> FontStyle {
157        self.style
158    }
159
160    /// Get the size of font
161    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
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
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
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}