From f8463fcf7e0e85ebaacaedbbcd587c49793a6273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Kozlovsk=C3=BD?= Date: Tue, 3 Nov 2026 08:47:46 +0100 Subject: [PATCH] Cryptomatte eyedropper: Esc that closes a dialog keeps it armed (#473) The Esc that closed New Solid or Composition Settings also disarmed the eyedropper. An open dialog now takes Esc like a focused text field or an open popup, so that Esc only closes the dialog and the next one disarms. long_sequence asserts both instead of logging a finding. --- crates/ui-egui/src/panels/crypto_pick.rs | 14 ++++++++------ crates/ui-egui/tests/it/ui_crypto_pick_undo.rs | 13 ++++++++----- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/crates/ui-egui/src/panels/crypto_pick.rs b/crates/ui-egui/src/panels/crypto_pick.rs index 56479c476..2310ba93b 100644 --- a/crates/ui-egui/src/panels/crypto_pick.rs +++ b/crates/ui-egui/src/panels/crypto_pick.rs @@ -97,8 +97,9 @@ struct State { /// The waiting clicks took the focus from a text field (the Selection being typed): they /// are made once it has committed, on top of what it committed. after_typing: bool, - /// A text field or a popup had the keyboard the pass before: its Esc isn't the pick's - /// (egui lets go of the focus and closes popups before the viewer runs). + /// A text field, a popup or a dialog had the keyboard the pass before: its Esc isn't the + /// pick's (egui lets go of the focus and closes popups, and Esc closes the dialog, before + /// the viewer runs). esc_taken: bool, /// The press of the click in progress. press: Option, @@ -507,12 +508,13 @@ fn draw_status_chip(app: &mut EffectcraftApp, ctx: &egui::Context, painter: &egu painter.galley(chip.left_center() + vec2(12.0, -galley.size().y / 2.0), galley, colour); } -/// Esc disarms the eyedropper only when no text field or popup had the keyboard this pass or -/// the pass before (egui lets go of the focus and closes popups before the viewer runs). +/// Esc disarms the eyedropper only when no text field, popup, or dialog had the keyboard this +/// pass or the pass before (egui lets go of the focus and closes popups, and Esc closes the +/// dialog, before the viewer runs). fn handle_escape(app: &mut EffectcraftApp, ui: &mut egui::Ui, st: &mut State) { let ctx = ui.ctx(); - // (Esc in a text field, the Selection being typed, only ends the typing; in a menu, it.) - let esc_taken = std::mem::replace(&mut st.esc_taken, ctx.text_edit_focused() || egui::Popup::is_any_open(ctx)); + // (Esc in a text field, the Selection being typed, only ends the typing; in a menu or dialog, it.) + let esc_taken = std::mem::replace(&mut st.esc_taken, ctx.text_edit_focused() || egui::Popup::is_any_open(ctx) || app.dialog.is_some()); if ui.input(|i| i.key_pressed(egui::Key::Escape)) && !esc_taken && !st.esc_taken { app.ui.fx_pick = None; app.ui.status.clear(); diff --git a/crates/ui-egui/tests/it/ui_crypto_pick_undo.rs b/crates/ui-egui/tests/it/ui_crypto_pick_undo.rs index 32635084a..973cd58da 100644 --- a/crates/ui-egui/tests/it/ui_crypto_pick_undo.rs +++ b/crates/ui-egui/tests/it/ui_crypto_pick_undo.rs @@ -697,16 +697,19 @@ fn long_sequence(tag: &str, size: egui::Vec2, res: Resolution) { for _ in 0..3 { step_history(&mut h, &f, &mut m, dims, false, "undo before Ctrl+Y"); } - let armed = m.armed; + if m.armed.is_none() { + let l = if m.state().iter().find(|l| l.id == pl).and_then(|l| l.crypto()).is_some() { pl } else { pre }; + run_step(&mut h, &f, &mut m, dims, &Arm(l), 99); + } key(&mut h, Key::Y, CTRL); assert!(h.state().dialog.is_some(), "Ctrl+Y opens the New Solid dialog"); assert_eq!(h.state().session.history.redo.len(), 3, "Ctrl+Y doesn't redo"); key(&mut h, Key::Escape, Modifiers::NONE); assert!(h.state().dialog.is_none()); - if armed.is_some() && h.state().ui.fx_pick.is_none() { - eprintln!("FINDING {tag}: Esc that closed the New Solid dialog also disarmed the eyedropper"); - m.armed = None; - } + assert!(h.state().ui.fx_pick.is_some(), "Esc that closes the New Solid dialog keeps the eyedropper armed"); + key(&mut h, Key::Escape, Modifiers::NONE); + assert!(h.state().ui.fx_pick.is_none(), "a second Esc disarms"); + m.armed = None; verify(&mut h, &f, &mut m, dims, "after Ctrl+Y and Esc"); // Undo partway, then a new pick: no redo left, the undone steps kept as a branch. for k in 0..4 {