Skip to content

Commit ccfb200

Browse files
committed
Nav: small refactor of forwarding, clarified that MoveDir only set when RequestActive, removed one indent level in NavUpdatePageUpPageDown().
1 parent 4351feb commit ccfb200

File tree

3 files changed

+77
-83
lines changed

3 files changed

+77
-83
lines changed

imgui.cpp

Lines changed: 67 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -8943,12 +8943,12 @@ void ImGui::NavMoveRequestCancel()
89438943
void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags)
89448944
{
89458945
ImGuiContext& g = *GImGui;
8946-
IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None);
8946+
IM_ASSERT(g.NavMoveRequestForwardToNextFrame == false);
89478947
NavMoveRequestCancel();
8948+
g.NavMoveRequestForwardToNextFrame = true;
89488949
g.NavMoveDir = move_dir;
89498950
g.NavMoveClipDir = clip_dir;
8950-
g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
8951-
g.NavMoveRequestFlags = move_flags;
8951+
g.NavMoveRequestFlags = move_flags | ImGuiNavMoveFlags_Forwarded;
89528952
}
89538953

89548954
// Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire
@@ -9151,6 +9151,7 @@ static void ImGui::NavUpdate()
91519151
// Process navigation move request
91529152
if (g.NavMoveRequest)
91539153
NavMoveRequestApplyResult();
9154+
g.NavMoveRequest = false;
91549155

91559156
// Apply application mouse position movement, after we had a chance to process move request result.
91569157
if (g.NavMousePosDirty && g.NavIdIsAlive)
@@ -9203,16 +9204,24 @@ static void ImGui::NavUpdate()
92039204
g.NavDisableHighlight = true;
92049205
if (g.NavActivateId != 0)
92059206
IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
9206-
g.NavMoveRequest = false;
92079207

92089208
// Process programmatic activation request
92099209
if (g.NavNextActivateId != 0)
92109210
g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId;
92119211
g.NavNextActivateId = 0;
92129212

9213-
// Initiate directional inputs request
9214-
if (g.NavMoveRequestForward == ImGuiNavForward_None)
9213+
if (g.NavMoveRequestForwardToNextFrame)
9214+
{
9215+
// 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)
9217+
IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
9218+
IM_ASSERT(g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded);
9219+
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
9220+
g.NavMoveRequestForwardToNextFrame = false;
9221+
}
9222+
else
92159223
{
9224+
// Initiate directional inputs request
92169225
g.NavMoveDir = ImGuiDir_None;
92179226
g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
92189227
if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
@@ -9225,14 +9234,6 @@ static void ImGui::NavUpdate()
92259234
}
92269235
g.NavMoveClipDir = g.NavMoveDir;
92279236
}
9228-
else if (g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued)
9229-
{
9230-
// 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)
9231-
// (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
9232-
IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
9233-
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
9234-
g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
9235-
}
92369237

92379238
// Update PageUp/PageDown/Home/End scroll
92389239
// FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
@@ -9256,6 +9257,8 @@ static void ImGui::NavUpdate()
92569257
g.NavDisableHighlight = false;
92579258
}
92589259
NavUpdateAnyRequestFlag();
9260+
if (g.NavMoveDir != ImGuiDir_None)
9261+
IM_ASSERT(g.NavMoveRequest);
92599262

92609263
// Scrolling
92619264
if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
@@ -9344,9 +9347,6 @@ void ImGui::NavMoveRequestApplyResult()
93449347
{
93459348
ImGuiContext& g = *GImGui;
93469349

9347-
if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
9348-
g.NavMoveRequestForward = ImGuiNavForward_None;
9349-
93509350
if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
93519351
{
93529352
// In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result)
@@ -9471,60 +9471,60 @@ static float ImGui::NavUpdatePageUpPageDown()
94719471
const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown);
94729472
const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home);
94739473
const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End);
9474-
if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed
9474+
if (page_up_held == page_down_held && home_pressed == end_pressed) // Proceed if either (not both) are pressed, otherwise early out
9475+
return 0.0f;
9476+
9477+
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll)
94759478
{
9476-
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll)
9479+
// Fallback manual-scroll when window has no navigable item
9480+
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
9481+
SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
9482+
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
9483+
SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
9484+
else if (home_pressed)
9485+
SetScrollY(window, 0.0f);
9486+
else if (end_pressed)
9487+
SetScrollY(window, window->ScrollMax.y);
9488+
}
9489+
else
9490+
{
9491+
ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
9492+
const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
9493+
float nav_scoring_rect_offset_y = 0.0f;
9494+
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
94779495
{
9478-
// Fallback manual-scroll when window has no navigable item
9479-
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
9480-
SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
9481-
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
9482-
SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
9483-
else if (home_pressed)
9484-
SetScrollY(window, 0.0f);
9485-
else if (end_pressed)
9486-
SetScrollY(window, window->ScrollMax.y);
9496+
nav_scoring_rect_offset_y = -page_offset_y;
9497+
g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item)
9498+
g.NavMoveClipDir = ImGuiDir_Up;
9499+
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
94879500
}
9488-
else
9501+
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
94899502
{
9490-
ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
9491-
const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
9492-
float nav_scoring_rect_offset_y = 0.0f;
9493-
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
9494-
{
9495-
nav_scoring_rect_offset_y = -page_offset_y;
9496-
g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item)
9497-
g.NavMoveClipDir = ImGuiDir_Up;
9498-
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
9499-
}
9500-
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
9501-
{
9502-
nav_scoring_rect_offset_y = +page_offset_y;
9503-
g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item)
9504-
g.NavMoveClipDir = ImGuiDir_Down;
9505-
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
9506-
}
9507-
else if (home_pressed)
9508-
{
9509-
// FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
9510-
// Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result.
9511-
// Preserve current horizontal position if we have any.
9512-
nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y;
9513-
if (nav_rect_rel.IsInverted())
9514-
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
9515-
g.NavMoveDir = ImGuiDir_Down;
9516-
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
9517-
}
9518-
else if (end_pressed)
9519-
{
9520-
nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y;
9521-
if (nav_rect_rel.IsInverted())
9522-
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
9523-
g.NavMoveDir = ImGuiDir_Up;
9524-
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
9525-
}
9526-
return nav_scoring_rect_offset_y;
9503+
nav_scoring_rect_offset_y = +page_offset_y;
9504+
g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item)
9505+
g.NavMoveClipDir = ImGuiDir_Down;
9506+
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
9507+
}
9508+
else if (home_pressed)
9509+
{
9510+
// FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
9511+
// Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result.
9512+
// Preserve current horizontal position if we have any.
9513+
nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y;
9514+
if (nav_rect_rel.IsInverted())
9515+
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
9516+
g.NavMoveDir = ImGuiDir_Down;
9517+
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
9518+
}
9519+
else if (end_pressed)
9520+
{
9521+
nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y;
9522+
if (nav_rect_rel.IsInverted())
9523+
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
9524+
g.NavMoveDir = ImGuiDir_Up;
9525+
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
95279526
}
9527+
return nav_scoring_rect_offset_y;
95289528
}
95299529
return 0.0f;
95309530
}
@@ -9542,7 +9542,7 @@ static void ImGui::NavEndFrame()
95429542
ImGuiWindow* window = g.NavWindow;
95439543
const ImGuiNavMoveFlags move_flags = g.NavMoveRequestFlags;
95449544
const ImGuiNavMoveFlags wanted_flags = ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY;
9545-
if (window && NavMoveRequestButNoResultYet() && (g.NavMoveRequestFlags & wanted_flags) && g.NavMoveRequestForward == ImGuiNavForward_None)
9545+
if (window && NavMoveRequestButNoResultYet() && (g.NavMoveRequestFlags & wanted_flags) && (g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded) == 0)
95469546
{
95479547
bool do_forward = false;
95489548
ImRect bb_rel = window->NavRectRel[g.NavLayer];

imgui_internal.h

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,14 +1181,8 @@ enum ImGuiNavMoveFlags_
11811181
ImGuiNavMoveFlags_WrapY = 1 << 3, // This is not super useful but provided for completeness
11821182
ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place)
11831183
ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, // Store alternate result in NavMoveResultLocalVisibleSet that only comprise elements that are already fully visible (used by PageUp/PageDown)
1184-
ImGuiNavMoveFlags_ScrollToEdge = 1 << 6
1185-
};
1186-
1187-
enum ImGuiNavForward
1188-
{
1189-
ImGuiNavForward_None,
1190-
ImGuiNavForward_ForwardQueued,
1191-
ImGuiNavForward_ForwardActive
1184+
ImGuiNavMoveFlags_ScrollToEdge = 1 << 6,
1185+
ImGuiNavMoveFlags_Forwarded = 1 << 7
11921186
};
11931187

11941188
enum ImGuiNavLayer
@@ -1525,14 +1519,14 @@ struct ImGuiContext
15251519
bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default)
15261520
bool NavDisableHighlight; // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover)
15271521
bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again.
1528-
bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest
1522+
bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd()
15291523
bool NavInitRequest; // Init request for appearing window to select first item
15301524
bool NavInitRequestFromMove;
15311525
ImGuiID NavInitResultId; // Init request result (first item of the window, or one for which SetItemDefaultFocus() was called)
15321526
ImRect NavInitResultRectRel; // Init request result rectangle (relative to parent window)
15331527
bool NavMoveRequest; // Move request for this frame
1528+
bool NavMoveRequestForwardToNextFrame;
15341529
ImGuiNavMoveFlags NavMoveRequestFlags;
1535-
ImGuiNavForward NavMoveRequestForward; // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu)
15361530
ImGuiKeyModFlags NavMoveRequestKeyMods;
15371531
ImGuiDir NavMoveDir, NavMoveDirLast; // Direction of the move request (left/right/up/down), direction of the previous move request
15381532
ImGuiDir NavMoveClipDir; // FIXME-NAV: Describe the purpose of this better. Might want to rename?
@@ -1733,8 +1727,8 @@ struct ImGuiContext
17331727
NavInitRequestFromMove = false;
17341728
NavInitResultId = 0;
17351729
NavMoveRequest = false;
1730+
NavMoveRequestForwardToNextFrame = false;
17361731
NavMoveRequestFlags = ImGuiNavMoveFlags_None;
1737-
NavMoveRequestForward = ImGuiNavForward_None;
17381732
NavMoveRequestKeyMods = ImGuiKeyModFlags_None;
17391733
NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None;
17401734

imgui_widgets.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5897,12 +5897,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
58975897
toggled = true;
58985898
}
58995899

5900-
if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Left && is_open)
5900+
if (g.NavId == id && g.NavMoveDir == ImGuiDir_Left && is_open)
59015901
{
59025902
toggled = true;
59035903
NavMoveRequestCancel();
59045904
}
5905-
if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority?
5905+
if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority?
59065906
{
59075907
toggled = true;
59085908
NavMoveRequestCancel();
@@ -6690,7 +6690,7 @@ void ImGui::EndMenuBar()
66906690
ImGuiWindow* nav_earliest_child = g.NavWindow;
66916691
while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu))
66926692
nav_earliest_child = nav_earliest_child->ParentWindow;
6693-
if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && g.NavMoveRequestForward == ImGuiNavForward_None)
6693+
if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && (g.NavMoveRequestFlags & ImGuiNavMoveFlags_Forwarded) == 0)
66946694
{
66956695
// To do so we claim focus back, restore NavId and then process the movement request for yet another frame.
66966696
// This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth bothering)
@@ -6910,7 +6910,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
69106910
want_close = menu_is_open;
69116911
want_open = !menu_is_open;
69126912
}
6913-
if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open
6913+
if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open
69146914
{
69156915
want_open = true;
69166916
NavMoveRequestCancel();
@@ -6928,7 +6928,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
69286928
{
69296929
want_open = true;
69306930
}
6931-
else if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open
6931+
else if (g.NavId == id && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open
69326932
{
69336933
want_open = true;
69346934
NavMoveRequestCancel();

0 commit comments

Comments
 (0)