use super::{BackendColor, BackendCoord}; use std::error::Error; /// Describes font family. /// This can be either a specific font family name, such as "arial", /// or a general font family class, such as "serif" and "sans-serif" #[derive(Clone, Copy)] pub enum FontFamily<'a> { /// The system default serif font family Serif, /// The system default sans-serif font family SansSerif, /// The system default monospace font Monospace, /// A specific font family name Name(&'a str), } impl<'a> FontFamily<'a> { /// Make a CSS compatible string for the font family name. /// This can be used as the value of `font-family` attribute in SVG. pub fn as_str(&self) -> &str { match self { FontFamily::Serif => "serif", FontFamily::SansSerif => "sans-serif", FontFamily::Monospace => "monospace", FontFamily::Name(face) => face, } } } impl<'a> From<&'a str> for FontFamily<'a> { fn from(from: &'a str) -> FontFamily<'a> { match from.to_lowercase().as_str() { "serif" => FontFamily::Serif, "sans-serif" => FontFamily::SansSerif, "monospace" => FontFamily::Monospace, _ => FontFamily::Name(from), } } } /// Text anchor attributes are used to properly position the text. /// /// # Examples /// /// In the example below, the text anchor (X) position is `Pos::new(HPos::Right, VPos::Center)`. /// ```text /// ***** X /// ``` /// The position is always relative to the text regardless of its rotation. /// In the example below, the text has style /// `style.transform(FontTransform::Rotate90).pos(Pos::new(HPos::Center, VPos::Top))`. /// ```text /// * /// * /// * X /// * /// * /// ``` pub mod text_anchor { /// The horizontal position of the anchor point relative to the text. #[derive(Clone, Copy)] pub enum HPos { /// Anchor point is on the left side of the text Left, /// Anchor point is on the right side of the text Right, /// Anchor point is in the horizontal center of the text Center, } /// The vertical position of the anchor point relative to the text. #[derive(Clone, Copy)] pub enum VPos { /// Anchor point is on the top of the text Top, /// Anchor point is in the vertical center of the text Center, /// Anchor point is on the bottom of the text Bottom, } /// The text anchor position. #[derive(Clone, Copy)] pub struct Pos { /// The horizontal position of the anchor point pub h_pos: HPos, /// The vertical position of the anchor point pub v_pos: VPos, } impl Pos { /// Create a new text anchor position. /// /// - `h_pos`: The horizontal position of the anchor point /// - `v_pos`: The vertical position of the anchor point /// - **returns** The newly created text anchor position /// /// ```rust /// use plotters_backend::text_anchor::{Pos, HPos, VPos}; /// /// let pos = Pos::new(HPos::Left, VPos::Top); /// ``` pub fn new(h_pos: HPos, v_pos: VPos) -> Self { Pos { h_pos, v_pos } } /// Create a default text anchor position (top left). /// /// - **returns** The default text anchor position /// /// ```rust /// use plotters_backend::text_anchor::{Pos, HPos, VPos}; /// /// let pos = Pos::default(); /// ``` pub fn default() -> Self { Pos { h_pos: HPos::Left, v_pos: VPos::Top, } } } } /// Specifying text transformations #[derive(Clone)] pub enum FontTransform { /// Nothing to transform None, /// Rotating the text 90 degree clockwise Rotate90, /// Rotating the text 180 degree clockwise Rotate180, /// Rotating the text 270 degree clockwise Rotate270, } impl FontTransform { /// Transform the coordinate to perform the rotation /// /// - `x`: The x coordinate in pixels before transform /// - `y`: The y coordinate in pixels before transform /// - **returns**: The coordinate after transform pub fn transform(&self, x: i32, y: i32) -> (i32, i32) { match self { FontTransform::None => (x, y), FontTransform::Rotate90 => (-y, x), FontTransform::Rotate180 => (-x, -y), FontTransform::Rotate270 => (y, -x), } } } /// Describes the font style. Such as Italic, Oblique, etc. #[derive(Clone, Copy)] pub enum FontStyle { /// The normal style Normal, /// The oblique style Oblique, /// The italic style Italic, /// The bold style Bold, } impl FontStyle { /// Convert the font style into a CSS compatible string which can be used in `font-style` attribute. pub fn as_str(&self) -> &str { match self { FontStyle::Normal => "normal", FontStyle::Italic => "italic", FontStyle::Oblique => "oblique", FontStyle::Bold => "bold", } } } impl<'a> From<&'a str> for FontStyle { fn from(from: &'a str) -> FontStyle { match from.to_lowercase().as_str() { "normal" => FontStyle::Normal, "italic" => FontStyle::Italic, "oblique" => FontStyle::Oblique, "bold" => FontStyle::Bold, _ => FontStyle::Normal, } } } /// The trait that abstracts a style of a text. /// /// This is used because the the backend crate have no knowledge about how /// the text handling is implemented in plotters. /// /// But the backend still wants to know some information about the font, for /// the backend doesn't handles text drawing, may want to call the `draw` method which /// is implemented by the plotters main crate. While for the backend that handles the /// text drawing, those font information provides instructions about how the text should be /// rendered: color, size, slant, anchor, font, etc. /// /// This trait decouples the detailed implementaiton about the font and the backend code which /// wants to perfome some operation on the font. /// pub trait BackendTextStyle { /// The error type of this text style implementation type FontError: Error + Sync + Send + 'static; fn color(&self) -> BackendColor { BackendColor { alpha: 1.0, rgb: (0, 0, 0), } } fn size(&self) -> f64 { 1.0 } fn transform(&self) -> FontTransform { FontTransform::None } fn style(&self) -> FontStyle { FontStyle::Normal } fn anchor(&self) -> text_anchor::Pos { text_anchor::Pos::default() } fn family(&self) -> FontFamily; #[allow(clippy::type_complexity)] fn layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError>; fn draw Result<(), E>>( &self, text: &str, pos: BackendCoord, draw: DrawFunc, ) -> Result, Self::FontError>; }