From 78d1f184142e8b265ef38ba57cbe00340582e6bc Mon Sep 17 00:00:00 2001 From: "L. Wlcek" Date: Sat, 27 Sep 2025 16:24:42 +0200 Subject: [PATCH 1/2] reimplemented variable window size --- core/src/window.rs | 2 + core/src/window/settings.rs | 4 +- core/src/window/size.rs | 67 ++++++++++++++++ examples/solar_system/src/main.rs | 2 +- src/application.rs | 6 +- test/src/simulator.rs | 2 +- tester/src/lib.rs | 10 ++- winit/src/conversion.rs | 123 ++++++++++++++++++------------ 8 files changed, 158 insertions(+), 58 deletions(-) create mode 100644 core/src/window/size.rs diff --git a/core/src/window.rs b/core/src/window.rs index d0e741d86e..5705df2d5e 100644 --- a/core/src/window.rs +++ b/core/src/window.rs @@ -10,6 +10,7 @@ mod level; mod mode; mod position; mod redraw_request; +mod size; mod user_attention; pub use direction::Direction; @@ -22,4 +23,5 @@ pub use position::Position; pub use redraw_request::RedrawRequest; pub use screenshot::Screenshot; pub use settings::Settings; +pub use size::Size; pub use user_attention::UserAttention; diff --git a/core/src/window/settings.rs b/core/src/window/settings.rs index 94bcfd78b4..8f22d2be32 100644 --- a/core/src/window/settings.rs +++ b/core/src/window/settings.rs @@ -33,7 +33,7 @@ pub use platform::PlatformSpecific; #[derive(Debug, Clone)] pub struct Settings { /// The initial logical dimensions of the window. - pub size: Size, + pub size: crate::window::Size, /// Whether the window should start maximized. pub maximized: bool, @@ -85,7 +85,7 @@ pub struct Settings { impl Default for Settings { fn default() -> Self { Self { - size: Size::new(1024.0, 768.0), + size: crate::window::Size::default(), maximized: false, fullscreen: false, position: Position::default(), diff --git a/core/src/window/size.rs b/core/src/window/size.rs new file mode 100644 index 0000000000..98d288479e --- /dev/null +++ b/core/src/window/size.rs @@ -0,0 +1,67 @@ +use std::{fmt::Debug, ops::Add, sync::Arc}; + +/// The size of a window upon creation. +#[derive(Clone)] +pub enum Size { + /// Sets the size of the window directly. + Fixed(crate::Size), + /// Allows you to set the size of the window based on the monitors resolution + /// + /// The function receives the the monitor's resolution as input. + FromScreensize(Arc crate::Size>), +} + +impl Size { + /// Returns the default fixed windows size. + /// The output is an [`iced::Size`]. + /// + /// If you want to populate the [`iced::window::Settings`], you can use the `default()` function instead. + pub fn default_window_size() -> crate::Size { + crate::Size::new(1024.0, 768.0) + } + + fn from_screen_size( + func: impl 'static + Send + Sync + Fn(crate::Size) -> crate::Size, + ) -> Self { + Self::FromScreensize(Arc::new(func)) + } +} + +impl Default for Size { + fn default() -> Self { + Self::Fixed(Self::default_window_size()) + } +} + +impl Debug for Size { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Fixed(size) => write!(f, "Fixed({:?})", size), + Self::FromScreensize(_) => { + write!(f, "FromScreensize(...)") + } + } + } +} + +impl From for Size +where + Source: Into, +{ + fn from(value: Source) -> Self { + Self::Fixed(value.into()) + } +} + +impl Add for Size { + type Output = Self; + + fn add(self, other: crate::Size) -> Self { + match self { + Self::Fixed(size) => Self::Fixed(size + other), + Self::FromScreensize(func) => { + Self::from_screen_size(move |size| func(size) + other) + } + } + } +} diff --git a/examples/solar_system/src/main.rs b/examples/solar_system/src/main.rs index 958fc672ec..a53fb6c9fe 100644 --- a/examples/solar_system/src/main.rs +++ b/examples/solar_system/src/main.rs @@ -89,7 +89,7 @@ impl State { pub fn new() -> State { let now = Instant::now(); - let size = window::Settings::default().size; + let size = window::Size::default_window_size(); State { sun: image::Handle::from_bytes( diff --git a/src/application.rs b/src/application.rs index f007e9dc3c..461b41d3f0 100644 --- a/src/application.rs +++ b/src/application.rs @@ -36,8 +36,8 @@ use crate::shell; use crate::theme; use crate::window; use crate::{ - Element, Executor, Font, Preset, Result, Settings, Size, Subscription, - Task, Theme, + Element, Executor, Font, Preset, Result, Settings, Subscription, Task, + Theme, }; use iced_debug as debug; @@ -277,7 +277,7 @@ impl Application

{ } /// Sets the [`window::Settings::size`] of the [`Application`]. - pub fn window_size(self, size: impl Into) -> Self { + pub fn window_size(self, size: impl Into) -> Self { Self { window: window::Settings { size: size.into(), diff --git a/test/src/simulator.rs b/test/src/simulator.rs index b0a9a5d171..5a8caf8f9a 100644 --- a/test/src/simulator.rs +++ b/test/src/simulator.rs @@ -53,7 +53,7 @@ where settings: Settings, element: impl Into>, ) -> Self { - Self::with_size(settings, window::Settings::default().size, element) + Self::with_size(settings, window::Size::default_window_size(), element) } /// Creates a new [`Simulator`] with the given [`Settings`] and size. diff --git a/tester/src/lib.rs b/tester/src/lib.rs index 334f17bcdb..8b14598d79 100644 --- a/tester/src/lib.rs +++ b/tester/src/lib.rs @@ -177,9 +177,17 @@ impl Tester

{ let (state, _) = program.boot(); let window = program.window().unwrap_or_default(); + let size = match window.size { + window::Size::Fixed(size) => size, + // Since there is no monitor, we fall back to a default size + window::Size::FromScreensize(_) => { + window::Size::default_window_size() + } + }; + Self { mode: emulator::Mode::default(), - viewport: window.size, + viewport: size, presets: combo_box::State::new( program .presets() diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index 250918ab78..3999832236 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -22,10 +22,6 @@ pub fn window_attributes( attributes = attributes .with_title(title) - .with_inner_size(winit::dpi::LogicalSize { - width: settings.size.width * scale_factor, - height: settings.size.height * scale_factor, - }) .with_maximized(settings.maximized) .with_fullscreen( settings @@ -45,8 +41,17 @@ pub fn window_attributes( .with_window_level(window_level(settings.level)) .with_visible(settings.visible); + let size = size(primary_monitor.as_ref(), settings.size, scale_factor); + + if let Some(size) = size { + attributes = attributes.with_inner_size(winit::dpi::LogicalSize { + width: size.width, + height: size.height, + }); + } + if let Some(position) = - position(primary_monitor.as_ref(), settings.size, settings.position) + position(primary_monitor.as_ref(), size, settings.position) { attributes = attributes.with_position(position); } @@ -336,12 +341,36 @@ pub fn window_level(level: window::Level) -> winit::window::WindowLevel { } } +/// Converts a [`window::Size`] into a [`winit`] logical size for a given monitor and scale factor. +/// +/// [`winit`]: https://github.com/rust-windowing/winit +pub fn size( + monitor: Option<&winit::monitor::MonitorHandle>, + size: window::Size, + scale_factor: f32, +) -> Option { + let monitor = monitor?; + + match size { + window::Size::Fixed(size) => Some(size * scale_factor), + window::Size::FromScreensize(to_size) => { + let resolution: winit::dpi::LogicalSize = + monitor.size().to_logical(monitor.scale_factor()); + + let size = to_size(Size::new(resolution.width, resolution.height)) + * scale_factor; + + Some(size) + } + } +} + /// Converts a [`window::Position`] into a [`winit`] logical position for a given monitor. /// /// [`winit`]: https://github.com/rust-windowing/winit pub fn position( monitor: Option<&winit::monitor::MonitorHandle>, - size: Size, + size: Option, position: window::Position, ) -> Option { match position { @@ -353,57 +382,51 @@ pub fn position( })) } window::Position::SpecificWith(to_position) => { - if let Some(monitor) = monitor { - let start = monitor.position(); + let (monitor, size) = monitor.zip(size)?; + let start = monitor.position(); - let resolution: winit::dpi::LogicalSize = - monitor.size().to_logical(monitor.scale_factor()); - - let position = to_position( - size, - Size::new(resolution.width, resolution.height), - ); + let resolution: winit::dpi::LogicalSize = + monitor.size().to_logical(monitor.scale_factor()); - let centered: winit::dpi::PhysicalPosition = - winit::dpi::LogicalPosition { - x: position.x, - y: position.y, - } - .to_physical(monitor.scale_factor()); + let position = to_position( + size, + Size::new(resolution.width, resolution.height), + ); - Some(winit::dpi::Position::Physical( - winit::dpi::PhysicalPosition { - x: start.x + centered.x, - y: start.y + centered.y, - }, - )) - } else { - None - } + let centered: winit::dpi::PhysicalPosition = + winit::dpi::LogicalPosition { + x: position.x, + y: position.y, + } + .to_physical(monitor.scale_factor()); + + Some(winit::dpi::Position::Physical( + winit::dpi::PhysicalPosition { + x: start.x + centered.x, + y: start.y + centered.y, + }, + )) } window::Position::Centered => { - if let Some(monitor) = monitor { - let start = monitor.position(); + let (monitor, size) = monitor.zip(size)?; + let start = monitor.position(); - let resolution: winit::dpi::LogicalSize = - monitor.size().to_logical(monitor.scale_factor()); - - let centered: winit::dpi::PhysicalPosition = - winit::dpi::LogicalPosition { - x: (resolution.width - f64::from(size.width)) / 2.0, - y: (resolution.height - f64::from(size.height)) / 2.0, - } - .to_physical(monitor.scale_factor()); + let resolution: winit::dpi::LogicalSize = + monitor.size().to_logical(monitor.scale_factor()); - Some(winit::dpi::Position::Physical( - winit::dpi::PhysicalPosition { - x: start.x + centered.x, - y: start.y + centered.y, - }, - )) - } else { - None - } + let centered: winit::dpi::PhysicalPosition = + winit::dpi::LogicalPosition { + x: (resolution.width - f64::from(size.width)) / 2.0, + y: (resolution.height - f64::from(size.height)) / 2.0, + } + .to_physical(monitor.scale_factor()); + + Some(winit::dpi::Position::Physical( + winit::dpi::PhysicalPosition { + x: start.x + centered.x, + y: start.y + centered.y, + }, + )) } } } From 8996835ad3ed35bcbf128d8926f7e85158b9e300 Mon Sep 17 00:00:00 2001 From: "L. Wlcek" Date: Thu, 9 Oct 2025 16:56:59 +0200 Subject: [PATCH 2/2] fix from_screen_size helper function not public --- core/src/window/size.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/window/size.rs b/core/src/window/size.rs index 98d288479e..3d0b6b2aa6 100644 --- a/core/src/window/size.rs +++ b/core/src/window/size.rs @@ -20,7 +20,7 @@ impl Size { crate::Size::new(1024.0, 768.0) } - fn from_screen_size( + pub fn from_screen_size( func: impl 'static + Send + Sync + Fn(crate::Size) -> crate::Size, ) -> Self { Self::FromScreensize(Arc::new(func))