From 8133eb7d7107fdf5688e94ae4cf822e1f3f76e67 Mon Sep 17 00:00:00 2001 From: Mads Marquart Date: Mon, 4 Nov 2024 14:18:12 +0100 Subject: [PATCH] Add inset types --- dpi/CHANGELOG.md | 2 + dpi/src/lib.rs | 139 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) diff --git a/dpi/CHANGELOG.md b/dpi/CHANGELOG.md index 0c4e4544f3..6dd72ea3d8 100644 --- a/dpi/CHANGELOG.md +++ b/dpi/CHANGELOG.md @@ -11,6 +11,8 @@ Unreleased` header. ## Unreleased +- Added `Insets`, `LogicalInsets` and `PhysicalInsets` types. + ## 0.1.1 - Derive `Debug`, `Copy`, `Clone`, `PartialEq`, `Serialize`, `Deserialize` traits for `PixelUnit`. diff --git a/dpi/src/lib.rs b/dpi/src/lib.rs index 04b7df00bc..38a3b85e59 100644 --- a/dpi/src/lib.rs +++ b/dpi/src/lib.rs @@ -759,6 +759,145 @@ impl From> for Position { } } +/// The logical distance between the edges of two rectangles. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct LogicalInsets

{ + /// The distance to the top edge. + pub top: P, + /// The distance to the left edge. + pub left: P, + /// The distance to the bottom edge. + pub bottom: P, + /// The distance to the right edge. + pub right: P, +} + +impl

LogicalInsets

{ + #[inline] + pub const fn new(top: P, + left: P, + bottom: P, + right: P,) -> Self { + Self { top, left, bottom, right } + } +} + +impl LogicalInsets

{ + #[inline] + pub fn from_physical>, X: Pixel>( + physical: T, + scale_factor: f64, + ) -> Self { + physical.into().to_logical(scale_factor) + } + + #[inline] + pub fn to_physical(&self, scale_factor: f64) -> PhysicalInsets { + assert!(validate_scale_factor(scale_factor)); + let top = self.top.into() * scale_factor; + let left = self.left.into() * scale_factor; + let bottom = self.bottom.into() * scale_factor; + let right = self.right.into() * scale_factor; + PhysicalInsets::new(top, left, bottom, right).cast() + } + + #[inline] + pub fn cast(&self) -> LogicalInsets { + LogicalInsets { top: self.top.cast(), left: self.left.cast(), bottom: self.bottom.cast(), right: self.right.cast() } + } +} + +/// The physical distance between the edges of two rectangles. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct PhysicalInsets

{ + /// The distance to the top edge. + pub top: P, + /// The distance to the left edge. + pub left: P, + /// The distance to the bottom edge. + pub bottom: P, + /// The distance to the right edge. + pub right: P, +} + +impl

PhysicalInsets

{ + #[inline] + pub const fn new(top: P, + left: P, + bottom: P, + right: P,) -> Self { + Self { top, left, bottom, right } + } +} + +impl PhysicalInsets

{ + #[inline] + pub fn from_logical>, X: Pixel>(logical: T, scale_factor: f64) -> Self { + logical.into().to_physical(scale_factor) + } + + #[inline] + pub fn to_logical(&self, scale_factor: f64) -> LogicalInsets { + assert!(validate_scale_factor(scale_factor)); + let width = self.width.into() / scale_factor; + let height = self.height.into() / scale_factor; + let top = self.top.into() / scale_factor; + let left = self.left.into() / scale_factor; + let bottom = self.bottom.into() / scale_factor; + let right = self.right.into() / scale_factor; + LogicalInsets::new(top, left, bottom, right).cast() + } + + #[inline] + pub fn cast(&self) -> PhysicalInsets { + PhysicalInsets { top: self.top.cast(), left: self.left.cast(), bottom: self.bottom.cast(), right: self.right.cast() } + } +} + +/// Insets that are either physical or logical. +#[derive(Debug, Copy, Clone, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub enum Insets { + Physical(PhysicalInsets), + Logical(LogicalInsets), +} + +impl Insets { + pub fn new>(insets: S) -> Self { + insets.into() + } + + pub fn to_logical(&self, scale_factor: f64) -> LogicalInsets

{ + match *self { + Self::Physical(insets) => insets.to_logical(scale_factor), + Self::Logical(insets) => insets.cast(), + } + } + + pub fn to_physical(&self, scale_factor: f64) -> PhysicalInsets

{ + match *self { + Self::Physical(insets) => insets.cast(), + Self::Logical(insets) => insets.to_physical(scale_factor), + } + } +} + +impl From> for Insets { + #[inline] + fn from(insets: PhysicalInsets

) -> Self { + Self::Physical(insets.cast()) + } +} + +impl From> for Insets { + #[inline] + fn from(insets: LogicalInsets

) -> Self { + Self::Logical(insets.cast()) + } +} + #[cfg(test)] mod tests { use std::collections::HashSet;