forked from 1b-agent/opencadstudio-upstream
fix(command): keyword/radius input for ribbon-started modify commands (#90)
Starting FILLET/CHAMFER from the ribbon left the command-line field
unfocused, so its Enter arrived as CommandFinalize and discarded a
typed option keyword ("R"/"D"), cancelling the command. Several
related dynamic-input issues surfaced from the same flow:
- CommandFinalize now forwards a non-empty command-line buffer through
CommandSubmit, so a typed keyword is handled the same whether the
command was started from the ribbon or the command line.
- sync_dyn_fields shows no coordinate box during an object-pick step
(needs_entity_pick / needs_structure_point_pick) — there is no point
to enter there, so typed keywords reach the command line cleanly.
- apply_cmd_result rebuilds the dynamic-input fields on NeedPoint, so a
step change (object pick -> radius entry) shows the matching box
immediately and typed digits land in it instead of the command line.
- Object-pick steps now draw a prompt-only hint pill at the cursor
(no input box).
- FILLET/CHAMFER remember the first pick across a mid-selection radius
or distance entry, resuming the second pick instead of restarting
selection.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
3bafe45ab3
commit
57d3e620ea
5 files changed
+141
-17
No files matched your search
@@ -1196,6 +1196,10 @@ pub struct FilletCommand {
|
||||
radius: f64,
|
||||
step: FilletStep,
|
||||
all_entities: Vec<EntityType>,
|
||||
/// First-object pick to restore after a radius entry made mid-selection
|
||||
/// (i.e. "R" pressed after the first object was already picked), so the
|
||||
/// command resumes at the second pick instead of restarting selection.
|
||||
resume_second: Option<(Handle, FilletEntity, [f64; 2])>,
|
||||
}
|
||||
|
||||
impl FilletCommand {
|
||||
@@ -1204,8 +1208,29 @@ impl FilletCommand {
|
||||
radius: radius as f64,
|
||||
step: FilletStep::First,
|
||||
all_entities,
|
||||
resume_second: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Switch to the radius sub-step, remembering the first pick (if any) so
|
||||
/// it can be restored afterwards.
|
||||
fn enter_radius_substep(&mut self) {
|
||||
self.resume_second = if let FilletStep::Second { h1, e1, click1 } = &self.step {
|
||||
Some((*h1, e1.clone(), *click1))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.step = FilletStep::WaitingForRadius;
|
||||
}
|
||||
|
||||
/// Leave the radius sub-step, resuming the second pick when a first object
|
||||
/// was already chosen, otherwise restarting at the first pick.
|
||||
fn resume_after_radius(&mut self) {
|
||||
self.step = match self.resume_second.take() {
|
||||
Some((h1, e1, click1)) => FilletStep::Second { h1, e1, click1 },
|
||||
None => FilletStep::First,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl CadCommand for FilletCommand {
|
||||
@@ -1248,8 +1273,8 @@ impl CadCommand for FilletCommand {
|
||||
FilletStep::WaitingForRadius => {
|
||||
let t = text.trim();
|
||||
if t.is_empty() {
|
||||
// Keep current radius, return to First
|
||||
self.step = FilletStep::First;
|
||||
// Keep current radius, resume where the radius was requested.
|
||||
self.resume_after_radius();
|
||||
return Some(CmdResult::NeedPoint);
|
||||
}
|
||||
if let Ok(v) = t.replace(',', ".").parse::<f64>() {
|
||||
@@ -1257,7 +1282,7 @@ impl CadCommand for FilletCommand {
|
||||
self.radius = v;
|
||||
defaults::set_fillet_radius(v as f32);
|
||||
}
|
||||
self.step = FilletStep::First;
|
||||
self.resume_after_radius();
|
||||
return Some(CmdResult::NeedPoint);
|
||||
}
|
||||
// Invalid — stay and re-prompt
|
||||
@@ -1268,7 +1293,7 @@ impl CadCommand for FilletCommand {
|
||||
let upper = t.to_uppercase();
|
||||
// "R" alone → enter sub-step to collect radius
|
||||
if upper == "R" {
|
||||
self.step = FilletStep::WaitingForRadius;
|
||||
self.enter_radius_substep();
|
||||
return Some(CmdResult::NeedPoint);
|
||||
}
|
||||
// "R 5.0" inline shorthand
|
||||
@@ -1279,10 +1304,11 @@ impl CadCommand for FilletCommand {
|
||||
self.radius = v;
|
||||
defaults::set_fillet_radius(v as f32);
|
||||
}
|
||||
// Stay in the current step (keeps any first pick).
|
||||
return Some(CmdResult::NeedPoint);
|
||||
}
|
||||
// "R" + invalid body → enter sub-step
|
||||
self.step = FilletStep::WaitingForRadius;
|
||||
self.enter_radius_substep();
|
||||
return Some(CmdResult::NeedPoint);
|
||||
}
|
||||
None
|
||||
@@ -1533,6 +1559,10 @@ pub struct ChamferCommand {
|
||||
dist2: f64,
|
||||
step: ChamferStep,
|
||||
all_entities: Vec<EntityType>,
|
||||
/// First-object pick (line or polyline segment) to restore after a
|
||||
/// distance entry made mid-selection, so the command resumes at the
|
||||
/// second pick instead of restarting selection.
|
||||
resume_pick: Option<ChamferStep>,
|
||||
}
|
||||
|
||||
impl ChamferCommand {
|
||||
@@ -1542,8 +1572,33 @@ impl ChamferCommand {
|
||||
dist2: defaults::get_chamfer_dist2() as f64,
|
||||
step: ChamferStep::First,
|
||||
all_entities,
|
||||
resume_pick: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Switch to the distance sub-step, remembering the first pick (if any).
|
||||
fn enter_dist_substep(&mut self) {
|
||||
self.resume_pick = match &self.step {
|
||||
ChamferStep::Second { h1, l1, click1 } => Some(ChamferStep::Second {
|
||||
h1: *h1,
|
||||
l1: l1.clone(),
|
||||
click1: *click1,
|
||||
}),
|
||||
ChamferStep::SecondPoly { h1, poly, click1 } => Some(ChamferStep::SecondPoly {
|
||||
h1: *h1,
|
||||
poly: poly.clone(),
|
||||
click1: *click1,
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
self.step = ChamferStep::WaitingForDist1;
|
||||
}
|
||||
|
||||
/// Leave the distance sub-step, resuming the second pick when a first
|
||||
/// object was already chosen, otherwise restarting at the first pick.
|
||||
fn resume_after_dist(&mut self) {
|
||||
self.step = self.resume_pick.take().unwrap_or(ChamferStep::First);
|
||||
}
|
||||
}
|
||||
|
||||
impl CadCommand for ChamferCommand {
|
||||
@@ -1614,14 +1669,14 @@ impl CadCommand for ChamferCommand {
|
||||
ChamferStep::WaitingForDist2 => {
|
||||
let t = text.trim();
|
||||
if t.is_empty() {
|
||||
// Keep current dist2, return to First
|
||||
self.step = ChamferStep::First;
|
||||
// Keep current dist2, resume where the distance was requested.
|
||||
self.resume_after_dist();
|
||||
return Some(CmdResult::NeedPoint);
|
||||
}
|
||||
if let Ok(v) = t.replace(',', ".").parse::<f64>() {
|
||||
self.dist2 = v.max(0.0);
|
||||
defaults::set_chamfer_dist2(self.dist2 as f32);
|
||||
self.step = ChamferStep::First;
|
||||
self.resume_after_dist();
|
||||
return Some(CmdResult::NeedPoint);
|
||||
}
|
||||
// Invalid — stay and re-prompt
|
||||
@@ -1634,7 +1689,7 @@ impl CadCommand for ChamferCommand {
|
||||
let upper = t.to_uppercase();
|
||||
// "D" alone → enter sub-step to collect distances
|
||||
if upper == "D" {
|
||||
self.step = ChamferStep::WaitingForDist1;
|
||||
self.enter_dist_substep();
|
||||
return Some(CmdResult::NeedPoint);
|
||||
}
|
||||
// "D 5.0" or "D 5.0 3.0" inline shorthand
|
||||
@@ -1659,7 +1714,7 @@ impl CadCommand for ChamferCommand {
|
||||
return Some(CmdResult::NeedPoint);
|
||||
}
|
||||
// "D" + invalid body → enter sub-step
|
||||
self.step = ChamferStep::WaitingForDist1;
|
||||
self.enter_dist_substep();
|
||||
return Some(CmdResult::NeedPoint);
|
||||
}
|
||||
None
|
||||
|
||||
Reference in new issue
Block a user