feat(plot): paper catalogue with AutoCAD canonical media names

AutoCAD stores a layout's sheet as the plotter driver's canonical media
name (`ISO_A4_(210.00_x_297.00_MM)`, `ANSI_full_bleed_B_(11.00_x_17.00_Inches)`),
so a drawing saved here has to carry the same spelling for AutoCAD to find
the sheet in its DWG To PDF list, and a name that arrives from AutoCAD must
resolve to its dimensions and go back out untouched.

- New `io::paper_catalog` replaces the eight-entry `paper_sizes`: ISO A/B,
  ANSI, ARCH (incl. E1) and JIS series with full-bleed / expand variants,
  Letter / Legal / Tabloid, millimetre and inch units, a parser that
  reconstructs any well-formed AutoCAD name (custom or driver-specific)
  from its embedded dimensions, driver / legacy-config aliases (`A4`,
  `Letter`, `Ledger`), and dimension matching that prefers the plain sheet.
- The Plot dialog stores the canonical name and shows the sheet as
  `ISO A4 (210 × 297 mm)`; a sheet that only exists in the drawing is
  listed first so it stays selectable.
- A sheet the user did not change keeps the drawing's own media name
  (`paper_name_for_settings`), so a Windows printer's `A4` is not rewritten
  to `ISO_A4_(…)` just by passing through the dialog.
- Drops the unused `PlotFormat` / `PlotOrientation` messages,
  `paper_label_from_dims`, and three duplicated `match "A4" | …` tables.

Tests: catalogue spelling, parser round-trip, aliases, dimension matching,
display formatting, plus dialog ↔ layout round-trips for driver-named,
catalogue and unknown sheets.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
PanosandClaude Opus 5 committed 2026-09-16 16:05:46 +03:00
1 parent d894b8eb05
commit 567eb90925
8 files changed
+909 -253

No files matched your search

+31 -15
View File
@@ -5,7 +5,7 @@
//! PDF. Styled to match the other OCS dialogs (dark pills + fields).
use crate::app::Message;
use crate::io::paper_sizes::PaperSize;
use crate::io::paper_catalog::{self, PaperSize};
use iced::widget::{
button, checkbox, column, container, mouse_area, row, scrollable, text, text_input,
Space,
@@ -28,25 +28,39 @@ pub const STYLE_NONE: &str = "<none>";
/// A plot dropdown value keeps its persisted/raw value separate from the
/// localized label shown by Iced. Printer names, scale names, paper sizes, and
/// style-table file names remain verbatim; built-in choices use the catalog.
/// A paper choice keeps the canonical media name as its value and shows the
/// sheet's human name with its dimensions.
#[derive(Clone, Debug, Eq, PartialEq)]
struct PlotChoice {
raw: String,
localized: bool,
/// Display text when it differs from `raw` (paper sizes).
display: Option<String>,
}
impl PlotChoice {
fn raw(value: impl Into<String>) -> Self {
Self { raw: value.into(), localized: false }
Self { raw: value.into(), localized: false, display: None }
}
fn localized(value: impl Into<String>) -> Self {
Self { raw: value.into(), localized: true }
Self { raw: value.into(), localized: true, display: None }
}
fn paper(paper: &PaperSize) -> Self {
Self {
raw: paper.canonical.to_string(),
localized: false,
display: Some(paper.display()),
}
}
}
impl fmt::Display for PlotChoice {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.localized {
if let Some(display) = &self.display {
formatter.write_str(display)
} else if self.localized {
if let Some(name) = self.raw.strip_prefix("View: ") {
formatter.write_str(crate::tf!("View: {name}").as_ref())
} else {
@@ -212,7 +226,7 @@ impl Default for PlotDialogState {
printers: Vec::new(),
printer: None,
to_file: false,
paper: "A4".into(),
paper: paper_catalog::default_paper().canonical.to_string(),
paper_width_mm: 297.0,
paper_height_mm: 210.0,
orientation: "Landscape".into(),
@@ -659,9 +673,17 @@ pub fn view_window(
None => PlotChoice::localized(OUT_DEFAULT),
})
};
let mut paper_opts: Vec<String> = PaperSize::ALL.iter().map(|p| p.label().to_string()).collect();
if !paper_opts.iter().any(|name| name == &s.paper) {
paper_opts.push(s.paper.clone());
// The picker lists the catalogue by series; a sheet that only exists in
// the drawing (a driver's custom size, an old config's bare name) is added
// at the top so the current selection is always visible and re-selectable.
let selected_paper = paper_catalog::from_drawing(&s.paper, s.paper_width_mm, s.paper_height_mm);
let mut paper_opts: Vec<PlotChoice> = paper_catalog::catalog()
.iter()
.map(PlotChoice::paper)
.collect();
let paper_sel = PlotChoice::paper(&selected_paper);
if !paper_opts.contains(&paper_sel) {
paper_opts.insert(0, paper_sel.clone());
}
let paper_note: Element<'_, Message> = if s.area == "Layout" {
text(t!("Layout plots the current sheet using the selected paper size."))
@@ -712,13 +734,7 @@ pub fn view_window(
// ── Paper, area, offset, scale ────────────────────────────────────────
let paper_panel = panel(column![
section_label(t!("Paper")),
drop_row(
t!("Size"),
paper_opts.into_iter().map(PlotChoice::raw).collect(),
Some(PlotChoice::raw(s.paper.clone())),
PlotDlgMsg::Paper,
width,
),
drop_row(t!("Size"), paper_opts, Some(paper_sel), PlotDlgMsg::Paper, width),
paper_note,
].spacing(7));