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 <noreply@anthropic.com>
This commit is contained in:
1 parent
3bafe45ab3
commit
57d3e620ea
5 files changed
+141
-17
No files matched your search
@@ -42,6 +42,12 @@ impl OpenCADStudio {
|
||||
if let Some(p) = prompt {
|
||||
self.command_line.push_info(&p);
|
||||
}
|
||||
// The command may have advanced to a step with a different
|
||||
// dynamic-input shape (e.g. FILLET object-pick → radius entry).
|
||||
// Rebuild the fields now so the matching box appears immediately
|
||||
// and typed digits land in it rather than the command line,
|
||||
// instead of waiting for the next cursor move to resync.
|
||||
self.sync_dyn_fields();
|
||||
}
|
||||
CmdResult::Preview(wire) => {
|
||||
self.tabs[i].scene.set_preview_wires(vec![wire]);
|
||||
|
||||
+21
-3
@@ -1382,6 +1382,15 @@ impl OpenCADStudio {
|
||||
let idx = self.grip_popup.as_ref().map(|p| p.selected).unwrap_or(0);
|
||||
return Task::done(Message::GripMenuPick(idx));
|
||||
}
|
||||
// Pending typed command-line text (e.g. an option keyword like
|
||||
// "R") must be submitted rather than finalising the command.
|
||||
// The focused-input Enter routes through CommandSubmit, but a
|
||||
// command started from the ribbon never focuses the field, so
|
||||
// its Enter arrives here — forward to the same submit path.
|
||||
let i = self.active_tab;
|
||||
if self.tabs[i].active_cmd.is_some() && !self.command_line.input.trim().is_empty() {
|
||||
return self.update(Message::CommandSubmit);
|
||||
}
|
||||
// A typed dynamic-input value commits as a point pick
|
||||
// before the plain-Enter (on_enter) path runs.
|
||||
if let Some(task) = self.try_dyn_commit() {
|
||||
@@ -7327,7 +7336,7 @@ impl OpenCADStudio {
|
||||
/// command-state changes. The field set only changes shape when the
|
||||
/// command's `dyn_field()` or the presence of a base point changes;
|
||||
/// existing typed buffers survive an unchanged shape.
|
||||
fn sync_dyn_fields(&mut self) {
|
||||
pub(super) fn sync_dyn_fields(&mut self) {
|
||||
use super::document::{DynComponent, DynFieldEntry};
|
||||
let i = self.active_tab;
|
||||
if !self.dyn_input || self.tabs[i].active_cmd.is_none() {
|
||||
@@ -7351,6 +7360,15 @@ impl OpenCADStudio {
|
||||
.as_ref()
|
||||
.map(|c| c.wants_text_input())
|
||||
.unwrap_or(false);
|
||||
// A step that hit-tests for an object (entity / structure pick) has no
|
||||
// coordinate to enter — clicks select, they don't place a point. Show
|
||||
// no coordinate box so the cursor stays clean and typed option keywords
|
||||
// (e.g. FILLET's "R") reach the command line instead of an X/Y field.
|
||||
let picks_object = self.tabs[i]
|
||||
.active_cmd
|
||||
.as_ref()
|
||||
.map(|c| c.needs_entity_pick() || c.needs_structure_point_pick())
|
||||
.unwrap_or(false);
|
||||
let has_base = self.last_point.is_some();
|
||||
// While aligned to an OTRACK ray, the point step reads a single
|
||||
// distance along the ray (issue #69) — show one Distance box.
|
||||
@@ -7366,7 +7384,7 @@ impl OpenCADStudio {
|
||||
// a name / a keyword (which may itself contain digits) from the
|
||||
// command line — show no scalar box, so digits reach the command
|
||||
// line instead of being captured into a dyn buffer.
|
||||
crate::command::DynField::Point if wants_text => vec![],
|
||||
crate::command::DynField::Point if wants_text || picks_object => vec![],
|
||||
crate::command::DynField::Point if has_base => {
|
||||
vec![DynComponent::Distance, DynComponent::Angle]
|
||||
}
|
||||
@@ -7388,7 +7406,7 @@ impl OpenCADStudio {
|
||||
// the command's default so e.g. clicking the first point of LINE
|
||||
// flips a stale `[X, Y]` (from before there was a base) over to
|
||||
// the polar `[Distance, Angle]` the prompt actually wants.
|
||||
let current_is_acceptable = if self.dyn_user_reshaped && !wants_text {
|
||||
let current_is_acceptable = if self.dyn_user_reshaped && !wants_text && !picks_object {
|
||||
match field {
|
||||
crate::command::DynField::Distance => {
|
||||
matches!(current.as_slice(), [DynComponent::Distance])
|
||||
|
||||
+11
-1
@@ -691,8 +691,18 @@ impl OpenCADStudio {
|
||||
// between boxes; typing locks a box to a fixed value while the
|
||||
// rest keep tracking the cursor. The field set is maintained in
|
||||
// `tab.dyn_fields` by `sync_dyn_fields`.
|
||||
// A pick step (object selection) has no input box, but still shows
|
||||
// its prompt ("Select first object …") near the cursor as a hint.
|
||||
let dyn_picks_object = tab
|
||||
.active_cmd
|
||||
.as_ref()
|
||||
.map(|c| c.needs_entity_pick() || c.needs_structure_point_pick())
|
||||
.unwrap_or(false);
|
||||
let dyn_input_overlay: Option<Element<'_, Message>> =
|
||||
if self.dyn_input && tab.active_cmd.is_some() && !tab.dyn_fields.is_empty() {
|
||||
if self.dyn_input
|
||||
&& tab.active_cmd.is_some()
|
||||
&& (!tab.dyn_fields.is_empty() || dyn_picks_object)
|
||||
{
|
||||
let w = tab.last_cursor_world;
|
||||
let base = self.last_point;
|
||||
// A command may drive a typed scalar by mouse (e.g. a
|
||||
|
||||
Reference in new issue
Block a user