From 8497abecfd2625461738f87e821fedcb0940ab03 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 8 Sep 2026 08:34:58 +0200 Subject: [PATCH 1/3] Fix ribbon command labels wrapping in the middle of words Replace Wrapping::WordOrGlyph with Wrapping::Word to prevent labels like 'Dimensions' from breaking as 'Dimensio' + 'ns'. Word-only wrapping ensures labels only wrap at word boundaries. Fixes #1046 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/ui/ribbon/widgets.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/ribbon/widgets.rs b/src/ui/ribbon/widgets.rs index 333147351..7d9276c40 100644 --- a/src/ui/ribbon/widgets.rs +++ b/src/ui/ribbon/widgets.rs @@ -132,7 +132,7 @@ fn measure_large_width(renderer: &iced::Renderer, label: &str) -> f32 { renderer, label, width, - advanced_text::Wrapping::WordOrGlyph, + advanced_text::Wrapping::Word, ) .height <= max_label_height @@ -685,7 +685,7 @@ pub(super) fn render_large_dropdown<'a>( .size(10) .width(Fill) .align_x(iced::Center) - .wrapping(advanced_text::Wrapping::WordOrGlyph), + .wrapping(advanced_text::Wrapping::Word), ] .align_x(iced::Center) .spacing(0) @@ -818,7 +818,7 @@ pub(super) fn render_large<'a>( .size(10) .width(Fill) .align_x(iced::Center) - .wrapping(advanced_text::Wrapping::WordOrGlyph), + .wrapping(advanced_text::Wrapping::Word), ] .align_x(iced::Center) .spacing(0) From 7a706e24acf6acdef8b82e25f6a051e1c5f9ba7c Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 8 Sep 2026 08:52:18 +0200 Subject: [PATCH 2/3] Improve Dutch CAD terminology translations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Multiverwijslijn → Multiverwijs Lijn (proper spacing) - Multiline → Multilijn Tekst (better clarity) - Unie → Samenvoegen (more accurate for boolean union) - Aftrekken → Verschil (better term for boolean subtract) These terms align better with Dutch CAD industry standards. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- locales/nl-NL/opencadstudio.ftl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/locales/nl-NL/opencadstudio.ftl b/locales/nl-NL/opencadstudio.ftl index 93a868eef..08dc9dfc3 100644 --- a/locales/nl-NL/opencadstudio.ftl +++ b/locales/nl-NL/opencadstudio.ftl @@ -2771,7 +2771,7 @@ annotate = .mleader = MLeader .mtext-specify-insertion-point = MTEXT Plaatsingspunt specificeren: .markup = Markering - .multileader = Multiverwijslijn + .multileader = Multiverwijs Lijn .multileader-draw-order = Tekenvolgorde multiverwijslijn: .multiline-text = Multiline @@ -3142,7 +3142,7 @@ model = .revolve-entity = Rotatieobject .revolve-flags = Vlaggen omdraaien .spherical = Sferisch - .subtract = Aftrekken + .subtract = Verschil .surface-construction = Oppervlaktebouw .sweep-path = Vegen / Pad .sweep-entity = Sweepobject @@ -3154,7 +3154,7 @@ model = .u-vector-1 = U-vector 1 .u-vector-2 = U-vector 2 .uid = UID - .union = Unie + .union = Samenvoegen .v-isolines = V-isolijnen .v-vector-1 = Vector 1 .v-vector-2 = Vector 2 @@ -3879,9 +3879,9 @@ properties = .mode = Modus .monochrome = Monochroom .more-colors = Meer kleuren... - .multileader = Multiverwijslijn - .multiline = Multiline - .multileader-style = Multiverwijslijnstijl + .multileader = Multiverwijs Lijn + .multiline = Multilijn Tekst + .multileader-style = Multiverwijs Lijnstijl .multiple-lines = Meerdere regels .n-closed = N gesloten .n-density = N-dichtheid From 92ac3f60e5e590f0a057365a367ba8a8b2b14e65 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Tue, 8 Sep 2026 09:04:52 +0200 Subject: [PATCH 3/3] Fix crash when overwriting an existing PDF file Use atomic file operations (write to temp file, then rename) instead of direct File::create() to avoid crashes when the target PDF is locked by another process (e.g., open in PDF reader). The new write_pdf_atomically() function ensures the file is either fully written or left unchanged, with a clear error message if the file is in use. Fixes #1062 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/io/pdf_export.rs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/io/pdf_export.rs b/src/io/pdf_export.rs index 0ff656d13..88911fd21 100644 --- a/src/io/pdf_export.rs +++ b/src/io/pdf_export.rs @@ -175,8 +175,7 @@ pub fn export_pdf( plot_style, options, ); - let mut file = std::fs::File::create(path).map_err(|e| e.to_string())?; - file.write_all(&bytes).map_err(|e| e.to_string()) + write_pdf_atomically(path, &bytes) } /// Export several independently sized pages into one PDF file. @@ -190,8 +189,27 @@ pub fn export_pdf_pages( return Err("No pages were selected.".into()); } let bytes = build_pdf_pages(pages, plot_style); - let mut file = std::fs::File::create(path).map_err(|e| e.to_string())?; - file.write_all(&bytes).map_err(|e| e.to_string()) + write_pdf_atomically(path, &bytes) +} + +/// Atomically write PDF bytes to a file. Writes to a temporary file first, +/// then renames it to the target path to avoid crashes when overwriting +/// a file that is locked by another process (e.g., PDF reader). +#[cfg(not(target_arch = "wasm32"))] +fn write_pdf_atomically(path: &Path, bytes: &[u8]) -> Result<(), String> { + let dir = path.parent().unwrap_or_else(|| std::path::Path::new(".")); + let file_name = path.file_name() + .and_then(|n| n.to_str()) + .ok_or_else(|| "Invalid file path".to_string())?; + let temp_path = dir.join(format!(".{}.tmp", file_name)); + + let mut file = std::fs::File::create(&temp_path) + .map_err(|e| format!("Failed to create temporary PDF file: {}", e))?; + file.write_all(bytes) + .map_err(|e| format!("Failed to write PDF data: {}", e))?; + + std::fs::rename(&temp_path, path) + .map_err(|e| format!("Failed to write PDF file: {} (the file may be open in another application)", e)) } /// Show a parented PDF save-file dialog and return the chosen path.