forked from 1b-agent/opencadstudio-upstream
feat(viewport): RMB=Enter option + timed right-click
Adds a configurable right-mouse-button behavior without disturbing orbit or the context menu. - New persisted setting `rmb_enter` (command `RMBENTER [ON|OFF]`, default off): when on, a right-click while a command is active acts as Enter (commit/close); when idle it still opens the context menu. Right-drag always orbits, so nothing is lost. - Right-click vs orbit is now time-based: orbit engages only after the button is held >=150ms and the pointer moves, so a quick right-click is no longer swallowed by slight pointer jitter (was an 8px distance gate). - The right-click Repeat menu now lists commands from every source (command line, ribbon, context menu, shortcuts) via a unified recents list recorded at the dispatch choke point, instead of only typed commands. Closes #185 Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
63de137106
commit
098585bb2d
10 files changed
+160
-56
No files matched your search
@@ -40,6 +40,7 @@ impl OpenCADStudio {
|
||||
},
|
||||
plugin_repos: self.plugin_repos.clone(),
|
||||
texteditmode: self.texteditmode,
|
||||
rmb_enter: self.rmb_enter,
|
||||
bg_color: self.default_bg_color.map(f4_to_u3),
|
||||
paper_bg_color: self.default_paper_bg_color.map(f4_to_u3),
|
||||
}
|
||||
@@ -58,6 +59,7 @@ impl OpenCADStudio {
|
||||
self.disabled_plugins = s.disabled_plugins.iter().cloned().collect();
|
||||
self.plugin_repos = s.plugin_repos.clone();
|
||||
self.texteditmode = s.texteditmode;
|
||||
self.rmb_enter = s.rmb_enter;
|
||||
self.default_bg_color = s.bg_color.map(u3_to_f4);
|
||||
self.default_paper_bg_color = s.paper_bg_color.map(u3_to_f4);
|
||||
// Push the restored background onto every drawing tab that exists now
|
||||
|
||||
+23
-10
@@ -1095,6 +1095,7 @@ impl OpenCADStudio {
|
||||
sel.context_menu = None;
|
||||
sel.right_down = true;
|
||||
sel.right_press_pos = Some(p);
|
||||
sel.right_press_time = Some(iced::time::Instant::now());
|
||||
sel.right_last_pos = Some(p);
|
||||
sel.right_dragging = false;
|
||||
Task::none()
|
||||
@@ -1103,19 +1104,31 @@ impl OpenCADStudio {
|
||||
Message::ViewportRightRelease => {
|
||||
let i = self.active_tab;
|
||||
let mut sel = self.tabs[i].scene.selection.borrow_mut();
|
||||
let Some(_p) = sel.last_move_pos else {
|
||||
let Some(click_pos) = sel.last_move_pos else {
|
||||
return Task::none();
|
||||
};
|
||||
if sel.right_down {
|
||||
if !sel.right_dragging {
|
||||
sel.context_menu = sel.last_move_pos;
|
||||
sel.draworder_submenu = false;
|
||||
}
|
||||
sel.right_down = false;
|
||||
sel.right_press_pos = None;
|
||||
sel.right_last_pos = None;
|
||||
sel.right_dragging = false;
|
||||
if !sel.right_down {
|
||||
return Task::none();
|
||||
}
|
||||
let was_click = !sel.right_dragging;
|
||||
sel.right_down = false;
|
||||
sel.right_press_pos = None;
|
||||
sel.right_press_time = None;
|
||||
sel.right_last_pos = None;
|
||||
sel.right_dragging = false;
|
||||
if !was_click {
|
||||
return Task::none();
|
||||
}
|
||||
// A right-click (no orbit). With "RMB = Enter" enabled, a click
|
||||
// while a command is active fires Enter (commit/close) instead
|
||||
// of the menu; when idle — or the option is off — it opens the
|
||||
// context menu as before, so the menu is never lost.
|
||||
if self.rmb_enter && self.tabs[i].active_cmd.is_some() {
|
||||
drop(sel);
|
||||
return self.update(Message::CommandFinalize);
|
||||
}
|
||||
sel.context_menu = Some(click_pos);
|
||||
sel.draworder_submenu = false;
|
||||
Task::none()
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,10 @@ use acadrust::{EntityType as AcadEntityType, Handle};
|
||||
use iced::time::Instant;
|
||||
use iced::{mouse, Point, Task};
|
||||
|
||||
/// How long the right button must be held (ms) before a right-drag is treated
|
||||
/// as an orbit. A press + release inside this window stays a click (context
|
||||
/// menu / Enter), so quick right-clicks aren't lost to slight pointer jitter.
|
||||
const RIGHT_HOLD_MS: u128 = 150;
|
||||
/// Pixel radius for grabbing a UCS-icon grip (origin dot or an axis tip).
|
||||
const UCS_GRIP_HIT_PX: f32 = 9.0;
|
||||
/// Pixel reach for hovering/clicking the icon body (origin, tips, or an arm).
|
||||
@@ -559,16 +563,31 @@ pub(super) fn on_tick(&mut self, t: Instant) -> Task<Message> {
|
||||
}
|
||||
|
||||
if sel.right_down {
|
||||
if let Some(press) = sel.right_press_pos {
|
||||
let dx = p.x - press.x;
|
||||
let dy = p.y - press.y;
|
||||
// 8 px (64 squared) threshold so normal hand jitter
|
||||
// between a right-button press and release doesn't
|
||||
// promote a click-and-release to an orbit drag, which
|
||||
// would suppress the context menu on release.
|
||||
if !sel.right_dragging && (dx * dx + dy * dy) > 64.0 {
|
||||
// Time-based click-vs-orbit split: a quick right-click
|
||||
// (press + release within RIGHT_HOLD_MS) is always a click —
|
||||
// it opens the context menu / fires Enter on release, even if
|
||||
// the pointer drifted a little. Orbit only engages once the
|
||||
// button has been *held* past the threshold and the pointer
|
||||
// is actually moving, so hand jitter during a click never
|
||||
// promotes it to an orbit drag.
|
||||
if !sel.right_dragging {
|
||||
let held = sel
|
||||
.right_press_time
|
||||
.map(|t| t.elapsed().as_millis() >= RIGHT_HOLD_MS)
|
||||
.unwrap_or(false);
|
||||
let moved = sel
|
||||
.right_press_pos
|
||||
.map(|press| {
|
||||
let (dx, dy) = (p.x - press.x, p.y - press.y);
|
||||
dx * dx + dy * dy > 4.0
|
||||
})
|
||||
.unwrap_or(false);
|
||||
if held && moved {
|
||||
sel.right_dragging = true;
|
||||
sel.context_menu = None;
|
||||
// Start the orbit from the current position so the
|
||||
// view doesn't jump by the pre-threshold movement.
|
||||
sel.right_last_pos = Some(p);
|
||||
}
|
||||
}
|
||||
if sel.right_dragging {
|
||||
@@ -1204,6 +1223,7 @@ pub(super) fn on_tick(&mut self, t: Instant) -> Task<Message> {
|
||||
sel.left_dragging = false;
|
||||
sel.right_down = false;
|
||||
sel.right_press_pos = None;
|
||||
sel.right_press_time = None;
|
||||
sel.right_last_pos = None;
|
||||
sel.right_dragging = false;
|
||||
sel.middle_down = false;
|
||||
|
||||
Reference in new issue
Block a user