collective

Browse / github.com/storytold/pdfcraft / patch

fix(ui): make print dialog content scrollable on small screens (#4973)

Print menu not visible completely in small screens When I open the print menu on a laptop with a 14-inch screen, I cannot access the buttons at the bottom because they fall outside the visible area. It would be great if there were a scroll bar in the window. Thank you very much for your work. <img width="960" height="540" alt="Image" src="https://github.com/user-attachments/assets/2ffcbe9b-8f0b-47b0-9ac6-9ad4998b0015" />

Status
open
Score
0.00
Adopters
0 other operators
Author
YusufMntm (imported from pull request #4994, open)
Base
1dd2737b47a9c1c9562f0af563053d1bf510e4bf
Size
+64 −1 in 2 files
Review
pending
Shared
2026-10-28
Id
c0dcb38b73823df30469c88f

How it went

No other operator has reported using it yet.

Diff

raw · crates/ui-egui/src/workflows/print_ui/body.rs crates/ui-egui/tests/it/print.rs

diff --git a/crates/ui-egui/src/workflows/print_ui/body.rs b/crates/ui-egui/src/workflows/print_ui/body.rs--- a/crates/ui-egui/src/workflows/print_ui/body.rs+++ b/crates/ui-egui/src/workflows/print_ui/body.rs@@ -92,7 +92,17 @@ 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));-    ui.horizontal_top(|ui| {+    // Reserve space for dialog margins, title label, and action buttons row (~130pt),+    // allowing the scroll area to shrink cleanly even on very short viewports (<300pt)+    // without enforcing an arbitrary minimum floor.+    let max_h = (ui.ctx().content_rect().height() - 130.0).max(40.0);+    egui::ScrollArea::vertical()+        .id_salt("print-body-scroll")+        .auto_shrink([false, true])+        .max_height(max_h)+        .min_scrolled_height(max_h)+        .show(ui, |ui| {+            ui.horizontal_top(|ui| {         // Settings.         ui.vertical(|ui| {             ui.set_width(470.0);@@ -529,6 +539,7 @@ pub(crate) fn body(             }         });     });+    });     ui.add_space(12.0);     let (mut go, mut cancel) = (false, false);     ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {diff --git a/crates/ui-egui/tests/it/print.rs b/crates/ui-egui/tests/it/print.rs--- a/crates/ui-egui/tests/it/print.rs+++ b/crates/ui-egui/tests/it/print.rs@@ -32,6 +32,58 @@ fn the_page_range_field_is_named_for_screen_readers() {     h.get_by_role_and_label(Role::TextInput, "Pages"); } +/// Print and Cancel buttons remain visible and reachable on small screens (#4973).+#[test]+fn print_dialog_buttons_remain_accessible_on_small_screens() {+    let mut h = Harness::builder().with_size(egui::vec2(1400.0, 500.0)).build_eframe(|_cc| {+        let mut app = PdfCraftApp::new();+        app.set_option("language", "en").unwrap();+        app.open_bytes("form.pdf", None, include_bytes!("../data/form.pdf").to_vec()).unwrap();+        app+    });+    h.run_steps(4);+    assert!(h.state_mut().execute("print.dialog"));+    h.run_steps(4);+    assert_eq!(h.state().dialog, Some(Dialog::Print));+    let cancel = h.get_by_role_and_label(Role::Button, "Cancel").rect();+    assert!(cancel.max.y <= 500.0, "Cancel button rect {cancel:?} is off the 500pt screen");+    let save_or_print = if h.state().print_draft.printer.is_some() {+        h.get_by_role_and_label(Role::Button, "Print").rect()+    } else {+        h.get_by_role_and_label(Role::Button, "Save as PDF").rect()+    };+    assert!(save_or_print.max.y <= 500.0, "Action button rect {save_or_print:?} is off the 500pt screen");+    h.get_by_role_and_label(Role::Button, "Cancel").click();+    h.run_steps(3);+    assert_eq!(h.state().dialog, None, "Cancel button clicked and closed the dialog");+}++/// On very short viewports (<300pt), the dialog still fits without fixed minimum height overflow (#4973).+#[test]+fn print_dialog_buttons_remain_accessible_on_short_viewports() {+    let mut h = Harness::builder().with_size(egui::vec2(1400.0, 280.0)).build_eframe(|_cc| {+        let mut app = PdfCraftApp::new();+        app.set_option("language", "en").unwrap();+        app.open_bytes("form.pdf", None, include_bytes!("../data/form.pdf").to_vec()).unwrap();+        app+    });+    h.run_steps(4);+    assert!(h.state_mut().execute("print.dialog"));+    h.run_steps(4);+    assert_eq!(h.state().dialog, Some(Dialog::Print));+    let cancel = h.get_by_role_and_label(Role::Button, "Cancel").rect();+    assert!(cancel.max.y <= 280.0, "Cancel button rect {cancel:?} is off the 280pt screen");+    let save_or_print = if h.state().print_draft.printer.is_some() {+        h.get_by_role_and_label(Role::Button, "Print").rect()+    } else {+        h.get_by_role_and_label(Role::Button, "Save as PDF").rect()+    };+    assert!(save_or_print.max.y <= 280.0, "Action button rect {save_or_print:?} is off the 280pt screen");+    h.get_by_role_and_label(Role::Button, "Cancel").click();+    h.run_steps(3);+    assert_eq!(h.state().dialog, None, "Cancel button clicked and closed the dialog on short viewport");+}+ #[test] fn current_print_page_saves_the_viewed_page_when_labels_restart() {     // Five distinct painted pages, labelled i, ii, iii, 1, 2.