mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2025-11-17 23:14:23 +00:00
refactor: unified dimensions system
This commit is contained in:
parent
c3c2690e84
commit
acece2dbf3
12 changed files with 416 additions and 120 deletions
|
|
@ -40,7 +40,7 @@ impl WaylandWindowConfig {
|
||||||
domain_config: DomainWindowConfig,
|
domain_config: DomainWindowConfig,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
height: domain_config.height,
|
height: domain_config.height.value(),
|
||||||
layer: convert_layer(domain_config.layer),
|
layer: convert_layer(domain_config.layer),
|
||||||
margin: domain_config.margin,
|
margin: domain_config.margin,
|
||||||
anchor: convert_anchor(domain_config.anchor),
|
anchor: convert_anchor(domain_config.anchor),
|
||||||
|
|
@ -48,7 +48,7 @@ impl WaylandWindowConfig {
|
||||||
domain_config.keyboard_interactivity,
|
domain_config.keyboard_interactivity,
|
||||||
),
|
),
|
||||||
exclusive_zone: domain_config.exclusive_zone,
|
exclusive_zone: domain_config.exclusive_zone,
|
||||||
scale_factor: domain_config.scale_factor,
|
scale_factor: domain_config.scale_factor.value(),
|
||||||
namespace: domain_config.namespace,
|
namespace: domain_config.namespace,
|
||||||
component_definition,
|
component_definition,
|
||||||
compilation_result,
|
compilation_result,
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,16 @@ use layer_shika_domain::surface_dimensions::SurfaceDimensions;
|
||||||
use slint::PhysicalSize;
|
use slint::PhysicalSize;
|
||||||
|
|
||||||
pub trait SurfaceDimensionsExt {
|
pub trait SurfaceDimensionsExt {
|
||||||
fn logical_size(&self) -> PhysicalSize;
|
fn to_slint_logical_size(&self) -> PhysicalSize;
|
||||||
fn physical_size(&self) -> PhysicalSize;
|
fn to_slint_physical_size(&self) -> PhysicalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SurfaceDimensionsExt for SurfaceDimensions {
|
impl SurfaceDimensionsExt for SurfaceDimensions {
|
||||||
fn logical_size(&self) -> PhysicalSize {
|
fn to_slint_logical_size(&self) -> PhysicalSize {
|
||||||
PhysicalSize::new(self.logical_width, self.logical_height)
|
PhysicalSize::new(self.logical_width(), self.logical_height())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn physical_size(&self) -> PhysicalSize {
|
fn to_slint_physical_size(&self) -> PhysicalSize {
|
||||||
PhysicalSize::new(self.physical_width, self.physical_height)
|
PhysicalSize::new(self.physical_width(), self.physical_height())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use core::result::Result as CoreResult;
|
||||||
use layer_shika_domain::errors::DomainError;
|
use layer_shika_domain::errors::DomainError;
|
||||||
use layer_shika_domain::ports::windowing::RuntimeStatePort;
|
use layer_shika_domain::ports::windowing::RuntimeStatePort;
|
||||||
use layer_shika_domain::surface_dimensions::SurfaceDimensions;
|
use layer_shika_domain::surface_dimensions::SurfaceDimensions;
|
||||||
use log::info;
|
use log::{error, info};
|
||||||
use slint::{LogicalPosition, PhysicalSize, ComponentHandle};
|
use slint::{LogicalPosition, PhysicalSize, ComponentHandle};
|
||||||
use slint::platform::{WindowAdapter, WindowEvent};
|
use slint::platform::{WindowAdapter, WindowEvent};
|
||||||
use slint_interpreter::{ComponentInstance, CompilationResult};
|
use slint_interpreter::{ComponentInstance, CompilationResult};
|
||||||
|
|
@ -179,22 +179,22 @@ impl WindowState {
|
||||||
self.window.set_scale_factor(self.scale_factor);
|
self.window.set_scale_factor(self.scale_factor);
|
||||||
self.window
|
self.window
|
||||||
.set_size(slint::WindowSize::Logical(slint::LogicalSize::new(
|
.set_size(slint::WindowSize::Logical(slint::LogicalSize::new(
|
||||||
dimensions.logical_width as f32,
|
dimensions.logical_width() as f32,
|
||||||
dimensions.logical_height as f32,
|
dimensions.logical_height() as f32,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
ScalingMode::FractionalOnly => {
|
ScalingMode::FractionalOnly => {
|
||||||
self.window.set_scale_factor(dimensions.buffer_scale as f32);
|
self.window.set_scale_factor(dimensions.buffer_scale() as f32);
|
||||||
self.window
|
self.window
|
||||||
.set_size(slint::WindowSize::Logical(slint::LogicalSize::new(
|
.set_size(slint::WindowSize::Logical(slint::LogicalSize::new(
|
||||||
dimensions.logical_width as f32,
|
dimensions.logical_width() as f32,
|
||||||
dimensions.logical_height as f32,
|
dimensions.logical_height() as f32,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
ScalingMode::Integer => {
|
ScalingMode::Integer => {
|
||||||
self.window.set_scale_factor(self.scale_factor);
|
self.window.set_scale_factor(self.scale_factor);
|
||||||
self.window
|
self.window
|
||||||
.set_size(slint::WindowSize::Physical(dimensions.physical_size()));
|
.set_size(slint::WindowSize::Physical(dimensions.to_slint_physical_size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -206,18 +206,18 @@ impl WindowState {
|
||||||
self.surface.set_buffer_scale(1);
|
self.surface.set_buffer_scale(1);
|
||||||
if let Some(viewport) = &self.viewport {
|
if let Some(viewport) = &self.viewport {
|
||||||
viewport.set_destination(
|
viewport.set_destination(
|
||||||
dimensions.logical_width as i32,
|
dimensions.logical_width() as i32,
|
||||||
dimensions.logical_height as i32,
|
dimensions.logical_height() as i32,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ScalingMode::FractionalOnly | ScalingMode::Integer => {
|
ScalingMode::FractionalOnly | ScalingMode::Integer => {
|
||||||
self.surface.set_buffer_scale(dimensions.buffer_scale);
|
self.surface.set_buffer_scale(dimensions.buffer_scale());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.layer_surface
|
self.layer_surface
|
||||||
.set_size(dimensions.logical_width, dimensions.logical_height);
|
.set_size(dimensions.logical_width(), dimensions.logical_height());
|
||||||
self.layer_surface.set_exclusive_zone(self.exclusive_zone);
|
self.layer_surface.set_exclusive_zone(self.exclusive_zone);
|
||||||
self.surface.commit();
|
self.surface.commit();
|
||||||
}
|
}
|
||||||
|
|
@ -229,17 +229,23 @@ impl WindowState {
|
||||||
}
|
}
|
||||||
|
|
||||||
let scale_factor = self.scale_factor();
|
let scale_factor = self.scale_factor();
|
||||||
let dimensions = SurfaceDimensions::calculate(width, height, scale_factor);
|
let dimensions = match SurfaceDimensions::calculate(width, height, scale_factor) {
|
||||||
|
Ok(d) => d,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to calculate surface dimensions: {e}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
let scaling_mode = self.determine_scaling_mode();
|
let scaling_mode = self.determine_scaling_mode();
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Updating window size: logical {}x{}, physical {}x{}, scale {}, buffer_scale {}, mode {:?}",
|
"Updating window size: logical {}x{}, physical {}x{}, scale {}, buffer_scale {}, mode {:?}",
|
||||||
dimensions.logical_width,
|
dimensions.logical_width(),
|
||||||
dimensions.logical_height,
|
dimensions.logical_height(),
|
||||||
dimensions.physical_width,
|
dimensions.physical_width(),
|
||||||
dimensions.physical_height,
|
dimensions.physical_height(),
|
||||||
scale_factor,
|
scale_factor,
|
||||||
dimensions.buffer_scale,
|
dimensions.buffer_scale(),
|
||||||
scaling_mode
|
scaling_mode
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -248,8 +254,8 @@ impl WindowState {
|
||||||
|
|
||||||
info!("Window physical size: {:?}", self.window.size());
|
info!("Window physical size: {:?}", self.window.size());
|
||||||
|
|
||||||
self.size = dimensions.physical_size();
|
self.size = dimensions.to_slint_physical_size();
|
||||||
self.logical_size = dimensions.logical_size();
|
self.logical_size = dimensions.to_slint_logical_size();
|
||||||
self.window.request_redraw();
|
self.window.request_redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use crate::system::WindowingSystem;
|
||||||
use layer_shika_adapters::platform::slint_interpreter::{CompilationResult, Compiler};
|
use layer_shika_adapters::platform::slint_interpreter::{CompilationResult, Compiler};
|
||||||
use layer_shika_domain::errors::DomainError;
|
use layer_shika_domain::errors::DomainError;
|
||||||
use layer_shika_domain::prelude::{
|
use layer_shika_domain::prelude::{
|
||||||
AnchorEdges, KeyboardInteractivity, Layer, Margins, WindowConfig,
|
AnchorEdges, KeyboardInteractivity, Layer, Margins, ScaleFactor, WindowConfig, WindowHeight,
|
||||||
};
|
};
|
||||||
use spin_on::spin_on;
|
use spin_on::spin_on;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
@ -135,10 +135,9 @@ impl LayerShika<NeedsComponent> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayerShika<HasComponent> {
|
impl LayerShika<HasComponent> {
|
||||||
#[must_use]
|
pub fn with_height(mut self, height: u32) -> Result<Self> {
|
||||||
pub const fn with_height(mut self, height: u32) -> Self {
|
self.config.height = WindowHeight::new(height)?;
|
||||||
self.config.height = height;
|
Ok(self)
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -176,10 +175,9 @@ impl LayerShika<HasComponent> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
pub fn with_scale_factor(mut self, scale_factor: f32) -> Result<Self> {
|
||||||
pub const fn with_scale_factor(mut self, scale_factor: f32) -> Self {
|
self.config.scale_factor = ScaleFactor::new(scale_factor)?;
|
||||||
self.config.scale_factor = scale_factor;
|
Ok(self)
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
|
use crate::dimensions::ScaleFactor;
|
||||||
use crate::value_objects::anchor::AnchorEdges;
|
use crate::value_objects::anchor::AnchorEdges;
|
||||||
|
use crate::value_objects::dimensions::WindowHeight;
|
||||||
use crate::value_objects::keyboard_interactivity::KeyboardInteractivity;
|
use crate::value_objects::keyboard_interactivity::KeyboardInteractivity;
|
||||||
use crate::value_objects::layer::Layer;
|
use crate::value_objects::layer::Layer;
|
||||||
use crate::value_objects::margins::Margins;
|
use crate::value_objects::margins::Margins;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct WindowConfig {
|
pub struct WindowConfig {
|
||||||
pub height: u32,
|
pub height: WindowHeight,
|
||||||
pub margin: Margins,
|
pub margin: Margins,
|
||||||
pub exclusive_zone: i32,
|
pub exclusive_zone: i32,
|
||||||
pub scale_factor: f32,
|
pub scale_factor: ScaleFactor,
|
||||||
pub namespace: String,
|
pub namespace: String,
|
||||||
pub layer: Layer,
|
pub layer: Layer,
|
||||||
pub anchor: AnchorEdges,
|
pub anchor: AnchorEdges,
|
||||||
|
|
@ -19,11 +21,11 @@ impl WindowConfig {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
height: 30,
|
height: WindowHeight::default(),
|
||||||
margin: Margins::default(),
|
margin: Margins::default(),
|
||||||
exclusive_zone: -1,
|
exclusive_zone: -1,
|
||||||
namespace: "layer-shika".to_owned(),
|
namespace: "layer-shika".to_owned(),
|
||||||
scale_factor: 1.0,
|
scale_factor: ScaleFactor::default(),
|
||||||
layer: Layer::default(),
|
layer: Layer::default(),
|
||||||
anchor: AnchorEdges::default(),
|
anchor: AnchorEdges::default(),
|
||||||
keyboard_interactivity: KeyboardInteractivity::default(),
|
keyboard_interactivity: KeyboardInteractivity::default(),
|
||||||
|
|
|
||||||
233
domain/src/dimensions.rs
Normal file
233
domain/src/dimensions.rs
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
use crate::errors::DomainError;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub struct LogicalSize {
|
||||||
|
width: f32,
|
||||||
|
height: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LogicalSize {
|
||||||
|
pub fn new(width: f32, height: f32) -> Result<Self, DomainError> {
|
||||||
|
if width <= 0.0 || height <= 0.0 {
|
||||||
|
return Err(DomainError::InvalidInput {
|
||||||
|
message: format!("Dimensions must be positive, got width={width}, height={height}"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if !width.is_finite() || !height.is_finite() {
|
||||||
|
return Err(DomainError::InvalidInput {
|
||||||
|
message: "Dimensions must be finite values".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(Self { width, height })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn from_raw(width: f32, height: f32) -> Self {
|
||||||
|
Self { width, height }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn width(&self) -> f32 {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn height(&self) -> f32 {
|
||||||
|
self.height
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_physical(&self, scale_factor: ScaleFactor) -> PhysicalSize {
|
||||||
|
scale_factor.to_physical(*self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_tuple(&self) -> (f32, f32) {
|
||||||
|
(self.width, self.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LogicalSize {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
width: 120.0,
|
||||||
|
height: 120.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct PhysicalSize {
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PhysicalSize {
|
||||||
|
pub fn new(width: u32, height: u32) -> Result<Self, DomainError> {
|
||||||
|
if width == 0 || height == 0 {
|
||||||
|
return Err(DomainError::InvalidDimensions { width, height });
|
||||||
|
}
|
||||||
|
Ok(Self { width, height })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn from_raw(width: u32, height: u32) -> Self {
|
||||||
|
Self { width, height }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn width(&self) -> u32 {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn height(&self) -> u32 {
|
||||||
|
self.height
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_logical(&self, scale_factor: ScaleFactor) -> LogicalSize {
|
||||||
|
scale_factor.to_logical(*self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_tuple(&self) -> (u32, u32) {
|
||||||
|
(self.width, self.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PhysicalSize {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
width: 120,
|
||||||
|
height: 120,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub struct ScaleFactor(f32);
|
||||||
|
|
||||||
|
impl ScaleFactor {
|
||||||
|
pub fn new(factor: f32) -> Result<Self, DomainError> {
|
||||||
|
if factor <= 0.0 {
|
||||||
|
return Err(DomainError::InvalidInput {
|
||||||
|
message: format!("Scale factor must be positive, got {factor}"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if !factor.is_finite() {
|
||||||
|
return Err(DomainError::InvalidInput {
|
||||||
|
message: "Scale factor must be a finite value".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(Self(factor))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn from_raw(factor: f32) -> Self {
|
||||||
|
Self(factor)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn value(&self) -> f32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
|
||||||
|
pub fn to_physical(&self, logical: LogicalSize) -> PhysicalSize {
|
||||||
|
let width = (logical.width * self.0).round() as u32;
|
||||||
|
let height = (logical.height * self.0).round() as u32;
|
||||||
|
PhysicalSize::from_raw(width.max(1), height.max(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
|
pub fn to_logical(&self, physical: PhysicalSize) -> LogicalSize {
|
||||||
|
let width = physical.width as f32 / self.0;
|
||||||
|
let height = physical.height as f32 / self.0;
|
||||||
|
LogicalSize::from_raw(width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
pub fn buffer_scale(&self) -> i32 {
|
||||||
|
self.0.round() as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scale_coordinate(&self, logical_coord: f32) -> f32 {
|
||||||
|
logical_coord * self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unscale_coordinate(&self, physical_coord: f32) -> f32 {
|
||||||
|
physical_coord / self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ScaleFactor {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(1.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub struct LogicalPosition {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LogicalPosition {
|
||||||
|
pub fn new(x: f32, y: f32) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn x(&self) -> f32 {
|
||||||
|
self.x
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn y(&self) -> f32 {
|
||||||
|
self.y
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
pub fn to_physical(&self, scale_factor: ScaleFactor) -> PhysicalPosition {
|
||||||
|
PhysicalPosition::new(
|
||||||
|
(self.x * scale_factor.value()).round() as i32,
|
||||||
|
(self.y * scale_factor.value()).round() as i32,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_tuple(&self) -> (f32, f32) {
|
||||||
|
(self.x, self.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LogicalPosition {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { x: 0.0, y: 0.0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct PhysicalPosition {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PhysicalPosition {
|
||||||
|
pub const fn new(x: i32, y: i32) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn x(&self) -> i32 {
|
||||||
|
self.x
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn y(&self) -> i32 {
|
||||||
|
self.y
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_precision_loss)]
|
||||||
|
pub fn to_logical(&self, scale_factor: ScaleFactor) -> LogicalPosition {
|
||||||
|
LogicalPosition::new(
|
||||||
|
self.x as f32 / scale_factor.value(),
|
||||||
|
self.y as f32 / scale_factor.value(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_tuple(&self) -> (i32, i32) {
|
||||||
|
(self.x, self.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::derivable_impls)]
|
||||||
|
impl Default for PhysicalPosition {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { x: 0, y: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod dimensions;
|
||||||
pub mod entities;
|
pub mod entities;
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub mod ports;
|
pub mod ports;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
#![allow(clippy::pub_use)]
|
#![allow(clippy::pub_use)]
|
||||||
|
|
||||||
pub use crate::config::WindowConfig;
|
pub use crate::config::WindowConfig;
|
||||||
|
pub use crate::dimensions::{
|
||||||
|
LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, ScaleFactor,
|
||||||
|
};
|
||||||
pub use crate::entities::component::UiComponentHandle;
|
pub use crate::entities::component::UiComponentHandle;
|
||||||
pub use crate::entities::surface::SurfaceHandle;
|
pub use crate::entities::surface::SurfaceHandle;
|
||||||
pub use crate::entities::window::WindowHandle;
|
pub use crate::entities::window::WindowHandle;
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,62 @@
|
||||||
|
use crate::dimensions::{LogicalSize, PhysicalSize, ScaleFactor};
|
||||||
|
use crate::errors::Result;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct SurfaceDimensions {
|
pub struct SurfaceDimensions {
|
||||||
pub logical_width: u32,
|
logical: LogicalSize,
|
||||||
pub logical_height: u32,
|
physical: PhysicalSize,
|
||||||
pub physical_width: u32,
|
scale_factor: ScaleFactor,
|
||||||
pub physical_height: u32,
|
|
||||||
pub buffer_scale: i32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SurfaceDimensions {
|
impl SurfaceDimensions {
|
||||||
#[must_use]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
#[allow(
|
pub fn calculate(
|
||||||
clippy::cast_possible_truncation,
|
logical_width: u32,
|
||||||
clippy::cast_sign_loss,
|
logical_height: u32,
|
||||||
clippy::cast_precision_loss
|
scale_factor: f32,
|
||||||
)]
|
) -> Result<Self> {
|
||||||
pub fn calculate(logical_width: u32, logical_height: u32, scale_factor: f32) -> Self {
|
let logical = LogicalSize::new(logical_width as f32, logical_height as f32)?;
|
||||||
let physical_width = (logical_width as f32 * scale_factor).round() as u32;
|
let scale = ScaleFactor::new(scale_factor)?;
|
||||||
let physical_height = (logical_height as f32 * scale_factor).round() as u32;
|
let physical = scale.to_physical(logical);
|
||||||
let buffer_scale = scale_factor.round() as i32;
|
|
||||||
|
|
||||||
Self {
|
Ok(Self {
|
||||||
logical_width,
|
logical,
|
||||||
logical_height,
|
physical,
|
||||||
physical_width,
|
scale_factor: scale,
|
||||||
physical_height,
|
})
|
||||||
buffer_scale,
|
}
|
||||||
}
|
|
||||||
|
pub const fn logical_size(&self) -> LogicalSize {
|
||||||
|
self.logical
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn physical_size(&self) -> PhysicalSize {
|
||||||
|
self.physical
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn scale_factor(&self) -> ScaleFactor {
|
||||||
|
self.scale_factor
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn buffer_scale(&self) -> i32 {
|
||||||
|
self.scale_factor.buffer_scale()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
|
||||||
|
pub fn logical_width(&self) -> u32 {
|
||||||
|
self.logical.width() as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
|
||||||
|
pub fn logical_height(&self) -> u32 {
|
||||||
|
self.logical.height() as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn physical_width(&self) -> u32 {
|
||||||
|
self.physical.width()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn physical_height(&self) -> u32 {
|
||||||
|
self.physical.height()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,23 @@
|
||||||
#[derive(Debug, Clone, Copy)]
|
use crate::errors::{DomainError, Result};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct WindowHeight(u32);
|
pub struct WindowHeight(u32);
|
||||||
|
|
||||||
impl WindowHeight {
|
impl WindowHeight {
|
||||||
#[must_use]
|
pub fn new(height: u32) -> Result<Self> {
|
||||||
pub const fn new(height: u32) -> Self {
|
if height == 0 {
|
||||||
|
return Err(DomainError::InvalidDimensions {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(Self(height))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn from_raw(height: u32) -> Self {
|
||||||
Self(height)
|
Self(height)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub const fn value(&self) -> u32 {
|
pub const fn value(&self) -> u32 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
@ -18,3 +28,11 @@ impl Default for WindowHeight {
|
||||||
Self(30)
|
Self(30)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u32> for WindowHeight {
|
||||||
|
type Error = DomainError;
|
||||||
|
|
||||||
|
fn try_from(height: u32) -> Result<Self> {
|
||||||
|
Self::new(height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,16 @@
|
||||||
use super::popup_positioning_mode::PopupPositioningMode;
|
use super::popup_positioning_mode::PopupPositioningMode;
|
||||||
|
use crate::dimensions::{LogicalPosition, LogicalSize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct PopupConfig {
|
pub struct PopupConfig {
|
||||||
reference_x: f32,
|
reference_position: LogicalPosition,
|
||||||
reference_y: f32,
|
popup_size: LogicalSize,
|
||||||
width: f32,
|
output_size: LogicalSize,
|
||||||
height: f32,
|
|
||||||
positioning_mode: PopupPositioningMode,
|
positioning_mode: PopupPositioningMode,
|
||||||
output_width: f32,
|
|
||||||
output_height: f32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PopupConfig {
|
impl PopupConfig {
|
||||||
#[must_use]
|
pub fn new(
|
||||||
pub const fn new(
|
|
||||||
reference_x: f32,
|
reference_x: f32,
|
||||||
reference_y: f32,
|
reference_y: f32,
|
||||||
width: f32,
|
width: f32,
|
||||||
|
|
@ -23,62 +20,68 @@ impl PopupConfig {
|
||||||
output_height: f32,
|
output_height: f32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
reference_x,
|
reference_position: LogicalPosition::new(reference_x, reference_y),
|
||||||
reference_y,
|
popup_size: LogicalSize::from_raw(width, height),
|
||||||
width,
|
output_size: LogicalSize::from_raw(output_width, output_height),
|
||||||
height,
|
|
||||||
positioning_mode,
|
positioning_mode,
|
||||||
output_width,
|
|
||||||
output_height,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
pub const fn reference_position(&self) -> LogicalPosition {
|
||||||
|
self.reference_position
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn reference_x(&self) -> f32 {
|
pub const fn reference_x(&self) -> f32 {
|
||||||
self.reference_x
|
self.reference_position.x()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub const fn reference_y(&self) -> f32 {
|
pub const fn reference_y(&self) -> f32 {
|
||||||
self.reference_y
|
self.reference_position.y()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn popup_size(&self) -> LogicalSize {
|
||||||
|
self.popup_size
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub const fn width(&self) -> f32 {
|
pub const fn width(&self) -> f32 {
|
||||||
self.width
|
self.popup_size.width()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub const fn height(&self) -> f32 {
|
pub const fn height(&self) -> f32 {
|
||||||
self.height
|
self.popup_size.height()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn output_size(&self) -> LogicalSize {
|
||||||
|
self.output_size
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub const fn positioning_mode(&self) -> PopupPositioningMode {
|
pub const fn positioning_mode(&self) -> PopupPositioningMode {
|
||||||
self.positioning_mode
|
self.positioning_mode
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
pub fn calculated_top_left_position(&self) -> LogicalPosition {
|
||||||
|
LogicalPosition::new(self.calculated_top_left_x(), self.calculated_top_left_y())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn calculated_top_left_x(&self) -> f32 {
|
pub fn calculated_top_left_x(&self) -> f32 {
|
||||||
let unclamped_x = if self.positioning_mode.center_x() {
|
let unclamped_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_width - self.width;
|
let max_x = self.output_size.width() - self.width();
|
||||||
unclamped_x.max(0.0).min(max_x)
|
unclamped_x.max(0.0).min(max_x)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn calculated_top_left_y(&self) -> f32 {
|
pub fn calculated_top_left_y(&self) -> f32 {
|
||||||
let unclamped_y = if self.positioning_mode.center_y() {
|
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_height - self.height;
|
let max_y = self.output_size.height() - self.height();
|
||||||
unclamped_y.max(0.0).min(max_y)
|
unclamped_y.max(0.0).min(max_y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,42 @@
|
||||||
|
use crate::dimensions::LogicalSize;
|
||||||
use crate::errors::{DomainError, Result};
|
use crate::errors::{DomainError, Result};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
||||||
pub struct PopupDimensions {
|
pub struct PopupDimensions {
|
||||||
width: f32,
|
size: LogicalSize,
|
||||||
height: f32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PopupDimensions {
|
impl PopupDimensions {
|
||||||
#[must_use]
|
pub fn new(width: f32, height: f32) -> Result<Self> {
|
||||||
pub const fn new(width: f32, height: f32) -> Self {
|
let size = LogicalSize::new(width, height)?;
|
||||||
Self { width, height }
|
Ok(Self { size })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn from_logical(size: LogicalSize) -> Self {
|
||||||
|
Self { size }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub const fn width(&self) -> f32 {
|
pub const fn width(&self) -> f32 {
|
||||||
self.width
|
self.size.width()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub const fn height(&self) -> f32 {
|
pub const fn height(&self) -> f32 {
|
||||||
self.height
|
self.size.height()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate(&self) -> Result<()> {
|
pub const fn logical_size(&self) -> LogicalSize {
|
||||||
if self.width <= 0.0 || self.height <= 0.0 {
|
self.size
|
||||||
return Err(DomainError::Configuration {
|
}
|
||||||
message: format!(
|
|
||||||
"Invalid popup dimensions: width={}, height={}. Both must be positive.",
|
pub fn as_tuple(&self) -> (f32, f32) {
|
||||||
self.width, self.height
|
self.size.as_tuple()
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PopupDimensions {
|
impl TryFrom<(f32, f32)> for PopupDimensions {
|
||||||
fn default() -> Self {
|
type Error = DomainError;
|
||||||
Self::new(120.0, 120.0)
|
|
||||||
|
fn try_from((width, height): (f32, f32)) -> Result<Self> {
|
||||||
|
Self::new(width, height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue