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  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