diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:50 +0000 |
commit | 9835e2ae736235810b4ea1c162ca5e65c547e770 (patch) | |
tree | 3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/plotters/src/style/text.rs | |
parent | Releasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff) | |
download | rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/plotters/src/style/text.rs')
-rw-r--r-- | vendor/plotters/src/style/text.rs | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/vendor/plotters/src/style/text.rs b/vendor/plotters/src/style/text.rs new file mode 100644 index 000000000..e98f3193d --- /dev/null +++ b/vendor/plotters/src/style/text.rs @@ -0,0 +1,327 @@ +use super::color::Color; +use super::font::{FontDesc, FontError, FontFamily, FontStyle, FontTransform}; +use super::size::{HasDimension, SizeDesc}; +use super::BLACK; +pub use plotters_backend::text_anchor; +use plotters_backend::{BackendColor, BackendCoord, BackendStyle, BackendTextStyle}; + +/// Style of a text +#[derive(Clone)] +pub struct TextStyle<'a> { + /// The font description + pub font: FontDesc<'a>, + /// The text color + pub color: BackendColor, + /// The anchor point position + pub pos: text_anchor::Pos, +} + +/// Trait for values that can be converted into `TextStyle` values +pub trait IntoTextStyle<'a> { + /** Converts the value into a TextStyle value. + + `parent` is used in some cases to convert a font size from points to pixels. + + # Example + + ``` + use plotters::prelude::*; + let drawing_area = SVGBackend::new("into_text_style.svg", (200, 100)).into_drawing_area(); + drawing_area.fill(&WHITE).unwrap(); + let text_style = ("sans-serif", 20, &RED).into_text_style(&drawing_area); + drawing_area.draw_text("This is a big red label", &text_style, (10, 50)).unwrap(); + ``` + + The result is a text label styled accordingly: + + ![](https://cdn.jsdelivr.net/gh/facorread/plotters-doc-data@f030ed3/apidoc/into_text_style.svg) + + */ + fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a>; + + /** Specifies the color of the text element + + # Example + + ``` + use plotters::prelude::*; + let drawing_area = SVGBackend::new("with_color.svg", (200, 100)).into_drawing_area(); + drawing_area.fill(&WHITE).unwrap(); + let text_style = ("sans-serif", 20).with_color(RED).into_text_style(&drawing_area); + drawing_area.draw_text("This is a big red label", &text_style, (10, 50)).unwrap(); + ``` + + The result is a text label styled accordingly: + + ![](https://cdn.jsdelivr.net/gh/facorread/plotters-doc-data@f030ed3/apidoc/with_color.svg) + + # See also + + [`FontDesc::color()`] + + [`IntoTextStyle::into_text_style()`] for a more succinct example + + */ + fn with_color<C: Color>(self, color: C) -> TextStyleBuilder<'a, Self> + where + Self: Sized, + { + TextStyleBuilder { + base: self, + new_color: Some(color.to_backend_color()), + new_pos: None, + _phatom: std::marker::PhantomData, + } + } + + /** Specifies the position of the text anchor relative to the text element + + # Example + + ``` + use plotters::{prelude::*,style::text_anchor::{HPos, Pos, VPos}}; + let anchor_position = (200,100); + let anchor_left_bottom = Pos::new(HPos::Left, VPos::Bottom); + let anchor_right_top = Pos::new(HPos::Right, VPos::Top); + let drawing_area = SVGBackend::new("with_anchor.svg", (400, 200)).into_drawing_area(); + drawing_area.fill(&WHITE).unwrap(); + drawing_area.draw(&Circle::new(anchor_position, 5, RED.filled())); + let text_style_right_top = BLACK.with_anchor::<RGBColor>(anchor_right_top).into_text_style(&drawing_area); + drawing_area.draw_text("The anchor sits at the right top of this label", &text_style_right_top, anchor_position); + let text_style_left_bottom = BLACK.with_anchor::<RGBColor>(anchor_left_bottom).into_text_style(&drawing_area); + drawing_area.draw_text("The anchor sits at the left bottom of this label", &text_style_left_bottom, anchor_position); + ``` + + The result has a red pixel at the center and two text labels positioned accordingly: + + ![](https://cdn.jsdelivr.net/gh/facorread/plotters-doc-data@b0b94d5/apidoc/with_anchor.svg) + + # See also + + [`TextStyle::pos()`] + + */ + fn with_anchor<C: Color>(self, pos: text_anchor::Pos) -> TextStyleBuilder<'a, Self> + where + Self: Sized, + { + TextStyleBuilder { + base: self, + new_pos: Some(pos), + new_color: None, + _phatom: std::marker::PhantomData, + } + } +} + +pub struct TextStyleBuilder<'a, T: IntoTextStyle<'a>> { + base: T, + new_color: Option<BackendColor>, + new_pos: Option<text_anchor::Pos>, + _phatom: std::marker::PhantomData<&'a T>, +} + +impl<'a, T: IntoTextStyle<'a>> IntoTextStyle<'a> for TextStyleBuilder<'a, T> { + fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a> { + let mut base = self.base.into_text_style(parent); + if let Some(color) = self.new_color { + base.color = color; + } + if let Some(pos) = self.new_pos { + base = base.pos(pos); + } + base + } +} + +impl<'a> TextStyle<'a> { + /// Sets the color of the style. + /// + /// - `color`: The required color + /// - **returns** The up-to-dated text style + /// + /// ```rust + /// use plotters::prelude::*; + /// + /// let style = TextStyle::from(("sans-serif", 20).into_font()).color(&RED); + /// ``` + pub fn color<C: Color>(&self, color: &'a C) -> Self { + Self { + font: self.font.clone(), + color: color.to_backend_color(), + pos: self.pos, + } + } + + /// Sets the font transformation of the style. + /// + /// - `trans`: The required transformation + /// - **returns** The up-to-dated text style + /// + /// ```rust + /// use plotters::prelude::*; + /// + /// let style = TextStyle::from(("sans-serif", 20).into_font()).transform(FontTransform::Rotate90); + /// ``` + pub fn transform(&self, trans: FontTransform) -> Self { + Self { + font: self.font.clone().transform(trans), + color: self.color, + pos: self.pos, + } + } + + /// Sets the anchor position. + /// + /// - `pos`: The required anchor position + /// - **returns** The up-to-dated text style + /// + /// ```rust + /// use plotters::prelude::*; + /// use plotters::style::text_anchor::{Pos, HPos, VPos}; + /// + /// let pos = Pos::new(HPos::Left, VPos::Top); + /// let style = TextStyle::from(("sans-serif", 20).into_font()).pos(pos); + /// ``` + /// + /// # See also + /// + /// [`IntoTextStyle::with_anchor()`] + pub fn pos(&self, pos: text_anchor::Pos) -> Self { + Self { + font: self.font.clone(), + color: self.color, + pos, + } + } +} + +impl<'a> IntoTextStyle<'a> for FontDesc<'a> { + fn into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a> { + self.into() + } +} + +impl<'a> IntoTextStyle<'a> for TextStyle<'a> { + fn into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a> { + self + } +} + +impl<'a> IntoTextStyle<'a> for &'a str { + fn into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a> { + self.into() + } +} + +impl<'a> IntoTextStyle<'a> for FontFamily<'a> { + fn into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a> { + self.into() + } +} + +impl IntoTextStyle<'static> for u32 { + fn into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'static> { + TextStyle::from((FontFamily::SansSerif, self)) + } +} + +impl IntoTextStyle<'static> for f64 { + fn into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'static> { + TextStyle::from((FontFamily::SansSerif, self)) + } +} + +impl<'a, T: Color> IntoTextStyle<'a> for &'a T { + fn into_text_style<P: HasDimension>(self, _: &P) -> TextStyle<'a> { + TextStyle::from(FontFamily::SansSerif).color(self) + } +} + +impl<'a, F: Into<FontFamily<'a>>, T: SizeDesc> IntoTextStyle<'a> for (F, T) { + fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a> { + (self.0.into(), self.1.in_pixels(parent)).into() + } +} + +impl<'a, F: Into<FontFamily<'a>>, T: SizeDesc, C: Color> IntoTextStyle<'a> for (F, T, &'a C) { + fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a> { + IntoTextStyle::into_text_style((self.0, self.1), parent).color(self.2) + } +} + +impl<'a, F: Into<FontFamily<'a>>, T: SizeDesc> IntoTextStyle<'a> for (F, T, FontStyle) { + fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a> { + (self.0.into(), self.1.in_pixels(parent), self.2).into() + } +} + +impl<'a, F: Into<FontFamily<'a>>, T: SizeDesc, C: Color> IntoTextStyle<'a> + for (F, T, FontStyle, &'a C) +{ + fn into_text_style<P: HasDimension>(self, parent: &P) -> TextStyle<'a> { + IntoTextStyle::into_text_style((self.0, self.1, self.2), parent).color(self.3) + } +} + +/// Make sure that we are able to automatically copy the `TextStyle` +impl<'a, 'b: 'a> From<&'b TextStyle<'a>> for TextStyle<'a> { + fn from(this: &'b TextStyle<'a>) -> Self { + this.clone() + } +} + +impl<'a, T: Into<FontDesc<'a>>> From<T> for TextStyle<'a> { + fn from(font: T) -> Self { + Self { + font: font.into(), + color: BLACK.to_backend_color(), + pos: text_anchor::Pos::default(), + } + } +} + +impl<'a> BackendTextStyle for TextStyle<'a> { + type FontError = FontError; + fn color(&self) -> BackendColor { + self.color + } + + fn size(&self) -> f64 { + self.font.get_size() + } + + fn transform(&self) -> FontTransform { + self.font.get_transform() + } + + fn style(&self) -> FontStyle { + self.font.get_style() + } + + #[allow(clippy::type_complexity)] + fn layout_box(&self, text: &str) -> Result<((i32, i32), (i32, i32)), Self::FontError> { + self.font.layout_box(text) + } + + fn anchor(&self) -> text_anchor::Pos { + self.pos + } + + fn family(&self) -> FontFamily { + self.font.get_family() + } + + fn draw<E, DrawFunc: FnMut(i32, i32, BackendColor) -> Result<(), E>>( + &self, + text: &str, + pos: BackendCoord, + mut draw: DrawFunc, + ) -> Result<Result<(), E>, Self::FontError> { + let color = self.color.color(); + self.font.draw(text, pos, move |x, y, a| { + let mix_color = color.mix(a as f64); + draw(x, y, mix_color) + }) + } +} |