From fe4e2ff3efe2dfc5c6f4871c968a9fb561fd5305 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Tue, 3 Nov 2026 23:06:04 -0500 Subject: [PATCH] menu: never activate a row from an earlier frame (#574) Nav kept the rows of the last frame that drew them. When a title click closed the popup before its rows drew again, Enter or Space ran the cached command with its old enabled state. Nav::load now clears the rows, so the keys act only on rows drawn this frame under the current gate. --- crates/menu/src/bar/nav.rs | 3 +++ crates/menu/src/tests/bar.rs | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/crates/menu/src/bar/nav.rs b/crates/menu/src/bar/nav.rs index acdb5811..643784ee 100644 --- a/crates/menu/src/bar/nav.rs +++ b/crates/menu/src/bar/nav.rs @@ -120,6 +120,9 @@ impl Nav { if top != nav.top { nav = Nav { top, tops: std::mem::take(&mut nav.tops), ..Default::default() }; } + // Rows hold the command and enabled state of the frame that drew them. A popup that is + // not drawn this frame (closed by a title click) must leave nothing for the keys to run. + nav.rows.clear(); nav } diff --git a/crates/menu/src/tests/bar.rs b/crates/menu/src/tests/bar.rs index 5227839b..f7142b39 100644 --- a/crates/menu/src/tests/bar.rs +++ b/crates/menu/src/tests/bar.rs @@ -10,6 +10,23 @@ use crate::bar::nav::{ARROW, Nav, heading, is_open}; #[path = "bar_keys.rs"] mod keys; +#[test] +fn rows_from_an_earlier_frame_are_never_activated() { + let ctx = egui::Context::default(); + let id = Id::unique("nav"); + let row = crate::bar::nav::Row { + widget: Id::unique("row"), + enabled: true, + command: Some(Builtin::Quit.command()), + rect: Rect::NOTHING, + mnemonic: None, + }; + let mut stale = Nav::default(); + stale.rows = vec![vec![row]]; + ctx.data_mut(|d| d.insert_temp(id, stale)); + assert!(Nav::load(&ctx, id).rows.is_empty(), "rows are this frame's only"); +} + fn item(id: &str, label: &str) -> Item { Item::new(id, label) }