mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-26 02:59:17 -06:00
LR-BEHAV-DIALOGS: the click that opens a dialog never closes it
A quick click on a slow frame presses and releases in the frame where the panels open a dialog, and the backdrop check read that press as one on the backdrop, closing the dialog at once. Input now counts only once the dialog was already shown the frame before; a pending press is dropped otherwise. The test opens Copy Settings from the bottom-bar gear with press and release in one frame and checks it stays open, then that the next backdrop click closes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a2a1505953
commit
4a6c43ce06
@@ -1515,16 +1515,31 @@ pub fn show(app: &mut LightcraftApp, ctx: &egui::Context) {
|
||||
if app.ui.dialog.as_ref().is_some_and(|now| *now != at_start) {
|
||||
return;
|
||||
}
|
||||
if !close {
|
||||
let frame = ctx.cumulative_frame_nr();
|
||||
ctx.data_mut(|d| d.insert_temp(egui::Id::new(BACKDROP_SHOWN), frame));
|
||||
}
|
||||
app.ui.dialog = if close { None } else { Some(dlg) };
|
||||
}
|
||||
|
||||
/// The last frame a dialog was drawn and stayed open, for [`clicked_backdrop`].
|
||||
const BACKDROP_SHOWN: &str = "dialog-backdrop-shown";
|
||||
|
||||
/// A click on the dimmed backdrop around the dialog: it closes the dialog like Esc. Pressed and
|
||||
/// released outside the window, so a slider dragged past its edge doesn't close it; a press while a
|
||||
/// popup is open (a dropdown, a date picker's calendar) only closes the popup. Only a press made
|
||||
/// while the dialog is shown counts, so the click that opened it never closes it. (Read from the
|
||||
/// raw events: egui forgets the press origin on release, and a scripted click is one frame.)
|
||||
/// while the dialog is shown counts: in the frame a dialog appears, its input is the click that
|
||||
/// opened it (a quick click on a slow frame presses and releases in that one frame), so it never
|
||||
/// closes it. (Read from the raw events: egui forgets the press origin on release.)
|
||||
fn clicked_backdrop(ctx: &egui::Context, window: egui::Rect) -> bool {
|
||||
let press_id = egui::Id::new("dialog-backdrop-press");
|
||||
let frame = ctx.cumulative_frame_nr();
|
||||
// the same frame too: a second pass of it gets no input
|
||||
let shown = ctx.data(|d| d.get_temp::<u64>(egui::Id::new(BACKDROP_SHOWN))).is_some_and(|f| f + 1 >= frame);
|
||||
if !shown {
|
||||
ctx.data_mut(|d| d.remove_temp::<bool>(press_id));
|
||||
return false;
|
||||
}
|
||||
let (press, release, clicked) = ctx.input(|i| {
|
||||
let at = |down: bool| {
|
||||
i.events.iter().rev().find_map(|e| match e {
|
||||
|
||||
@@ -114,6 +114,18 @@ fn a_click_outside_closes_the_dialog_when_settings_allow_it() {
|
||||
h.step();
|
||||
assert!(h.app.ui.dialog.is_none(), "a click on the backdrop closes the dialog");
|
||||
assert_eq!(h.app.session.catalog.photo(active).unwrap().rating, rating, "the click doesn't reach the panel below");
|
||||
// the click that opens a dialog lands outside its window; a quick one on a slow frame arrives
|
||||
// pressed and released in that one frame
|
||||
let gear = h.app.widgets.iter().find(|(id, _)| id == "icon:copyGear").map(|(_, r)| r.center()).unwrap();
|
||||
let press = |pressed| egui::Event::PointerButton { pos: gear, button: egui::PointerButton::Primary, pressed, modifiers: egui::Modifiers::NONE };
|
||||
h.events.extend([egui::Event::PointerMoved(gear), press(true), press(false)]);
|
||||
h.step();
|
||||
h.step();
|
||||
assert!(h.app.ui.dialog.is_some(), "the click that opens a dialog doesn't close it");
|
||||
let r = h.request("ui.clickWidget", json!({"id": "star:bottom:5"}), T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
h.step();
|
||||
assert!(h.app.ui.dialog.is_none(), "the next click on the backdrop does");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user