mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-10 13:01:29 +00:00
fix: cap print dialog height to the screen so it can't overflow top/b… (#6223)
* fix: cap print dialog height to the screen so it can't overflow top/bottom The Print dialog modal had no height constraint, so on screens where the settings+preview content (especially with the driver's Properties... panel expanded) exceeds available screen height, the dialog overflowed equally off the top and bottom, making Print/Cancel unreachable. Wrap the settings+preview area in a ScrollArea capped to the viewport's available height (read through viewport_rect(), which holds steady across frames unlike raw screen_rect), keeping the title and button row outside so they stay reachable. Includes a kittest regression test. * Print dialog: size the scroll area from its cap, not from what the modal offers this frame Opened after a taller dialog, the shared modal remeasures from a height of zero (#5118) and offers less, so the settings area took the previous dialog's leftover height: Print was 408 pt after Preferences against 674 pt fresh (dialog_chrome::a_dialog_keeps_its_own_height_after_a_taller_one). min_scrolled_height(max_h) makes the viewport the cap; auto_shrink still fits shorter contents. Comments cite #4252 and #5317. --------- Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
This commit is contained in:
1 parent
6914607f17
commit
ca66667f33
1 file changed
+43
@@ -95,6 +95,20 @@ pub(crate) fn body(
|
||||
let settings = d.settings(sizes.len(), labels);
|
||||
let sheets = settings.as_ref().ok().and_then(|s| print::layout(sizes, s).ok()).unwrap_or_default();
|
||||
d.sheet = d.sheet.min(sheets.len().saturating_sub(1));
|
||||
// Cap the settings+preview area to the screen's available height (#4252, #5317):
|
||||
// on a short screen, or with the driver's own Properties… panel expanded below, this row can
|
||||
// otherwise grow taller than the display and push the Print/Cancel buttons off both edges.
|
||||
// The title and the button row stay outside, so they are always reachable.
|
||||
// `viewport_rect()` is egui's own idea of the current viewport, kept from the latest
|
||||
// `RawInput::screen_rect` it was handed — unlike reading `raw.screen_rect` directly, it
|
||||
// does not go blank on a frame where the backend didn't resend it.
|
||||
let screen_h = ui.ctx().input(|i| i.viewport_rect().height());
|
||||
let max_h = (screen_h - 220.0).max(300.0);
|
||||
// The viewport is `max_h` itself, not what the modal offers this frame: when a different
|
||||
// dialog was shown before, the shared modal remeasures from a height of zero (#5118) and
|
||||
// offers less, which would size this area by the dialog shown before. `auto_shrink` still
|
||||
// shrinks it to contents that fit.
|
||||
egui::ScrollArea::vertical().max_height(max_h).min_scrolled_height(max_h).auto_shrink([false, true]).show(ui, |ui| {
|
||||
ui.horizontal_top(|ui| {
|
||||
// Settings.
|
||||
ui.vertical(|ui| {
|
||||
@@ -559,6 +573,7 @@ pub(crate) fn body(
|
||||
}
|
||||
});
|
||||
});
|
||||
}); // end ScrollArea (#4252, #5317)
|
||||
ui.add_space(12.0);
|
||||
let (mut go, mut cancel) = (false, false);
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
@@ -573,3 +588,31 @@ pub(crate) fn body(
|
||||
});
|
||||
(go, cancel)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use egui_kittest::Harness;
|
||||
use egui_kittest::kittest::Queryable;
|
||||
|
||||
use crate::{Dialog, PdfCraftApp};
|
||||
|
||||
/// #4252, #5317: on a short screen the settings+preview area used to grow past
|
||||
/// both the top and bottom of the screen (centered modals overflow both edges equally),
|
||||
/// taking the Cancel button with it. It must now stay reachable, scrolling instead.
|
||||
#[test]
|
||||
fn the_print_dialog_keeps_its_buttons_within_a_short_screen() {
|
||||
let screen = egui::vec2(1000.0, 480.0); // shorter than the settings+preview column alone
|
||||
let mut h = Harness::builder().with_size(screen).build_eframe(|_cc| {
|
||||
let mut app = PdfCraftApp::new();
|
||||
app.set_option("language", "en").unwrap();
|
||||
let bytes = app.session.create_blank(612.0, 792.0, 1).unwrap();
|
||||
app.open_bytes("one-page.pdf", None, bytes.as_ref().clone()).unwrap();
|
||||
app.dialog = Some(Dialog::Print);
|
||||
app
|
||||
});
|
||||
h.run_steps(4);
|
||||
|
||||
let cancel = h.get_by_label("Cancel").rect();
|
||||
assert!(cancel.min.y >= 0.0 && cancel.max.y <= screen.y, "Cancel must stay within the {}×{} screen, got {cancel:?}", screen.x, screen.y);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user