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
@@ -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)));