menu: fix submenu dismiss propagation and ESC handling#2232
menu: fix submenu dismiss propagation and ESC handling#2232boboshan wants to merge 1 commit intolongbridge:mainfrom
Conversation
huacnlee
left a comment
There was a problem hiding this comment.
This is a monkey-patch, not a good solution.
ea6c0f7 to
3f1dfd1
Compare
3f1dfd1 to
87e7f10
Compare
| } | ||
| }); | ||
| } | ||
| } |
There was a problem hiding this comment.
Every frame render will hit this loop...
This is unacceptable.
|
Thanks for the feedback — the render-time approach was wrong. We've explored several alternatives but each has trade-offs: Our problem: Options we considered:
Do you have a preferred approach, or a different idea for handling submenus built outside |
Three related fixes for submenu dismiss behavior in PopupMenu: 1. Wire parent_menu in PopupMenu::build (one-shot at construction). Submenus added via PopupMenuItem::submenu(label, entity) — the data constructor — can't reach the parent's entity at build time, so they land with parent_menu = None. After the user closure populates the menu, iterate menu_items once and wire any orphan submenus to point at the menu being built. Zero per-frame cost, handles arbitrary nesting because every submenu also goes through PopupMenu::build. This was previously done in Render::render which iterated and notified every frame — replaced with the one-shot approach. 2. Fix ESC not closing menus when a submenu is open. When a submenu is opened by hover, the parent menu retains focus. Pressing ESC hit the parent's dismiss(), which bailed out early because active_submenu() was Some. Split dismiss into dismiss (Cancel handler — clears the active submenu first) and dismiss_menu (internal — propagates up the chain). 3. Guard handle_dismiss for submenu clicks. handle_dismiss (click-outside) now returns early if a submenu is active. Without this, clicking a submenu item triggers the parent's on_mouse_down_out, tearing down the submenu before the item's on_click fires. Fixes longbridge#2229
87e7f10 to
6f60e63
Compare
|
Rebased onto current The The Tested locally in a downstream app with table context menus carrying nested collection submenus: ESC closes the full chain, click-outside closes everything, click on a submenu item fires the action and dismisses cleanly. |
Summary
Fixes #2229 — three related fixes for submenu dismiss behavior in
PopupMenu:Auto-wire
parent_menuinrender(): Submenus added viaPopupMenuItem::submenu()(the data constructor) don't getparent_menuset, unlikePopupMenu::submenu()(the builder method). This breaks the dismiss chain. NowPopupMenu::render()auto-wiresparent_menuon any submenu child that doesn't have it set. This is needed because table delegates operate inContext<TableState>and cannot callPopupMenu::submenu()which requiresContext<PopupMenu>.Fix ESC not closing menus when a submenu is open: When a submenu is opened by hover, the parent menu retains focus. Pressing ESC would hit the parent's
dismiss(), which bailed out early becauseactive_submenu()wasSome. Splitdismissintodismiss(ESC action handler that clears the active submenu first) anddismiss_menu(internal dismiss that propagates up the chain).Guard
handle_dismissfor submenu clicks:handle_dismiss(click-outside) returns early if a submenu is active. Without this, clicking a submenu item triggers the parent'son_mouse_down_out, tearing down the submenu before the item'son_clickfires.Changes are in
popup_menu.rsonly — no table code changes needed.No dependency on #2231.
AI Disclosure
Implementation was developed with AI assistance (Claude). All code has been reviewed, tested, and follows existing
popup_menu.rspatterns.Test plan
cargo run --example table— right-click context menu with submenus workscargo run(story) — Menu story context menu: ESC closes full chain