Perspective Crop: the swap button swaps W and H (#7059) (#7060)

* 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 <noreply@anthropic.com>

* 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) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
David Mann
2026-10-23 18:34:16 -04:00
committed by GitHub
co-authored by Claude Opus 5.5 Brandon Thomas
parent 427fb34042
commit f719f0bfac
2 changed files with 39 additions and 3 deletions
+9 -3
View File
@@ -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);
+30
View File
@@ -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]