mirror of
https://github.com/emilk/egui.git
synced 2026-08-29 04:40:03 -04:00
Allow explicit popup sizing passes (#8407)
* [x] I have followed the instructions in the PR template ## Summary - Add an opt-in `Popup::sizing_pass(bool)` builder for remeasuring a popup whose contents change while it remains open. - Preserve the automatic first-open/reopen sizing pass and all existing default behavior. - Add a headless regression covering growth to a capped scroll viewport with overflowing content remaining scrollable. ## Why this is necessary A continuously open popup can first shrink around a short result set and later receive more content, such as an autocomplete after its query changes or a “show more” action. The cached `Area` height constrains the `ScrollArea` input size, so `ScrollArea::max_height` can cap the viewport but cannot make the containing popup grow again. PR #8315 taught `Popup` to rerun its sizing pass after closing and reopening. That fixes the same cached-size feedback loop when `was_open_last_frame` is false, but a continuously open popup keeps that value true while its contents change. In that case the caller is the component that knows the cached natural size is stale. This API exposes the existing one-frame `Area` sizing mechanism through `Popup`. It is additive, defaults to false, and combines with the automatic reopen pass, so unrelated popups, menus, tooltips, and areas keep their current behavior.
This commit is contained in:
committed by
GitHub
parent
9338f23bc6
commit
6d98e1dccb
@@ -67,6 +67,85 @@ fn reopened_popup_resizes_for_wider_items() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn open_popup_resizes_after_explicit_sizing_pass() {
|
||||
const POPUP_BUTTON: &str = "Growing popup";
|
||||
const MAX_HEIGHT: f32 = 100.0;
|
||||
|
||||
struct State {
|
||||
item_count: usize,
|
||||
needs_sizing_pass: bool,
|
||||
popup_height: f32,
|
||||
viewport_height: f32,
|
||||
content_height: f32,
|
||||
}
|
||||
|
||||
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);
|
||||
let needs_sizing_pass = core::mem::take(&mut state.needs_sizing_pass);
|
||||
let item_count = state.item_count;
|
||||
|
||||
if let Some(popup) = Popup::from_response(&response)
|
||||
.sizing_pass(needs_sizing_pass)
|
||||
.show(|ui| {
|
||||
egui::ScrollArea::vertical()
|
||||
.max_height(MAX_HEIGHT)
|
||||
.show(ui, |ui| {
|
||||
for index in 0..item_count {
|
||||
ui.label(format!("Item {index}"));
|
||||
}
|
||||
})
|
||||
})
|
||||
{
|
||||
state.popup_height = popup.response.rect.height();
|
||||
state.viewport_height = popup.inner.inner_rect.height();
|
||||
state.content_height = popup.inner.content_size.y;
|
||||
}
|
||||
},
|
||||
State {
|
||||
item_count: 2,
|
||||
needs_sizing_pass: false,
|
||||
popup_height: 0.0,
|
||||
viewport_height: 0.0,
|
||||
content_height: 0.0,
|
||||
},
|
||||
);
|
||||
|
||||
harness.run();
|
||||
let initial_popup_height = harness.state().popup_height;
|
||||
|
||||
harness.state_mut().item_count = 20;
|
||||
harness.run();
|
||||
let stale_viewport_height = harness.state().viewport_height;
|
||||
assert!(
|
||||
stale_viewport_height < MAX_HEIGHT,
|
||||
"viewport unexpectedly reached its maximum without a sizing pass"
|
||||
);
|
||||
|
||||
harness.state_mut().needs_sizing_pass = true;
|
||||
harness.run();
|
||||
|
||||
assert!(
|
||||
harness.state().popup_height > initial_popup_height,
|
||||
"popup did not grow after an explicit sizing pass"
|
||||
);
|
||||
assert!(
|
||||
harness.state().viewport_height > stale_viewport_height,
|
||||
"scroll viewport did not grow after an explicit sizing pass"
|
||||
);
|
||||
assert!(
|
||||
(harness.state().viewport_height - MAX_HEIGHT).abs() <= 0.5,
|
||||
"scroll viewport did not stop at its maximum height"
|
||||
);
|
||||
assert!(
|
||||
harness.state().content_height > harness.state().viewport_height,
|
||||
"popup contents did not remain scrollable at the maximum height"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_interactive_tooltip() {
|
||||
struct State {
|
||||
|
||||
Reference in New Issue
Block a user