From f4cb103120ca72dbabd9eb65902ce40a34866b9d Mon Sep 17 00:00:00 2001 From: Bruno-Alumn <171815746+Bruno-Alumn@users.noreply.github.com> Date: Fri, 30 Oct 2026 15:36:03 +0100 Subject: [PATCH] Export sizes keep the pixels typed (#3300) The pixel fields of Export > Image Sizing had a step of 16, and a typed value is snapped to the step, so 1080 became 1088 and 3000 became 3008. Use whole pixels; keyboard nudges stay about 100 px (range / 200). --- crates/ui-egui/src/dialogs/export.rs | 7 +++--- crates/ui-egui/src/headless/tests.rs | 36 ++++++++++++++++++++++++++++ docs/whats-new.md | 6 +++++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/crates/ui-egui/src/dialogs/export.rs b/crates/ui-egui/src/dialogs/export.rs index ce9cffe77..9d7ebcf28 100644 --- a/crates/ui-egui/src/dialogs/export.rs +++ b/crates/ui-egui/src/dialogs/export.rs @@ -179,11 +179,12 @@ pub(super) const QUALITY: ControlSpec = spec("export.quality", "Quality", 1.0, 1 pub(super) const LIMIT_KB: ControlSpec = spec("export.limitKb", "Limit file size (KB, 0 = off)", 0.0, 20_000.0, 0.0, 10.0); -const SIZE_PX: ControlSpec = spec("export.sizePx", "Pixels", 16.0, 20_000.0, 2048.0, 16.0); +// whole pixels: a typed size is snapped to the step, and 1080 or 1350 must stay what was typed +const SIZE_PX: ControlSpec = spec("export.sizePx", "Pixels", 16.0, 20_000.0, 2048.0, 1.0); -const SIZE_W: ControlSpec = spec("export.sizeW", "Width (px)", 16.0, 20_000.0, 2048.0, 16.0); +const SIZE_W: ControlSpec = spec("export.sizeW", "Width (px)", 16.0, 20_000.0, 2048.0, 1.0); -const SIZE_H: ControlSpec = spec("export.sizeH", "Height (px)", 16.0, 20_000.0, 2048.0, 16.0); +const SIZE_H: ControlSpec = spec("export.sizeH", "Height (px)", 16.0, 20_000.0, 2048.0, 1.0); const SIZE_MP: ControlSpec = ControlSpec { decimals: 1, ..spec("export.sizeMp", "Megapixels", 0.1, 100.0, 12.0, 0.1) }; diff --git a/crates/ui-egui/src/headless/tests.rs b/crates/ui-egui/src/headless/tests.rs index 13bd7a2ae..f273edf6f 100644 --- a/crates/ui-egui/src/headless/tests.rs +++ b/crates/ui-egui/src/headless/tests.rs @@ -4953,3 +4953,39 @@ fn screenshot_request_is_answered_without_a_window() { let r = h.request("ui.screenshot", json!({"headless": true}), SETTLE); assert_eq!(r["result"]["width"], 640, "{r}"); } + +/// A size typed in the Export dialog is the size exported: the pixel fields kept only multiples +/// of 16, so 1080 became 1088 and 3000 became 3008 (issue #3300). +#[test] +fn export_sizes_keep_the_pixels_typed() { + let mut h = demo([1400.0, 900.0]); + let t = Duration::from_secs(10); + h.request("engine.execute", json!({"command": "dialog.export", "params": {}}), t); + h.settle(SETTLE); + let type_value = |h: &mut Headless, id: &str, text: &str| { + let r = h.request("ui.clickWidget", json!({"id": id}), t); + assert_eq!(r["ok"], true, "{id}: {r}"); + h.request("ui.text", json!({"text": text}), t); + h.request("ui.key", json!({"key": "Enter"}), t); + h.settle(SETTLE); + }; + let resize = |h: &Headless| match &h.app.ui.dialog { + Some(crate::state::Dialog::Export { resize, .. }) => *resize, + _ => panic!("the dialog closed"), + }; + if let Some(crate::state::Dialog::Export { full_size, resize, .. }) = &mut h.app.ui.dialog { + *full_size = false; + *resize = lightcraft_engine::export::Resize::long_edge(2048); + } + h.settle(SETTLE); + type_value(&mut h, "sliderValue:export.sizePx", "3000"); + assert_eq!(resize(&h).value, 3000.0); + if let Some(crate::state::Dialog::Export { resize, .. }) = &mut h.app.ui.dialog { + resize.mode = lightcraft_engine::export::ResizeMode::WidthHeight; + resize.height = 2048; + } + h.settle(SETTLE); + type_value(&mut h, "sliderValue:export.sizeW", "1080"); + type_value(&mut h, "sliderValue:export.sizeH", "1350"); + assert_eq!((resize(&h).value, resize(&h).height), (1080.0, 1350)); +} diff --git a/docs/whats-new.md b/docs/whats-new.md index c6c259200..cdfb62ac6 100644 --- a/docs/whats-new.md +++ b/docs/whats-new.md @@ -1,5 +1,11 @@ # What's new in LightCraft +## 2026-10-30 + +### Export sizes keep the pixels typed +- Export ▸ Image Sizing kept pixel sizes only in steps of 16, so a typed 1080 became 1088 and 3000 became 3008. The + long edge, short edge, width and height fields now keep any whole number of pixels. + ## 2026-10-24 ### Relative-date filters and smart albums follow the clock