diff --git a/imgui.cpp b/imgui.cpp index ed1c6560a..17f02f4e3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8524,12 +8524,14 @@ static void ImGui::NavUpdate() #if 0 if (g.NavScoringCount > 0) printf("[%05d] NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest); #endif + // Set input source as Gamepad when buttons are pressed before we map Keyboard (some features differs when used with Gamepad vs Keyboard) bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; if (nav_gamepad_active) if (g.IO.NavInputs[ImGuiNavInput_Activate] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Input] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Cancel] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Menu] > 0.0f) g.NavInputSource = ImGuiInputSource_NavGamepad; + // Update Keyboard->Nav inputs mapping if (nav_keyboard_active) { @@ -8549,6 +8551,7 @@ static void ImGui::NavUpdate() memcpy(g.IO.NavInputsDownDurationPrev, g.IO.NavInputsDownDuration, sizeof(g.IO.NavInputsDownDuration)); for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++) g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f; + // Process navigation init request (select first/default focus) if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove)) { @@ -8564,9 +8567,11 @@ static void ImGui::NavUpdate() g.NavInitRequestFromMove = false; g.NavInitResultId = 0; g.NavJustMovedToId = 0; + // Process navigation move request if (g.NavMoveRequest && (g.NavMoveResultLocal.ID != 0 || g.NavMoveResultOther.ID != 0)) NavUpdateMoveResult(); + // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive) { @@ -8575,6 +8580,7 @@ static void ImGui::NavUpdate() g.NavDisableHighlight = false; g.NavMoveRequestForward = ImGuiNavForward_None; } + // Apply application mouse position movement, after we had a chance to process move request result. if (g.NavMousePosDirty && g.NavIdIsAlive) { @@ -8592,16 +8598,20 @@ static void ImGui::NavUpdate() g.NavIdIsAlive = false; g.NavJustTabbedId = 0; IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1); + // Store our return window (for returning from Layer 1 to Layer 0) and clear it as soon as we step back in our own Layer 0 if (g.NavWindow) NavSaveLastChildNavWindow(g.NavWindow); if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == 0) g.NavWindow->NavLastChildNavWindow = NULL; + // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.) NavUpdateWindowing(); + // Set output flags for user application g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL) || g.NavInitRequest; + // Process NavCancel input (to close a popup, get back to parent, clear focus) if (IsNavInputPressed(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed)) { @@ -8640,6 +8650,7 @@ static void ImGui::NavUpdate() g.NavId = 0; } } + // Process manual activation request g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0; if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) @@ -8660,10 +8671,12 @@ static void ImGui::NavUpdate() if (g.NavActivateId != 0) IM_ASSERT(g.NavActivateDownId == g.NavActivateId); g.NavMoveRequest = false; + // Process programmatic activation request if (g.NavNextActivateId != 0) g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId; g.NavNextActivateId = 0; + // Initiate directional inputs request const int allowed_dir_flags = (g.ActiveId == 0) ? ~0 : g.ActiveIdAllowNavDirFlags; if (g.NavMoveRequestForward == ImGuiNavForward_None) @@ -8687,10 +8700,12 @@ static void ImGui::NavUpdate() IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued); g.NavMoveRequestForward = ImGuiNavForward_ForwardActive; } + // Update PageUp/PageDown scroll float nav_scoring_rect_offset_y = 0.0f; if (nav_keyboard_active) nav_scoring_rect_offset_y = NavUpdatePageUpPageDown(allowed_dir_flags); + // If we initiate a movement request and have no current NavId, we initiate a InitDefautRequest that will be used as a fallback if the direction fails to find a match if (g.NavMoveDir != ImGuiDir_None) { @@ -8704,6 +8719,7 @@ static void ImGui::NavUpdate() g.NavDisableHighlight = false; } NavUpdateAnyRequestFlag(); + // Scrolling if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget) { @@ -8732,10 +8748,12 @@ static void ImGui::NavUpdate() g.NavMoveFromClampedRefRect = true; } } + // Reset search results g.NavMoveResultLocal.Clear(); g.NavMoveResultLocalVisibleSet.Clear(); g.NavMoveResultOther.Clear(); + // When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0) { @@ -8750,6 +8768,7 @@ static void ImGui::NavUpdate() } g.NavMoveFromClampedRefRect = false; } + // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items) ImRect nav_rect_rel = (g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted()) ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0,0,0,0); g.NavScoringRectScreen = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : ImRect(0,0,0,0);