plotters_backend/
text.rs

1use super::{BackendColor, BackendCoord};
2use std::error::Error;
3
4/// Describes font family.
5/// This can be either a specific font family name, such as "arial",
6/// or a general font family class, such as "serif" and "sans-serif"
7#[derive(Clone, Copy)]
8pub enum FontFamily<'a> {
9    /// The system default serif font family
10    Serif,
11    /// The system default sans-serif font family
12    SansSerif,
13    /// The system default monospace font
14    Monospace,
15    /// A specific font family name
16    Name(&'a str),
17}
18
19impl<'a> FontFamily<'a> {
20    /// Make a CSS compatible string for the font family name.
21    /// This can be used as the value of `font-family` attribute in SVG.
22    pub fn as_str(&self) -> &str {
23        match self {
24            FontFamily::Serif => "serif",
25            FontFamily::SansSerif => "sans-serif",
26            FontFamily::Monospace => "monospace",
27            FontFamily::Name(face) => face,
28        }
29    }
30}
31
32impl<'a> From<&'a str> for FontFamily<'a> {
33    fn from(from: &'a str) -> FontFamily<'a> {
34        match from.to_lowercase().as_str() {
35            "serif" => FontFamily::Serif,
36            "sans-serif" => FontFamily::SansSerif,
37            "monospace" => FontFamily::Monospace,
38            _ => FontFamily::Name(from),
39        }
40    }
41}
42
43/// Text anchor attributes are used to properly position the text.
44///
45/// # Examples
46///
47/// In the example below, the text anchor (X) position is `Pos::new(HPos::Right, VPos::Center)`.
48/// ```text
49///    ***** X
50/// ```
51/// The position is always relative to the text regardless of its rotation.
52/// In the example below, the text has style
53/// `style.transform(FontTransform::Rotate90).pos(Pos::new(HPos::Center, VPos::Top))`.
54/// ```text
55///        *
56///        *
57///        * X
58///        *
59///        *
60/// ```
61pub mod text_anchor {
62    /// The horizontal position of the anchor point relative to the text.
63    #[derive(Clone, Copy)]
64    pub enum HPos {
65        /// Anchor point is on the left side of the text
66        Left,
67        /// Anchor point is on the right side of the text
68        Right,
69        /// Anchor point is in the horizontal center of the text
70        Center,
71    }
72
73    /// The vertical position of the anchor point relative to the text.
74    #[derive(Clone, Copy)]
75    pub enum VPos {
76        /// Anchor point is on the top of the text
77        Top,
78        /// Anchor point is in the vertical center of the text
79        Center,
80        /// Anchor point is on the bottom of the text
81        Bottom,
82    }
83
84    /// The text anchor position.
85    #[derive(Clone, Copy)]
86    pub struct Pos {
87        /// The horizontal position of the anchor point
88        pub h_pos: HPos,
89        /// The vertical position of the anchor point
90        pub v_pos: VPos,
91    }
92
93    impl Pos {
94        /// Create a new text anchor position.
95        ///
96        /// - `h_pos`: The horizontal position of the anchor point
97        /// - `v_pos`: The vertical position of the anchor point
98        /// - **returns** The newly created text anchor position
99        ///
100        /// ```rust
101        /// use plotters_backend::text_anchor::{Pos, HPos, VPos};
102        ///
103        /// let pos = Pos::new(HPos::Left, VPos::Top);
104        /// ```
105        pub fn new(h_pos: HPos, v_pos: VPos) -> Self {
106            Pos { h_pos, v_pos }
107        }
108
109        /// Create a default text anchor position (top left).
110        ///
111        /// - **returns** The default text anchor position
112        ///
113        /// ```rust
114        /// use plotters_backend::text_anchor::{Pos, HPos, VPos};
115        ///
116        /// let pos = Pos::default();
117        /// ```
118        pub fn default() -> Self {
119            Pos {
120                h_pos: HPos::Left,
121                v_pos: VPos::Top,
122            }
123        }
124    }
125}
126
127/// Specifying text transformations
128#[derive(Clone)]
129pub enum FontTransform {
130    /// Nothing to transform
131    None,
132    /// Rotating the text 90 degree clockwise
133    Rotate90,
134    /// Rotating the text 180 degree clockwise
135    Rotate180,
136    /// Rotating the text 270 degree clockwise
137    Rotate270,
138}
139
140impl FontTransform {
141    /// Transform the coordinate to perform the rotation
142    ///
143    /// - `x`: The x coordinate in pixels before transform
144    /// - `y`: The y coordinate in pixels before transform
145    /// - **returns**: The coordinate after transform
146    pub fn transform(&self, x: i32, y: i32) -> (i32, i32) {
147        match self {
148            FontTransform::None => (x, y),
149            FontTransform::Rotate90 => (-y, x),
150            FontTransform::Rotate180 => (-x, -y),
151            FontTransform::Rotate270 => (y, -x),
152        }
153    }
154}
155
156/// Describes the font style. Such as Italic, Oblique, etc.
157#[derive(Clone, Copy)]
158pub enum FontStyle {
159    /// The normal style
160    Normal,
161    /// The oblique style
162    Oblique,
163    /// The italic style
164    Italic,
165    /// The bold style
166    Bold,
167}
168
169impl FontStyle {
170    /// Convert the font style into a CSS compatible string which can be used in `font-style` attribute.
171    pub fn as_str(&self) -> &str {
172        match self {
173            FontStyle::Normal => "normal",
174            FontStyle::Italic => "italic",
175            FontStyle::Oblique => "oblique",
176            FontStyle::Bold => "bold",
177        }
178    }
179}
180
181impl<'a> From<&'a str> for FontStyle {
182    fn from(from: &'a str) -> FontStyle {
183        match from.to_lowercase().as_str() {
184            "normal" => FontStyle::Normal,
185            "italic" => FontStyle::Italic,
186            "oblique" => FontStyle::Oblique,
187            "bold" => FontStyle::Bold,
188            _ => FontStyle::Normal,
189        }
190    }
191}
192
193/// The trait that abstracts a style of a text.
194///
195/// This is used because the the backend crate have no knowledge about how
196/// the text handling is implemented in plotters.
197///
198/// But the backend still wants to know some information about the font, for
199/// the backend doesn't handles text drawing, may want to call the `draw` method which
200/// is implemented by the plotters main crate. While for the backend that handles the
201/// text drawing, those font information provides instructions about how the text should be
202/// rendered: color, size, slant, anchor, font, etc.
203///
204/// This trait decouples the detailed implementaiton about the font and the backend code which
205/// wants to perfome some operation on the font.
206///
207pub trait BackendTextStyle {
208    /// The error type of this text style implementation
209    type FontError: Error + Sync + Send + 'static;
210
211    fn color(&self) -> BackendColor {
212        BackendColor {
213            alpha: 1.0,
214            rgb: (0, 0, 0),
215        }
216    }
217
218    fn size(&self) -> f64 {
219        1.0
220    }
221
222    fn transform(&self) -> FontTransform {
223        FontTransform::None
224    }
225
226    fn style(&self) -> FontStyle {
227        FontStyle::Normal
228    }
229
230    fn anchor(&self) -> text_anchor::Pos {
231        text_anchor::Pos::default()
232    }
233
234    fn family(&self) -> FontFamily;
235
236    fn layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError>;
237
238    fn draw<E, DrawFunc: FnMut(i32, i32, BackendColor) -> Result<(), E>>(
239        &self,
240        text: &str,
241        pos: BackendCoord,
242        draw: DrawFunc,
243    ) -> Result<Result<(), E>, Self::FontError>;
244}