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> From<&'a str> for FontDesc<'a> { from(from: &'a str) -> FontDesc<'a>26 fn from(from: &'a str) -> FontDesc<'a> { 27 FontDesc::new(from.into(), 1.0, FontStyle::Normal) 28 } 29 } 30 31 impl<'a> From<FontFamily<'a>> for FontDesc<'a> { from(family: FontFamily<'a>) -> FontDesc<'a>32 fn from(family: FontFamily<'a>) -> FontDesc<'a> { 33 FontDesc::new(family, 1.0, FontStyle::Normal) 34 } 35 } 36 37 impl<'a, T: Into<f64>> From<(FontFamily<'a>, T)> for FontDesc<'a> { from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a>38 fn from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a> { 39 FontDesc::new(family, size.into(), FontStyle::Normal) 40 } 41 } 42 43 impl<'a, T: Into<f64>> From<(&'a str, T)> for FontDesc<'a> { from((typeface, size): (&'a str, T)) -> FontDesc<'a>44 fn from((typeface, size): (&'a str, T)) -> FontDesc<'a> { 45 FontDesc::new(typeface.into(), size.into(), FontStyle::Normal) 46 } 47 } 48 49 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>50 fn from((family, size, style): (FontFamily<'a>, T, S)) -> FontDesc<'a> { 51 FontDesc::new(family, size.into(), style.into()) 52 } 53 } 54 55 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>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 62 pub trait IntoFont<'a> { 63 /// Make the font description from the source type into_font(self) -> FontDesc<'a>64 fn into_font(self) -> FontDesc<'a>; 65 } 66 67 impl<'a, T: Into<FontDesc<'a>>> IntoFont<'a> for T { into_font(self) -> FontDesc<'a>68 fn into_font(self) -> FontDesc<'a> { 69 self.into() 70 } 71 } 72 73 impl<'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 new(family: FontFamily<'a>, size: f64, style: FontStyle) -> Self80 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 resize(&self, size: f64) -> FontDesc<'a>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 style(&self, style: FontStyle) -> Self108 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 transform(&self, trans: FontTransform) -> Self122 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 get_transform(&self) -> FontTransform133 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 color<C: Color>(&self, color: &C) -> TextStyle<'a>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 get_family(&self) -> FontFamily146 pub fn get_family(&self) -> FontFamily { 147 self.family 148 } 149 150 /// Get the name of the font get_name(&self) -> &str151 pub fn get_name(&self) -> &str { 152 self.family.as_str() 153 } 154 155 /// Get the name of the style get_style(&self) -> FontStyle156 pub fn get_style(&self) -> FontStyle { 157 self.style 158 } 159 160 /// Get the size of font get_size(&self) -> f64161 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 layout_box(&self, text: &str) -> FontResult<((i32, i32), (i32, i32))>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 box_size(&self, text: &str) -> FontResult<(u32, u32)>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 draw<E, DrawFunc: FnMut(i32, i32, f32) -> Result<(), E>>( &self, text: &str, (x, y): (i32, i32), draw: DrawFunc, ) -> FontResult<Result<(), E>>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 } 198