feat(ui): feature-parity context menu — Snap Overrides, transparent Pan/Zoom, ARC keyword flow

The command menu now follows the commercial solutions' layout row for row: Enter, Cancel,
Recent Input ▸, the command's keywords, Snap Overrides ▸ (every object snap
with its glyph, Mid Between 2 Points, None, Osnap Settings…), then Pan and
Zoom. Pan / Zoom run transparently while a command is active ('PAN,
'ZOOM …): navigation modes leave the command untouched and an interactive
ZOOM Window parks it and resumes it afterwards. Rows carry an icon gutter
so labels align; the Enter row shows a default value ("<0.5000>") as its
hint instead of a second finish row.

ARC gets the commercial solutions' prompt flow with all keywords: start [Center], second
point [Center/End], end; after Center: end [Angle/chord Length]; after
End: center [Angle/Direction/Radius]; Enter continues tangent. The
previous default (Center/Start/End with method codes) stays as ARC_CSE.

Object snaps gain a one-shot "None" override. New strings in all locales.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
PanosandClaude Opus 5 committed 2026-09-17 12:05:15 +03:00
1 parent 96df4928c7
commit 02cd98e790
34 files changed
+1305 -67

No files matched your search

+35
View File
@@ -920,6 +920,9 @@ impl OpenCADStudio {
);
let task = self.apply_cmd_result_inner(result);
let i = self.active_tab;
// A transparent zoom that just finished hands control back to the
// command it interrupted before the "command ended" bookkeeping below.
self.resume_transparent_parent(i);
let preview_hidden = self.tabs[i]
.active_cmd
.as_ref()
@@ -1394,6 +1397,38 @@ impl OpenCADStudio {
Task::none()
}
/// Bring back the command a transparent zoom parked, once the zoom is
/// over (no command active any more). No-op otherwise.
pub(in crate::app) fn resume_transparent_parent(&mut self, i: usize) {
if !self.tabs[i].transparent_resume {
return;
}
if self.tabs[i].active_cmd.is_some() {
// The transparent prompt is still up (or the parent was already
// restored by a Cancel).
if self.tabs[i].suspended_cmd.is_none() {
self.tabs[i].transparent_resume = false;
}
return;
}
self.tabs[i].transparent_resume = false;
let Some(parent) = self.tabs[i].suspended_cmd.take() else {
return;
};
self.tabs[i].active_cmd = Some(parent);
let prompt = self.tabs[i].active_cmd.as_ref().map(|c| c.prompt());
if let Some(p) = prompt {
self.command_line.push_info(&p);
}
let opts = self.tabs[i]
.active_cmd
.as_ref()
.map(|c| c.options())
.unwrap_or_default();
self.command_line.set_step_options(opts);
self.refresh_active_cmd_preview(i);
}
pub(in crate::app) fn start_mtp_modifier(&mut self, i: usize) {
let parent = self.tabs[i].active_cmd.take();
self.tabs[i].suspended_cmd = parent;