forked from 1b-agent/opencadstudio-upstream
feat(commands): interactive value prompts for PDMODE/PDSIZE/LTSCALE/CELTSCALE (F4)
Bare PDMODE / PDSIZE / LTSCALE / CELTSCALE now enter a generic ValuePromptCommand front-end that prompts for the value and delegates to the existing inline `<name> <value>` handler via CmdResult::Dispatch, so they prompt step-by-step like UCS. A bare Enter reports the current value; `PDMODE 3` still works as one typed / headless line. Only pure single-value setting commands are converted. Dialog-opening commands (LAYER, PURGE, DIMSTYLE, STYLE …) intentionally keep their bare-name behaviour (open the panel), and subcommand-tree commands keep their inline handlers — all already typable with arguments since F1. Adds headless test value_prompt_commands_inline_args. Fourth phase of the unified step driver. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
52f6aed2f2
commit
df0e283eba
3 files changed
+109
-4
No files matched your search
@@ -497,6 +497,27 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn value_prompt_commands_inline_args() {
|
||||
// A single-value setting command entered with its value on one line
|
||||
// drives the interactive front-end (start + value step) and applies via
|
||||
// the inline handler. (F4)
|
||||
let mut app = OpenCADStudio::new_for_test();
|
||||
app.automation_op(r#"{"op":"new"}"#);
|
||||
app.automation_op(r#"{"op":"run","cmd":"PDMODE 3"}"#);
|
||||
app.automation_op(r#"{"op":"run","cmd":"LTSCALE 2.5"}"#);
|
||||
let i = app.active_tab;
|
||||
let h = &app.tabs[i].scene.document.header;
|
||||
assert_eq!(h.point_display_mode, 3, "PDMODE 3 should set point mode");
|
||||
assert!(
|
||||
(h.linetype_scale - 2.5).abs() < 1e-9,
|
||||
"LTSCALE 2.5 should set scale, got {}",
|
||||
h.linetype_scale
|
||||
);
|
||||
// No command should be left dangling.
|
||||
assert!(app.tabs[i].active_cmd.is_none(), "command must have finished");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn save_then_open_round_trips() {
|
||||
let mut app = OpenCADStudio::new_for_test();
|
||||
|
||||
+37
-4
@@ -4944,7 +4944,13 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
}
|
||||
cmd if cmd == "LTSCALE" || cmd.starts_with("LTSCALE ") => {
|
||||
"LTSCALE" => {
|
||||
use crate::command::ValuePromptCommand;
|
||||
let c = ValuePromptCommand::new("LTSCALE", "LTSCALE new global line-type scale:");
|
||||
self.command_line.push_info(&c.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(c));
|
||||
}
|
||||
cmd if cmd.starts_with("LTSCALE ") => {
|
||||
let val_str = cmd.trim_start_matches("LTSCALE").trim();
|
||||
if val_str.is_empty() {
|
||||
let v = self.tabs[i].scene.document.header.linetype_scale;
|
||||
@@ -4964,7 +4970,16 @@ impl OpenCADStudio {
|
||||
self.command_line.push_error("Usage: LTSCALE [value]");
|
||||
}
|
||||
}
|
||||
cmd if cmd == "PDMODE" || cmd.starts_with("PDMODE ") => {
|
||||
"PDMODE" => {
|
||||
use crate::command::ValuePromptCommand;
|
||||
let c = ValuePromptCommand::new(
|
||||
"PDMODE",
|
||||
"PDMODE new value [0=dot 1=none 2=+ 3=x 4=tick; +32 circle +64 square]:",
|
||||
);
|
||||
self.command_line.push_info(&c.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(c));
|
||||
}
|
||||
cmd if cmd.starts_with("PDMODE ") => {
|
||||
let val_str = cmd.trim_start_matches("PDMODE").trim();
|
||||
if val_str.is_empty() {
|
||||
let v = self.tabs[i].scene.document.header.point_display_mode;
|
||||
@@ -4999,7 +5014,16 @@ impl OpenCADStudio {
|
||||
.push_error("Requires 0 OR 1 OR MULTIPLE OR SINGLE");
|
||||
}
|
||||
}
|
||||
cmd if cmd == "PDSIZE" || cmd.starts_with("PDSIZE ") => {
|
||||
"PDSIZE" => {
|
||||
use crate::command::ValuePromptCommand;
|
||||
let c = ValuePromptCommand::new(
|
||||
"PDSIZE",
|
||||
"PDSIZE new point size (0 = 5% of viewport, <0 = absolute):",
|
||||
);
|
||||
self.command_line.push_info(&c.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(c));
|
||||
}
|
||||
cmd if cmd.starts_with("PDSIZE ") => {
|
||||
let val_str = cmd.trim_start_matches("PDSIZE").trim();
|
||||
if val_str.is_empty() {
|
||||
let v = self.tabs[i].scene.document.header.point_display_size;
|
||||
@@ -5057,7 +5081,16 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
}
|
||||
cmd if cmd == "CELTSCALE" || cmd.starts_with("CELTSCALE ") => {
|
||||
"CELTSCALE" => {
|
||||
use crate::command::ValuePromptCommand;
|
||||
let c = ValuePromptCommand::new(
|
||||
"CELTSCALE",
|
||||
"CELTSCALE new current-object line-type scale:",
|
||||
);
|
||||
self.command_line.push_info(&c.prompt());
|
||||
self.tabs[i].active_cmd = Some(Box::new(c));
|
||||
}
|
||||
cmd if cmd.starts_with("CELTSCALE ") => {
|
||||
let val_str = cmd.trim_start_matches("CELTSCALE").trim();
|
||||
if val_str.is_empty() {
|
||||
let v = self.tabs[i]
|
||||
|
||||
@@ -79,6 +79,57 @@ pub enum StepInput {
|
||||
Escape,
|
||||
}
|
||||
|
||||
/// Generic interactive front-end for a single-value setting command (PDMODE,
|
||||
/// PDSIZE, LTSCALE, CELTSCALE, …). Bare `<name>` enters this command, which
|
||||
/// prompts for one value and then delegates to the existing inline
|
||||
/// `<name> <value>` handler via [`CmdResult::Dispatch`]. A bare Enter delegates
|
||||
/// to `<name> ` (trailing space) so the inline handler reports the current
|
||||
/// value. Keeps the value math + persistence in the one inline place while
|
||||
/// making the command prompt for its argument step-by-step.
|
||||
pub struct ValuePromptCommand {
|
||||
name: &'static str,
|
||||
prompt: &'static str,
|
||||
}
|
||||
|
||||
impl ValuePromptCommand {
|
||||
pub fn new(name: &'static str, prompt: &'static str) -> Self {
|
||||
Self { name, prompt }
|
||||
}
|
||||
}
|
||||
|
||||
impl CadCommand for ValuePromptCommand {
|
||||
fn name(&self) -> &'static str {
|
||||
self.name
|
||||
}
|
||||
|
||||
fn prompt(&self) -> String {
|
||||
self.prompt.to_string()
|
||||
}
|
||||
|
||||
fn wants_text_input(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
|
||||
let t = text.trim();
|
||||
if t.is_empty() {
|
||||
Some(CmdResult::Dispatch(format!("{} ", self.name)))
|
||||
} else {
|
||||
Some(CmdResult::Dispatch(format!("{} {t}", self.name)))
|
||||
}
|
||||
}
|
||||
|
||||
fn on_point(&mut self, _pt: DVec3) -> CmdResult {
|
||||
// A value command takes no point; ignore stray clicks, keep prompting.
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
|
||||
fn on_enter(&mut self) -> CmdResult {
|
||||
// Bare Enter → report the current value via the inline handler.
|
||||
CmdResult::Dispatch(format!("{} ", self.name))
|
||||
}
|
||||
}
|
||||
|
||||
// ── Result token ──────────────────────────────────────────────────────────
|
||||
|
||||
/// Returned by every `CadCommand` method to tell main.rs what to do.
|
||||
|
||||
Reference in new issue
Block a user