|
@@ -2962,254 +2962,6 @@ static void NavScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void ImGui::NavUpdate()
|
|
|
-{
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- g.IO.WantSetMousePos = false;
|
|
|
-#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)
|
|
|
- {
|
|
|
- #define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; }
|
|
|
- NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate );
|
|
|
- NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input );
|
|
|
- NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel );
|
|
|
- NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ );
|
|
|
- NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_);
|
|
|
- NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ );
|
|
|
- NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ );
|
|
|
- if (g.IO.KeyCtrl) g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
|
|
|
- if (g.IO.KeyShift) g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
|
|
|
- if (g.IO.KeyAlt) g.IO.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f;
|
|
|
- #undef NAV_MAP_KEY
|
|
|
- }
|
|
|
- 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))
|
|
|
- {
|
|
|
- // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
|
|
|
- IM_ASSERT(g.NavWindow);
|
|
|
- if (g.NavInitRequestFromMove)
|
|
|
- SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel);
|
|
|
- else
|
|
|
- SetNavID(g.NavInitResultId, g.NavLayer);
|
|
|
- g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel;
|
|
|
- }
|
|
|
- g.NavInitRequest = false;
|
|
|
- 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)
|
|
|
- {
|
|
|
- IM_ASSERT(g.NavMoveRequest);
|
|
|
- if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
|
|
|
- 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)
|
|
|
- {
|
|
|
- // Set mouse position given our knowledge of the navigated item position from last frame
|
|
|
- if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (g.IO.BackendFlags & ImGuiBackendFlags_HasSetMousePos))
|
|
|
- {
|
|
|
- if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow)
|
|
|
- {
|
|
|
- g.IO.MousePos = g.IO.MousePosPrev = NavCalcPreferredRefPos();
|
|
|
- g.IO.WantSetMousePos = true;
|
|
|
- }
|
|
|
- }
|
|
|
- g.NavMousePosDirty = false;
|
|
|
- }
|
|
|
- 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))
|
|
|
- {
|
|
|
- if (g.ActiveId != 0)
|
|
|
- {
|
|
|
- ClearActiveID();
|
|
|
- }
|
|
|
- else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
|
|
|
- {
|
|
|
- // Exit child window
|
|
|
- ImGuiWindow* child_window = g.NavWindow;
|
|
|
- ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
|
|
|
- IM_ASSERT(child_window->ChildId != 0);
|
|
|
- FocusWindow(parent_window);
|
|
|
- SetNavID(child_window->ChildId, 0);
|
|
|
- g.NavIdIsAlive = false;
|
|
|
- if (g.NavDisableMouseHover)
|
|
|
- g.NavMousePosDirty = true;
|
|
|
- }
|
|
|
- else if (g.OpenPopupStack.Size > 0)
|
|
|
- {
|
|
|
- // Close open popup/menu
|
|
|
- if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
|
|
|
- ClosePopupToLevel(g.OpenPopupStack.Size - 1);
|
|
|
- }
|
|
|
- else if (g.NavLayer != 0)
|
|
|
- {
|
|
|
- // Leave the "menu" layer
|
|
|
- NavRestoreLayer(0);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
|
|
|
- if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
|
|
|
- g.NavWindow->NavLastIds[0] = 0;
|
|
|
- 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))
|
|
|
- {
|
|
|
- bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
|
|
|
- bool activate_pressed = activate_down && IsNavInputPressed(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
|
|
|
- if (g.ActiveId == 0 && activate_pressed)
|
|
|
- g.NavActivateId = g.NavId;
|
|
|
- if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down)
|
|
|
- g.NavActivateDownId = g.NavId;
|
|
|
- if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed)
|
|
|
- g.NavActivatePressedId = g.NavId;
|
|
|
- if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputPressed(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
|
|
|
- g.NavInputId = g.NavId;
|
|
|
- }
|
|
|
- if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
|
|
|
- g.NavDisableHighlight = true;
|
|
|
- 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)
|
|
|
- {
|
|
|
- g.NavMoveDir = ImGuiDir_None;
|
|
|
- g.NavMoveRequestFlags = 0;
|
|
|
- if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
|
|
|
- {
|
|
|
- if ((allowed_dir_flags & (1<<ImGuiDir_Left)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Left;
|
|
|
- if ((allowed_dir_flags & (1<<ImGuiDir_Right)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight,ImGuiNavInput_KeyRight_,ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Right;
|
|
|
- if ((allowed_dir_flags & (1<<ImGuiDir_Up)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp, ImGuiNavInput_KeyUp_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Up;
|
|
|
- if ((allowed_dir_flags & (1<<ImGuiDir_Down)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Down;
|
|
|
- }
|
|
|
- g.NavMoveClipDir = g.NavMoveDir;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // 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)
|
|
|
- // (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
|
|
|
- IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
|
|
|
- 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)
|
|
|
- {
|
|
|
- g.NavMoveRequest = true;
|
|
|
- g.NavMoveDirLast = g.NavMoveDir;
|
|
|
- }
|
|
|
- if (g.NavMoveRequest && g.NavId == 0)
|
|
|
- {
|
|
|
- g.NavInitRequest = g.NavInitRequestFromMove = true;
|
|
|
- g.NavInitResultId = 0;
|
|
|
- g.NavDisableHighlight = false;
|
|
|
- }
|
|
|
- NavUpdateAnyRequestFlag();
|
|
|
- // Scrolling
|
|
|
- if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
|
|
|
- {
|
|
|
- // *Fallback* manual-scroll with Nav directional keys when window has no navigable item
|
|
|
- ImGuiWindow* window = g.NavWindow;
|
|
|
- const float scroll_speed = ImFloor(window->CalcFontSize() * 100 * g.IO.DeltaTime + 0.5f); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
|
|
|
- if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
|
|
|
- {
|
|
|
- if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
|
|
|
- SetWindowScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
|
|
|
- if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
|
|
|
- SetWindowScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
|
|
|
- }
|
|
|
-
|
|
|
- // *Normal* Manual scroll with NavScrollXXX keys
|
|
|
- // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
|
|
|
- ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f/10.0f, 10.0f);
|
|
|
- if (scroll_dir.x != 0.0f && window->ScrollbarX)
|
|
|
- {
|
|
|
- SetWindowScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
|
|
|
- g.NavMoveFromClampedRefRect = true;
|
|
|
- }
|
|
|
- if (scroll_dir.y != 0.0f)
|
|
|
- {
|
|
|
- SetWindowScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
|
|
|
- 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)
|
|
|
- {
|
|
|
- ImGuiWindow* window = g.NavWindow;
|
|
|
- ImRect window_rect_rel(window->InnerMainRect.Min - window->Pos - ImVec2(1,1), window->InnerMainRect.Max - window->Pos + ImVec2(1,1));
|
|
|
- if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
|
|
|
- {
|
|
|
- float pad = window->CalcFontSize() * 0.5f;
|
|
|
- window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item
|
|
|
- window->NavRectRel[g.NavLayer].ClipWith(window_rect_rel);
|
|
|
- g.NavId = 0;
|
|
|
- }
|
|
|
- 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) : GetViewportRect();
|
|
|
- g.NavScoringRectScreen.TranslateY(nav_scoring_rect_offset_y);
|
|
|
- g.NavScoringRectScreen.Min.x = ImMin(g.NavScoringRectScreen.Min.x + 1.0f, g.NavScoringRectScreen.Max.x);
|
|
|
- g.NavScoringRectScreen.Max.x = g.NavScoringRectScreen.Min.x;
|
|
|
- IM_ASSERT(!g.NavScoringRectScreen.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
|
|
|
- //g.OverlayDrawList.AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
|
|
|
- g.NavScoringCount = 0;
|
|
|
-#if IMGUI_DEBUG_NAV_RECTS
|
|
|
- if (g.NavWindow) { for (int layer = 0; layer < 2; layer++) GetOverlayDrawList()->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } // [DEBUG]
|
|
|
- if (g.NavWindow) { ImU32 col = (g.NavWindow->HiddenFrames == 0) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); g.OverlayDrawList.AddCircleFilled(p, 3.0f, col); g.OverlayDrawList.AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); }
|
|
|
-#endif
|
|
|
-}
|
|
|
-
|
|
|
void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
|
|
|
{
|
|
|
// Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows.
|
|
@@ -7764,7 +7516,253 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags mov
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-//
|
|
|
+static void ImGui::NavUpdate()
|
|
|
+{
|
|
|
+ ImGuiContext& g = *GImGui;
|
|
|
+ g.IO.WantSetMousePos = false;
|
|
|
+#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)
|
|
|
+ {
|
|
|
+ #define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; }
|
|
|
+ NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate );
|
|
|
+ NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input );
|
|
|
+ NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel );
|
|
|
+ NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ );
|
|
|
+ NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_);
|
|
|
+ NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ );
|
|
|
+ NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ );
|
|
|
+ if (g.IO.KeyCtrl) g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
|
|
|
+ if (g.IO.KeyShift) g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
|
|
|
+ if (g.IO.KeyAlt) g.IO.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f;
|
|
|
+ #undef NAV_MAP_KEY
|
|
|
+ }
|
|
|
+ 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))
|
|
|
+ {
|
|
|
+ // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
|
|
|
+ IM_ASSERT(g.NavWindow);
|
|
|
+ if (g.NavInitRequestFromMove)
|
|
|
+ SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel);
|
|
|
+ else
|
|
|
+ SetNavID(g.NavInitResultId, g.NavLayer);
|
|
|
+ g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel;
|
|
|
+ }
|
|
|
+ g.NavInitRequest = false;
|
|
|
+ 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)
|
|
|
+ {
|
|
|
+ IM_ASSERT(g.NavMoveRequest);
|
|
|
+ if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
|
|
|
+ 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)
|
|
|
+ {
|
|
|
+ // Set mouse position given our knowledge of the navigated item position from last frame
|
|
|
+ if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (g.IO.BackendFlags & ImGuiBackendFlags_HasSetMousePos))
|
|
|
+ {
|
|
|
+ if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow)
|
|
|
+ {
|
|
|
+ g.IO.MousePos = g.IO.MousePosPrev = NavCalcPreferredRefPos();
|
|
|
+ g.IO.WantSetMousePos = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ g.NavMousePosDirty = false;
|
|
|
+ }
|
|
|
+ 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))
|
|
|
+ {
|
|
|
+ if (g.ActiveId != 0)
|
|
|
+ {
|
|
|
+ ClearActiveID();
|
|
|
+ }
|
|
|
+ else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
|
|
|
+ {
|
|
|
+ // Exit child window
|
|
|
+ ImGuiWindow* child_window = g.NavWindow;
|
|
|
+ ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
|
|
|
+ IM_ASSERT(child_window->ChildId != 0);
|
|
|
+ FocusWindow(parent_window);
|
|
|
+ SetNavID(child_window->ChildId, 0);
|
|
|
+ g.NavIdIsAlive = false;
|
|
|
+ if (g.NavDisableMouseHover)
|
|
|
+ g.NavMousePosDirty = true;
|
|
|
+ }
|
|
|
+ else if (g.OpenPopupStack.Size > 0)
|
|
|
+ {
|
|
|
+ // Close open popup/menu
|
|
|
+ if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
|
|
|
+ ClosePopupToLevel(g.OpenPopupStack.Size - 1);
|
|
|
+ }
|
|
|
+ else if (g.NavLayer != 0)
|
|
|
+ {
|
|
|
+ // Leave the "menu" layer
|
|
|
+ NavRestoreLayer(0);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
|
|
|
+ if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
|
|
|
+ g.NavWindow->NavLastIds[0] = 0;
|
|
|
+ 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))
|
|
|
+ {
|
|
|
+ bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
|
|
|
+ bool activate_pressed = activate_down && IsNavInputPressed(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
|
|
|
+ if (g.ActiveId == 0 && activate_pressed)
|
|
|
+ g.NavActivateId = g.NavId;
|
|
|
+ if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down)
|
|
|
+ g.NavActivateDownId = g.NavId;
|
|
|
+ if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed)
|
|
|
+ g.NavActivatePressedId = g.NavId;
|
|
|
+ if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputPressed(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
|
|
|
+ g.NavInputId = g.NavId;
|
|
|
+ }
|
|
|
+ if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
|
|
|
+ g.NavDisableHighlight = true;
|
|
|
+ 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)
|
|
|
+ {
|
|
|
+ g.NavMoveDir = ImGuiDir_None;
|
|
|
+ g.NavMoveRequestFlags = 0;
|
|
|
+ if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
|
|
|
+ {
|
|
|
+ if ((allowed_dir_flags & (1<<ImGuiDir_Left)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Left;
|
|
|
+ if ((allowed_dir_flags & (1<<ImGuiDir_Right)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight,ImGuiNavInput_KeyRight_,ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Right;
|
|
|
+ if ((allowed_dir_flags & (1<<ImGuiDir_Up)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp, ImGuiNavInput_KeyUp_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Up;
|
|
|
+ if ((allowed_dir_flags & (1<<ImGuiDir_Down)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Down;
|
|
|
+ }
|
|
|
+ g.NavMoveClipDir = g.NavMoveDir;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // 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)
|
|
|
+ // (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
|
|
|
+ IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
|
|
|
+ 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)
|
|
|
+ {
|
|
|
+ g.NavMoveRequest = true;
|
|
|
+ g.NavMoveDirLast = g.NavMoveDir;
|
|
|
+ }
|
|
|
+ if (g.NavMoveRequest && g.NavId == 0)
|
|
|
+ {
|
|
|
+ g.NavInitRequest = g.NavInitRequestFromMove = true;
|
|
|
+ g.NavInitResultId = 0;
|
|
|
+ g.NavDisableHighlight = false;
|
|
|
+ }
|
|
|
+ NavUpdateAnyRequestFlag();
|
|
|
+ // Scrolling
|
|
|
+ if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
|
|
|
+ {
|
|
|
+ // *Fallback* manual-scroll with Nav directional keys when window has no navigable item
|
|
|
+ ImGuiWindow* window = g.NavWindow;
|
|
|
+ const float scroll_speed = ImFloor(window->CalcFontSize() * 100 * g.IO.DeltaTime + 0.5f); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
|
|
|
+ if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
|
|
|
+ {
|
|
|
+ if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
|
|
|
+ SetWindowScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
|
|
|
+ if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
|
|
|
+ SetWindowScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
|
|
|
+ }
|
|
|
+
|
|
|
+ // *Normal* Manual scroll with NavScrollXXX keys
|
|
|
+ // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
|
|
|
+ ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f/10.0f, 10.0f);
|
|
|
+ if (scroll_dir.x != 0.0f && window->ScrollbarX)
|
|
|
+ {
|
|
|
+ SetWindowScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
|
|
|
+ g.NavMoveFromClampedRefRect = true;
|
|
|
+ }
|
|
|
+ if (scroll_dir.y != 0.0f)
|
|
|
+ {
|
|
|
+ SetWindowScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
|
|
|
+ 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)
|
|
|
+ {
|
|
|
+ ImGuiWindow* window = g.NavWindow;
|
|
|
+ ImRect window_rect_rel(window->InnerMainRect.Min - window->Pos - ImVec2(1,1), window->InnerMainRect.Max - window->Pos + ImVec2(1,1));
|
|
|
+ if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
|
|
|
+ {
|
|
|
+ float pad = window->CalcFontSize() * 0.5f;
|
|
|
+ window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item
|
|
|
+ window->NavRectRel[g.NavLayer].ClipWith(window_rect_rel);
|
|
|
+ g.NavId = 0;
|
|
|
+ }
|
|
|
+ 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) : GetViewportRect();
|
|
|
+ g.NavScoringRectScreen.TranslateY(nav_scoring_rect_offset_y);
|
|
|
+ g.NavScoringRectScreen.Min.x = ImMin(g.NavScoringRectScreen.Min.x + 1.0f, g.NavScoringRectScreen.Max.x);
|
|
|
+ g.NavScoringRectScreen.Max.x = g.NavScoringRectScreen.Min.x;
|
|
|
+ IM_ASSERT(!g.NavScoringRectScreen.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
|
|
|
+ //g.OverlayDrawList.AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
|
|
|
+ g.NavScoringCount = 0;
|
|
|
+#if IMGUI_DEBUG_NAV_RECTS
|
|
|
+ if (g.NavWindow) { for (int layer = 0; layer < 2; layer++) GetOverlayDrawList()->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } // [DEBUG]
|
|
|
+ if (g.NavWindow) { ImU32 col = (g.NavWindow->HiddenFrames == 0) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); g.OverlayDrawList.AddCircleFilled(p, 3.0f, col); g.OverlayDrawList.AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); }
|
|
|
+#endif
|
|
|
+}
|
|
|
|
|
|
static void ImGui::NavUpdateMoveResult()
|
|
|
{
|