fix(grip): open hover popup without requiring mouse motion

Dwell timing only advanced when `ViewportMove` fired; a perfectly
still cursor never triggered the popup. Subscribe to animation
frames while `grip_hover` is set and dispatch `GripDwellTick` from
them so `update_grip_hover` re-checks the elapsed dwell each frame.
Subscription auto-stops as soon as the hover clears or the popup
opens.
This commit is contained in:
Hakan Seven committed 2026-05-29 09:38:37 +03:00
1 parent 6c1462932d
commit 595ee3e245
3 files changed
+29

No files matched your search

+3
View File
@@ -453,6 +453,9 @@ pub enum Message {
/// User picked an item in the multi-functional grip popup menu —
/// the index is into `grip_popup.items`.
GripMenuPick(usize),
/// Timer pulse while the cursor is dwelling on a grip; drives the
/// dwell-to-popup transition without requiring further mouse motion.
GripDwellTick,
WindowResized(f32, f32),
/// Enter pressed globally — finalises the active command (no text-input involvement).
CommandFinalize,
+15
View File
@@ -3067,6 +3067,21 @@ impl OpenCADStudio {
Task::none()
}
Message::GripDwellTick => {
let i = self.active_tab;
// Reuse the move-time logic — `p` is the last cursor
// position the viewport saw, which is also what the
// hover state was last set with.
let p = self.tabs[i]
.scene
.selection
.borrow()
.last_move_pos
.unwrap_or(self.cursor_pos);
self.update_grip_hover(i, p);
Task::none()
}
Message::GripMenuPick(idx) => {
let i = self.active_tab;
let Some(popup) = self.grip_popup.take() else {
+11
View File
@@ -932,9 +932,20 @@ impl OpenCADStudio {
} else {
Subscription::none()
};
// While the cursor sits over a grip, request animation frames
// so the multi-functional popup opens even when the user keeps
// the mouse perfectly still — `ViewportMove` alone would never
// fire again. Auto-stops once the hover clears or the popup is
// already open.
let grip_dwell = if self.grip_hover.is_some() && self.grip_popup.is_none() {
window::frames().map(|_| Message::GripDwellTick)
} else {
Subscription::none()
};
iced::Subscription::batch([
frames,
history_tick,
grip_dwell,
event::listen_with(|ev, status, win_id| {
use iced::event::Status;
match ev {