use crate::{EditorModel, MainWindow};
use slint::{ComponentHandle, winit_030::WinitWindowAccessor};
use tracing::{debug, warn};
const PREFERRED_WIDTH: f32 = 1600.0;
const PREFERRED_HEIGHT: f32 = 900.0;
const MAX_WIDTH_FRACTION: f32 = 0.94;
const MAX_HEIGHT_FRACTION: f32 = 0.88;
const SMALL_SCREEN_HEIGHT_THRESHOLD: f32 = 820.0;
const SMALL_SCREEN_DOCK_WIDTH: f32 = 600.0;
pub fn fit_initial_window_size(ui: &MainWindow, editor_layout_touched: bool) {
let weak = ui.as_weak();
slint::Timer::single_shot(std::time::Duration::ZERO, move || {
let Some(ui) = weak.upgrade() else {
return;
};
let monitor = ui
.window()
.with_winit_window(|winit_window| {
winit_window
.current_monitor()
.or_else(|| winit_window.primary_monitor())
.map(|monitor| {
let physical = monitor.size();
let scale = monitor.scale_factor();
(
f64::from(physical.width) / scale,
f64::from(physical.height) / scale,
)
})
})
.flatten();
let Some((monitor_width, monitor_height)) = monitor else {
warn!(
"Could not determine the monitor size for the main window -- keeping the \
.slint preferred size; the window stays resizable."
);
return;
};
let current = ui.window().size().to_logical(ui.window().scale_factor());
let target = fitted_size(monitor_width as f32, monitor_height as f32, current);
let fitted_height = target.map_or(current.height, |size| size.height);
if let Some(size) = target {
debug!(
monitor_width,
monitor_height,
width = size.width,
height = size.height,
"Fitting the main window to its monitor"
);
ui.window().set_size(size);
}
apply_small_screen_layout_default(&ui, editor_layout_touched, fitted_height);
});
}
fn apply_small_screen_layout_default(
ui: &MainWindow,
editor_layout_touched: bool,
fitted_height: f32,
) {
if editor_layout_touched || fitted_height >= SMALL_SCREEN_HEIGHT_THRESHOLD {
return;
}
let editor = ui.global::<EditorModel>();
editor.set_inspector_collapsed(true);
editor.set_dock_width(SMALL_SCREEN_DOCK_WIDTH);
}
fn fitted_size(
monitor_width: f32,
monitor_height: f32,
current: slint::LogicalSize,
) -> Option<slint::LogicalSize> {
if monitor_width <= 0.0 || monitor_height <= 0.0 {
return None;
}
let width = PREFERRED_WIDTH
.min(monitor_width * MAX_WIDTH_FRACTION)
.min(current.width.max(1.0));
let height = PREFERRED_HEIGHT
.min(monitor_height * MAX_HEIGHT_FRACTION)
.min(current.height.max(1.0));
let changed = (width - current.width).abs() > 0.5 || (height - current.height).abs() > 0.5;
changed.then(|| slint::LogicalSize::new(width.floor(), height.floor()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn leaves_a_window_that_already_fits_alone() {
let current = slint::LogicalSize::new(1600.0, 900.0);
assert!(fitted_size(2560.0, 1440.0, current).is_none());
}
#[test]
fn shrinks_to_a_scaled_full_hd_monitor() {
let current = slint::LogicalSize::new(1600.0, 900.0);
let size = fitted_size(1536.0, 864.0, current).expect("must shrink");
assert_eq!(size.width, (1536.0f32 * MAX_WIDTH_FRACTION).floor());
assert_eq!(size.height, (864.0f32 * MAX_HEIGHT_FRACTION).floor());
}
#[test]
fn never_grows_a_window_the_os_already_clamped() {
let current = slint::LogicalSize::new(1400.0, 800.0);
assert!(fitted_size(3840.0, 2160.0, current).is_none());
}
#[test]
fn ignores_a_degenerate_monitor() {
let current = slint::LogicalSize::new(1600.0, 900.0);
assert!(fitted_size(0.0, 0.0, current).is_none());
}
}