forked from 1b-agent/opencadstudio-upstream
feat(commands): integrate standard CAD commands and fix behavior gaps
Broad pass over the command set: integrate missing commands, wire previously-unreachable ribbon/menu buttons, and correct name/behaviour mismatches. Every UI command token now resolves (real handler where the infrastructure exists, an honest "not yet implemented" status otherwise). New commands: - Draw: 3DPOLY, 2D solid (SO/SOLID2D), HELIX, TRACE, SKETCH, DIMCENTER (DCE/CENTERMARK) - Modify/inquiry: REVERSE, MEASUREGEOM (MEA), DBLIST - Data/manage: BASE, OVERKILL (exact-duplicate removal), AUDIT (read-only integrity report), SETVAR (system-variable get/set), SCRIPT (.scr runner), FINDNONPURGEABLE Behaviour fixes: - LINE and SPLINE gain Close/Undo; AREA computes area/perimeter in f64 (correct at large coordinates) - ATTEDIT/ATE unified so the alias and the ribbon button open the interactive editor; -ATTEDIT is the command-line form - Linear/aligned/radius/diameter dimensions gain a text override (Text) and text angle (Angle) option - INSERT gains Scale/Rotate options; COPY gains an Array option - LINETYPE SET sets the current entity linetype; SETBYLAYER resets overrides - UNDO accepts a step count Integrations: standard dimension/block aliases (DLI/DRA/DAN, BMAKE, EXPORTPDF, DDIM), drafting-aid and screen toggles (GRID/SNAP/POLAR/OSNAP/ DSETTINGS/CLEANSCREEN/QUICKPROPERTIES), viewport tiling (CASCADE/HORIZONTAL/VERTICAL/VPJOIN), and customization entry points (CUI/ALIASEDIT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
e04b580a70
commit
0ca3954b5d
32 files changed
+2763
-67
No files matched your search
@@ -32,9 +32,24 @@ enum Step {
|
||||
},
|
||||
}
|
||||
|
||||
/// Which numeric value the insertion-point step is currently waiting for after
|
||||
/// a Scale / Rotate keyword.
|
||||
#[derive(Clone, Copy)]
|
||||
enum AwaitKind {
|
||||
Scale,
|
||||
Rotation,
|
||||
}
|
||||
|
||||
pub struct InsertBlockCommand {
|
||||
available: Vec<String>,
|
||||
step: Step,
|
||||
/// Uniform X/Y scale applied to the placed block (default 1).
|
||||
x_scale: f64,
|
||||
y_scale: f64,
|
||||
/// Rotation applied to the placed block, in radians (default 0).
|
||||
rotation_rad: f64,
|
||||
/// Set while a Scale/Rotate value is being typed at the insertion step.
|
||||
awaiting: Option<AwaitKind>,
|
||||
/// Pending Insert entity stored while attr-filling is in progress.
|
||||
pending_insert: Option<Insert>,
|
||||
/// Optional drag preview: the block's wire geometry plus the base point it
|
||||
@@ -48,6 +63,10 @@ impl InsertBlockCommand {
|
||||
Self {
|
||||
available,
|
||||
step: Step::Name,
|
||||
x_scale: 1.0,
|
||||
y_scale: 1.0,
|
||||
rotation_rad: 0.0,
|
||||
awaiting: None,
|
||||
pending_insert: None,
|
||||
preview: None,
|
||||
}
|
||||
@@ -61,6 +80,10 @@ impl InsertBlockCommand {
|
||||
Self {
|
||||
available: vec![name.clone()],
|
||||
step: Step::Point { name },
|
||||
x_scale: 1.0,
|
||||
y_scale: 1.0,
|
||||
rotation_rad: 0.0,
|
||||
awaiting: None,
|
||||
pending_insert: None,
|
||||
preview: Some((preview_wires, base)),
|
||||
}
|
||||
@@ -82,7 +105,14 @@ impl CadCommand for InsertBlockCommand {
|
||||
};
|
||||
format!("INSERT Enter block name:{hint}")
|
||||
}
|
||||
Step::Point { name } => format!("INSERT Specify insertion point for \"{}\":", name),
|
||||
Step::Point { name } => match self.awaiting {
|
||||
Some(AwaitKind::Scale) => "INSERT Specify scale factor <1>:".to_string(),
|
||||
Some(AwaitKind::Rotation) => "INSERT Specify rotation angle <0>:".to_string(),
|
||||
None => format!(
|
||||
"INSERT Specify insertion point for \"{}\" [Scale/Rotate]:",
|
||||
name
|
||||
),
|
||||
},
|
||||
Step::FillAttr { attdefs, idx, .. } => {
|
||||
if let Some((tag, prompt, default)) = attdefs.get(*idx) {
|
||||
let default_hint = if default.is_empty() {
|
||||
@@ -107,10 +137,13 @@ impl CadCommand for InsertBlockCommand {
|
||||
match &self.step {
|
||||
Step::Name => CmdResult::NeedPoint,
|
||||
Step::Point { name } => {
|
||||
let ins = Insert::new(
|
||||
let mut ins = Insert::new(
|
||||
name.clone(),
|
||||
Vector3::new(pt.x as f64, pt.y as f64, pt.z as f64),
|
||||
);
|
||||
ins.set_x_scale(self.x_scale);
|
||||
ins.set_y_scale(self.y_scale);
|
||||
ins.rotation = self.rotation_rad;
|
||||
let block_name = name.clone();
|
||||
self.pending_insert = Some(ins);
|
||||
// Signal the host to check for attdefs.
|
||||
@@ -122,6 +155,12 @@ impl CadCommand for InsertBlockCommand {
|
||||
|
||||
fn on_enter(&mut self) -> CmdResult {
|
||||
match &self.step {
|
||||
// A bare Enter while a scale/rotation value is awaited keeps the
|
||||
// current default instead of cancelling the command.
|
||||
Step::Point { .. } if self.awaiting.is_some() => {
|
||||
self.awaiting = None;
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
Step::Name | Step::Point { .. } => CmdResult::Cancel,
|
||||
Step::FillAttr { .. } => {
|
||||
// Treat Enter as accepting the default.
|
||||
@@ -131,7 +170,17 @@ impl CadCommand for InsertBlockCommand {
|
||||
}
|
||||
|
||||
fn wants_text_input(&self) -> bool {
|
||||
matches!(self.step, Step::Name | Step::FillAttr { .. })
|
||||
matches!(
|
||||
self.step,
|
||||
Step::Name | Step::FillAttr { .. } | Step::Point { .. }
|
||||
)
|
||||
}
|
||||
|
||||
fn point_step_accepts_keywords(&self) -> bool {
|
||||
// The insertion-point step also takes Scale / Rotate keywords while
|
||||
// still accepting a point pick. Once a value is being typed (awaiting),
|
||||
// route the whole number through `on_text_input` instead.
|
||||
matches!(self.step, Step::Point { .. }) && self.awaiting.is_none()
|
||||
}
|
||||
|
||||
fn wants_text_with_spaces(&self) -> bool {
|
||||
@@ -152,7 +201,34 @@ impl CadCommand for InsertBlockCommand {
|
||||
Some(CmdResult::NeedPoint)
|
||||
}
|
||||
Step::FillAttr { .. } => Some(self.accept_attr_value(text)),
|
||||
Step::Point { .. } => None,
|
||||
Step::Point { .. } => {
|
||||
// Typing the value awaited after a Scale / Rotate keyword.
|
||||
if let Some(kind) = self.awaiting {
|
||||
if let Ok(v) = text.trim().parse::<f64>() {
|
||||
match kind {
|
||||
AwaitKind::Scale if v != 0.0 => {
|
||||
self.x_scale = v;
|
||||
self.y_scale = v;
|
||||
}
|
||||
AwaitKind::Scale => {}
|
||||
AwaitKind::Rotation => self.rotation_rad = v.to_radians(),
|
||||
}
|
||||
}
|
||||
self.awaiting = None;
|
||||
return Some(CmdResult::NeedPoint);
|
||||
}
|
||||
match text.trim().to_uppercase().as_str() {
|
||||
"S" | "SCALE" => {
|
||||
self.awaiting = Some(AwaitKind::Scale);
|
||||
Some(CmdResult::NeedPoint)
|
||||
}
|
||||
"R" | "ROTATE" => {
|
||||
self.awaiting = Some(AwaitKind::Rotation);
|
||||
Some(CmdResult::NeedPoint)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user