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 /// Set the color of the font and return the result text style object color<C: Color>(&self, color: &C) -> TextStyle<'a>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 get_family(&self) -> FontFamily98 pub fn get_family(&self) -> FontFamily { 99 self.family 100 } 101 102 /// Get the name of the font get_name(&self) -> &str103 pub fn get_name(&self) -> &str { 104 self.family.as_str() 105 } 106 107 /// Get the name of the style get_style(&self) -> FontStyle108 pub fn get_style(&self) -> FontStyle { 109 self.style 110 } 111 112 /// Get the size of font get_size(&self) -> f64113 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 layout_box(&self, text: &str) -> FontResult<((i32, i32), (i32, i32))>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 box_size(&self, text: &str) -> FontResult<(u32, u32)>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 draw<E, DrawFunc: FnMut(i32, i32, f32) -> Result<(), E>>( &self, text: &str, (x, y): (i32, i32), draw: DrawFunc, ) -> FontResult<Result<(), E>>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 151 impl<'a> From<&'a str> for FontDesc<'a> { from(from: &'a str) -> FontDesc<'a>152 fn from(from: &'a str) -> FontDesc<'a> { 153 FontDesc::new(from.into(), 12.0, FontStyle::Normal) 154 } 155 } 156 157 impl<'a> From<FontFamily<'a>> for FontDesc<'a> { from(family: FontFamily<'a>) -> FontDesc<'a>158 fn from(family: FontFamily<'a>) -> FontDesc<'a> { 159 FontDesc::new(family, 12.0, FontStyle::Normal) 160 } 161 } 162 163 impl<'a, T: Into<f64>> From<(FontFamily<'a>, T)> for FontDesc<'a> { from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a>164 fn from((family, size): (FontFamily<'a>, T)) -> FontDesc<'a> { 165 FontDesc::new(family, size.into(), FontStyle::Normal) 166 } 167 } 168 169 impl<'a, T: Into<f64>> From<(&'a str, T)> for FontDesc<'a> { from((typeface, size): (&'a str, T)) -> FontDesc<'a>170 fn from((typeface, size): (&'a str, T)) -> FontDesc<'a> { 171 FontDesc::new(typeface.into(), size.into(), FontStyle::Normal) 172 } 173 } 174 175 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>176 fn from((family, size, style): (FontFamily<'a>, T, S)) -> FontDesc<'a> { 177 FontDesc::new(family, size.into(), style.into()) 178 } 179 } 180 181 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>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 188 pub trait IntoFont<'a> { 189 /// Make the font description from the source type into_font(self) -> FontDesc<'a>190 fn into_font(self) -> FontDesc<'a>; 191 } 192 193 impl<'a, T: Into<FontDesc<'a>>> IntoFont<'a> for T { into_font(self) -> FontDesc<'a>194 fn into_font(self) -> FontDesc<'a> { 195 self.into() 196 } 197 } 198