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 /** 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 */
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
121 pub fn get_family(&self) -> FontFamily {
122 self.family
123 }
124
125 /// Get the name of the font
126 pub fn get_name(&self) -> &str {
127 self.family.as_str()
128 }
129
130 /// Get the name of the style
131 pub fn get_style(&self) -> FontStyle {
132 self.style
133 }
134
135 /// Get the size of font
136 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
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
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
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
174impl<'a> From<&'a str> for FontDesc<'a> {
175 fn from(from: &'a str) -> FontDesc<'a> {
176 FontDesc::new(from.into(), 12.0, FontStyle::Normal)
177 }
178}
179
180impl<'a> From<FontFamily<'a>> for FontDesc<'a> {
181 fn from(family: FontFamily<'a>) -> FontDesc<'a> {
182 FontDesc::new(family, 12.0, FontStyle::Normal)
183 }
184}
185
186impl<'a, T: Into<f64>> From<(FontFamily<'a>, T)> for FontDesc<'a> {
187 fn from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a> {
188 FontDesc::new(family, size.into(), FontStyle::Normal)
189 }
190}
191
192impl<'a, T: Into<f64>> From<(&'a str, T)> for FontDesc<'a> {
193 fn from((typeface, size): (&'a str, T)) -> FontDesc<'a> {
194 FontDesc::new(typeface.into(), size.into(), FontStyle::Normal)
195 }
196}
197
198impl<'a, T: Into<f64>, S: Into<FontStyle>> From<(FontFamily<'a>, T, S)> for 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
204impl<'a, T: Into<f64>, S: Into<FontStyle>> From<(&'a str, T, S)> for 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
211pub trait IntoFont<'a> {
212 /// Make the font description from the source type
213 fn into_font(self) -> FontDesc<'a>;
214}
215
216impl<'a, T: Into<FontDesc<'a>>> IntoFont<'a> for T {
217 fn into_font(self) -> FontDesc<'a> {
218 self.into()
219 }
220}
221