diff options
Diffstat (limited to 'vendor/plotters/src/style/size.rs')
-rw-r--r-- | vendor/plotters/src/style/size.rs | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/vendor/plotters/src/style/size.rs b/vendor/plotters/src/style/size.rs new file mode 100644 index 000000000..254df8d4f --- /dev/null +++ b/vendor/plotters/src/style/size.rs @@ -0,0 +1,186 @@ +use crate::coord::CoordTranslate; +use crate::drawing::DrawingArea; +use plotters_backend::DrawingBackend; + +/// The trait indicates that the type has a dimensional data. +/// This is the abstraction for the relative sizing model. +/// A relative sizing value is able to be converted into a concrete size +/// when coupling with a type with `HasDimension` type. +pub trait HasDimension { + /// Get the dimensional data for this object + fn dim(&self) -> (u32, u32); +} + +impl<D: DrawingBackend, C: CoordTranslate> HasDimension for DrawingArea<D, C> { + fn dim(&self) -> (u32, u32) { + self.dim_in_pixel() + } +} + +impl HasDimension for (u32, u32) { + fn dim(&self) -> (u32, u32) { + *self + } +} + +/// The trait that describes a size, it may be a relative size which the +/// size is determined by the parent size, e.g., 10% of the parent width +pub trait SizeDesc { + /// Convert the size into the number of pixels + /// + /// - `parent`: The reference to the parent container of this size + /// - **returns**: The number of pixels + fn in_pixels<T: HasDimension>(&self, parent: &T) -> i32; +} + +impl SizeDesc for i32 { + fn in_pixels<D: HasDimension>(&self, _parent: &D) -> i32 { + *self + } +} + +impl SizeDesc for u32 { + fn in_pixels<D: HasDimension>(&self, _parent: &D) -> i32 { + *self as i32 + } +} + +impl SizeDesc for f32 { + fn in_pixels<D: HasDimension>(&self, _parent: &D) -> i32 { + *self as i32 + } +} + +impl SizeDesc for f64 { + fn in_pixels<D: HasDimension>(&self, _parent: &D) -> i32 { + *self as i32 + } +} + +/// Describes a relative size, might be +/// 1. portion of height +/// 2. portion of width +/// 3. portion of the minimal of height and weight +pub enum RelativeSize { + /// Percentage height + Height(f64), + /// Percentage width + Width(f64), + /// Percentage of either height or width, which is smaller + Smaller(f64), +} + +impl RelativeSize { + /// Set the lower bound of the relative size. + /// + /// - `min_sz`: The minimal size the relative size can be in pixels + /// - **returns**: The relative size with the bound + pub fn min(self, min_sz: i32) -> RelativeSizeWithBound { + RelativeSizeWithBound { + size: self, + min: Some(min_sz), + max: None, + } + } + + /// Set the upper bound of the relative size + /// + /// - `max_size`: The maximum size in pixels for this relative size + /// - **returns** The relative size with the upper bound + pub fn max(self, max_sz: i32) -> RelativeSizeWithBound { + RelativeSizeWithBound { + size: self, + max: Some(max_sz), + min: None, + } + } +} + +impl SizeDesc for RelativeSize { + fn in_pixels<D: HasDimension>(&self, parent: &D) -> i32 { + let (w, h) = parent.dim(); + match self { + RelativeSize::Width(p) => *p * f64::from(w), + RelativeSize::Height(p) => *p * f64::from(h), + RelativeSize::Smaller(p) => *p * f64::from(w.min(h)), + } + .round() as i32 + } +} + +/// Allows a value turns into a relative size +pub trait AsRelative: Into<f64> { + /// Make the value a relative size of percentage of width + fn percent_width(self) -> RelativeSize { + RelativeSize::Width(self.into() / 100.0) + } + /// Make the value a relative size of percentage of height + fn percent_height(self) -> RelativeSize { + RelativeSize::Height(self.into() / 100.0) + } + /// Make the value a relative size of percentage of minimal of height and width + fn percent(self) -> RelativeSize { + RelativeSize::Smaller(self.into() / 100.0) + } +} + +impl<T: Into<f64>> AsRelative for T {} + +/// The struct describes a relative size with upper bound and lower bound +pub struct RelativeSizeWithBound { + size: RelativeSize, + min: Option<i32>, + max: Option<i32>, +} + +impl RelativeSizeWithBound { + /// Set the lower bound of the bounded relative size + /// + /// - `min_sz`: The lower bound of this size description + /// - **returns**: The newly created size description with the bound + pub fn min(mut self, min_sz: i32) -> RelativeSizeWithBound { + self.min = Some(min_sz); + self + } + + /// Set the upper bound of the bounded relative size + /// + /// - `min_sz`: The upper bound of this size description + /// - **returns**: The newly created size description with the bound + pub fn max(mut self, max_sz: i32) -> RelativeSizeWithBound { + self.max = Some(max_sz); + self + } +} + +impl SizeDesc for RelativeSizeWithBound { + fn in_pixels<D: HasDimension>(&self, parent: &D) -> i32 { + let size = self.size.in_pixels(parent); + let size_lower_capped = self.min.map_or(size, |x| x.max(size)); + self.max.map_or(size_lower_capped, |x| x.min(size)) + } +} + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn test_relative_size() { + let size = (10).percent_height(); + assert_eq!(size.in_pixels(&(100, 200)), 20); + + let size = (10).percent_width(); + assert_eq!(size.in_pixels(&(100, 200)), 10); + + let size = (-10).percent_width(); + assert_eq!(size.in_pixels(&(100, 200)), -10); + + let size = (10).percent_width().min(30); + assert_eq!(size.in_pixels(&(100, 200)), 30); + assert_eq!(size.in_pixels(&(400, 200)), 40); + + let size = (10).percent(); + assert_eq!(size.in_pixels(&(100, 200)), 10); + assert_eq!(size.in_pixels(&(400, 200)), 20); + } +} |