Skip to content

Commit 022deea

Browse files
committed
improve logic around double-clicks and selection
1 parent d034498 commit 022deea

File tree

1 file changed

+30
-10
lines changed

1 file changed

+30
-10
lines changed

src/polyscope.cpp

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,11 @@ namespace {
431431

432432
float dragDistSinceLastRelease = 0.0;
433433

434+
// State for delayed pick selection
435+
bool pendingPickActive = false;
436+
PickResult pendingPickResult;
437+
float pendingPickTime = 0.0f;
438+
434439
void processInputEvents() {
435440
ImGuiIO& io = ImGui::GetIO();
436441

@@ -516,24 +521,36 @@ void processInputEvents() {
516521
}
517522
}
518523

519-
{ // Click picks
524+
{ // Click picks to select content onscreen
520525
float dragIgnoreThreshold = 0.01;
521526
bool anyModifierHeld = io.KeyShift || io.KeyCtrl || io.KeyAlt;
522527
bool ctrlShiftHeld = io.KeyShift && io.KeyCtrl;
523528

524-
// NOTE: there is annoyance here that we use single click for picking, and double click
525-
// to recenter the view. However, there's no way to distingish which is happening
526-
// after the first click without waiting. After trying several solutions, it feels
527-
// best to let the first click always do a pick, but clear the selection if a
528-
// double click comes in.
529+
// NOTE: there is some extra 'pending' logic here, because we use double clicks to recenter the view, but we
530+
// don't want a pick to trigger after the first click of a double click. To handle this, we delay applying
531+
// picks until enough time has passed that a double click would have been registered.
532+
533+
// Check if enough time has passed for a pending pick to be applied
534+
if (pendingPickActive) {
535+
float elapsedSec = ImGui::GetTime() - pendingPickTime;
536+
float pickDelaySec = ImGui::GetIO().MouseDoubleClickTime + 0.05f; // 50ms margin for safety
537+
if (haveSelection() || elapsedSec >= pickDelaySec) {
538+
// enough time has passed, apply the pending pick
539+
setSelection(pendingPickResult);
540+
pendingPickActive = false;
541+
}
542+
}
529543

530544
if (!anyModifierHeld && (io.MouseReleased[0] && io.MouseClickedLastCount[0] == 1)) {
531545

532-
// Don't pick at the end of a long drag
546+
// don't pick at the end of a long drag
533547
if (dragDistSinceLastRelease < dragIgnoreThreshold) {
534548
glm::vec2 screenCoords{io.MousePos.x, io.MousePos.y};
535549
PickResult pickResult = pickAtScreenCoords(screenCoords);
536-
setSelection(pickResult);
550+
// queue the pick for delayed application
551+
pendingPickResult = pickResult;
552+
pendingPickTime = ImGui::GetTime();
553+
pendingPickActive = true;
537554
}
538555
}
539556

@@ -543,15 +560,15 @@ void processInputEvents() {
543560
resetSelection();
544561
}
545562
dragDistSinceLastRelease = 0.0;
563+
pendingPickActive = false;
546564
}
547565

548566
// Double-click or Ctrl-shift left-click to set new center
549567
if ((io.MouseReleased[0] && io.MouseClickedLastCount[0] == 2) || (io.MouseReleased[0] && ctrlShiftHeld)) {
550568
if (dragDistSinceLastRelease < dragIgnoreThreshold) {
551569
glm::vec2 screenCoords{io.MousePos.x, io.MousePos.y};
552570
view::processSetCenter(screenCoords);
553-
resetSelection(); // the single-click creates a selection, this clears it. unfortunately that leads to a
554-
// flicker, but its unavoidable without introducing a lag
571+
pendingPickActive = false; // cancel any pending pick from the first click
555572
}
556573
}
557574
}
@@ -974,7 +991,10 @@ void buildPickGui() {
974991
} else {
975992
// this is a paranoid check, it _should_ never happen since we
976993
// clear the selection when a structure is deleted
994+
// NOTE: it might be possible to hit this due to the way we set delayed picks, if the structure is deleted during
995+
// the delay
977996
ImGui::TextUnformatted("ERROR: INVALID STRUCTURE");
997+
resetSelection();
978998
}
979999

9801000
internal::rightWindowsWidth = ImGui::GetWindowWidth();

0 commit comments

Comments
 (0)