@@ -431,6 +431,11 @@ namespace {
431431
432432float dragDistSinceLastRelease = 0.0 ;
433433
434+ // State for delayed pick selection
435+ bool pendingPickActive = false ;
436+ PickResult pendingPickResult;
437+ float pendingPickTime = 0 .0f ;
438+
434439void 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