1 use super::color::Color; 2 use super::font::{FontDesc, FontError, FontFamily, FontStyle, FontTransform}; 3 use super::size::{HasDimension, SizeDesc}; 4 use super::BLACK; 5 pub use plotters_backend::text_anchor; 6 use plotters_backend::{BackendColor, BackendCoord, BackendStyle, BackendTextStyle}; 7 8 /// Style of a text 9 #[derive(Clone)] 10 pub struct TextStyle<'a> { 11 /// The font description 12 pub font: FontDesc<'a>, 13 /// The text color 14 pub color: BackendColor, 15 /// The anchor point position 16 pub pos: text_anchor::Pos, 17 } 18 19 pub trait IntoTextStyle<'a> { into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a>20 fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a>; 21 } 22 23 impl<'a> IntoTextStyle<'a> for FontDesc<'a> { into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a>24 fn into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a> { 25 self.into() 26 } 27 } 28 29 impl<'a> IntoTextStyle<'a> for TextStyle<'a> { into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a>30 fn into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a> { 31 self 32 } 33 } 34 35 impl<'a> IntoTextStyle<'a> for FontFamily<'a> { into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a>36 fn into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a> { 37 self.into() 38 } 39 } 40 41 impl<'a, T: SizeDesc> IntoTextStyle<'a> for (&'a str, T) { into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a>42 fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a> { 43 (self.0, self.1.in_pixels(parent)).into() 44 } 45 } 46 47 impl<'a, T: SizeDesc> IntoTextStyle<'a> for (FontFamily<'a>, T) { into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a>48 fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a> { 49 (self.0, self.1.in_pixels(parent)).into() 50 } 51 } 52 53 impl<'a, T: SizeDesc> IntoTextStyle<'a> for (&'a str, T, FontStyle) { into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a>54 fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a> { 55 Into::<FontDesc>::into((self.0, self.1.in_pixels(parent), self.2)).into() 56 } 57 } 58 59 impl<'a, T: SizeDesc> IntoTextStyle<'a> for (FontFamily<'a>, T, FontStyle) { into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a>60 fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a> { 61 Into::<FontDesc>::into((self.0, self.1.in_pixels(parent), self.2)).into() 62 } 63 } 64 65 impl<'a> TextStyle<'a> { 66 /// Sets the color of the style. 67 /// 68 /// - `color`: The required color 69 /// - **returns** The up-to-dated text style 70 /// 71 /// ```rust 72 /// use plotters::prelude::*; 73 /// 74 /// let style = TextStyle::from(("sans-serif", 20).into_font()).color(&RED); 75 /// ``` color<C: Color>(&self, color: &'a C) -> Self76 pub fn color<C: Color>(&self, color: &'a C) -> Self { 77 Self { 78 font: self.font.clone(), 79 color: color.color(), 80 pos: self.pos, 81 } 82 } 83 84 /// Sets the font transformation of the style. 85 /// 86 /// - `trans`: The required transformation 87 /// - **returns** The up-to-dated text style 88 /// 89 /// ```rust 90 /// use plotters::prelude::*; 91 /// 92 /// let style = TextStyle::from(("sans-serif", 20).into_font()).transform(FontTransform::Rotate90); 93 /// ``` transform(&self, trans: FontTransform) -> Self94 pub fn transform(&self, trans: FontTransform) -> Self { 95 Self { 96 font: self.font.clone().transform(trans), 97 color: self.color, 98 pos: self.pos, 99 } 100 } 101 102 /// Sets the anchor position. 103 /// 104 /// - `pos`: The required anchor position 105 /// - **returns** The up-to-dated text style 106 /// 107 /// ```rust 108 /// use plotters::prelude::*; 109 /// use plotters::style::text_anchor::{Pos, HPos, VPos}; 110 /// 111 /// let pos = Pos::new(HPos::Left, VPos::Top); 112 /// let style = TextStyle::from(("sans-serif", 20).into_font()).pos(pos); 113 /// ``` pos(&self, pos: text_anchor::Pos) -> Self114 pub fn pos(&self, pos: text_anchor::Pos) -> Self { 115 Self { 116 font: self.font.clone(), 117 color: self.color, 118 pos, 119 } 120 } 121 } 122 123 /// Make sure that we are able to automatically copy the `TextStyle` 124 impl<'a, 'b: 'a> Into<TextStyle<'a>> for &'b TextStyle<'a> { into(self) -> TextStyle<'a>125 fn into(self) -> TextStyle<'a> { 126 self.clone() 127 } 128 } 129 130 impl<'a, T: Into<FontDesc<'a>>> From<T> for TextStyle<'a> { from(font: T) -> Self131 fn from(font: T) -> Self { 132 Self { 133 font: font.into(), 134 color: BLACK.color(), 135 pos: text_anchor::Pos::default(), 136 } 137 } 138 } 139 140 impl<'a> BackendTextStyle for TextStyle<'a> { 141 type FontError = FontError; color(&self) -> BackendColor142 fn color(&self) -> BackendColor { 143 self.color.color() 144 } 145 size(&self) -> f64146 fn size(&self) -> f64 { 147 self.font.get_size() 148 } 149 transform(&self) -> FontTransform150 fn transform(&self) -> FontTransform { 151 self.font.get_transform() 152 } 153 style(&self) -> FontStyle154 fn style(&self) -> FontStyle { 155 self.font.get_style() 156 } 157 158 #[allow(clippy::type_complexity)] layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError>159 fn layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError> { 160 self.font.layout_box(text) 161 } 162 anchor(&self) -> text_anchor::Pos163 fn anchor(&self) -> text_anchor::Pos { 164 self.pos 165 } 166 family(&self) -> FontFamily167 fn family(&self) -> FontFamily { 168 self.font.get_family() 169 } 170 draw<E, DrawFunc: FnMut(i32, i32, BackendColor) -> Result<(), E>>( &self, text: &str, pos: BackendCoord, mut draw: DrawFunc, ) -> Result<Result<(), E>, Self::FontError>171 fn draw<E, DrawFunc: FnMut(i32, i32, BackendColor) -> Result<(), E>>( 172 &self, 173 text: &str, 174 pos: BackendCoord, 175 mut draw: DrawFunc, 176 ) -> Result<Result<(), E>, Self::FontError> { 177 let color = self.color.color(); 178 self.font.draw(text, pos, move |x, y, a| { 179 let mix_color = color.mix(a as f64); 180 draw(x, y, mix_color) 181 }) 182 } 183 } 184