From e85e2aeb78162dce772a62a3403bf98a334c5051 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Thu, 16 Jul 2026 14:47:45 +0300 Subject: [PATCH] feat(commands): step POLYSOLID (select polyline, then width + height) Add SelectThenTwoValueCommand (gather a selection, then two values) and use it for POLYSOLID: bare POLYSOLID gathers the polyline if none is selected, prompts for wall width then height, and dispatches POLYSOLID . --- src/app/commands/draw.rs | 14 +++++- src/command.rs | 92 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/src/app/commands/draw.rs b/src/app/commands/draw.rs index 4a914079c..231643daf 100644 --- a/src/app/commands/draw.rs +++ b/src/app/commands/draw.rs @@ -761,7 +761,19 @@ impl OpenCADStudio { // POLYSOLID — extrude a selected polyline into a // wall-like solid. - cmd if cmd == "POLYSOLID" || cmd.starts_with("POLYSOLID ") => { + "POLYSOLID" => { + use crate::command::SelectThenTwoValueCommand; + let has_sel = !self.tabs[i].scene.selected_entities().is_empty(); + let c = SelectThenTwoValueCommand::new( + "POLYSOLID", + "POLYSOLID wall width:", + "POLYSOLID wall height:", + has_sel, + ); + self.command_line.push_info(&c.prompt()); + self.tabs[i].active_cmd = Some(Box::new(c)); + } + cmd if cmd.starts_with("POLYSOLID ") => { let nums: Vec = cmd .split_whitespace() .skip(1) diff --git a/src/command.rs b/src/command.rs index 98af4b89d..f854107b6 100644 --- a/src/command.rs +++ b/src/command.rs @@ -673,6 +673,98 @@ impl CadCommand for SelectThenValueCommand { } } +/// Generic front-end for a two-value command that operates on the current +/// selection (POLYSOLID width + height on a selected polyline). Gathers a +/// selection first when none is set, prompts for two values, and dispatches +/// ` ` to the inline handler. +pub struct SelectThenTwoValueCommand { + name: &'static str, + prompt1: &'static str, + prompt2: &'static str, + gathering: bool, + selected: Vec, + first: Option, +} + +impl SelectThenTwoValueCommand { + pub fn new( + name: &'static str, + prompt1: &'static str, + prompt2: &'static str, + has_selection: bool, + ) -> Self { + Self { + name, + prompt1, + prompt2, + gathering: !has_selection, + selected: Vec::new(), + first: None, + } + } +} + +impl CadCommand for SelectThenTwoValueCommand { + fn name(&self) -> &'static str { + self.name + } + + fn prompt(&self) -> String { + if self.gathering { + format!("{} select objects, then press Enter:", self.name) + } else if self.first.is_none() { + self.prompt1.to_string() + } else { + self.prompt2.to_string() + } + } + + fn wants_text_input(&self) -> bool { + !self.gathering + } + + fn is_selection_gathering(&self) -> bool { + self.gathering + } + + fn on_selection_complete(&mut self, handles: Vec) -> CmdResult { + self.selected = handles; + CmdResult::NeedPoint + } + + fn on_text_input(&mut self, text: &str) -> Option { + if self.gathering { + return None; + } + let t = text.trim(); + if t.is_empty() { + return None; + } + match &self.first { + None => { + self.first = Some(t.to_string()); + None + } + Some(first) => Some(CmdResult::Dispatch(format!("{} {first} {t}", self.name))), + } + } + + fn on_point(&mut self, _pt: DVec3) -> CmdResult { + CmdResult::NeedPoint + } + + fn on_enter(&mut self) -> CmdResult { + if self.gathering { + if self.selected.is_empty() { + return CmdResult::Cancel; + } + self.gathering = false; + return CmdResult::NeedPoint; + } + CmdResult::Cancel + } +} + // ── Result token ────────────────────────────────────────────────────────── /// Returned by every `CadCommand` method to tell main.rs what to do.