`set_zoom_factor` breaks `Area::default_pos` persistence
Describe the bug
When calling ctx.set_zoom_factor(2.0) at the very begining, there are two problems:
Area::default_pos()generates an incorrect initial position into memory- Enabling "persist_window" while disabling "persist_egui_memory", causes the window to shrink each time App is launched.
To Reproduce Demo codes, with two workarounds to make the codes working.
use eframe::egui;
fn main() -> Result<(), eframe::Error> {
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([400.0, 400.0])
.with_window_level(egui::WindowLevel::Normal)
.with_app_id("egui_demo"),
centered: true,
persist_window: true,
..Default::default()
};
eframe::run_native(
"My egui App",
options,
Box::new(|cc| {
// Setting zoom_factor here has similar issue
// cc.egui_ctx.set_zoom_factor(2.0);
Box::<MyApp>::default()
}),
)
}
#[derive(Default)]
struct MyApp {
not_first_frame: bool,
}
impl eframe::App for MyApp {
fn persist_egui_memory(&self) -> bool {
false // Actually I only want to persist main window size and position
}
fn save(&mut self, storage: &mut dyn eframe::Storage) {
// Without this trick, the main window become smaller every time launching
// storage.set_string("egui", format!("(options:(zoom_factor:{}))", 2.0))
}
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
ctx.set_zoom_factor(2.0);
// Without this trick, the following "center" is based on zoom_factor=1.0 at first frame
// Emiting wrong default position in storage.
// if !self.not_first_frame {
// self.not_first_frame = true;
// return;
// }
let center = ctx.screen_rect().center();
let area = egui::Area::new("area_id")
.pivot(egui::Align2::CENTER_CENTER)
.default_pos(center);
area.show(ctx, |ui| {
egui::Frame::popup(ui.style()).show(ui, |ui| ui.label("TEST"))
});
}
}
Expected behavior
- The area should appear at the center of the window, without the need to manually skip the first frame
- The window size/postition remain consistent upon restarting. This could possibly solved by saving the zoom_factor along with window field in storage, or by saving the unscaled pixels
Desktop
- OS: Windows 10
- Version: 0.24.1, master
Screenshot
Without having looked into this, I suspect this code, which applies the new zoom factor: https://github.com/emilk/egui/blob/1efa66014981b39f0357b8a49599e7266a96ad79/crates/egui/src/context.rs#L273-L287
A very dirty hack we can do is explicitly save the scale factor memory bit on exit, which addresses half of the bug. I don't understand the problem with the area at the moment, so I can't comment on it
Have a briefly looked into this, the problem occurs when:
persist_egui_memory()is falseNativeOptions.persist_windowis true- zoom_factor is manually set by
ctx.set_zoom_factor(), orctx.memory_mut(|m| m.options.zoom_factor = XXX), insideAppCreatororeframe::App::update
Far before zoom_factor is actually set by user codes, the initial window size is decided by: https://github.com/emilk/egui/blob/cd3e9ea5b68107c34449f6355c7076ca5621bae4/crates/eframe/src/native/glow_integration.rs#L146-L161 Unfortunately, the initial window size is not that right since:
- Window size is calculated from
zoom_factorandinner_size_pointspersisted in storage inner_size_pointsis correctly loaded from STORAGE_WINDOW_KEYzoom_factorcannot be loaded from STORAGE_EGUI_MEMORY_KEY, sincepersist_egui_memory()is false. The default 1.0 is used- the initial window size and default pos of area is based on these incorrect value, so finally the window shrinks and the area shifted
Ideas on resolving the problem:
- persist
zoom_factorunder STORAGE_WINDOW_KEY instead of STORAGE_EGUI_MEMORY_KEY. A broken change though - provide an API like
ViewportBuilder.with_zoom_factor()to allow user setting the value before App init_run_state