fix(commandline): empty Space/Enter repeats the last command
Two follow-ups to the always-on keyboard work: 1. **Repeat last command on empty Submit.** Pressing Space (or Enter) after a command ended did nothing — the trailing-space submit path reached `CommandSubmit`, found no active command and no buffered text, and bailed. `CommandFinalize` already had the repeat-last shortcut via `tab.last_cmd`; mirror it inside `CommandSubmit` so the space-as-submit path picks it up too. 2. **Drop the per-event focus_cmd_input calls** added in the previous commit for `ViewportLeftPress`, `ViewportClick`, `TabNew`, `TabSwitch`, `RibbonSelectTab` and `RibbonToolClick`. The global keyboard subscription routes unhandled character / backspace events into the buffer regardless of focus, so the only places that still need an explicit refocus are `cmd_result.rs` (command lifecycle), `boot()` (initial caret), and the per-char append handlers (caret feedback while typing). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
39150d617f
commit
979ca28632
1 changed files with 16 additions and 13 deletions
|
|
@ -691,7 +691,7 @@ impl OpenCADStudio {
|
||||||
|
|
||||||
Message::RibbonSelectTab(idx) => {
|
Message::RibbonSelectTab(idx) => {
|
||||||
self.ribbon.select(idx);
|
self.ribbon.select(idx);
|
||||||
self.focus_cmd_input()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::RibbonToolClick { tool_id, event } => {
|
Message::RibbonToolClick { tool_id, event } => {
|
||||||
|
|
@ -727,7 +727,7 @@ impl OpenCADStudio {
|
||||||
return Task::done(Message::ToggleLayers);
|
return Task::done(Message::ToggleLayers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.focus_cmd_input()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Application menu ──────────────────────────────────────────
|
// ── Application menu ──────────────────────────────────────────
|
||||||
|
|
@ -759,7 +759,7 @@ impl OpenCADStudio {
|
||||||
// fresh tab's defaults (ByLayer) instead of inheriting the
|
// fresh tab's defaults (ByLayer) instead of inheriting the
|
||||||
// previous tab's last selection.
|
// previous tab's last selection.
|
||||||
self.sync_ribbon_from_selection();
|
self.sync_ribbon_from_selection();
|
||||||
self.focus_cmd_input()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::TabSwitch(idx) => {
|
Message::TabSwitch(idx) => {
|
||||||
|
|
@ -772,7 +772,7 @@ impl OpenCADStudio {
|
||||||
// if there is one), not the prior tab's choice.
|
// if there is one), not the prior tab's choice.
|
||||||
self.sync_ribbon_from_selection();
|
self.sync_ribbon_from_selection();
|
||||||
}
|
}
|
||||||
self.focus_cmd_input()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::TabClose(idx) => {
|
Message::TabClose(idx) => {
|
||||||
|
|
@ -922,6 +922,13 @@ impl OpenCADStudio {
|
||||||
if let Some(cmd) = self.command_line.submit() {
|
if let Some(cmd) = self.command_line.submit() {
|
||||||
return self.dispatch_command(&cmd);
|
return self.dispatch_command(&cmd);
|
||||||
}
|
}
|
||||||
|
// Empty Enter / Space with no active command repeats the
|
||||||
|
// last dispatched command — same shortcut `CommandFinalize`
|
||||||
|
// already implements, mirrored here so the trailing-space
|
||||||
|
// submit path goes through it too.
|
||||||
|
if let Some(cmd) = self.tabs[i].last_cmd.clone() {
|
||||||
|
return self.dispatch_command(&cmd);
|
||||||
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1752,15 +1759,11 @@ impl OpenCADStudio {
|
||||||
|
|
||||||
Message::ViewportLeftPress => {
|
Message::ViewportLeftPress => {
|
||||||
let i = self.active_tab;
|
let i = self.active_tab;
|
||||||
// Clicking inside the viewport must not park focus on the
|
|
||||||
// viewport widget — typed characters need to keep flowing
|
|
||||||
// into the command-line input. Refocus on every exit path.
|
|
||||||
let refocus = self.focus_cmd_input();
|
|
||||||
let (p, vp_size) = {
|
let (p, vp_size) = {
|
||||||
let sel = self.tabs[i].scene.selection.borrow();
|
let sel = self.tabs[i].scene.selection.borrow();
|
||||||
let p = match sel.last_move_pos {
|
let p = match sel.last_move_pos {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => return refocus,
|
None => return Task::none(),
|
||||||
};
|
};
|
||||||
(p, sel.vp_size)
|
(p, sel.vp_size)
|
||||||
};
|
};
|
||||||
|
|
@ -1777,7 +1780,7 @@ impl OpenCADStudio {
|
||||||
if scene::hit_test(p.x, p.y, vw, vh, cam.view_rotation_mat(), VIEWCUBE_PX)
|
if scene::hit_test(p.x, p.y, vw, vh, cam.view_rotation_mat(), VIEWCUBE_PX)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
return refocus;
|
return Task::none();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1813,7 +1816,7 @@ impl OpenCADStudio {
|
||||||
origin_world: world,
|
origin_world: world,
|
||||||
last_world: world,
|
last_world: world,
|
||||||
});
|
});
|
||||||
return refocus;
|
return Task::none();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1824,7 +1827,7 @@ impl OpenCADStudio {
|
||||||
sel.left_press_pos = Some(p);
|
sel.left_press_pos = Some(p);
|
||||||
sel.left_press_time = Some(Instant::now());
|
sel.left_press_time = Some(Instant::now());
|
||||||
sel.left_dragging = false;
|
sel.left_dragging = false;
|
||||||
refocus
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::ViewportLeftRelease => {
|
Message::ViewportLeftRelease => {
|
||||||
|
|
@ -2476,7 +2479,7 @@ impl OpenCADStudio {
|
||||||
) {
|
) {
|
||||||
return Task::done(Message::ViewCubeSnap(region));
|
return Task::done(Message::ViewCubeSnap(region));
|
||||||
}
|
}
|
||||||
self.focus_cmd_input()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::WindowResized(w, h) => {
|
Message::WindowResized(w, h) => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue