From ccd1086f9f6fced535e2072280e72edba2e0bf0e Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Tue, 21 Jul 2026 22:00:55 +0300 Subject: [PATCH] fix(app): running OSNAP set is app-level, not per-drawing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modern DWG (R2000+) has no file slot for OSMODE — reading a file left the header at 0, and adopt_header_sysvars wiped the user's running snap set on every open. Persist the set (as an $OSMODE-style bitmask) in settings.json, save it on every snap toggle, and only let a file override it when it actually carries a nonzero mask (R13/R14 DWG, DXF). Co-Authored-By: Claude Fable 5 --- src/app/commands/styleprops.rs | 2 ++ src/app/settings.rs | 9 +++++++++ src/app/update/file.rs | 19 ++++++++++++++++--- src/app/update/mod.rs | 2 ++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/app/commands/styleprops.rs b/src/app/commands/styleprops.rs index 76b0754a9..71c195316 100644 --- a/src/app/commands/styleprops.rs +++ b/src/app/commands/styleprops.rs @@ -1309,6 +1309,8 @@ impl OpenCADStudio { ); self.snapper.enabled = modes.into_iter().collect(); self.snapper.snap_enabled = en; + // The OSNAP set is app-level (no modern-DWG file slot). + self.persist_settings_if_changed(); } } } diff --git a/src/app/settings.rs b/src/app/settings.rs index f0b50cb55..b5191df7e 100644 --- a/src/app/settings.rs +++ b/src/app/settings.rs @@ -116,6 +116,12 @@ pub struct UserSettings { /// instead of submitting (as if every line started with `>`), until the /// user toggles it back off. pub literal_spaces: bool, + /// Running object-snap set + master toggle as an `$OSMODE`-style bitmask. + /// App-level, not per-drawing: modern DWG (R2000+) has no file slot for + /// OSMODE (it moved to the registry), so the set follows the user. A + /// legacy R13/R14 or DXF file carrying a nonzero `$OSMODE` still overrides + /// it on open (see `adopt_header_sysvars`). + pub osmode: i32, /// Controls whether the TEXTEDIT command repeats automatically (0 = Multiple, 1 = Single). pub texteditmode: bool, /// TEXTFILL: fill TrueType glyphs (true) or draw them hollow (false). @@ -148,6 +154,9 @@ impl Default for UserSettings { disabled_plugins: Vec::new(), plugin_repos: Vec::new(), literal_spaces: false, + // Snapper::default(): END|MID|CEN|NODE|QUAD|INT|NEA (575), master + // off (suppress bit 16384). + osmode: 575 | OSMODE_SUPPRESS, texteditmode: false, textfill: true, backup_on_save: true, diff --git a/src/app/update/file.rs b/src/app/update/file.rs index d2bc61863..af6d1d268 100644 --- a/src/app/update/file.rs +++ b/src/app/update/file.rs @@ -76,6 +76,10 @@ impl OpenCADStudio { }, plugin_repos: self.plugin_repos.clone(), literal_spaces: self.command_line.literal_spaces, + osmode: crate::app::settings::osmode_from_snaps( + self.snapper.enabled.iter(), + self.snapper.snap_enabled, + ), texteditmode: self.texteditmode, textfill: crate::scene::text::sdf_atlas::textfill(), backup_on_save: self.backup_on_save, @@ -98,6 +102,9 @@ impl OpenCADStudio { self.disabled_plugins = s.disabled_plugins.iter().cloned().collect(); self.plugin_repos = s.plugin_repos.clone(); self.command_line.literal_spaces = s.literal_spaces; + let (modes, snap_enabled) = crate::app::settings::snaps_from_osmode(s.osmode); + self.snapper.enabled = modes.into_iter().collect(); + self.snapper.snap_enabled = snap_enabled; self.texteditmode = s.texteditmode; crate::scene::text::sdf_atlas::set_textfill(s.textfill); self.backup_on_save = s.backup_on_save; @@ -132,9 +139,15 @@ impl OpenCADStudio { if ortho { self.polar_mode = false; } - let (modes, snap_enabled) = crate::app::settings::snaps_from_osmode(osmode); - self.snapper.enabled = modes.into_iter().collect(); - self.snapper.snap_enabled = snap_enabled; + // OSMODE has no file slot in modern DWG (R2000+ moved it to the + // registry), so a header value of 0 just means "absent" — keep the + // user's app-level set instead of wiping it. Only a legacy R13/R14 or + // DXF file that really carries a nonzero mask overrides. + if osmode != 0 { + let (modes, snap_enabled) = crate::app::settings::snaps_from_osmode(osmode); + self.snapper.enabled = modes.into_iter().collect(); + self.snapper.snap_enabled = snap_enabled; + } } /// Stamp the live per-drawing sysvars (Ortho, running OSNAP) onto tab `i`'s diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index 063bbf22d..af01aeb31 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -1548,6 +1548,7 @@ impl OpenCADStudio { Message::ToggleSnapEnabled => { self.snapper.toggle_global(); self.sync_vport_display(self.active_tab); + self.persist_settings_if_changed(); Task::none() } Message::ToggleGridSnap => { @@ -2048,6 +2049,7 @@ impl OpenCADStudio { } Message::ToggleSnap(t) => { self.snapper.toggle(t); + self.persist_settings_if_changed(); Task::none() } Message::ToggleSnapPopup => {