From db3543d034b3de310b20036959b5a100e4977b0e Mon Sep 17 00:00:00 2001 From: Blackberry Float Date: Thu, 3 Jul 2025 07:14:07 -0400 Subject: [PATCH] Update area struct to allow force resizing (#7114) This is a really small PR so I am skipping the issue (based on contributing.md). This change adds an optional field and thus non breaking for the API. I ran into an issue during my development of an alerts manager widget ([see PR](https://github.com/blackberryfloat/egui_widget_ext/pull/2)) where I needed a scrollable overlay that did not block clicking areas of a parent widget when my alerts did not take up the entire parent. To achieve this I detect the sizing pass via the invisible flag and only render the alerts content and then on the next pass I add the scroll bar in around the alert content. Whenever the alert content changed though I would need to create a new Area with a new id to get proper sizing. That is a memory leak so I wanted to reset the size state to trigger a sizing pass. Memory is rightfully protected enough that the path to remove memory was dropped and I just added a hook to set a resize flag. I am sure there are better ways but this is what made sense to me. Looking forward to thoughts. ~~Logistics wise, I have proposed it as a patch because I was based off 0.31.1 for testing. I was also thinking it could be released quickly. I am happy to cherry pick onto main after. If that is not allowed I can rebase to main and pull against that.~~ (rebased on main) --------- Co-authored-by: Wesley Murray --- crates/egui/src/containers/area.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/crates/egui/src/containers/area.rs b/crates/egui/src/containers/area.rs index d40df835..5ae4a4b3 100644 --- a/crates/egui/src/containers/area.rs +++ b/crates/egui/src/containers/area.rs @@ -121,6 +121,7 @@ pub struct Area { new_pos: Option, fade_in: bool, layout: Layout, + sizing_pass: bool, } impl WidgetWithState for Area { @@ -147,6 +148,7 @@ impl Area { anchor: None, fade_in: true, layout: Layout::default(), + sizing_pass: false, } } @@ -357,6 +359,27 @@ impl Area { self.layout = layout; self } + + /// While true, a sizing pass will be done. This means the area will be invisible + /// and the contents will be laid out to estimate the proper containing size of the area. + /// If false, there will be no change to the default area behavior. This is useful if the + /// area contents area dynamic and you need to need to make sure the area adjusts its size + /// accordingly. + /// + /// This should only be set to true during the specific frames you want force a sizing pass. + /// Do NOT hard-code this as `.sizing_pass(true)`, as it will cause the area to never be + /// visible. + /// + /// # Arguments + /// - resize: If true, the area will be resized to fit its contents. False will keep the + /// default area resizing behavior. + /// + /// Default: `false`. + #[inline] + pub fn sizing_pass(mut self, resize: bool) -> Self { + self.sizing_pass = resize; + self + } } pub(crate) struct Prepared { @@ -410,6 +433,7 @@ impl Area { constrain_rect, fade_in, layout, + sizing_pass: force_sizing_pass, } = self; let constrain_rect = constrain_rect.unwrap_or_else(|| ctx.screen_rect()); @@ -425,6 +449,10 @@ impl Area { interactable, last_became_visible_at: None, }); + if force_sizing_pass { + sizing_pass = true; + state.size = None; + } state.pivot = pivot; state.interactable = interactable; if let Some(new_pos) = new_pos {