diff --git a/crates/ui-egui/src/panels/dialogs.rs b/crates/ui-egui/src/panels/dialogs.rs index 8ec8bb0b..6f86bc78 100644 --- a/crates/ui-egui/src/panels/dialogs.rs +++ b/crates/ui-egui/src/panels/dialogs.rs @@ -158,6 +158,14 @@ fn modal_space(ctx: &egui::Context) -> egui::Vec2 { } pub(crate) fn modal(ctx: &egui::Context, title: &str, size: egui::Vec2, t: &Tokens, body: impl FnOnce(&mut egui::Ui)) { + modal_with_scroll(ctx, title, size, t, false, body); +} + +pub(crate) fn modal_vertical(ctx: &egui::Context, title: &str, size: egui::Vec2, t: &Tokens, body: impl FnOnce(&mut egui::Ui)) { + modal_with_scroll(ctx, title, size, t, true, body); +} + +fn modal_with_scroll(ctx: &egui::Context, title: &str, size: egui::Vec2, t: &Tokens, vertical_only: bool, body: impl FnOnce(&mut egui::Ui)) { let max_height = (modal_space(ctx).y - 84.0).max(40.0); modal_fit(ctx, title, size, t, |ui, _| { egui::ScrollArea::both().max_height(max_height).auto_shrink([false, true]).show(ui, body); @@ -178,7 +186,8 @@ pub(crate) fn modal_fit(ctx: &egui::Context, title: &str, size: egui::Vec2, t: & // The id stays keyed on the untranslated source, so switching language cannot move it. ui.label(egui::RichText::new(tr(title)).font(Tokens::semibold(15.0)).color(t.tab_text_active)); ui.add_space(10.0); - let title_h = ui.cursor().top() - ui.min_rect().top(); + let scroll = if vertical_only { egui::ScrollArea::vertical() } else { let title_h = ui.cursor() }; + scroll.top() - ui.min_rect().top(); body(ui, (size.y - 36.0 - title_h).max(40.0)); }); } diff --git a/crates/ui-egui/src/panels/forms.rs b/crates/ui-egui/src/panels/forms.rs index dacdef28..dedd48f1 100644 --- a/crates/ui-egui/src/panels/forms.rs +++ b/crates/ui-egui/src/panels/forms.rs @@ -904,7 +904,8 @@ pub(crate) fn close_info(app: &mut EffectcraftApp) { pub fn show_info(app: &mut EffectcraftApp, ctx: &egui::Context, t: &Tokens) { let (title, body) = app.dialog_state.info.clone(); let mut close = false; - super::dialogs::modal(ctx, &title, vec2(440.0, 160.0), t, |ui| { + // The text wraps within this small dialog; avoid a horizontal scrollbar changing its height. + super::dialogs::modal_vertical(ctx, &title, vec2(440.0, 160.0), t, |ui| { ui.label(tr(&body)); ui.add_space(16.0); ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { diff --git a/crates/ui-egui/tests/ui_settings_info.rs b/crates/ui-egui/tests/ui_settings_info.rs index f110ce0f..9d87eb04 100644 --- a/crates/ui-egui/tests/ui_settings_info.rs +++ b/crates/ui-egui/tests/ui_settings_info.rs @@ -134,3 +134,23 @@ fn gpu_information_names_the_adapter_and_why_the_gpu_is_off() { assert!(h.query_by_label_contains("Window graphics: NVIDIA GeForce RTX 4070").is_some(), "the window's adapter is shown"); assert!(h.query_by_label_contains("GPU compositing is off: GPU compositor unavailable").is_some(), "the reason is shown"); } + +#[test] +fn gpu_information_dialog_stays_in_place() { + let mut session = Session::default(); + session.prefs.appearance.ui_scale = 125; + session.execute("comp.new", json!({"width":32,"height":32,"duration":2})).unwrap(); + let mut h = Harness::builder().with_size(vec2(1280.0, 720.0)).build_eframe(|_| EffectcraftApp::new(session)); + h.run_steps(4); + let ctx = h.ctx.clone(); + menus::invoke(h.state_mut(), &ctx, "app.settings", json!({"page":"previews"})).unwrap(); + h.run_steps(3); + let button = rect(&h, "settings.button.GPU Information").center(); + click(&mut h, button); + let start = h.get_by_label("GPU Information").rect(); + for _ in 0..20 { + h.step(); + let current = h.get_by_label("GPU Information").rect(); + assert!((current.min - start.min).length() < 1.0, "GPU Information dialog moved"); + } +}