Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

frame.set_window_size(ctx.used_size()); is broken #403

Open
Mubelotix opened this issue May 16, 2021 · 2 comments
Open

frame.set_window_size(ctx.used_size()); is broken #403

Mubelotix opened this issue May 16, 2021 · 2 comments
Labels
bug Something is broken

Comments

@Mubelotix
Copy link

Manually resizing the OS window makes the height of the window increase too much. It will even overflow the screen height, and can actually grow infinitely.

To Reproduce

  1. Run any native egui app
  2. Resize the window horizontally
  3. Press Alt+tab to see the window growing vertically

Expected behavior
The height of the window should be conserved when resizing the window horizontally, and should increase slower when resizing the window vertically.

Screenshots
The bug

Desktop

  • OS: Ubuntu
  • Version: 21.04
@Mubelotix Mubelotix added the bug Something is broken label May 16, 2021
@Mubelotix
Copy link
Author

Actually it comes from the code of the example I copied.

frame.set_window_size(ctx.used_size());

I don't know why, but this does not work as expected.

@follower
Copy link
Contributor

follower commented May 17, 2021

Actually it comes from the code of the example I copied.

frame.set_window_size(ctx.used_size());

That snippet is unfortunately known to cause issues: e.g. #114 (comment)

I also encountered it when I started using egui on Ubuntu-based Elementary OS--eventually I worked around it by only setting the size once.

Observations

At the time I did investigate it a bit as I wondered if it was related to the resize events happening in the windowing back end.

But I actually just revisited the issue today and my current thinking is that it seems like it may actually just be something within egui.

The issue seems to be that there's some feedback loop that happens that causes the (height) value of used_size() to always be larger than the current window size (even after a resize), so the window height just keeps increasing.

I got a similar situation (using 0.11.0 currently) occurring when programatically setting the max height of a ScrollArea--it seemed like if it was followed by a label the used height increased by 1, if it was followed by a button it increased by 7 but if it was followed by a separator line the used height didn't increase at all.

Possible workaround(s)

One option for a workaround is to shrink used_size() height by a 1 or more pixels (e.g. try 1 or 7) before using it to set the window size.

Another approach would be only set the size once like here: #69 (comment)

Troubleshooting

Additionally you could log the related values at the end of the update() function to see what the incorrect value is, e.g.:

info!("u: {:?}", ctx.used_size());
info!("a: {:?}", ctx.available_rect());
info!("c: {:?}", ctx.input().screen_rect());

I haven't yet tried this with the standard hello world example to see the values it produces.

Related links
Potentially related code areas to remind me for next time. :)
  • egui/egui/src/context.rs

    Lines 637 to 650 in 7b0f991

    /// How much space is used by panels and windows.
    pub fn used_rect(&self) -> Rect {
    let mut used = self.frame_state().used_by_panels;
    for window in self.memory().areas.visible_windows() {
    used = used.union(window.rect());
    }
    used
    }
    /// How much space is used by panels and windows.
    /// You can shrink your egui area to this size and still fit all egui components.
    pub fn used_size(&self) -> Vec2 {
    self.used_rect().max - Pos2::new(0.0, 0.0)
    }
  • /// How much space is still available after panels has been added.
    /// This is the "background" area, what egui doesn't cover with panels (but may cover with windows).
    /// This is also the area to which windows are constrained.
    pub(crate) fn available_rect(&self) -> Rect {
    debug_assert!(
    self.available_rect.is_finite(),
    "Called `available_rect()` before `CtxRef::begin_frame()`"
    );
    self.available_rect
    }
    /// Shrink `available_rect`.
    pub(crate) fn allocate_left_panel(&mut self, panel_rect: Rect) {
    debug_assert!(
    panel_rect.min.distance(self.available_rect.min) < 0.1,
    "Mismatching left panel. You must not create a panel from within another panel."
    );
    self.available_rect.min.x = panel_rect.max.x;
    self.unused_rect.min.x = panel_rect.max.x;
    self.used_by_panels = self.used_by_panels.union(panel_rect);
    }
    /// Shrink `available_rect`.
    pub(crate) fn allocate_top_panel(&mut self, panel_rect: Rect) {
    debug_assert!(
    panel_rect.min.distance(self.available_rect.min) < 0.1,
    "Mismatching top panel. You must not create a panel from within another panel."
    );
    self.available_rect.min.y = panel_rect.max.y;
    self.unused_rect.min.y = panel_rect.max.y;
    self.used_by_panels = self.used_by_panels.union(panel_rect);
    }
    pub(crate) fn allocate_central_panel(&mut self, panel_rect: Rect) {
    // Note: we do not shrink `available_rect`, because
    // we allow windows to cover the CentralPanel.
    self.unused_rect = Rect::NOTHING; // Nothing left unused after this
    self.used_by_panels = self.used_by_panels.union(panel_rect);
    }
    }
  • let available_outer = ui.available_rect_before_wrap();
    let outer_size = vec2(
    available_outer.width(),
    available_outer.height().at_most(max_height),
    );
    let inner_size = outer_size - vec2(current_scroll_bar_width, 0.0);
    let inner_rect = Rect::from_min_size(available_outer.min, inner_size);
    let mut content_ui = ui.child_ui(
    Rect::from_min_size(
    inner_rect.min - state.offset,
    vec2(inner_size.x, f32::INFINITY),
    ),
    *ui.layout(),
    );
    let mut content_clip_rect = inner_rect.expand(ui.visuals().clip_rect_margin);
    content_clip_rect = content_clip_rect.intersect(ui.clip_rect());
    content_clip_rect.max.x = ui.clip_rect().max.x - current_scroll_bar_width; // Nice handling of forced resizing beyond the possible
    content_ui.set_clip_rect(content_clip_rect);
  • let screen_rect = new.screen_rect.unwrap_or_else(|| {
    if new.screen_size != Default::default() {
    Rect::from_min_size(Default::default(), new.screen_size) // backwards compatibility
    } else {
    self.screen_rect
    }
  • if let Some(window_size) = window_size {
    display.gl_window().window().set_inner_size(
    glutin::dpi::PhysicalSize {
    width: (egui.ctx().pixels_per_point() * window_size.x).round(),
    height: (egui.ctx().pixels_per_point() * window_size.y).round(),
    }
    .to_logical::<f32>(native_pixels_per_point(&display) as f64),
    );
  • egui/epi/src/lib.rs

    Lines 468 to 469 in b155996

    /// Set to some size to resize the outer window (e.g. glium window) to this size.
    pub window_size: Option<egui::Vec2>,
  • https://github.com/rust-windowing/winit/blob/1c4d6e7613c3a3870cecb4cfa0eecc97409d45ff/src/platform_impl/linux/x11/window.rs#L1051-L1055
  • https://github.com/rust-windowing/winit/blob/1c4d6e7613c3a3870cecb4cfa0eecc97409d45ff/src/platform_impl/linux/mod.rs#L327-L329
  • https://github.com/glium/glium/blob/48cd807e8e08d8932bc4e35411018dd024791dc2/src/backend/glutin/mod.rs#L39-L43
  • https://github.com/rust-windowing/glutin/blob/bab33a84dfb094ff65c059400bed7993434638e2/glutin/src/windowed.rs#L159-L173

Edited: Added additional related links.

@emilk emilk changed the title OS window overgrow on manual resize frame.set_window_size(ctx.used_size()); is broken Apr 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something is broken
Projects
None yet
Development

No branches or pull requests

2 participants