feat(viewport): RMB 1st=Enter, 2nd=menu (no setting)

Replaces the opt-in `rmb_enter` setting (and `RMBENTER` command) with
always-on behavior. While a command is active, the first viewport
right-click acts as Enter (commit / close) and a second consecutive
right-click opens the context menu instead. Idle right-click still opens
the menu; right-drag still orbits.

The cycle is tracked per tab (`right_click_entered`) and restarts on any
other interaction — a left-click pick, a new command, an orbit, or
leaving the viewport — so the next right-click is Enter again.

Refines #185.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-06-27 16:32:40 +03:00
commit b691854e7a
8 changed files with 26 additions and 41 deletions

View file

@ -40,7 +40,6 @@ 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),
}
@ -59,7 +58,6 @@ 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

View file

@ -1119,14 +1119,18 @@ impl OpenCADStudio {
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() {
// A right-click (no orbit). While a command is active the first
// right-click acts as Enter (commit / close); a second
// consecutive right-click opens the context menu instead. When
// idle it always opens the menu. (Right-drag, handled above,
// always orbits.) Any other interaction — a left-click pick or a
// new command — resets the cycle so the next right-click is Enter.
if self.tabs[i].active_cmd.is_some() && !sel.right_click_entered {
sel.right_click_entered = true;
drop(sel);
return self.update(Message::CommandFinalize);
}
sel.right_click_entered = false;
sel.context_menu = Some(click_pos);
sel.draworder_submenu = false;
Task::none()

View file

@ -585,6 +585,8 @@ pub(super) fn on_tick(&mut self, t: Instant) -> Task<Message> {
if held && moved {
sel.right_dragging = true;
sel.context_menu = None;
// An orbit restarts the right-click cycle.
sel.right_click_entered = false;
// Start the orbit from the current position so the
// view doesn't jump by the pre-threshold movement.
sel.right_last_pos = Some(p);
@ -1226,6 +1228,7 @@ pub(super) fn on_tick(&mut self, t: Instant) -> Task<Message> {
sel.right_press_time = None;
sel.right_last_pos = None;
sel.right_dragging = false;
sel.right_click_entered = false;
sel.middle_down = false;
sel.middle_last_pos = None;
sel.box_anchor = None;
@ -1440,6 +1443,10 @@ pub(super) fn on_tick(&mut self, t: Instant) -> Task<Message> {
pub(super) fn on_viewport_left_press(&mut self) -> Task<Message> {
let i = self.active_tab;
// A left-click during a command resets the right-click cycle, so
// the next right-click acts as Enter again rather than opening
// the context menu.
self.tabs[i].scene.selection.borrow_mut().right_click_entered = false;
// A click in the viewport dismisses any open ribbon dropdown
// (e.g. the annotation style combo), which has no backdrop of
// its own to catch outside clicks.