1 use super::{BackendColor, BackendCoord};
2 use 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)]
8 pub 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 
19 impl<'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.
as_str(&self) -> &str22     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 
32 impl<'a> From<&'a str> for FontFamily<'a> {
from(from: &'a str) -> 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 /// ```
61 pub 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         /// ```
new(h_pos: HPos, v_pos: VPos) -> Self105         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         /// ```
default() -> Self118         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)]
129 pub 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 
140 impl 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
transform(&self, x: i32, y: i32) -> (i32, i32)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)]
158 pub 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 
169 impl FontStyle {
170     /// Convert the font style into a CSS compatible string which can be used in `font-style` attribute.
as_str(&self) -> &str171     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 
181 impl<'a> From<&'a str> for FontStyle {
from(from: &'a str) -> FontStyle182     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 ///
207 pub trait BackendTextStyle {
208     /// The error type of this text style implementation
209     type FontError: Error + Sync + Send + 'static;
210 
color(&self) -> BackendColor211     fn color(&self) -> BackendColor {
212         BackendColor {
213             alpha: 1.0,
214             rgb: (0, 0, 0),
215         }
216     }
217 
size(&self) -> f64218     fn size(&self) -> f64 {
219         1.0
220     }
221 
transform(&self) -> FontTransform222     fn transform(&self) -> FontTransform {
223         FontTransform::None
224     }
225 
style(&self) -> FontStyle226     fn style(&self) -> FontStyle {
227         FontStyle::Normal
228     }
229 
anchor(&self) -> text_anchor::Pos230     fn anchor(&self) -> text_anchor::Pos {
231         text_anchor::Pos::default()
232     }
233 
family(&self) -> FontFamily234     fn family(&self) -> FontFamily;
235 
layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError>236     fn layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError>;
237 
draw<E, DrawFunc: FnMut(i32, i32, BackendColor) -> Result<(), E>>( &self, text: &str, pos: BackendCoord, draw: DrawFunc, ) -> Result<Result<(), E>, Self::FontError>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 }
245