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  
236      #[allow(clippy::type_complexity)]
layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError>237      fn layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError>;
238  
draw<E, DrawFunc: FnMut(i32, i32, BackendColor) -> Result<(), E>>( &self, text: &str, pos: BackendCoord, draw: DrawFunc, ) -> Result<Result<(), E>, Self::FontError>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