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 #[allow(clippy::type_complexity)]
237 fn layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError>;
238
239 fn draw<E, DrawFunc: FnMut(i32, i32, BackendColor) -> Result<(), E>>(
240 &self,
241 text: &str,
242 pos: BackendCoord,
243 draw: DrawFunc,
244 ) -> Result<Result<(), E>, Self::FontError>;
245}
246