• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, Default)]
64     pub enum HPos {
65         /// Anchor point is on the left side of the text
66         #[default]
67         Left,
68         /// Anchor point is on the right side of the text
69         Right,
70         /// Anchor point is in the horizontal center of the text
71         Center,
72     }
73 
74     /// The vertical position of the anchor point relative to the text.
75     #[derive(Clone, Copy, Default)]
76     pub enum VPos {
77         /// Anchor point is on the top of the text
78         #[default]
79         Top,
80         /// Anchor point is in the vertical center of the text
81         Center,
82         /// Anchor point is on the bottom of the text
83         Bottom,
84     }
85 
86     /// The text anchor position.
87     #[derive(Clone, Copy, Default)]
88     pub struct Pos {
89         /// The horizontal position of the anchor point
90         pub h_pos: HPos,
91         /// The vertical position of the anchor point
92         pub v_pos: VPos,
93     }
94 
95     impl Pos {
96         /// Create a new text anchor position.
97         ///
98         /// - `h_pos`: The horizontal position of the anchor point
99         /// - `v_pos`: The vertical position of the anchor point
100         /// - **returns** The newly created text anchor position
101         ///
102         /// ```rust
103         /// use plotters_backend::text_anchor::{Pos, HPos, VPos};
104         ///
105         /// let pos = Pos::new(HPos::Left, VPos::Top);
106         /// ```
new(h_pos: HPos, v_pos: VPos) -> Self107         pub fn new(h_pos: HPos, v_pos: VPos) -> Self {
108             Pos { h_pos, v_pos }
109         }
110     }
111 }
112 
113 /// Specifying text transformations
114 #[derive(Clone)]
115 pub enum FontTransform {
116     /// Nothing to transform
117     None,
118     /// Rotating the text 90 degree clockwise
119     Rotate90,
120     /// Rotating the text 180 degree clockwise
121     Rotate180,
122     /// Rotating the text 270 degree clockwise
123     Rotate270,
124 }
125 
126 impl FontTransform {
127     /// Transform the coordinate to perform the rotation
128     ///
129     /// - `x`: The x coordinate in pixels before transform
130     /// - `y`: The y coordinate in pixels before transform
131     /// - **returns**: The coordinate after transform
transform(&self, x: i32, y: i32) -> (i32, i32)132     pub fn transform(&self, x: i32, y: i32) -> (i32, i32) {
133         match self {
134             FontTransform::None => (x, y),
135             FontTransform::Rotate90 => (-y, x),
136             FontTransform::Rotate180 => (-x, -y),
137             FontTransform::Rotate270 => (y, -x),
138         }
139     }
140 }
141 
142 /// Describes the font style. Such as Italic, Oblique, etc.
143 #[derive(Clone, Copy)]
144 pub enum FontStyle {
145     /// The normal style
146     Normal,
147     /// The oblique style
148     Oblique,
149     /// The italic style
150     Italic,
151     /// The bold style
152     Bold,
153 }
154 
155 impl FontStyle {
156     /// Convert the font style into a CSS compatible string which can be used in `font-style` attribute.
as_str(&self) -> &str157     pub fn as_str(&self) -> &str {
158         match self {
159             FontStyle::Normal => "normal",
160             FontStyle::Italic => "italic",
161             FontStyle::Oblique => "oblique",
162             FontStyle::Bold => "bold",
163         }
164     }
165 }
166 
167 impl<'a> From<&'a str> for FontStyle {
from(from: &'a str) -> FontStyle168     fn from(from: &'a str) -> FontStyle {
169         match from.to_lowercase().as_str() {
170             "normal" => FontStyle::Normal,
171             "italic" => FontStyle::Italic,
172             "oblique" => FontStyle::Oblique,
173             "bold" => FontStyle::Bold,
174             _ => FontStyle::Normal,
175         }
176     }
177 }
178 
179 /// The trait that abstracts a style of a text.
180 ///
181 /// This is used because the the backend crate have no knowledge about how
182 /// the text handling is implemented in plotters.
183 ///
184 /// But the backend still wants to know some information about the font, for
185 /// the backend doesn't handles text drawing, may want to call the `draw` method which
186 /// is implemented by the plotters main crate. While for the backend that handles the
187 /// text drawing, those font information provides instructions about how the text should be
188 /// rendered: color, size, slant, anchor, font, etc.
189 ///
190 /// This trait decouples the detailed implementation about the font and the backend code which
191 /// wants to perform some operation on the font.
192 ///
193 pub trait BackendTextStyle {
194     /// The error type of this text style implementation
195     type FontError: Error + Sync + Send + 'static;
196 
color(&self) -> BackendColor197     fn color(&self) -> BackendColor {
198         BackendColor {
199             alpha: 1.0,
200             rgb: (0, 0, 0),
201         }
202     }
203 
size(&self) -> f64204     fn size(&self) -> f64 {
205         1.0
206     }
207 
transform(&self) -> FontTransform208     fn transform(&self) -> FontTransform {
209         FontTransform::None
210     }
211 
style(&self) -> FontStyle212     fn style(&self) -> FontStyle {
213         FontStyle::Normal
214     }
215 
anchor(&self) -> text_anchor::Pos216     fn anchor(&self) -> text_anchor::Pos {
217         text_anchor::Pos::default()
218     }
219 
family(&self) -> FontFamily220     fn family(&self) -> FontFamily;
221 
222     #[allow(clippy::type_complexity)]
layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError>223     fn layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError>;
224 
draw<E, DrawFunc: FnMut(i32, i32, BackendColor) -> Result<(), E>>( &self, text: &str, pos: BackendCoord, draw: DrawFunc, ) -> Result<Result<(), E>, Self::FontError>225     fn draw<E, DrawFunc: FnMut(i32, i32, BackendColor) -> Result<(), E>>(
226         &self,
227         text: &str,
228         pos: BackendCoord,
229         draw: DrawFunc,
230     ) -> Result<Result<(), E>, Self::FontError>;
231 }
232