From f719f0bfac8bb53a17aae12f7f9e95468fbbabe5 Mon Sep 17 00:00:00 2001 From: David Mann Date: Sat, 24 Oct 2026 00:34:16 +0200 Subject: [PATCH] Perspective Crop: the swap button swaps W and H (#7059) (#7060) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Perspective Crop: the swap button swaps W and H (#7059) The W/H swap button called crop_size::swap, which only acts in the Crop tool's W x H x Resolution mode; Perspective Crop never sets that mode, so the button did nothing there. The button now always swaps the fields; X keeps the guard. Co-Authored-By: Claude Opus 5.5 * Address review: the test clicks Perspective Crop's ⇄ button The test now renders the real options bar with the Perspective Crop tool, clicks ⇄ through the egui_kittest harness and checks that W and H swapped, instead of calling `swap_fields` directly. It fails if the button goes back to calling `swap`. Co-Authored-By: Claude Opus 5.5 (1M context) --------- Co-authored-by: Claude Opus 5.5 Co-authored-by: Brandon Thomas --- crates/ui-egui/src/crop_size.rs | 12 ++++++--- crates/ui-egui/src/perspective_crop_ui.rs | 30 +++++++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/crates/ui-egui/src/crop_size.rs b/crates/ui-egui/src/crop_size.rs index dc91ec681b..71fc57f495 100644 --- a/crates/ui-egui/src/crop_size.rs +++ b/crates/ui-egui/src/crop_size.rs @@ -226,15 +226,21 @@ pub fn clear(o: &mut ToolOptions) { o.crop_resolution.clear(); } -/// Swaps W and H (the ⇄ button, X). False outside W x H x Resolution mode. +/// Swaps W and H for the Crop tool's X. False outside W x H x Resolution mode. pub fn swap(o: &mut ToolOptions) -> bool { if o.crop_ratio != WHR { return false; } - std::mem::swap(&mut o.crop_width, &mut o.crop_height); + swap_fields(o); true } +/// The ⇄ button between the W and H fields: always swaps, as Perspective Crop shows the fields +/// without the Crop tool's W x H x Resolution mode. +fn swap_fields(o: &mut ToolOptions) { + std::mem::swap(&mut o.crop_width, &mut o.crop_height); +} + /// After the preset dropdown chose `crop_ratio`: a size preset fills the fields and Front Image /// reads the document, both leaving W x H x Resolution mode on. pub fn chosen(app: &mut PhotocraftApp) { @@ -298,7 +304,7 @@ fn text_field(ui: &mut egui::Ui, id: &str, value: &mut String, hint: &str, width pub fn fields(o: &mut ToolOptions, ui: &mut egui::Ui) { text_field(ui, "crop-width", &mut o.crop_width, tl!("Width"), 64.0, normalize_length); if crate::icons::button(ui, "arrow-left-right", 22.0, false, tl!("Swaps height and width")).clicked() { - swap(o); + swap_fields(o); } text_field(ui, "crop-height", &mut o.crop_height, tl!("Height"), 64.0, normalize_length); text_field(ui, "crop-resolution", &mut o.crop_resolution, tl!("Resolution"), 64.0, normalize_resolution); diff --git a/crates/ui-egui/src/perspective_crop_ui.rs b/crates/ui-egui/src/perspective_crop_ui.rs index 396fb87997..2a696bd5ed 100644 --- a/crates/ui-egui/src/perspective_crop_ui.rs +++ b/crates/ui-egui/src/perspective_crop_ui.rs @@ -352,6 +352,36 @@ mod tests { assert_eq!(ordered([[10.0, 90.0], [100.0, 5.0], [0.0, 0.0], [90.0, 100.0]]), [[0.0, 0.0], [100.0, 5.0], [90.0, 100.0], [10.0, 90.0]]); } + /// Clicking ⇄ in the rendered options bar swaps W and H, although Perspective Crop never sets + /// the Crop tool's W x H x Resolution mode (#7059). + #[test] + fn the_options_bar_swap_button_swaps_w_and_h() { + use egui_kittest::kittest::Queryable; + let doc = Document::with_background("p", Size::new(200, 150), ColorMode::Rgb, SampleType::U8, Color::WHITE); + let mut s = photocraft_engine::Session::new(); + s.add_document(doc, None); + let mut app = PhotocraftApp::new(s, crate::Services::default()); + app.ui.tool = Tool::PerspectiveCrop; + app.ui.tool_options.crop_width = "4 in".into(); + app.ui.tool_options.crop_height = "6 in".into(); + assert_ne!(app.ui.tool_options.crop_ratio, crate::crop_size::WHR); + let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1400.0, 60.0)).build_ui_state( + |ui, app: &mut PhotocraftApp| { + if !ui.ctx().fonts(|f| f.families().contains(&egui::FontFamily::Name("medium".into()))) { + return; + } + crate::panels::options_bar(app, ui); + }, + app, + ); + PhotocraftApp::setup_context(&h.ctx, crate::theme::ThemeKind::ProMedium); + h.run_steps(4); + h.get_by_label("Swaps height and width").click(); + h.run_steps(2); + let o = &h.state().ui.tool_options; + assert_eq!((o.crop_width.as_str(), o.crop_height.as_str()), ("6 in", "4 in")); + } + /// The pending quad belongs to its document (#1918): switching documents drops it, so it is /// never drawn on the other one; on its own document it stays. #[test]