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