feat(commands): prompt the single-value settings step by step

Bare CLAYER / CDIMSTY / COLOR / LWDISPLAY / ISAVEBAK / FILEASSOC /
SAVETIME / ANNOSCALE printed the current value or a usage line and
stopped; only the fully-typed `NAME <value>` form set anything. Route the
bare form through ValuePromptCommand (the pattern LTSCALE / PDMODE / PDSIZE
already use): it prompts for the value and re-dispatches `NAME <value>` to
the existing inline handler, so the set/get logic stays in one place. The
bare-Enter getter is preserved — ValuePromptCommand dispatches `NAME `,
which the argument arm reports the current value for (added that empty
case to ISAVEBAK / FILEASSOC / SAVETIME, which previously errored on it).
COLOR keeps BYLAYER as an immediate shortcut rather than a prompt.

USERR / USERI are left as-is: they take two inputs (register 1-5 + value),
so they need a two-step command rather than the single-value prompt.
This commit is contained in:
Hakan Seven 2026-07-16 13:00:10 +03:00
commit 5f1019edec
2 changed files with 79 additions and 24 deletions

View file

@ -688,11 +688,16 @@ impl OpenCADStudio {
// ANNOSCALE / CANNOSCALE <ratio> — set the current annotation scale // ANNOSCALE / CANNOSCALE <ratio> — set the current annotation scale
// (e.g. 1:50, 2:1, or a plain factor). Drives annotative-object size // (e.g. 1:50, 2:1, or a plain factor). Drives annotative-object size
// in model space and is written to the drawing header. // in model space and is written to the drawing header.
cmd if cmd == "ANNOSCALE" "ANNOSCALE" | "CANNOSCALE" => {
|| cmd == "CANNOSCALE" use crate::command::ValuePromptCommand;
|| cmd.starts_with("ANNOSCALE ") let c = ValuePromptCommand::new(
|| cmd.starts_with("CANNOSCALE ") => "ANNOSCALE",
{ "ANNOSCALE new annotation scale (e.g. 1:50, 2:1, or a factor):",
);
self.command_line.push_info(&c.prompt());
self.tabs[i].active_cmd = Some(Box::new(c));
}
cmd if cmd.starts_with("ANNOSCALE ") || cmd.starts_with("CANNOSCALE ") => {
let arg = cmd let arg = cmd
.split_whitespace() .split_whitespace()
.nth(1) .nth(1)

View file

@ -5,11 +5,18 @@ impl OpenCADStudio {
match cmd { match cmd {
// COLOR <ByLayer|ByBlock|1-255|name> — the colour applied to new // COLOR <ByLayer|ByBlock|1-255|name> — the colour applied to new
// objects (CECOLOR). Bare COLOR reports the current value. // objects (CECOLOR). Bare COLOR reports the current value.
cmd if cmd == "COLOR" "COLOR" | "COLOUR" | "CECOLOR" | "DDCOLOR" => {
|| cmd == "COLOUR" use crate::command::ValuePromptCommand;
|| cmd == "CECOLOR" let c = ValuePromptCommand::new(
|| cmd == "DDCOLOR" "COLOR",
|| cmd == "BYLAYER" "COLOR new object colour [ByLayer / ByBlock / 1-255 / red / yellow / green / cyan / blue / magenta / white]:",
);
self.command_line.push_info(&c.prompt());
self.tabs[i].active_cmd = Some(Box::new(c));
}
// BYLAYER is an immediate shortcut (sets ByLayer without prompting);
// the `<name> <value>` forms and the bare-Enter getter route here too.
cmd if cmd == "BYLAYER"
|| cmd.starts_with("COLOR ") || cmd.starts_with("COLOR ")
|| cmd.starts_with("COLOUR ") || cmd.starts_with("COLOUR ")
|| cmd.starts_with("CECOLOR ") || cmd.starts_with("CECOLOR ")
@ -1474,7 +1481,13 @@ impl OpenCADStudio {
// TEXTSTYLE [name] — already handled above under STYLE SET // TEXTSTYLE [name] — already handled above under STYLE SET
// DIMSTYLE [name] — get or set active dim style // DIMSTYLE [name] — get or set active dim style
// LTSCALE [val] — global linetype scale // LTSCALE [val] — global linetype scale
cmd if cmd == "CLAYER" || cmd.starts_with("CLAYER ") => { "CLAYER" => {
use crate::command::ValuePromptCommand;
let c = ValuePromptCommand::new("CLAYER", "CLAYER new current layer name:");
self.command_line.push_info(&c.prompt());
self.tabs[i].active_cmd = Some(Box::new(c));
}
cmd if cmd.starts_with("CLAYER ") => {
let name_arg = cmd.trim_start_matches("CLAYER").trim(); let name_arg = cmd.trim_start_matches("CLAYER").trim();
if name_arg.is_empty() { if name_arg.is_empty() {
let cur = &self.tabs[i].scene.document.header.current_layer_name; let cur = &self.tabs[i].scene.document.header.current_layer_name;
@ -1493,11 +1506,14 @@ impl OpenCADStudio {
} }
} }
} }
cmd if cmd == "CDIMSTY" "CDIMSTY" | "DIMCURRENT" => {
|| cmd == "DIMCURRENT" use crate::command::ValuePromptCommand;
|| cmd.starts_with("CDIMSTY ") let c =
|| cmd.starts_with("DIMCURRENT ") => ValuePromptCommand::new("CDIMSTY", "CDIMSTY new current dimension style name:");
{ self.command_line.push_info(&c.prompt());
self.tabs[i].active_cmd = Some(Box::new(c));
}
cmd if cmd.starts_with("CDIMSTY ") || cmd.starts_with("DIMCURRENT ") => {
let name_arg = cmd.split_whitespace().skip(1).collect::<Vec<_>>().join(" "); let name_arg = cmd.split_whitespace().skip(1).collect::<Vec<_>>().join(" ");
if name_arg.is_empty() { if name_arg.is_empty() {
let cur = &self.tabs[i].scene.document.header.current_dimstyle_name; let cur = &self.tabs[i].scene.document.header.current_dimstyle_name;
@ -1587,11 +1603,18 @@ impl OpenCADStudio {
} }
} }
"ISAVEBAK" => { "ISAVEBAK" => {
let v = if self.backup_on_save { 1 } else { 0 }; use crate::command::ValuePromptCommand;
self.command_line.push_output(&format!("ISAVEBAK = {v}")); let c =
ValuePromptCommand::new("ISAVEBAK", "ISAVEBAK write a .bak on save? [1 / 0]:");
self.command_line.push_info(&c.prompt());
self.tabs[i].active_cmd = Some(Box::new(c));
} }
cmd if cmd.starts_with("ISAVEBAK ") => { cmd if cmd.starts_with("ISAVEBAK ") => {
match cmd.trim_start_matches("ISAVEBAK").trim() { match cmd.trim_start_matches("ISAVEBAK").trim() {
"" => {
let v = if self.backup_on_save { 1 } else { 0 };
self.command_line.push_output(&format!("ISAVEBAK = {v}"));
}
"0" => { "0" => {
self.backup_on_save = false; self.backup_on_save = false;
self.persist_settings_if_changed(); self.persist_settings_if_changed();
@ -1606,11 +1629,20 @@ impl OpenCADStudio {
} }
} }
"FILEASSOC" => { "FILEASSOC" => {
let v = if self.file_assoc_enabled { 1 } else { 0 }; use crate::command::ValuePromptCommand;
self.command_line.push_output(&format!("FILEASSOC = {v}")); let c = ValuePromptCommand::new(
"FILEASSOC",
"FILEASSOC register as a .dwg/.dxf handler? [1 / 0]:",
);
self.command_line.push_info(&c.prompt());
self.tabs[i].active_cmd = Some(Box::new(c));
} }
cmd if cmd.starts_with("FILEASSOC ") => { cmd if cmd.starts_with("FILEASSOC ") => {
match cmd.trim_start_matches("FILEASSOC").trim() { match cmd.trim_start_matches("FILEASSOC").trim() {
"" => {
let v = if self.file_assoc_enabled { 1 } else { 0 };
self.command_line.push_output(&format!("FILEASSOC = {v}"));
}
"1" => { "1" => {
self.file_assoc_enabled = true; self.file_assoc_enabled = true;
self.persist_settings_if_changed(); self.persist_settings_if_changed();
@ -1639,11 +1671,22 @@ impl OpenCADStudio {
} }
} }
"SAVETIME" => { "SAVETIME" => {
self.command_line use crate::command::ValuePromptCommand;
.push_output(&format!("SAVETIME = {}", self.savetime_min)); let c = ValuePromptCommand::new(
"SAVETIME",
"SAVETIME autosave interval in minutes (0 = off):",
);
self.command_line.push_info(&c.prompt());
self.tabs[i].active_cmd = Some(Box::new(c));
} }
cmd if cmd.starts_with("SAVETIME ") => { cmd if cmd.starts_with("SAVETIME ") => {
match cmd.trim_start_matches("SAVETIME").trim().parse::<i32>() { let arg = cmd.trim_start_matches("SAVETIME").trim();
if arg.is_empty() {
self.command_line
.push_output(&format!("SAVETIME = {}", self.savetime_min));
return Some(Task::none());
}
match arg.parse::<i32>() {
Ok(v) if v >= 0 => { Ok(v) if v >= 0 => {
self.savetime_min = v; self.savetime_min = v;
self.persist_settings_if_changed(); self.persist_settings_if_changed();
@ -1695,7 +1738,14 @@ impl OpenCADStudio {
self.point_size_buf = format!("{}", pdsize.abs()); self.point_size_buf = format!("{}", pdsize.abs());
self.active_modal = Some(super::super::ModalKind::PointStyle); self.active_modal = Some(super::super::ModalKind::PointStyle);
} }
cmd if cmd == "LWDISPLAY" || cmd.starts_with("LWDISPLAY ") => { "LWDISPLAY" => {
use crate::command::ValuePromptCommand;
let c =
ValuePromptCommand::new("LWDISPLAY", "LWDISPLAY show lineweights? [ON / OFF]:");
self.command_line.push_info(&c.prompt());
self.tabs[i].active_cmd = Some(Box::new(c));
}
cmd if cmd.starts_with("LWDISPLAY ") => {
let val_str = cmd.trim_start_matches("LWDISPLAY").trim(); let val_str = cmd.trim_start_matches("LWDISPLAY").trim();
let parsed: Result<Option<bool>, ()> = match val_str.to_ascii_uppercase().as_str() { let parsed: Result<Option<bool>, ()> = match val_str.to_ascii_uppercase().as_str() {
"" => Ok(None), "" => Ok(None),