plotters_unstable/style/
text.rs

1use super::color::Color;
2use super::font::{FontDesc, FontError, FontFamily, FontStyle, FontTransform};
3use super::size::{HasDimension, SizeDesc};
4use super::BLACK;
5pub use plotters_backend::text_anchor;
6use plotters_backend::{BackendColor, BackendCoord, BackendStyle, BackendTextStyle};
7
8/// Style of a text
9#[derive(Clone)]
10pub 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
19pub trait IntoTextStyle<'a> {
20    fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a>;
21}
22
23impl<'a> IntoTextStyle<'a> for FontDesc<'a> {
24    fn into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a> {
25        self.into()
26    }
27}
28
29impl<'a> IntoTextStyle<'a> for TextStyle<'a> {
30    fn into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a> {
31        self
32    }
33}
34
35impl<'a> IntoTextStyle<'a> for FontFamily<'a> {
36    fn into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a> {
37        self.into()
38    }
39}
40
41impl<'a, T: SizeDesc> IntoTextStyle<'a> for (&'a str, T) {
42    fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a> {
43        (self.0, self.1.in_pixels(parent)).into()
44    }
45}
46
47impl<'a, T: SizeDesc> IntoTextStyle<'a> for (FontFamily<'a>, T) {
48    fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a> {
49        (self.0, self.1.in_pixels(parent)).into()
50    }
51}
52
53impl<'a, T: SizeDesc> IntoTextStyle<'a> for (&'a str, T, FontStyle) {
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
59impl<'a, T: SizeDesc> IntoTextStyle<'a> for (FontFamily<'a>, T, FontStyle) {
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
65impl<'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    /// ```
76    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    /// ```
94    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    /// ```
114    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`
124impl<'a, 'b: 'a> Into<TextStyle<'a>> for &'b TextStyle<'a> {
125    fn into(self) -> TextStyle<'a> {
126        self.clone()
127    }
128}
129
130impl<'a, T: Into<FontDesc<'a>>> From<T> for TextStyle<'a> {
131    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
140impl<'a> BackendTextStyle for TextStyle<'a> {
141    type FontError = FontError;
142    fn color(&self) -> BackendColor {
143        self.color.color()
144    }
145
146    fn size(&self) -> f64 {
147        self.font.get_size()
148    }
149
150    fn transform(&self) -> FontTransform {
151        self.font.get_transform()
152    }
153
154    fn style(&self) -> FontStyle {
155        self.font.get_style()
156    }
157
158    #[allow(clippy::type_complexity)]
159    fn layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError> {
160        self.font.layout_box(text)
161    }
162
163    fn anchor(&self) -> text_anchor::Pos {
164        self.pos
165    }
166
167    fn family(&self) -> FontFamily {
168        self.font.get_family()
169    }
170
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}