macro_rules! gen_struct_from_to_impls { ($struct: ident, fields=($($field: ident),*)) => { impl From> for $struct { fn from(source: winit::dpi::$struct) -> Self { Self { $($field: source.$field),* } } } impl From<$struct> for winit::dpi::$struct { fn from(source: $struct) -> Self { Self { $($field: source.$field),* } } } }; } macro_rules! gen_enum_from_to_impls { ($enum: ident, variants=($($variant: ident),*)) => { impl From for $enum { fn from(source: winit::dpi::$enum) -> Self { match source { $(winit::dpi::$enum::$variant(pos) => Self::$variant(pos.into())),* } } } impl From<$enum> for winit::dpi::$enum { fn from(source: $enum) -> Self { match source { $($enum::$variant(pos) => Self::$variant(pos.into())),* } } } }; } #[derive(Debug, Default, Clone, PartialEq)] pub struct PhysicalPosition { pub x: Pixel, pub y: Pixel } impl PhysicalPosition { pub fn to_logical(&self, scale_factor: f64) -> LogicalPosition where Pixel: Into + Clone, LogicalPixel: From { let x = self.x.clone().into(); let y = self.y.clone().into(); LogicalPosition { x: (x / scale_factor).into(), y: (y / scale_factor).into() } } pub fn try_convert_from(source: PhysicalPosition) -> Result where Pixel: TryFrom { Ok(Self { x: source.x.try_into()?, y: source.y.try_into()? }) } } gen_struct_from_to_impls!(PhysicalPosition, fields=(x, y)); #[derive(Debug, Default, Clone, PartialEq)] pub struct LogicalPosition { pub x: Pixel, pub y: Pixel } impl LogicalPosition { pub fn try_convert_from(source: LogicalPosition) -> Result where Pixel: TryFrom { Ok(Self { x: source.x.try_into()?, y: source.y.try_into()? }) } } gen_struct_from_to_impls!(LogicalPosition, fields=(x, y)); #[derive(Debug, Clone, PartialEq)] pub enum Position { Physical(PhysicalPosition), Logical(LogicalPosition) } gen_enum_from_to_impls!(Position, variants=(Physical, Logical)); #[derive(Debug, Default, Clone, PartialEq)] pub struct PhysicalSize { pub width: Pixel, pub height: Pixel } impl PhysicalSize { pub fn to_logical(&self, scale_factor: f64) -> LogicalSize where Pixel: Into + Clone, LogicalPixel: From { let width = self.width.clone().into(); let height = self.height.clone().into(); LogicalSize { width: (width / scale_factor).into(), height: (height / scale_factor).into() } } } impl PhysicalSize { pub fn try_convert_from(source: PhysicalSize) -> Result where Pixel: TryFrom { Ok(Self { width: source.width.try_into()?, height: source.height.try_into()? }) } } gen_struct_from_to_impls!(PhysicalSize, fields=(width, height)); #[derive(Debug, Default, Clone, PartialEq)] pub struct LogicalSize { pub width: Pixel, pub height: Pixel } impl LogicalSize { pub fn try_convert_from(source: LogicalSize) -> Result where Pixel: TryFrom { Ok(Self { width: source.width.try_into()?, height: source.height.try_into()? }) } } gen_struct_from_to_impls!(LogicalSize, fields=(width, height)); #[derive(Debug, Clone, PartialEq)] pub enum Size { Physical(PhysicalSize), Logical(LogicalSize) } gen_enum_from_to_impls!(Size, variants=(Physical, Logical));