From c6c494e52e45c28ec04d8fbb953a26ac8555d7af Mon Sep 17 00:00:00 2001 From: Amr Bashir 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 { fn from_f64(f: f64) -> Self; - fn inner(&self) -> Self { - *self - } fn cast(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 From

for $t

{ + fn from($a: P) -> Self { + Self::new($a.cast()) + } + } + }; + ($t:ident, $a:ident, $b:ident$(,)? ) => { + impl From<(X, X)> for $t

{ + fn from(($a, $b): (X, X)) -> Self { + Self::new($a.cast(), $b.cast()) + } + } + + impl From<$t

> for (X, X) { + fn from(p: $t

) -> Self { + (p.$a.cast(), p.$b.cast()) + } + } + + impl From<[X; 2]> for $t

{ + fn from([$a, $b]: [X; 2]) -> Self { + Self::new($a.cast(), $b.cast()) + } + } + + impl From<$t

> for [X; 2] { + fn from(p: $t

) -> 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

{ - pub x: P, - pub y: P, -} - -impl

LogicalPosition

{ - #[inline] - pub const fn new(x: P, y: P) -> Self { - LogicalPosition { x, y } - } -} - -impl LogicalPosition

{ - #[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) -> PhysicalPosition { - 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(&self) -> LogicalPosition { - LogicalPosition { - x: self.x.cast(), - y: self.y.cast(), - } - } -} - -impl From<(X, X)> for LogicalPosition

{ - fn from((x, y): (X, X)) -> LogicalPosition

{ - LogicalPosition::new(x.cast(), y.cast()) - } -} - -impl Into<(X, X)> for LogicalPosition

{ - fn into(self) -> (X, X) { - (self.x.cast(), self.y.cast()) - } -} - -impl From<[X; 2]> for LogicalPosition

{ - fn from([x, y]: [X; 2]) -> LogicalPosition

{ - LogicalPosition::new(x.cast(), y.cast()) - } -} - -impl Into<[X; 2]> for LogicalPosition

{ - 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

{ - pub x: P, - pub y: P, -} - -impl

PhysicalPosition

{ - #[inline] - pub const fn new(x: P, y: P) -> Self { - PhysicalPosition { x, y } - } -} - -impl PhysicalPosition

{ - #[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) -> LogicalPosition { - 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(&self) -> PhysicalPosition { - PhysicalPosition { - x: self.x.cast(), - y: self.y.cast(), - } - } -} - -impl From<(X, X)> for PhysicalPosition

{ - fn from((x, y): (X, X)) -> PhysicalPosition

{ - PhysicalPosition::new(x.cast(), y.cast()) - } -} - -impl Into<(X, X)> for PhysicalPosition

{ - fn into(self) -> (X, X) { - (self.x.cast(), self.y.cast()) - } -} +macro_rules! dpi_type { + ( + $(let $a:ident;)* -impl From<[X; 2]> for PhysicalPosition

{ - fn from([x, y]: [X; 2]) -> PhysicalPosition

{ - PhysicalPosition::new(x.cast(), y.cast()) - } -} - -impl Into<[X; 2]> for PhysicalPosition

{ - 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), - Logical(LogicalPosition), -} - -impl Position { - pub fn new>(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

{ + $(pub $a: P,)* + } - pub fn to_logical(&self, scale_factor: f64) -> LogicalPosition

{ - match *self { - Position::Physical(position) => position.to_logical(scale_factor), - Position::Logical(position) => position.cast(), - } - } + impl

$LogicalType

{ + #[inline] + pub const fn new($($a: P,)*) -> Self { + $LogicalType { $($a,)* } + } + } - pub fn to_physical(&self, scale_factor: f64) -> PhysicalPosition

{ - match *self { - Position::Physical(position) => position.cast(), - Position::Logical(position) => position.to_physical(scale_factor), - } - } -} + impl $LogicalType

{ + #[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) -> $PhysicalType { + assert!(validate_scale_factor(scale_factor)); + $(let $a = self.$a.into() * scale_factor;)* + $PhysicalType::new($($a,)*).cast() + } + + #[inline] + pub fn cast(&self) -> $LogicalType { + $LogicalType { + $($a: self.$a.cast(),)* + } + } + } -impl From> for Position { - #[inline] - fn from(position: PhysicalPosition

) -> Position { - Position::Physical(position.cast()) - } -} + from_impls!($LogicalType, $($a,)*); -impl From> for Position { - #[inline] - fn from(position: LogicalPosition

) -> 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

{ + $(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

{ - pub width: P, - pub height: P, -} + impl

$PhysicalType

{ + #[inline] + pub const fn new($($a: P,)*) -> Self { + $PhysicalType { $($a,)* } + } + } -impl

LogicalSize

{ - #[inline] - pub const fn new(width: P, height: P) -> Self { - LogicalSize { width, height } - } -} + impl $PhysicalType

{ + #[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) -> $LogicalType { + assert!(validate_scale_factor(scale_factor)); + $(let $a = self.$a.into() / scale_factor;)* + $LogicalType::new($($a,)*).cast() + } + + #[inline] + pub fn cast(&self) -> $PhysicalType { + $PhysicalType { + $($a: self.$a.cast(),)* + } + } + } -impl LogicalSize

{ - #[inline] - pub fn from_physical>, X: Pixel>(physical: T, scale_factor: f64) -> Self { - physical.into().to_logical(scale_factor) - } + from_impls!($PhysicalType, $($a,)*); - #[inline] - pub fn to_physical(&self, scale_factor: f64) -> PhysicalSize { - 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(&self) -> LogicalSize { - LogicalSize { - width: self.width.cast(), - height: self.height.cast(), - } - } -} + impl $UnifiedType { + pub fn new>(val: S) -> $UnifiedType { + val.into() + } + + pub fn to_logical(&self, scale_factor: f64) -> $LogicalType

{ + match *self { + $UnifiedType::Physical(val) => val.to_logical(scale_factor), + $UnifiedType::Logical(val) => val.cast(), + } + } + + pub fn to_physical(&self, scale_factor: f64) -> $PhysicalType

{ + 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 From<(X, X)> for LogicalSize

{ - fn from((x, y): (X, X)) -> LogicalSize

{ - LogicalSize::new(x.cast(), y.cast()) - } -} + impl From<$PhysicalType

> for $UnifiedType { + #[inline] + fn from(val: $PhysicalType

) -> $UnifiedType { + $UnifiedType::Physical(val.cast()) + } + } -impl Into<(X, X)> for LogicalSize

{ - fn into(self: LogicalSize

) -> (X, X) { - (self.width.cast(), self.height.cast()) - } + impl From<$LogicalType

> for $UnifiedType { + #[inline] + fn from(val: $LogicalType

) -> $UnifiedType { + $UnifiedType::Logical(val.cast()) + } + } + }; } -impl From<[X; 2]> for LogicalSize

{ - fn from([x, y]: [X; 2]) -> LogicalSize

{ - LogicalSize::new(x.cast(), y.cast()) - } -} +dpi_type! { + let value; -impl Into<[X; 2]> for LogicalSize

{ - 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), + Logical(LogicalPixel), } } -/// A size represented in physical pixels. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct PhysicalSize

{ - 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

PhysicalSize

{ - #[inline] - pub const fn new(width: P, height: P) -> Self { - PhysicalSize { width, height } - } -} - -impl PhysicalSize

{ - #[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) -> LogicalSize { - 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(&self) -> PhysicalSize { - PhysicalSize { - width: self.width.cast(), - height: self.height.cast(), - } +impl From for PhysicalPixel { + fn from(value: u32) -> Self { + Self::new(value.cast()) } } -impl From<(X, X)> for PhysicalSize

{ - fn from((x, y): (X, X)) -> PhysicalSize

{ - PhysicalSize::new(x.cast(), y.cast()) - } -} +dpi_type! { + let x; + let y; -impl Into<(X, X)> for PhysicalSize

{ - 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), + Logical(LogicalPosition), } } -impl From<[X; 2]> for PhysicalSize

{ - fn from([x, y]: [X; 2]) -> PhysicalSize

{ - PhysicalSize::new(x.cast(), y.cast()) - } -} +dpi_type! { + let width; + let height; -impl Into<[X; 2]> for PhysicalSize

{ - 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), + Logical(LogicalSize), } } -/// 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), - Logical(LogicalSize), -} - impl Size { - pub fn new>(size: S) -> Size { - size.into() - } - - pub fn to_logical(&self, scale_factor: f64) -> LogicalSize

{ - match *self { - Size::Physical(size) => size.to_logical(scale_factor), - Size::Logical(size) => size.cast(), - } - } - - pub fn to_physical(&self, scale_factor: f64) -> PhysicalSize

{ - 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>(desired_size: S, min: S, max: S, scale_factor: f64) -> Size { let (desired_size, min, max) = ( desired_size.into().to_physical::(scale_factor), @@ -518,145 +397,3 @@ impl Size { PhysicalSize::new(width, height).into() } } - -impl From> for Size { - #[inline] - fn from(size: PhysicalSize

) -> Size { - Size::Physical(size.cast()) - } -} - -impl From> for Size { - #[inline] - fn from(size: LogicalSize

) -> 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

{ - pub value: P, -} - -impl

LogicalUnit

{ - #[inline] - pub const fn new(value: P) -> Self { - Self { value } - } -} - -impl LogicalUnit

{ - #[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) -> PhysicalUnit { - assert!(validate_scale_factor(scale_factor)); - let u = self.value.into() * scale_factor; - PhysicalUnit::new(u).cast() - } - - #[inline] - pub fn cast(&self) -> LogicalUnit { - LogicalUnit::new(self.value.cast()) - } -} - -impl From

for LogicalUnit

{ - fn from(p: P) -> LogicalUnit

{ - 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

{ - pub value: P, -} - -impl

PhysicalUnit

{ - #[inline] - pub const fn new(value: P) -> Self { - Self { value } - } -} - -impl PhysicalUnit

{ - #[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) -> LogicalUnit { - assert!(validate_scale_factor(scale_factor)); - let u = self.value.into() / scale_factor; - LogicalUnit::new(u).cast() - } - - #[inline] - pub fn cast(&self) -> PhysicalUnit { - PhysicalUnit::new(self.value.cast()) - } -} - -impl From

for PhysicalUnit

{ - fn from(p: P) -> PhysicalUnit

{ - PhysicalUnit::new(p.cast()) - } -} - -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum Unit { - Physical(PhysicalUnit), - Logical(LogicalUnit), -} - -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>(val: S) -> Unit { - val.into() - } - - pub fn to_logical(&self, scale_factor: f64) -> LogicalUnit

{ - match *self { - Unit::Physical(val) => val.to_logical(scale_factor), - Unit::Logical(val) => val.cast(), - } - } - - pub fn to_physical(&self, scale_factor: f64) -> PhysicalUnit

{ - match *self { - Unit::Physical(val) => val.cast(), - Unit::Logical(val) => val.to_physical(scale_factor), - } - } -} - -impl From> for Unit { - #[inline] - fn from(val: PhysicalUnit

) -> Unit { - Unit::Physical(val.cast()) - } -} - -impl From> for Unit { - #[inline] - fn from(val: LogicalUnit

) -> 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( } 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, + pub min_width: Option, /// 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, + pub min_height: Option, /// 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, + pub max_width: Option, /// 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, + pub max_height: Option, } impl WindowSizeConstraints { pub fn new( - min_width: Option, - min_height: Option, - max_width: Option, - max_height: Option, + min_width: Option, + min_height: Option, + max_width: Option, + max_height: Option, ) -> Self { Self { min_width, @@ -1448,82 +1448,80 @@ impl WindowSizeConstraints { } } - pub fn symmetrical(min: Option, max: Option) -> 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(&self, scale_factor: f64) -> PhysicalSize { 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(&self, scale_factor: f64) -> LogicalSize { 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(&self, scale_factor: f64) -> PhysicalSize { 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(&self, scale_factor: f64) -> LogicalSize { 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 = self.min_size_physical(scale_factor); let max_size: PhysicalSize = self.max_size_physical(scale_factor);