refactor: consolidate dimensions and scale

This commit is contained in:
drendog 2025-11-14 22:22:43 +01:00
parent cc385fde3b
commit af67a7ffb0
Signed by: dwenya
GPG key ID: 8DD77074645332D0
7 changed files with 127 additions and 108 deletions

View file

@ -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 log::info;
use slint::PhysicalSize; use slint::PhysicalSize;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
pub struct DisplayMetrics { pub struct DisplayMetrics {
scale_factor: f32, surface: SurfaceDimensions,
output_size: PhysicalSize, output_size: PhysicalSize,
surface_size: PhysicalSize,
has_fractional_scale: bool, has_fractional_scale: bool,
} }
impl DisplayMetrics { impl DisplayMetrics {
#[must_use] #[must_use]
pub fn new(scale_factor: f32, has_fractional_scale: bool) -> Self { 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 { Self {
scale_factor, surface,
output_size: PhysicalSize::new(0, 0), output_size: PhysicalSize::new(0, 0),
surface_size: PhysicalSize::new(0, 0),
has_fractional_scale, has_fractional_scale,
} }
} }
@ -24,12 +31,13 @@ impl DisplayMetrics {
#[must_use] #[must_use]
pub fn with_output_size(mut self, output_size: PhysicalSize) -> Self { pub fn with_output_size(mut self, output_size: PhysicalSize) -> Self {
self.output_size = output_size; self.output_size = output_size;
self.recalculate_surface_size();
self self
} }
#[must_use] #[must_use]
pub const fn scale_factor(&self) -> f32 { pub fn scale_factor(&self) -> f32 {
self.scale_factor self.surface.scale_factor().value()
} }
#[must_use] #[must_use]
@ -38,8 +46,11 @@ impl DisplayMetrics {
} }
#[must_use] #[must_use]
pub const fn surface_size(&self) -> PhysicalSize { pub fn surface_size(&self) -> PhysicalSize {
self.surface_size PhysicalSize::new(
self.surface.physical_width(),
self.surface.physical_height(),
)
} }
#[must_use] #[must_use]
@ -49,15 +60,16 @@ impl DisplayMetrics {
#[allow(clippy::cast_precision_loss)] #[allow(clippy::cast_precision_loss)]
pub fn update_scale_factor(&mut self, scale_120ths: u32) -> f32 { pub fn update_scale_factor(&mut self, scale_120ths: u32) -> f32 {
let new_scale_factor = scale_120ths as f32 / 120.0; let new_scale = DomainScaleFactor::from_120ths(scale_120ths);
let old_scale_factor = self.scale_factor; 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!( info!(
"DisplayMetrics: Updating scale factor from {} to {} ({}x)", "DisplayMetrics: Updating scale factor from {} to {} ({}x)",
old_scale_factor, new_scale_factor, scale_120ths 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(); self.recalculate_surface_size();
} }
@ -76,20 +88,15 @@ impl DisplayMetrics {
} }
pub fn update_surface_size(&mut self, surface_size: PhysicalSize) { 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) { fn recalculate_surface_size(&mut self) {
if self.output_size.width > 0 && self.output_size.height > 0 && self.scale_factor > 0.0 { if self.output_size.width > 0 && self.output_size.height > 0 && self.scale_factor() > 0.0 {
self.surface_size = PhysicalSize::new( let physical =
(self.output_size.width as f32 / self.scale_factor) as u32, DomainPhysicalSize::from_raw(self.output_size.width, self.output_size.height);
(self.output_size.height as f32 / self.scale_factor) as u32, self.surface = SurfaceDimensions::from_physical(physical, self.surface.scale_factor());
);
} }
} }
} }

View file

@ -2,6 +2,8 @@ use crate::errors::{LayerShikaError, Result};
use crate::rendering::egl::context::EGLContext; use crate::rendering::egl::context::EGLContext;
use crate::rendering::femtovg::{popup_window::PopupWindow, renderable_window::RenderableWindow}; use crate::rendering::femtovg::{popup_window::PopupWindow, renderable_window::RenderableWindow};
use crate::wayland::surfaces::display_metrics::SharedDisplayMetrics; 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_config::PopupConfig;
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode; use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
use layer_shika_domain::value_objects::popup_request::{PopupHandle, PopupRequest}; use layer_shika_domain::value_objects::popup_request::{PopupHandle, PopupRequest};
@ -233,26 +235,26 @@ impl PopupManager {
let output_size = self.output_size(); let output_size = self.output_size();
#[allow(clippy::cast_precision_loss)] #[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.width as f32 / scale_factor,
output_size.height 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( let popup_config = PopupConfig::new(
params.reference_x, params.reference_x,
params.reference_y, params.reference_y,
params.width, popup_dimensions,
params.height,
params.positioning_mode, params.positioning_mode,
output_logical_size.0, output_logical_size,
output_logical_size.1,
); );
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
let popup_size = PhysicalSize::new( let popup_size = PhysicalSize::new(
(params.width * scale_factor) as u32, popup_dimensions.physical_width(),
(params.height * scale_factor) as u32, popup_dimensions.physical_height(),
); );
info!("Popup physical size: {popup_size:?}"); 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_key) = self.find_popup_key_by_fractional_scale_id(&fractional_scale_id) {
if let Some(popup_window) = self.get_popup_window(popup_key) { 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)"); info!("Updating popup scale factor to {new_scale_factor} ({scale_120ths}x)");
popup_window.set_scale_factor(new_scale_factor); popup_window.set_scale_factor(new_scale_factor);
popup_window.request_redraw(); popup_window.request_redraw();

View file

@ -40,6 +40,20 @@ impl LogicalSize {
pub fn as_tuple(&self) -> (f32, f32) { pub fn as_tuple(&self) -> (f32, f32) {
(self.width, self.height) (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 { impl Default for LogicalSize {
@ -117,6 +131,11 @@ impl ScaleFactor {
Self(factor) 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 { pub const fn value(&self) -> f32 {
self.0 self.0
} }

View file

@ -10,11 +10,7 @@ pub struct SurfaceDimensions {
impl SurfaceDimensions { impl SurfaceDimensions {
#[allow(clippy::cast_precision_loss)] #[allow(clippy::cast_precision_loss)]
pub fn calculate( pub fn calculate(logical_width: u32, logical_height: u32, scale_factor: f32) -> Result<Self> {
logical_width: u32,
logical_height: u32,
scale_factor: f32,
) -> Result<Self> {
let logical = LogicalSize::new(logical_width as f32, logical_height as f32)?; let logical = LogicalSize::new(logical_width as f32, logical_height as f32)?;
let scale = ScaleFactor::new(scale_factor)?; let scale = ScaleFactor::new(scale_factor)?;
let physical = scale.to_physical(logical); 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 { pub const fn logical_size(&self) -> LogicalSize {
self.logical self.logical
} }

View file

@ -4,6 +4,5 @@ pub mod keyboard_interactivity;
pub mod layer; pub mod layer;
pub mod margins; pub mod margins;
pub mod popup_config; pub mod popup_config;
pub mod popup_dimensions;
pub mod popup_positioning_mode; pub mod popup_positioning_mode;
pub mod popup_request; pub mod popup_request;

View file

@ -1,11 +1,12 @@
use super::popup_positioning_mode::PopupPositioningMode; use super::popup_positioning_mode::PopupPositioningMode;
use crate::dimensions::{LogicalPosition, LogicalSize}; use crate::dimensions::{LogicalPosition, LogicalSize};
use crate::surface_dimensions::SurfaceDimensions;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct PopupConfig { pub struct PopupConfig {
reference_position: LogicalPosition, reference_position: LogicalPosition,
popup_size: LogicalSize, dimensions: SurfaceDimensions,
output_size: LogicalSize, output_bounds: LogicalSize,
positioning_mode: PopupPositioningMode, positioning_mode: PopupPositioningMode,
} }
@ -13,16 +14,14 @@ impl PopupConfig {
pub fn new( pub fn new(
reference_x: f32, reference_x: f32,
reference_y: f32, reference_y: f32,
width: f32, dimensions: SurfaceDimensions,
height: f32,
positioning_mode: PopupPositioningMode, positioning_mode: PopupPositioningMode,
output_width: f32, output_bounds: LogicalSize,
output_height: f32,
) -> Self { ) -> Self {
Self { Self {
reference_position: LogicalPosition::new(reference_x, reference_y), reference_position: LogicalPosition::new(reference_x, reference_y),
popup_size: LogicalSize::from_raw(width, height), dimensions,
output_size: LogicalSize::from_raw(output_width, output_height), output_bounds,
positioning_mode, positioning_mode,
} }
} }
@ -39,20 +38,24 @@ impl PopupConfig {
self.reference_position.y() self.reference_position.y()
} }
pub const fn popup_size(&self) -> LogicalSize { pub const fn dimensions(&self) -> SurfaceDimensions {
self.popup_size self.dimensions
} }
pub const fn width(&self) -> f32 { pub fn popup_size(&self) -> LogicalSize {
self.popup_size.width() self.dimensions.logical_size()
} }
pub const fn height(&self) -> f32 { pub fn width(&self) -> f32 {
self.popup_size.height() self.dimensions.logical_size().width()
} }
pub const fn output_size(&self) -> LogicalSize { pub fn height(&self) -> f32 {
self.output_size self.dimensions.logical_size().height()
}
pub const fn output_bounds(&self) -> LogicalSize {
self.output_bounds
} }
pub const fn positioning_mode(&self) -> PopupPositioningMode { pub const fn positioning_mode(&self) -> PopupPositioningMode {
@ -60,28 +63,32 @@ impl PopupConfig {
} }
pub fn calculated_top_left_position(&self) -> LogicalPosition { 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 { fn calculate_unclamped_position(&self) -> LogicalPosition {
let unclamped_x = if self.positioning_mode.center_x() { let x = if self.positioning_mode.center_x() {
self.reference_x() - (self.width() / 2.0) self.reference_x() - (self.width() / 2.0)
} else { } else {
self.reference_x() self.reference_x()
}; };
let max_x = self.output_size.width() - self.width(); let y = if self.positioning_mode.center_y() {
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() {
self.reference_y() - (self.height() / 2.0) self.reference_y() - (self.height() / 2.0)
} else { } else {
self.reference_y() self.reference_y()
}; };
let max_y = self.output_size.height() - self.height(); LogicalPosition::new(x, y)
unclamped_y.max(0.0).min(max_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()
} }
} }

View file

@ -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<Self> {
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> {
Self::new(width, height)
}
}