From af67a7ffb008c066265f1c338fb0cfa88d80a0ef Mon Sep 17 00:00:00 2001 From: drendog Date: Fri, 14 Nov 2025 22:22:43 +0100 Subject: [PATCH] refactor: consolidate dimensions and scale --- .../src/wayland/surfaces/display_metrics.rs | 53 +++++++++------- .../src/wayland/surfaces/popup_manager.rs | 23 ++++--- crates/domain/src/dimensions.rs | 19 ++++++ crates/domain/src/surface_dimensions.rs | 36 +++++++++-- crates/domain/src/value_objects/mod.rs | 1 - .../domain/src/value_objects/popup_config.rs | 61 +++++++++++-------- .../src/value_objects/popup_dimensions.rs | 42 ------------- 7 files changed, 127 insertions(+), 108 deletions(-) delete mode 100644 crates/domain/src/value_objects/popup_dimensions.rs diff --git a/crates/adapters/src/wayland/surfaces/display_metrics.rs b/crates/adapters/src/wayland/surfaces/display_metrics.rs index 968a910..35beec8 100644 --- a/crates/adapters/src/wayland/surfaces/display_metrics.rs +++ b/crates/adapters/src/wayland/surfaces/display_metrics.rs @@ -1,22 +1,29 @@ +use layer_shika_domain::dimensions::{ + LogicalSize as DomainLogicalSize, PhysicalSize as DomainPhysicalSize, + ScaleFactor as DomainScaleFactor, +}; +use layer_shika_domain::surface_dimensions::SurfaceDimensions; use log::info; use slint::PhysicalSize; use std::cell::RefCell; use std::rc::Rc; pub struct DisplayMetrics { - scale_factor: f32, + surface: SurfaceDimensions, output_size: PhysicalSize, - surface_size: PhysicalSize, has_fractional_scale: bool, } impl DisplayMetrics { #[must_use] pub fn new(scale_factor: f32, has_fractional_scale: bool) -> Self { + let scale = DomainScaleFactor::from_raw(scale_factor); + let logical = DomainLogicalSize::from_raw(1.0, 1.0); + let surface = SurfaceDimensions::from_logical(logical, scale); + Self { - scale_factor, + surface, output_size: PhysicalSize::new(0, 0), - surface_size: PhysicalSize::new(0, 0), has_fractional_scale, } } @@ -24,12 +31,13 @@ impl DisplayMetrics { #[must_use] pub fn with_output_size(mut self, output_size: PhysicalSize) -> Self { self.output_size = output_size; + self.recalculate_surface_size(); self } #[must_use] - pub const fn scale_factor(&self) -> f32 { - self.scale_factor + pub fn scale_factor(&self) -> f32 { + self.surface.scale_factor().value() } #[must_use] @@ -38,8 +46,11 @@ impl DisplayMetrics { } #[must_use] - pub const fn surface_size(&self) -> PhysicalSize { - self.surface_size + pub fn surface_size(&self) -> PhysicalSize { + PhysicalSize::new( + self.surface.physical_width(), + self.surface.physical_height(), + ) } #[must_use] @@ -49,15 +60,16 @@ impl DisplayMetrics { #[allow(clippy::cast_precision_loss)] pub fn update_scale_factor(&mut self, scale_120ths: u32) -> f32 { - let new_scale_factor = scale_120ths as f32 / 120.0; - let old_scale_factor = self.scale_factor; + let new_scale = DomainScaleFactor::from_120ths(scale_120ths); + let new_scale_factor = new_scale.value(); + let old_scale_factor = self.scale_factor(); - if (self.scale_factor - new_scale_factor).abs() > f32::EPSILON { + if (old_scale_factor - new_scale_factor).abs() > f32::EPSILON { info!( "DisplayMetrics: Updating scale factor from {} to {} ({}x)", old_scale_factor, new_scale_factor, scale_120ths ); - self.scale_factor = new_scale_factor; + self.surface.update_scale_factor(new_scale); self.recalculate_surface_size(); } @@ -76,20 +88,15 @@ impl DisplayMetrics { } pub fn update_surface_size(&mut self, surface_size: PhysicalSize) { - self.surface_size = surface_size; + let physical = DomainPhysicalSize::from_raw(surface_size.width, surface_size.height); + self.surface = SurfaceDimensions::from_physical(physical, self.surface.scale_factor()); } - #[allow( - clippy::cast_possible_truncation, - clippy::cast_sign_loss, - clippy::cast_precision_loss - )] fn recalculate_surface_size(&mut self) { - if self.output_size.width > 0 && self.output_size.height > 0 && self.scale_factor > 0.0 { - self.surface_size = PhysicalSize::new( - (self.output_size.width as f32 / self.scale_factor) as u32, - (self.output_size.height as f32 / self.scale_factor) as u32, - ); + if self.output_size.width > 0 && self.output_size.height > 0 && self.scale_factor() > 0.0 { + let physical = + DomainPhysicalSize::from_raw(self.output_size.width, self.output_size.height); + self.surface = SurfaceDimensions::from_physical(physical, self.surface.scale_factor()); } } } diff --git a/crates/adapters/src/wayland/surfaces/popup_manager.rs b/crates/adapters/src/wayland/surfaces/popup_manager.rs index 5e1a6d6..9f8d102 100644 --- a/crates/adapters/src/wayland/surfaces/popup_manager.rs +++ b/crates/adapters/src/wayland/surfaces/popup_manager.rs @@ -2,6 +2,8 @@ use crate::errors::{LayerShikaError, Result}; use crate::rendering::egl::context::EGLContext; use crate::rendering::femtovg::{popup_window::PopupWindow, renderable_window::RenderableWindow}; use crate::wayland::surfaces::display_metrics::SharedDisplayMetrics; +use layer_shika_domain::dimensions::{LogicalSize as DomainLogicalSize, ScaleFactor as DomainScaleFactor}; +use layer_shika_domain::surface_dimensions::SurfaceDimensions; use layer_shika_domain::value_objects::popup_config::PopupConfig; use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode; use layer_shika_domain::value_objects::popup_request::{PopupHandle, PopupRequest}; @@ -233,26 +235,26 @@ impl PopupManager { let output_size = self.output_size(); #[allow(clippy::cast_precision_loss)] - let output_logical_size = ( + let output_logical_size = DomainLogicalSize::from_raw( output_size.width as f32 / scale_factor, output_size.height as f32 / scale_factor, ); + let popup_logical_size = DomainLogicalSize::from_raw(params.width, params.height); + let domain_scale = DomainScaleFactor::from_raw(scale_factor); + let popup_dimensions = SurfaceDimensions::from_logical(popup_logical_size, domain_scale); + let popup_config = PopupConfig::new( params.reference_x, params.reference_y, - params.width, - params.height, + popup_dimensions, params.positioning_mode, - output_logical_size.0, - output_logical_size.1, + output_logical_size, ); - #[allow(clippy::cast_possible_truncation)] - #[allow(clippy::cast_sign_loss)] let popup_size = PhysicalSize::new( - (params.width * scale_factor) as u32, - (params.height * scale_factor) as u32, + popup_dimensions.physical_width(), + popup_dimensions.physical_height(), ); info!("Popup physical size: {popup_size:?}"); @@ -479,7 +481,8 @@ impl PopupManager { if let Some(popup_key) = self.find_popup_key_by_fractional_scale_id(&fractional_scale_id) { if let Some(popup_window) = self.get_popup_window(popup_key) { - let new_scale_factor = scale_120ths as f32 / 120.0; + let new_scale = DomainScaleFactor::from_120ths(scale_120ths); + let new_scale_factor = new_scale.value(); info!("Updating popup scale factor to {new_scale_factor} ({scale_120ths}x)"); popup_window.set_scale_factor(new_scale_factor); popup_window.request_redraw(); diff --git a/crates/domain/src/dimensions.rs b/crates/domain/src/dimensions.rs index e56cc89..56c8d32 100644 --- a/crates/domain/src/dimensions.rs +++ b/crates/domain/src/dimensions.rs @@ -40,6 +40,20 @@ impl LogicalSize { pub fn as_tuple(&self) -> (f32, f32) { (self.width, self.height) } + + pub fn clamp_position( + &self, + position: LogicalPosition, + bounds: LogicalSize, + ) -> LogicalPosition { + let max_x = (bounds.width - self.width).max(0.0); + let max_y = (bounds.height - self.height).max(0.0); + + LogicalPosition::new( + position.x().max(0.0).min(max_x), + position.y().max(0.0).min(max_y), + ) + } } impl Default for LogicalSize { @@ -117,6 +131,11 @@ impl ScaleFactor { Self(factor) } + #[allow(clippy::cast_precision_loss)] + pub fn from_120ths(scale_120ths: u32) -> Self { + Self(scale_120ths as f32 / 120.0) + } + pub const fn value(&self) -> f32 { self.0 } diff --git a/crates/domain/src/surface_dimensions.rs b/crates/domain/src/surface_dimensions.rs index f1c3e04..182c484 100644 --- a/crates/domain/src/surface_dimensions.rs +++ b/crates/domain/src/surface_dimensions.rs @@ -10,11 +10,7 @@ pub struct SurfaceDimensions { impl SurfaceDimensions { #[allow(clippy::cast_precision_loss)] - pub fn calculate( - logical_width: u32, - logical_height: u32, - scale_factor: f32, - ) -> Result { + pub fn calculate(logical_width: u32, logical_height: u32, scale_factor: f32) -> Result { let logical = LogicalSize::new(logical_width as f32, logical_height as f32)?; let scale = ScaleFactor::new(scale_factor)?; let physical = scale.to_physical(logical); @@ -26,6 +22,36 @@ impl SurfaceDimensions { }) } + pub fn from_logical(logical: LogicalSize, scale_factor: ScaleFactor) -> Self { + let physical = scale_factor.to_physical(logical); + Self { + logical, + physical, + scale_factor, + } + } + + pub fn from_physical(physical: PhysicalSize, scale_factor: ScaleFactor) -> Self { + let logical = scale_factor.to_logical(physical); + Self { + logical, + physical, + scale_factor, + } + } + + #[must_use] + pub fn with_scale_factor(mut self, scale_factor: ScaleFactor) -> Self { + self.scale_factor = scale_factor; + self.physical = scale_factor.to_physical(self.logical); + self + } + + pub fn update_scale_factor(&mut self, scale_factor: ScaleFactor) { + self.scale_factor = scale_factor; + self.physical = scale_factor.to_physical(self.logical); + } + pub const fn logical_size(&self) -> LogicalSize { self.logical } diff --git a/crates/domain/src/value_objects/mod.rs b/crates/domain/src/value_objects/mod.rs index 2e5b4f0..28ffb54 100644 --- a/crates/domain/src/value_objects/mod.rs +++ b/crates/domain/src/value_objects/mod.rs @@ -4,6 +4,5 @@ pub mod keyboard_interactivity; pub mod layer; pub mod margins; pub mod popup_config; -pub mod popup_dimensions; pub mod popup_positioning_mode; pub mod popup_request; diff --git a/crates/domain/src/value_objects/popup_config.rs b/crates/domain/src/value_objects/popup_config.rs index 7e0c10c..6c62631 100644 --- a/crates/domain/src/value_objects/popup_config.rs +++ b/crates/domain/src/value_objects/popup_config.rs @@ -1,11 +1,12 @@ use super::popup_positioning_mode::PopupPositioningMode; use crate::dimensions::{LogicalPosition, LogicalSize}; +use crate::surface_dimensions::SurfaceDimensions; #[derive(Debug, Clone, Copy)] pub struct PopupConfig { reference_position: LogicalPosition, - popup_size: LogicalSize, - output_size: LogicalSize, + dimensions: SurfaceDimensions, + output_bounds: LogicalSize, positioning_mode: PopupPositioningMode, } @@ -13,16 +14,14 @@ impl PopupConfig { pub fn new( reference_x: f32, reference_y: f32, - width: f32, - height: f32, + dimensions: SurfaceDimensions, positioning_mode: PopupPositioningMode, - output_width: f32, - output_height: f32, + output_bounds: LogicalSize, ) -> Self { Self { reference_position: LogicalPosition::new(reference_x, reference_y), - popup_size: LogicalSize::from_raw(width, height), - output_size: LogicalSize::from_raw(output_width, output_height), + dimensions, + output_bounds, positioning_mode, } } @@ -39,20 +38,24 @@ impl PopupConfig { self.reference_position.y() } - pub const fn popup_size(&self) -> LogicalSize { - self.popup_size + pub const fn dimensions(&self) -> SurfaceDimensions { + self.dimensions } - pub const fn width(&self) -> f32 { - self.popup_size.width() + pub fn popup_size(&self) -> LogicalSize { + self.dimensions.logical_size() } - pub const fn height(&self) -> f32 { - self.popup_size.height() + pub fn width(&self) -> f32 { + self.dimensions.logical_size().width() } - pub const fn output_size(&self) -> LogicalSize { - self.output_size + pub fn height(&self) -> f32 { + self.dimensions.logical_size().height() + } + + pub const fn output_bounds(&self) -> LogicalSize { + self.output_bounds } pub const fn positioning_mode(&self) -> PopupPositioningMode { @@ -60,28 +63,32 @@ impl PopupConfig { } pub fn calculated_top_left_position(&self) -> LogicalPosition { - LogicalPosition::new(self.calculated_top_left_x(), self.calculated_top_left_y()) + let unclamped = self.calculate_unclamped_position(); + self.popup_size() + .clamp_position(unclamped, self.output_bounds) } - pub fn calculated_top_left_x(&self) -> f32 { - let unclamped_x = if self.positioning_mode.center_x() { + fn calculate_unclamped_position(&self) -> LogicalPosition { + let x = if self.positioning_mode.center_x() { self.reference_x() - (self.width() / 2.0) } else { self.reference_x() }; - let max_x = self.output_size.width() - self.width(); - unclamped_x.max(0.0).min(max_x) - } - - pub fn calculated_top_left_y(&self) -> f32 { - let unclamped_y = if self.positioning_mode.center_y() { + let y = if self.positioning_mode.center_y() { self.reference_y() - (self.height() / 2.0) } else { self.reference_y() }; - let max_y = self.output_size.height() - self.height(); - unclamped_y.max(0.0).min(max_y) + LogicalPosition::new(x, y) + } + + pub fn calculated_top_left_x(&self) -> f32 { + self.calculated_top_left_position().x() + } + + pub fn calculated_top_left_y(&self) -> f32 { + self.calculated_top_left_position().y() } } diff --git a/crates/domain/src/value_objects/popup_dimensions.rs b/crates/domain/src/value_objects/popup_dimensions.rs deleted file mode 100644 index 6ab7248..0000000 --- a/crates/domain/src/value_objects/popup_dimensions.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::dimensions::LogicalSize; -use crate::errors::{DomainError, Result}; - -#[derive(Debug, Clone, Copy, PartialEq, Default)] -pub struct PopupDimensions { - size: LogicalSize, -} - -impl PopupDimensions { - pub fn new(width: f32, height: f32) -> Result { - let size = LogicalSize::new(width, height)?; - Ok(Self { size }) - } - - pub const fn from_logical(size: LogicalSize) -> Self { - Self { size } - } - - pub const fn width(&self) -> f32 { - self.size.width() - } - - pub const fn height(&self) -> f32 { - self.size.height() - } - - pub const fn logical_size(&self) -> LogicalSize { - self.size - } - - pub fn as_tuple(&self) -> (f32, f32) { - self.size.as_tuple() - } -} - -impl TryFrom<(f32, f32)> for PopupDimensions { - type Error = DomainError; - - fn try_from((width, height): (f32, f32)) -> Result { - Self::new(width, height) - } -}