From c6c494e52e45c28ec04d8fbb953a26ac8555d7af Mon Sep 17 00:00:00 2001 From: Amr Bashir <amr.bashir2015@gmail.com> Date: Fri, 7 Jul 2023 04:01:41 +0300 Subject: [PATCH] use macros to generate DPI types ref: https://github.com/rust-windowing/winit/pull/2148 --- examples/min_max_size.rs | 14 +- src/dpi.rs | 707 ++++++++---------------- src/platform_impl/windows/event_loop.rs | 10 +- src/window.rs | 50 +- 4 files changed, 258 insertions(+), 523 deletions(-) diff --git a/examples/min_max_size.rs b/examples/min_max_size.rs index 85894e5f8..527519727 100644 --- a/examples/min_max_size.rs +++ b/examples/min_max_size.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 use tao::{ - dpi::LogicalUnit, + dpi::LogicalPixel, event::{ElementState, Event, KeyEvent, WindowEvent}, event_loop::{ControlFlow, EventLoop}, keyboard::Key, @@ -53,22 +53,22 @@ fn main() { } => match key_str { "e" => { size_constraints.min_width = - (!size_constraints.min_width.is_some()).then_some(LogicalUnit::new(min_width).into()); + (!size_constraints.min_width.is_some()).then_some(LogicalPixel::new(min_width).into()); window.set_inner_size_constraints(size_constraints); } "f" => { size_constraints.max_width = - (!size_constraints.max_width.is_some()).then_some(LogicalUnit::new(max_width).into()); + (!size_constraints.max_width.is_some()).then_some(LogicalPixel::new(max_width).into()); window.set_inner_size_constraints(size_constraints); } "p" => { - size_constraints.min_height = - (!size_constraints.min_height.is_some()).then_some(LogicalUnit::new(min_height).into()); + size_constraints.min_height = (!size_constraints.min_height.is_some()) + .then_some(LogicalPixel::new(min_height).into()); window.set_inner_size_constraints(size_constraints); } "v" => { - size_constraints.max_height = - (!size_constraints.max_height.is_some()).then_some(LogicalUnit::new(max_height).into()); + size_constraints.max_height = (!size_constraints.max_height.is_some()) + .then_some(LogicalPixel::new(max_height).into()); window.set_inner_size_constraints(size_constraints); } _ => {} diff --git a/src/dpi.rs b/src/dpi.rs index dd2bb91a8..3b4fb4ae1 100644 --- a/src/dpi.rs +++ b/src/dpi.rs @@ -93,55 +93,70 @@ pub trait Pixel: Copy + Into<f64> { fn from_f64(f: f64) -> Self; - fn inner(&self) -> Self { - *self - } fn cast<P: Pixel>(self) -> P { P::from_f64(self.into()) } } -impl Pixel for u8 { - fn from_f64(f: f64) -> Self { - f.round() as u8 - } -} -impl Pixel for u16 { - fn from_f64(f: f64) -> Self { - f.round() as u16 - } -} -impl Pixel for u32 { - fn from_f64(f: f64) -> Self { - f.round() as u32 - } -} -impl Pixel for i8 { - fn from_f64(f: f64) -> Self { - f.round() as i8 - } -} -impl Pixel for i16 { - fn from_f64(f: f64) -> Self { - f.round() as i16 - } -} -impl Pixel for i32 { - fn from_f64(f: f64) -> Self { - f.round() as i32 - } +macro_rules! pixel_int_impl { + ($($t:ty),*) => {$( + impl Pixel for $t { + fn from_f64(f: f64) -> Self { + f.round() as $t + } + } + )*} } + +pixel_int_impl!(u8, u16, u32, i8, i16, i32); + impl Pixel for f32 { fn from_f64(f: f64) -> Self { f as f32 } } + impl Pixel for f64 { fn from_f64(f: f64) -> Self { f } } +macro_rules! from_impls { + ($t:ident, $a:ident, $(,)? ) => { + impl<P: Pixel> From<P> for $t<P> { + fn from($a: P) -> Self { + Self::new($a.cast()) + } + } + }; + ($t:ident, $a:ident, $b:ident$(,)? ) => { + impl<P: Pixel, X: Pixel> From<(X, X)> for $t<P> { + fn from(($a, $b): (X, X)) -> Self { + Self::new($a.cast(), $b.cast()) + } + } + + impl<P: Pixel, X: Pixel> From<$t<P>> for (X, X) { + fn from(p: $t<P>) -> Self { + (p.$a.cast(), p.$b.cast()) + } + } + + impl<P: Pixel, X: Pixel> From<[X; 2]> for $t<P> { + fn from([$a, $b]: [X; 2]) -> Self { + Self::new($a.cast(), $b.cast()) + } + } + + impl<P: Pixel, X: Pixel> From<$t<P>> for [X; 2] { + fn from(p: $t<P>) -> Self { + [p.$a.cast(), p.$b.cast()] + } + } + }; +} + /// Checks that the scale factor is a normal positive `f64`. /// /// All functions that take a scale factor assert that this will return `true`. If you're sourcing scale factors from @@ -152,349 +167,213 @@ pub fn validate_scale_factor(scale_factor: f64) -> bool { scale_factor.is_sign_positive() && scale_factor.is_normal() } -/// A position represented in logical pixels. -/// -/// The position is stored as floats, so please be careful. Casting floats to integers truncates the -/// fractional part, which can cause noticeable issues. To help with that, an `Into<(i32, i32)>` -/// implementation is provided which does the rounding for you. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct LogicalPosition<P> { - pub x: P, - pub y: P, -} - -impl<P> LogicalPosition<P> { - #[inline] - pub const fn new(x: P, y: P) -> Self { - LogicalPosition { x, y } - } -} - -impl<P: Pixel> LogicalPosition<P> { - #[inline] - pub fn from_physical<T: Into<PhysicalPosition<X>>, X: Pixel>( - physical: T, - scale_factor: f64, - ) -> Self { - physical.into().to_logical(scale_factor) - } - - #[inline] - pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalPosition<X> { - assert!(validate_scale_factor(scale_factor)); - let x = self.x.into() * scale_factor; - let y = self.y.into() * scale_factor; - PhysicalPosition::new(x, y).cast() - } - - #[inline] - pub fn cast<X: Pixel>(&self) -> LogicalPosition<X> { - LogicalPosition { - x: self.x.cast(), - y: self.y.cast(), - } - } -} - -impl<P: Pixel, X: Pixel> From<(X, X)> for LogicalPosition<P> { - fn from((x, y): (X, X)) -> LogicalPosition<P> { - LogicalPosition::new(x.cast(), y.cast()) - } -} - -impl<P: Pixel, X: Pixel> Into<(X, X)> for LogicalPosition<P> { - fn into(self) -> (X, X) { - (self.x.cast(), self.y.cast()) - } -} - -impl<P: Pixel, X: Pixel> From<[X; 2]> for LogicalPosition<P> { - fn from([x, y]: [X; 2]) -> LogicalPosition<P> { - LogicalPosition::new(x.cast(), y.cast()) - } -} - -impl<P: Pixel, X: Pixel> Into<[X; 2]> for LogicalPosition<P> { - fn into(self) -> [X; 2] { - [self.x.cast(), self.y.cast()] - } -} - -/// A position represented in physical pixels. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct PhysicalPosition<P> { - pub x: P, - pub y: P, -} - -impl<P> PhysicalPosition<P> { - #[inline] - pub const fn new(x: P, y: P) -> Self { - PhysicalPosition { x, y } - } -} - -impl<P: Pixel> PhysicalPosition<P> { - #[inline] - pub fn from_logical<T: Into<LogicalPosition<X>>, X: Pixel>( - logical: T, - scale_factor: f64, - ) -> Self { - logical.into().to_physical(scale_factor) - } - - #[inline] - pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalPosition<X> { - assert!(validate_scale_factor(scale_factor)); - let x = self.x.into() / scale_factor; - let y = self.y.into() / scale_factor; - LogicalPosition::new(x, y).cast() - } - - #[inline] - pub fn cast<X: Pixel>(&self) -> PhysicalPosition<X> { - PhysicalPosition { - x: self.x.cast(), - y: self.y.cast(), - } - } -} - -impl<P: Pixel, X: Pixel> From<(X, X)> for PhysicalPosition<P> { - fn from((x, y): (X, X)) -> PhysicalPosition<P> { - PhysicalPosition::new(x.cast(), y.cast()) - } -} - -impl<P: Pixel, X: Pixel> Into<(X, X)> for PhysicalPosition<P> { - fn into(self) -> (X, X) { - (self.x.cast(), self.y.cast()) - } -} +macro_rules! dpi_type { + ( + $(let $a:ident;)* -impl<P: Pixel, X: Pixel> From<[X; 2]> for PhysicalPosition<P> { - fn from([x, y]: [X; 2]) -> PhysicalPosition<P> { - PhysicalPosition::new(x.cast(), y.cast()) - } -} - -impl<P: Pixel, X: Pixel> Into<[X; 2]> for PhysicalPosition<P> { - fn into(self) -> [X; 2] { - [self.x.cast(), self.y.cast()] - } -} - -/// A position that's either physical or logical. -#[non_exhaustive] -#[derive(Debug, Copy, Clone, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum Position { - Physical(PhysicalPosition<i32>), - Logical(LogicalPosition<f64>), -} - -impl Position { - pub fn new<S: Into<Position>>(position: S) -> Position { - position.into() - } + $(#[$logical_meta:meta])* + pub struct $LogicalType:ident; + $(#[$physical_meta:meta])* + pub struct $PhysicalType:ident; + $(#[$unified_meta:meta])* + pub enum $UnifiedType:ident { + Physical($unified_physical:ty), + Logical($unified_logical:ty), + } + ) => { + $(#[$logical_meta])* + #[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, PartialOrd, Ord)] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + pub struct $LogicalType<P> { + $(pub $a: P,)* + } - pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalPosition<P> { - match *self { - Position::Physical(position) => position.to_logical(scale_factor), - Position::Logical(position) => position.cast(), - } - } + impl<P> $LogicalType<P> { + #[inline] + pub const fn new($($a: P,)*) -> Self { + $LogicalType { $($a,)* } + } + } - pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalPosition<P> { - match *self { - Position::Physical(position) => position.cast(), - Position::Logical(position) => position.to_physical(scale_factor), - } - } -} + impl<P: Pixel> $LogicalType<P> { + #[inline] + pub fn from_physical<T: Into<$PhysicalType<X>>, X: Pixel>( + physical: T, + scale_factor: f64, + ) -> Self { + physical.into().to_logical(scale_factor) + } + + #[inline] + pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> $PhysicalType<X> { + assert!(validate_scale_factor(scale_factor)); + $(let $a = self.$a.into() * scale_factor;)* + $PhysicalType::new($($a,)*).cast() + } + + #[inline] + pub fn cast<X: Pixel>(&self) -> $LogicalType<X> { + $LogicalType { + $($a: self.$a.cast(),)* + } + } + } -impl<P: Pixel> From<PhysicalPosition<P>> for Position { - #[inline] - fn from(position: PhysicalPosition<P>) -> Position { - Position::Physical(position.cast()) - } -} + from_impls!($LogicalType, $($a,)*); -impl<P: Pixel> From<LogicalPosition<P>> for Position { - #[inline] - fn from(position: LogicalPosition<P>) -> Position { - Position::Logical(position.cast()) - } -} + $(#[$physical_meta])* + #[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, PartialOrd, Ord)] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + pub struct $PhysicalType<P> { + $(pub $a: P,)* + } -/// A size represented in logical pixels. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct LogicalSize<P> { - pub width: P, - pub height: P, -} + impl<P> $PhysicalType<P> { + #[inline] + pub const fn new($($a: P,)*) -> Self { + $PhysicalType { $($a,)* } + } + } -impl<P> LogicalSize<P> { - #[inline] - pub const fn new(width: P, height: P) -> Self { - LogicalSize { width, height } - } -} + impl<P: Pixel> $PhysicalType<P> { + #[inline] + pub fn from_logical<T: Into<$LogicalType<X>>, X: Pixel>( + logical: T, + scale_factor: f64, + ) -> Self { + logical.into().to_physical(scale_factor) + } + + #[inline] + pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> $LogicalType<X> { + assert!(validate_scale_factor(scale_factor)); + $(let $a = self.$a.into() / scale_factor;)* + $LogicalType::new($($a,)*).cast() + } + + #[inline] + pub fn cast<X: Pixel>(&self) -> $PhysicalType<X> { + $PhysicalType { + $($a: self.$a.cast(),)* + } + } + } -impl<P: Pixel> LogicalSize<P> { - #[inline] - pub fn from_physical<T: Into<PhysicalSize<X>>, X: Pixel>(physical: T, scale_factor: f64) -> Self { - physical.into().to_logical(scale_factor) - } + from_impls!($PhysicalType, $($a,)*); - #[inline] - pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalSize<X> { - assert!(validate_scale_factor(scale_factor)); - let width = self.width.into() * scale_factor; - let height = self.height.into() * scale_factor; - PhysicalSize::new(width, height).cast() - } + $(#[$unified_meta])* + #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + pub enum $UnifiedType { + Physical($unified_physical), + Logical($unified_logical), + } - #[inline] - pub fn cast<X: Pixel>(&self) -> LogicalSize<X> { - LogicalSize { - width: self.width.cast(), - height: self.height.cast(), - } - } -} + impl $UnifiedType { + pub fn new<S: Into<$UnifiedType>>(val: S) -> $UnifiedType { + val.into() + } + + pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> $LogicalType<P> { + match *self { + $UnifiedType::Physical(val) => val.to_logical(scale_factor), + $UnifiedType::Logical(val) => val.cast(), + } + } + + pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> $PhysicalType<P> { + match *self { + $UnifiedType::Physical(val) => val.cast(), + $UnifiedType::Logical(val) => val.to_physical(scale_factor), + } + } + + $(pub fn $a(&self) -> PixelUnit { + match *self { + $UnifiedType::Physical(any) => PixelUnit::Physical(any.$a.into()), + $UnifiedType::Logical(any) => PixelUnit::Logical(any.$a.into()), + } + })* + } -impl<P: Pixel, X: Pixel> From<(X, X)> for LogicalSize<P> { - fn from((x, y): (X, X)) -> LogicalSize<P> { - LogicalSize::new(x.cast(), y.cast()) - } -} + impl<P: Pixel> From<$PhysicalType<P>> for $UnifiedType { + #[inline] + fn from(val: $PhysicalType<P>) -> $UnifiedType { + $UnifiedType::Physical(val.cast()) + } + } -impl<P: Pixel, X: Pixel> Into<(X, X)> for LogicalSize<P> { - fn into(self: LogicalSize<P>) -> (X, X) { - (self.width.cast(), self.height.cast()) - } + impl<P: Pixel> From<$LogicalType<P>> for $UnifiedType { + #[inline] + fn from(val: $LogicalType<P>) -> $UnifiedType { + $UnifiedType::Logical(val.cast()) + } + } + }; } -impl<P: Pixel, X: Pixel> From<[X; 2]> for LogicalSize<P> { - fn from([x, y]: [X; 2]) -> LogicalSize<P> { - LogicalSize::new(x.cast(), y.cast()) - } -} +dpi_type! { + let value; -impl<P: Pixel, X: Pixel> Into<[X; 2]> for LogicalSize<P> { - fn into(self) -> [X; 2] { - [self.width.cast(), self.height.cast()] + /// A logical pixel. + pub struct LogicalPixel; + /// A physical pixel. + pub struct PhysicalPixel; + /// A pixel that's either physical or logical. + pub enum PixelUnit { + Physical(PhysicalPixel<i32>), + Logical(LogicalPixel<f64>), } } -/// A size represented in physical pixels. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct PhysicalSize<P> { - pub width: P, - pub height: P, +impl PixelUnit { + /// Represents a minimum logical unit of `0` + pub const MIN: PixelUnit = PixelUnit::Logical(LogicalPixel::new(0.0)); + /// Represents a maximum logical unit that is equal to [`f64::MAX`] + pub const MAX: PixelUnit = PixelUnit::Logical(LogicalPixel::new(f64::MAX)); } -impl<P> PhysicalSize<P> { - #[inline] - pub const fn new(width: P, height: P) -> Self { - PhysicalSize { width, height } - } -} - -impl<P: Pixel> PhysicalSize<P> { - #[inline] - pub fn from_logical<T: Into<LogicalSize<X>>, X: Pixel>(logical: T, scale_factor: f64) -> Self { - logical.into().to_physical(scale_factor) - } - - #[inline] - pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalSize<X> { - assert!(validate_scale_factor(scale_factor)); - let width = self.width.into() / scale_factor; - let height = self.height.into() / scale_factor; - LogicalSize::new(width, height).cast() - } - - #[inline] - pub fn cast<X: Pixel>(&self) -> PhysicalSize<X> { - PhysicalSize { - width: self.width.cast(), - height: self.height.cast(), - } +impl From<u32> for PhysicalPixel<i32> { + fn from(value: u32) -> Self { + Self::new(value.cast()) } } -impl<P: Pixel, X: Pixel> From<(X, X)> for PhysicalSize<P> { - fn from((x, y): (X, X)) -> PhysicalSize<P> { - PhysicalSize::new(x.cast(), y.cast()) - } -} +dpi_type! { + let x; + let y; -impl<P: Pixel, X: Pixel> Into<(X, X)> for PhysicalSize<P> { - fn into(self) -> (X, X) { - (self.width.cast(), self.height.cast()) + /// A position represented in logical pixels. + /// + /// The position is stored as floats, so please be careful. Casting floats to integers truncates the + /// fractional part, which can cause noticable issues. To help with that, an `Into<(i32, i32)>` + /// implementation is provided which does the rounding for you. + pub struct LogicalPosition; + /// A position represented in physical pixels. + pub struct PhysicalPosition; + /// A position that's either physical or logical. + pub enum Position { + Physical(PhysicalPosition<i32>), + Logical(LogicalPosition<f64>), } } -impl<P: Pixel, X: Pixel> From<[X; 2]> for PhysicalSize<P> { - fn from([x, y]: [X; 2]) -> PhysicalSize<P> { - PhysicalSize::new(x.cast(), y.cast()) - } -} +dpi_type! { + let width; + let height; -impl<P: Pixel, X: Pixel> Into<[X; 2]> for PhysicalSize<P> { - fn into(self) -> [X; 2] { - [self.width.cast(), self.height.cast()] + /// A size represented in logical pixels. + pub struct LogicalSize; + /// A size represented in physical pixels. + pub struct PhysicalSize; + /// A size that's either physical or logical. + pub enum Size { + Physical(PhysicalSize<u32>), + Logical(LogicalSize<f64>), } } -/// A size that's either physical or logical. -#[non_exhaustive] -#[derive(Debug, Copy, Clone, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum Size { - Physical(PhysicalSize<u32>), - Logical(LogicalSize<f64>), -} - impl Size { - pub fn new<S: Into<Size>>(size: S) -> Size { - size.into() - } - - pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalSize<P> { - match *self { - Size::Physical(size) => size.to_logical(scale_factor), - Size::Logical(size) => size.cast(), - } - } - - pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalSize<P> { - match *self { - Size::Physical(size) => size.cast(), - Size::Logical(size) => size.to_physical(scale_factor), - } - } - - pub fn width(&self) -> Unit { - match *self { - Size::Physical(size) => Unit::Physical(size.width.into()), - Size::Logical(size) => Unit::Logical(size.width.into()), - } - } - - pub fn height(&self) -> Unit { - match *self { - Size::Physical(size) => Unit::Physical(size.height.into()), - Size::Logical(size) => Unit::Logical(size.height.into()), - } - } - pub fn clamp<S: Into<Size>>(desired_size: S, min: S, max: S, scale_factor: f64) -> Size { let (desired_size, min, max) = ( desired_size.into().to_physical::<f64>(scale_factor), @@ -518,145 +397,3 @@ impl Size { PhysicalSize::new(width, height).into() } } - -impl<P: Pixel> From<PhysicalSize<P>> for Size { - #[inline] - fn from(size: PhysicalSize<P>) -> Size { - Size::Physical(size.cast()) - } -} - -impl<P: Pixel> From<LogicalSize<P>> for Size { - #[inline] - fn from(size: LogicalSize<P>) -> Size { - Size::Logical(size.cast()) - } -} - -/// A unit represented in logical pixels. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, PartialOrd, Ord)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct LogicalUnit<P> { - pub value: P, -} - -impl<P> LogicalUnit<P> { - #[inline] - pub const fn new(value: P) -> Self { - Self { value } - } -} - -impl<P: Pixel> LogicalUnit<P> { - #[inline] - pub fn from_physical<T: Into<PhysicalUnit<X>>, X: Pixel>(physical: T, scale_factor: f64) -> Self { - physical.into().to_logical(scale_factor) - } - - #[inline] - pub fn to_physical<X: Pixel>(&self, scale_factor: f64) -> PhysicalUnit<X> { - assert!(validate_scale_factor(scale_factor)); - let u = self.value.into() * scale_factor; - PhysicalUnit::new(u).cast() - } - - #[inline] - pub fn cast<X: Pixel>(&self) -> LogicalUnit<X> { - LogicalUnit::new(self.value.cast()) - } -} - -impl<P: Pixel> From<P> for LogicalUnit<P> { - fn from(p: P) -> LogicalUnit<P> { - LogicalUnit::new(p.cast()) - } -} - -/// A unit represented in physical pixels. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, PartialOrd, Ord)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct PhysicalUnit<P> { - pub value: P, -} - -impl<P> PhysicalUnit<P> { - #[inline] - pub const fn new(value: P) -> Self { - Self { value } - } -} - -impl<P: Pixel> PhysicalUnit<P> { - #[inline] - pub fn from_logical<T: Into<LogicalUnit<X>>, X: Pixel>(logical: T, scale_factor: f64) -> Self { - logical.into().to_physical(scale_factor) - } - - #[inline] - pub fn to_logical<X: Pixel>(&self, scale_factor: f64) -> LogicalUnit<X> { - assert!(validate_scale_factor(scale_factor)); - let u = self.value.into() / scale_factor; - LogicalUnit::new(u).cast() - } - - #[inline] - pub fn cast<X: Pixel>(&self) -> PhysicalUnit<X> { - PhysicalUnit::new(self.value.cast()) - } -} - -impl<P: Pixel> From<P> for PhysicalUnit<P> { - fn from(p: P) -> PhysicalUnit<P> { - PhysicalUnit::new(p.cast()) - } -} - -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum Unit { - Physical(PhysicalUnit<u32>), - Logical(LogicalUnit<f64>), -} - -impl Default for Unit { - fn default() -> Self { - Self::Logical(LogicalUnit::new(f64::default())) - } -} - -impl Unit { - pub const MIN: Unit = Unit::Logical(LogicalUnit::new(0.0)); - pub const MAX: Unit = Unit::Logical(LogicalUnit::new(f64::MAX)); - - pub fn new<S: Into<Unit>>(val: S) -> Unit { - val.into() - } - - pub fn to_logical<P: Pixel>(&self, scale_factor: f64) -> LogicalUnit<P> { - match *self { - Unit::Physical(val) => val.to_logical(scale_factor), - Unit::Logical(val) => val.cast(), - } - } - - pub fn to_physical<P: Pixel>(&self, scale_factor: f64) -> PhysicalUnit<P> { - match *self { - Unit::Physical(val) => val.cast(), - Unit::Logical(val) => val.to_physical(scale_factor), - } - } -} - -impl<P: Pixel> From<PhysicalUnit<P>> for Unit { - #[inline] - fn from(val: PhysicalUnit<P>) -> Unit { - Unit::Physical(val.cast()) - } -} - -impl<P: Pixel> From<LogicalUnit<P>> for Unit { - #[inline] - fn from(val: LogicalUnit<P>) -> Unit { - Unit::Logical(val.cast()) - } -} diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index c2e623b4c..126c33afb 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -44,7 +44,7 @@ use windows::{ use crate::{ accelerator::AcceleratorId, - dpi::{PhysicalPosition, PhysicalSize, Unit}, + dpi::{PhysicalPosition, PhysicalSize, PixelUnit}, error::ExternalError, event::{DeviceEvent, Event, Force, RawKeyEvent, Touch, TouchPhase, WindowEvent}, event_loop::{ControlFlow, DeviceEventFilter, EventLoopClosed, EventLoopWindowTarget as RootELW}, @@ -1789,17 +1789,17 @@ unsafe fn public_window_callback_inner<T: 'static>( } if size_constraints.has_max() { // we can't use WindowSizeConstraints::max_size_physical because - // for Windows, in order to remove the max constraints, we need to fall to Unit::MIN (which is `0`) - // instead of Unit::MAX (which is f64::MAX) + // for Windows, in order to remove the max constraints, we need to fall to PixelUnit::MIN (which is `0`) + // instead of PixelUnit::MAX (which is f64::MAX) let max_size = PhysicalSize::new( size_constraints .max_width - .unwrap_or(Unit::MIN) + .unwrap_or(PixelUnit::MIN) .to_physical(window_state.scale_factor) .value, size_constraints .max_height - .unwrap_or(Unit::MIN) + .unwrap_or(PixelUnit::MIN) .to_physical(window_state.scale_factor) .value, ); diff --git a/src/window.rs b/src/window.rs index 4d7a70946..b59782797 100644 --- a/src/window.rs +++ b/src/window.rs @@ -8,7 +8,7 @@ use std::fmt; use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle}; use crate::{ - dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Pixel, Position, Size, Unit}, + dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Pixel, PixelUnit, Position, Size}, error::{ExternalError, NotSupportedError, OsError}, event_loop::EventLoopWindowTarget, menu::MenuBar, @@ -1418,27 +1418,27 @@ pub struct WindowSizeConstraints { /// The minimum width a window can be, If this is `None`, the window will have no minimum width (aside from reserved). /// /// The default is `None`. - pub min_width: Option<Unit>, + pub min_width: Option<PixelUnit>, /// The minimum height a window can be, If this is `None`, the window will have no minimum height (aside from reserved). /// /// The default is `None`. - pub min_height: Option<Unit>, + pub min_height: Option<PixelUnit>, /// The maximum width a window can be, If this is `None`, the window will have no maximum width (aside from reserved). /// /// The default is `None`. - pub max_width: Option<Unit>, + pub max_width: Option<PixelUnit>, /// The maximum height a window can be, If this is `None`, the window will have no maximum height (aside from reserved). /// /// The default is `None`. - pub max_height: Option<Unit>, + pub max_height: Option<PixelUnit>, } impl WindowSizeConstraints { pub fn new( - min_width: Option<Unit>, - min_height: Option<Unit>, - max_width: Option<Unit>, - max_height: Option<Unit>, + min_width: Option<PixelUnit>, + min_height: Option<PixelUnit>, + max_width: Option<PixelUnit>, + max_height: Option<PixelUnit>, ) -> Self { Self { min_width, @@ -1448,82 +1448,80 @@ impl WindowSizeConstraints { } } - pub fn symmetrical(min: Option<Size>, max: Option<Size>) -> Self { - Self { - min_width: min.map(|s| s.width()), - min_height: min.map(|s| s.height()), - max_width: max.map(|s| s.width()), - max_height: max.map(|s| s.height()), - } - } - + /// Returns true if `min_width` or `min_height` is set. pub fn has_min(&self) -> bool { self.min_width.is_some() || self.min_height.is_some() } + /// Returns true if `max_width` or `max_height` is set. pub fn has_max(&self) -> bool { self.max_width.is_some() || self.max_height.is_some() } + /// Returns a physical size that represents the minimum constraints set and fallbacks to [`PixelUnit::MIN`] for unset values pub fn min_size_physical<T: Pixel>(&self, scale_factor: f64) -> PhysicalSize<T> { PhysicalSize::new( self .min_width - .unwrap_or_default() + .unwrap_or(PixelUnit::MIN) .to_physical(scale_factor) .value, self .min_height - .unwrap_or_default() + .unwrap_or(PixelUnit::MIN) .to_physical(scale_factor) .value, ) } + /// Returns a logical size that represents the minimum constraints set and fallbacks to [`PixelUnit::MIN`] for unset values pub fn min_size_logical<T: Pixel>(&self, scale_factor: f64) -> LogicalSize<T> { LogicalSize::new( self .min_width - .unwrap_or_default() + .unwrap_or(PixelUnit::MIN) .to_logical(scale_factor) .value, self .min_height - .unwrap_or_default() + .unwrap_or(PixelUnit::MIN) .to_logical(scale_factor) .value, ) } + /// Returns a physical size that represents the maximum constraints set and fallbacks to [`PixelUnit::MAX`] for unset values pub fn max_size_physical<T: Pixel>(&self, scale_factor: f64) -> PhysicalSize<T> { PhysicalSize::new( self .max_width - .unwrap_or(Unit::MAX) + .unwrap_or(PixelUnit::MAX) .to_physical(scale_factor) .value, self .max_height - .unwrap_or(Unit::MAX) + .unwrap_or(PixelUnit::MAX) .to_physical(scale_factor) .value, ) } + /// Returns a logical size that represents the maximum constraints set and fallbacks to [`PixelUnit::MAX`] for unset values pub fn max_size_logical<T: Pixel>(&self, scale_factor: f64) -> LogicalSize<T> { LogicalSize::new( self .max_width - .unwrap_or(Unit::MAX) + .unwrap_or(PixelUnit::MAX) .to_logical(scale_factor) .value, self .max_height - .unwrap_or(Unit::MAX) + .unwrap_or(PixelUnit::MAX) .to_logical(scale_factor) .value, ) } + /// Clamps the desired size based on the constraints set pub fn clamp(&self, desired_size: Size, scale_factor: f64) -> Size { let min_size: PhysicalSize<f64> = self.min_size_physical(scale_factor); let max_size: PhysicalSize<f64> = self.max_size_physical(scale_factor);