From d28929ec7225205100590fce2836f885bc9ba688 Mon Sep 17 00:00:00 2001 From: Vitaly Kravchenko Date: Thu, 23 Jul 2026 15:58:26 +0100 Subject: [PATCH] Rerun `sizing_pass` when reopening popup (#8315) * Closes * [x] I have followed the instructions in the PR template ## Summary - Recalculate a menu popup's cached `Area` size when it reopens. - Preserve cached sizing for continuously open menus and leave tooltips and general popups unchanged. - Add a headless regression test covering a wider item added while the menu is closed. ## Root cause `Area` keeps its cached size after a menu closes. When that menu reopened with wider content, the cached width constrained the new item and caused it to wrap instead of allowing the popup to grow. The fix requests the same invisible sizing pass used for a first-open `Area` whenever a menu was not open during the previous frame. ## User impact Menus now expand to fit newly added wider items after reopening. Existing wrapping, explicit-width, alignment, screen-constraining, and continuously open menu behavior remain unchanged. ## Validation - `cargo test -p egui_kittest --test menu` - `cargo check -p egui` - `cargo fmt --all -- --check` --- crates/egui/src/containers/popup.rs | 1 + crates/egui_kittest/tests/popup.rs | 67 +++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/crates/egui/src/containers/popup.rs b/crates/egui/src/containers/popup.rs index 2a9335ede..080c00bd1 100644 --- a/crates/egui/src/containers/popup.rs +++ b/crates/egui/src/containers/popup.rs @@ -571,6 +571,7 @@ impl<'a> Popup<'a> { .fixed_pos(anchor) .sense(sense) .layout(layout) + .sizing_pass(!was_open_last_frame) .info(info.unwrap_or_else(|| { UiStackInfo::new(kind.into()).with_tag_value( MenuConfig::MENU_CONFIG_TAG, diff --git a/crates/egui_kittest/tests/popup.rs b/crates/egui_kittest/tests/popup.rs index a8d3bcc9d..4dbe33909 100644 --- a/crates/egui_kittest/tests/popup.rs +++ b/crates/egui_kittest/tests/popup.rs @@ -1,5 +1,72 @@ +use egui::{Align, Layout, Popup}; +use egui_kittest::Harness; use kittest::Queryable as _; +#[test] +fn reopened_popup_resizes_for_wider_items() { + const POPUP_BUTTON: &str = "Dynamic popup"; + const SHORT_ITEM: &str = "Short item"; + const WIDE_ITEM: &str = "Newly added item with a much wider label"; + + #[derive(Default)] + struct State { + open: bool, + show_wide_item: bool, + } + + let mut harness = Harness::builder() + .with_size(egui::Vec2::new(500.0, 300.0)) + .build_ui_state( + |ui, state| { + let response = ui.button(POPUP_BUTTON); + if response.clicked() { + state.open = !state.open; + } + + Popup::from_response(&response) + .open(state.open) + .layout(Layout::top_down_justified(Align::Min)) + .show(|ui| { + _ = ui.selectable_label(false, SHORT_ITEM); + _ = ui.selectable_label(false, "Another short item"); + if state.show_wide_item { + _ = ui.selectable_label(false, WIDE_ITEM); + } + }); + }, + State::default(), + ); + + harness.get_by_label(POPUP_BUTTON).click(); + harness.run(); + let initial_row_size = harness.get_by_label(SHORT_ITEM).rect().size(); + + harness.get_by_label(POPUP_BUTTON).click(); + harness.run(); + assert!(harness.query_by_label(SHORT_ITEM).is_none()); + + harness.state_mut().show_wide_item = true; + harness.run(); + harness.get_by_label(POPUP_BUTTON).click(); + harness.run(); + + let reopened_row_size = harness.get_by_label(SHORT_ITEM).rect().size(); + let wide_row_size = harness.get_by_label(WIDE_ITEM).rect().size(); + + assert!( + reopened_row_size.x > initial_row_size.x, + "reopened row width ({}) did not grow beyond its initial width ({})", + reopened_row_size.x, + initial_row_size.x + ); + assert!( + wide_row_size.y <= initial_row_size.y + 0.5, + "new row height ({}) exceeds the single-line row height ({})", + wide_row_size.y, + initial_row_size.y + ); +} + #[test] fn test_interactive_tooltip() { struct State {