collective

Browse / github.com/storytold/gridcraft / patch

Fit sheet on one page for PDF export

Fit sheet on one page for PDF export <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **New Features** * Added a “Fit to one page” option to PDF exports from the Save As and Export pages. It is off by default, and when enabled, scales the PDF content to fit on a single page. * The option applies only to PDF exports; CSV and HTML exports remain unchanged. <!-- end of auto-generated comment: release notes by coderabbit.ai -->

Status
open
Score
0.00
Adopters
0 other operators
Author
Dmussi (imported from pull request #2652, open)
Base
d8c5f5885fc5320f8f1023d5fdc9f484a185ba86
Size
+24 −9 in 1 file
Review
pending
Shared
2026-10-28
Id
e2668c4471819ce3b3cbf996

How it went

No other operator has reported using it yet.

Diff

raw · crates/ui-egui/src/backstage.rs

diff --git a/crates/ui-egui/src/backstage.rs b/crates/ui-egui/src/backstage.rs--- a/crates/ui-egui/src/backstage.rs+++ b/crates/ui-egui/src/backstage.rs@@ -112,6 +112,8 @@ pub struct Backstage {     pub print_all: bool,     /// Print: fit each sheet on one page.     pub fit_to_page: bool,+    /// Export and Save As: fit each sheet of a PDF on one page.+    pub pdf_fit_to_page: bool,     /// Print: the previewed page (0-based).     preview_page: usize,     /// Print: the preview for (document, revision, whole workbook, fit to page).@@ -134,6 +136,7 @@ impl Backstage {             props: Default::default(),             print_all: false,             fit_to_page: false,+            pdf_fit_to_page: false,             preview_page: 0,             preview: None,             save_format: "xlsx",@@ -216,7 +219,7 @@ pub fn show(app: &mut SheetApp, ui: &mut Ui) {                     Page::Info => info(app, ui, &mut bs),                     Page::SaveAs => save_as(app, ui, &mut bs, &mut out),                     Page::Print => print(app, ui, &mut bs, &mut out),-                    Page::Export => export(app, ui, &mut out),+                    Page::Export => export(app, ui, &mut bs, &mut out),                     Page::Options => options(app, ui),                     Page::Account => account(app, ui),                 }@@ -696,10 +699,14 @@ fn save_as(app: &mut SheetApp, ui: &mut Ui, bs: &mut Backstage, out: &mut Outcom             if after != before || app.services.pick_save.is_none() {                 out.close = true;             }-        } else if export_as(app, fmt) {+        } else if export_as(app, fmt, bs.pdf_fit_to_page) {             out.close = true;         }     }+    if fmt == "pdf" {+        ui.add_space(8.0);+        ui.checkbox(&mut bs.pdf_fit_to_page, lang.tr("Fit Sheet on One Page"));+    }     ui.add_space(18.0);     dim(ui, lang.tr("A CSV file, web page or PDF is a copy: the workbook keeps its own file.")); }@@ -870,28 +877,31 @@ fn paint_page(p: &egui::Painter, rect: Rect, paper_w: f32, page: &Json, wb: &gri     } } -fn export(app: &mut SheetApp, ui: &mut Ui, out: &mut Outcome) {+fn export(app: &mut SheetApp, ui: &mut Ui, bs: &mut Backstage, out: &mut Outcome) {     let lang = app.ui.language;     if action_row(ui, Icon::Paper, lang.tr("Create PDF"), lang.tr("Save the sheet as a PDF document that keeps its page layout.")).clicked()-        && export_as(app, "pdf")+        && export_as(app, "pdf", bs.pdf_fit_to_page)     {         out.close = true;     }+    ui.add_space(6.0);+    ui.checkbox(&mut bs.pdf_fit_to_page, lang.tr("Fit Sheet on One Page"));     ui.add_space(14.0);     section(ui, lang, "Change File Type");     for (fmt, icon, title, detail) in [         ("csv", Icon::TextColumns, "CSV (Comma delimited)", "Save the active sheet as comma-separated text."),         ("html", Icon::Link, "Web Page (.html)", "Save the workbook as a web page."),     ] {-        if action_row(ui, icon, lang.tr(title), lang.tr(detail)).clicked() && export_as(app, fmt) {+        if action_row(ui, icon, lang.tr(title), lang.tr(detail)).clicked() && export_as(app, fmt, false) {             out.close = true;         }     } }  /// Exports the active workbook as `pdf`, `csv` or `html`: through the save picker on the desktop,-/// as a browser download on the web. Returns whether a file was written or handed over.-pub fn export_as(app: &mut SheetApp, fmt: &str) -> bool {+/// as a browser download on the web. `fit_to_page` fits each sheet of a PDF on one page; the other+/// formats ignore it. Returns whether a file was written or handed over.+pub fn export_as(app: &mut SheetApp, fmt: &str, fit_to_page: bool) -> bool {     if !app.commit_edit(0, 0, false, false) {         return false;     }@@ -907,7 +917,11 @@ pub fn export_as(app: &mut SheetApp, fmt: &str) -> bool {         let Some(path) = pick(&format!("{stem}.{fmt}")) else { return false };         // The picker may suggest a workbook extension; the export writes the chosen format.         let path = std::path::Path::new(&path).with_extension(fmt).to_string_lossy().into_owned();-        return match app.run(id, json!({"path": path})) {+        let mut params = json!({"path": path});+        if fmt == "pdf" && fit_to_page {+            params["fitToPage"] = json!(true);+        }+        return match app.run(id, params) {             Ok(_) => true,             Err(e) => {                 app.message = Some(("GridCraft".into(), crate::clean_error(&e)));@@ -921,7 +935,8 @@ pub fn export_as(app: &mut SheetApp, fmt: &str) -> bool {     }     if fmt == "pdf" {         // Without a path the PDF comes back as bytes, which `SheetApp::run` hands to the browser.-        return match app.run(id, json!({})) {+        let params = if fit_to_page { json!({"fitToPage": true}) } else { json!({}) };+        return match app.run(id, params) {             Ok(_) => true,             Err(e) => {                 app.message = Some(("GridCraft".into(), crate::clean_error(&e)));