fix(engine): Esc dismisses the topmost modal when Profile stacks on Home
Clicking the new Home header chip opens Profile on top of Home. Pressing Esc then closed Home (because handle_home_cancel_button fired on Esc with no awareness of layered modals) and left Profile orphaned over the game — the player had to press P afterwards just to dismiss what they meant to dismiss in the first place. Two changes restore the standard "Esc closes the topmost modal" contract: - profile_plugin: split P/button (toggle) from Esc (close-only). Esc only fires when Profile is currently open. - home_plugin: handle_home_cancel_button now skips its Esc branch when any other ModalScrim exists, deferring to whichever modal is on top. Click on the explicit Cancel button is unaffected. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -475,13 +475,19 @@ fn handle_home_cancel_button(
|
||||
keys: Option<Res<ButtonInput<KeyCode>>>,
|
||||
cancel_buttons: Query<&Interaction, (With<HomeCancelButton>, Changed<Interaction>)>,
|
||||
screens: Query<Entity, With<HomeScreen>>,
|
||||
other_modal_scrims: Query<(), (With<crate::ui_modal::ModalScrim>, Without<HomeScreen>)>,
|
||||
) {
|
||||
if screens.is_empty() {
|
||||
return;
|
||||
}
|
||||
let click = cancel_buttons.iter().any(|i| *i == Interaction::Pressed);
|
||||
let esc = keys.is_some_and(|k| k.just_pressed(KeyCode::Escape));
|
||||
if !click && !esc {
|
||||
// Esc only closes Home when it is the *topmost* modal. With Profile
|
||||
// (or any other ModalScrim) layered on top, the topmost owns the
|
||||
// dismissal — without this gate a single Esc closed the back
|
||||
// modal (Home) and left the front modal orphaned.
|
||||
let esc_targets_home = esc && other_modal_scrims.is_empty();
|
||||
if !click && !esc_targets_home {
|
||||
return;
|
||||
}
|
||||
for entity in &screens {
|
||||
|
||||
@@ -146,7 +146,17 @@ fn toggle_profile_screen(
|
||||
screens: Query<Entity, With<ProfileScreen>>,
|
||||
) {
|
||||
let button_clicked = requests.read().count() > 0;
|
||||
if !keys.just_pressed(KeyCode::KeyP) && !button_clicked {
|
||||
let p_pressed = keys.just_pressed(KeyCode::KeyP);
|
||||
let esc_pressed = keys.just_pressed(KeyCode::Escape);
|
||||
let already_open = !screens.is_empty();
|
||||
// P / button toggles open-or-close. Esc only ever closes — when
|
||||
// Profile is layered over Home (clicking the new Home stats chip
|
||||
// opens this on top), Esc must dismiss the *topmost* modal.
|
||||
// Without this branch, Esc fell through to Home's cancel handler
|
||||
// and closed the wrong modal.
|
||||
let want_open = !already_open && (p_pressed || button_clicked);
|
||||
let want_close = already_open && (p_pressed || button_clicked || esc_pressed);
|
||||
if !want_open && !want_close {
|
||||
return;
|
||||
}
|
||||
if let Ok(entity) = screens.single() {
|
||||
|
||||
Reference in New Issue
Block a user