diff --git a/src/app/commands/mod.rs b/src/app/commands/mod.rs index 8efa97d5b..3c6a00624 100644 --- a/src/app/commands/mod.rs +++ b/src/app/commands/mod.rs @@ -554,6 +554,11 @@ inventory::submit!(crate::command::CommandRegistration { "GRIPHOT", "GRIPHOVER", "GRIPOBJLIMIT", + // Dispatched all along, but absent from the registry, so command-line + // completion never offered them. + "ISAVEBAK", + "SAVETIME", + "FILEASSOC", // Reset selected entities' overrides to follow their layer. "SETBYLAYER", // Remove duplicate objects; set drawing base point; audit integrity; diff --git a/src/app/commands/styleprops.rs b/src/app/commands/styleprops.rs index 12128fa88..b99da19b4 100644 --- a/src/app/commands/styleprops.rs +++ b/src/app/commands/styleprops.rs @@ -1167,24 +1167,37 @@ impl OpenCADStudio { let outcome: Result<(String, bool), String> = { let h = &mut self.tabs[i].scene.document.header; match name.as_str() { + // The standalone LTSCALE and CELTSCALE commands + // require a positive value; reaching the same + // variable through SETVAR used to accept zero or a + // negative one, which degenerates every dash + // pattern in the drawing. "LTSCALE" => match &value { Some(v) => v .parse::() + .ok() + .filter(|x| x.is_finite() && *x > 0.0) .map(|x| { h.linetype_scale = x; (format!("LTSCALE = {x}"), true) }) - .map_err(|_| "SETVAR: numeric value required.".into()), + .ok_or_else(|| { + "SETVAR: positive numeric value required.".into() + }), None => Ok((format!("LTSCALE = {}", h.linetype_scale), false)), }, "CELTSCALE" => match &value { Some(v) => v .parse::() + .ok() + .filter(|x| x.is_finite() && *x > 0.0) .map(|x| { h.current_entity_linetype_scale = x; (format!("CELTSCALE = {x}"), true) }) - .map_err(|_| "SETVAR: numeric value required.".into()), + .ok_or_else(|| { + "SETVAR: positive numeric value required.".into() + }), None => Ok(( format!("CELTSCALE = {}", h.current_entity_linetype_scale), false, @@ -2156,6 +2169,12 @@ impl OpenCADStudio { | "GRIPHOVER" | "GRIPOBJLIMIT" | "DELOBJ" + // App-level, not part of the drawing: + // it lives in a process global and is + // snapshotted into the settings file. + // Without this it marked the drawing + // modified instead of persisting. + | "TEXTFILL" ) { self.persist_settings_if_changed(); } else { @@ -3144,3 +3163,36 @@ mod tests { assert_eq!(app.delete_objects, 3); } } + +#[cfg(test)] +mod scale_validation_tests { + use crate::app::OpenCADStudio; + + /// A linetype scale of zero or less degenerates every dash pattern in the + /// drawing, which is why the standalone commands reject it. Reaching the + /// same variable through SETVAR used to accept it, so which door you came + /// through decided whether the drawing could be broken. + #[test] + fn both_doors_to_ltscale_refuse_a_non_positive_value() { + for name in ["LTSCALE", "CELTSCALE"] { + for entry in [format!("{name} -5"), format!("SETVAR {name} -5")] { + let mut app = OpenCADStudio::new_for_test(); + app.automation_op(r#"{"op":"new"}"#); + let i = app.active_tab; + let before = if name == "LTSCALE" { + app.tabs[i].scene.document.header.linetype_scale + } else { + app.tabs[i].scene.document.header.current_entity_linetype_scale + }; + let _ = app.run_command_line(&entry); + let after = if name == "LTSCALE" { + app.tabs[i].scene.document.header.linetype_scale + } else { + app.tabs[i].scene.document.header.current_entity_linetype_scale + }; + assert_eq!(before, after, "{entry} must be refused"); + } + } + } +} + diff --git a/src/app/settings.rs b/src/app/settings.rs index 3032b0a60..9db2d574c 100644 --- a/src/app/settings.rs +++ b/src/app/settings.rs @@ -269,12 +269,6 @@ pub struct UserSettings { pub pick_drag_rect: bool, /// Show the floating Quick Properties panel when objects are selected. pub quick_properties: bool, - /// Persisted viewport background colours (0–255 RGB); `None` = app default - /// (dark grey model / off-white paper). Applied to every drawing tab on - /// launch and to tabs opened later, so a chosen background survives restarts - /// (#188). - pub bg_color: Option<[u8; 3]>, - pub paper_bg_color: Option<[u8; 3]>, /// Interface language preference. `System` negotiates against the /// platform locale on every launch. pub language: crate::i18n::Language, @@ -384,8 +378,6 @@ impl Default for UserSettings { pick_add: true, pick_drag_rect: false, quick_properties: false, - bg_color: None, - paper_bg_color: None, language: crate::i18n::Language::default(), cliprompt_lines: 3, commandline_fade_ms: 3000, diff --git a/src/app/update/file.rs b/src/app/update/file.rs index 86694f6b2..a98df8247 100644 --- a/src/app/update/file.rs +++ b/src/app/update/file.rs @@ -435,8 +435,6 @@ impl OpenCADStudio { pick_add: self.pick_add, pick_drag_rect: self.pick_drag_rect, quick_properties: self.quick_properties, - bg_color: None, - paper_bg_color: None, language: self.language, cliprompt_lines: crate::app::settings::clamp_clipromptlines(self.cliprompt_lines), commandline_fade_ms: crate::app::settings::clamp_commandline_fade_ms( @@ -516,7 +514,6 @@ impl OpenCADStudio { self.pick_add = s.pick_add; self.pick_drag_rect = s.pick_drag_rect; self.quick_properties = s.quick_properties; - // Legacy settings.bg_color / paper_bg_color are superseded by model_space config. if crate::i18n::set_language(s.language).is_ok() { self.language = s.language; }