Skip to content

Commit 0c1e5bd

Browse files
committed
Nav: extracted sections of NavUpdate() into a NavUpdateCreateMoveRequest() function. Only clearing results when a request is activated.
1 parent ccfb200 commit 0c1e5bd

File tree

1 file changed

+86
-70
lines changed

1 file changed

+86
-70
lines changed

imgui.cpp

+86-70
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,7 @@ static void NavUpdateWindowing();
909909
static void NavUpdateWindowingOverlay();
910910
static void NavUpdateInitResult();
911911
static void NavUpdateCancelRequest();
912+
static void NavUpdateCreateMoveRequest();
912913
static float NavUpdatePageUpPageDown();
913914
static inline void NavUpdateAnyRequestFlag();
914915
static void NavEndFrame();
@@ -9110,8 +9111,8 @@ static void ImGui::NavUpdate()
91109111

91119112
// Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard)
91129113
// (do it before we map Keyboard input!)
9113-
bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
9114-
bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
9114+
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
9115+
const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
91159116
if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_Gamepad)
91169117
{
91179118
if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNavInput_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs[ImGuiNavInput_Menu] > 0.0f
@@ -9210,10 +9211,73 @@ static void ImGui::NavUpdate()
92109211
g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId;
92119212
g.NavNextActivateId = 0;
92129213

9214+
// Process move requests
9215+
NavUpdateCreateMoveRequest();
9216+
NavUpdateAnyRequestFlag();
9217+
9218+
// Scrolling
9219+
if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
9220+
{
9221+
// *Fallback* manual-scroll with Nav directional keys when window has no navigable item
9222+
ImGuiWindow* window = g.NavWindow;
9223+
const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
9224+
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
9225+
{
9226+
if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
9227+
SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
9228+
if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
9229+
SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
9230+
}
9231+
9232+
// *Normal* Manual scroll with NavScrollXXX keys
9233+
// Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
9234+
ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f / 10.0f, 10.0f);
9235+
if (scroll_dir.x != 0.0f && window->ScrollbarX)
9236+
SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
9237+
if (scroll_dir.y != 0.0f)
9238+
SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
9239+
}
9240+
9241+
// [DEBUG]
9242+
g.NavScoringCount = 0;
9243+
#if IMGUI_DEBUG_NAV_RECTS
9244+
if (g.NavWindow)
9245+
{
9246+
ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow);
9247+
if (1) { for (int layer = 0; layer < 2; layer++) draw_list->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } // [DEBUG]
9248+
if (1) { ImU32 col = (!g.NavWindow->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); }
9249+
}
9250+
#endif
9251+
}
9252+
9253+
static void ImGui::NavUpdateInitResult()
9254+
{
9255+
// In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void)
9256+
ImGuiContext& g = *GImGui;
9257+
if (!g.NavWindow)
9258+
return;
9259+
9260+
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
9261+
// FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently.
9262+
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
9263+
SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
9264+
if (g.NavInitRequestFromMove)
9265+
{
9266+
g.NavDisableHighlight = false;
9267+
g.NavDisableMouseHover = g.NavMousePosDirty = true;
9268+
}
9269+
}
9270+
9271+
void ImGui::NavUpdateCreateMoveRequest()
9272+
{
9273+
ImGuiContext& g = *GImGui;
9274+
ImGuiIO& io = g.IO;
9275+
ImGuiWindow* window = g.NavWindow;
9276+
92139277
if (g.NavMoveRequestForwardToNextFrame)
92149278
{
92159279
// Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window)
9216-
// (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
9280+
// (preserve most state, which were already set by the NavMoveRequestForward() function)
92179281
IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
92189282
IM_ASSERT(g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded);
92199283
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
@@ -9224,7 +9288,7 @@ static void ImGui::NavUpdate()
92249288
// Initiate directional inputs request
92259289
g.NavMoveDir = ImGuiDir_None;
92269290
g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
9227-
if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
9291+
if (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs))
92289292
{
92299293
const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
92309294
if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; }
@@ -9237,63 +9301,38 @@ static void ImGui::NavUpdate()
92379301

92389302
// Update PageUp/PageDown/Home/End scroll
92399303
// FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
9304+
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
92409305
float nav_scoring_rect_offset_y = 0.0f;
92419306
if (nav_keyboard_active)
92429307
nav_scoring_rect_offset_y = NavUpdatePageUpPageDown();
92439308

92449309
// If we initiate a movement request and have no current NavId, we initiate a InitDefaultRequest that will be used as a fallback if the direction fails to find a match
92459310
if (g.NavMoveDir != ImGuiDir_None)
92469311
{
9312+
IM_ASSERT(window != NULL);
92479313
g.NavMoveRequest = true;
92489314
g.NavMoveRequestKeyMods = io.KeyMods;
92499315
g.NavMoveDirLast = g.NavMoveDir;
9316+
g.NavMoveResultLocal.Clear();
9317+
g.NavMoveResultLocalVisibleSet.Clear();
9318+
g.NavMoveResultOther.Clear();
92509319
}
9320+
9321+
// Moving with no reference triggers a init request
92519322
if (g.NavMoveRequest && g.NavId == 0)
92529323
{
92539324
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
92549325
g.NavInitRequest = g.NavInitRequestFromMove = true;
9255-
// Reassigning with same value, we're being explicit here.
9256-
g.NavInitResultId = 0; // -V1048
9326+
g.NavInitResultId = 0;
92579327
g.NavDisableHighlight = false;
92589328
}
9259-
NavUpdateAnyRequestFlag();
9260-
if (g.NavMoveDir != ImGuiDir_None)
9261-
IM_ASSERT(g.NavMoveRequest);
9262-
9263-
// Scrolling
9264-
if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
9265-
{
9266-
// *Fallback* manual-scroll with Nav directional keys when window has no navigable item
9267-
ImGuiWindow* window = g.NavWindow;
9268-
const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
9269-
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
9270-
{
9271-
if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
9272-
SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
9273-
if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
9274-
SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
9275-
}
9276-
9277-
// *Normal* Manual scroll with NavScrollXXX keys
9278-
// Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
9279-
ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f / 10.0f, 10.0f);
9280-
if (scroll_dir.x != 0.0f && window->ScrollbarX)
9281-
SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
9282-
if (scroll_dir.y != 0.0f)
9283-
SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
9284-
}
9285-
9286-
// Reset search results
9287-
g.NavMoveResultLocal.Clear();
9288-
g.NavMoveResultLocalVisibleSet.Clear();
9289-
g.NavMoveResultOther.Clear();
92909329

92919330
// When using gamepad, we project the reference nav bounding box into window visible area.
92929331
// This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative
92939332
// (can't focus a visible object like we can with the mouse).
92949333
if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main)
92959334
{
9296-
ImGuiWindow* window = g.NavWindow;
9335+
IM_ASSERT(window);
92979336
ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
92989337
if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
92999338
{
@@ -9306,39 +9345,16 @@ static void ImGui::NavUpdate()
93069345
}
93079346

93089347
// 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)
9309-
ImRect nav_rect_rel = g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted() ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
9310-
g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : ImRect(0, 0, 0, 0);
9311-
g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y);
9312-
g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x);
9313-
g.NavScoringRect.Max.x = g.NavScoringRect.Min.x;
9314-
IM_ASSERT(!g.NavScoringRect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
9315-
//GetForegroundDrawList()->AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
9316-
g.NavScoringCount = 0;
9317-
#if IMGUI_DEBUG_NAV_RECTS
9318-
if (g.NavWindow)
9319-
{
9320-
ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow);
9321-
if (1) { for (int layer = 0; layer < 2; layer++) draw_list->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } // [DEBUG]
9322-
if (1) { ImU32 col = (!g.NavWindow->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); }
9323-
}
9324-
#endif
9325-
}
9326-
9327-
static void ImGui::NavUpdateInitResult()
9328-
{
9329-
// In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void)
9330-
ImGuiContext& g = *GImGui;
9331-
if (!g.NavWindow)
9332-
return;
9333-
9334-
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
9335-
// FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently.
9336-
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
9337-
SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
9338-
if (g.NavInitRequestFromMove)
9348+
g.NavScoringRect = ImRect();
9349+
if (window)
93399350
{
9340-
g.NavDisableHighlight = false;
9341-
g.NavDisableMouseHover = g.NavMousePosDirty = true;
9351+
ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
9352+
g.NavScoringRect = ImRect(window->Pos + nav_rect_rel.Min, window->Pos + nav_rect_rel.Max);
9353+
g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y);
9354+
g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x);
9355+
g.NavScoringRect.Max.x = g.NavScoringRect.Min.x;
9356+
IM_ASSERT(!g.NavScoringRect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
9357+
//GetForegroundDrawList()->AddRect(g.NavScoringRect.Min, g.NavScoringRect.Max, IM_COL32(255,200,0,255)); // [DEBUG]
93429358
}
93439359
}
93449360

0 commit comments

Comments
 (0)