Nav: Record/restore preferred position on each given axis.

Tagging #6344 #6003 #2694 #1688 as it relates to scoring, however this doesn't technically fix any of them fully yet.
But e.g. once we restore axial path for #2694 this commit will allow going back and forth to initial location.
This commit is contained in:
ocornut 2023-04-26 15:20:40 +02:00
parent 39f7248d4a
commit 6656553fa4
5 changed files with 83 additions and 15 deletions

View File

@ -51,6 +51,10 @@ Other changes:
- Drag, Sliders: if the format string doesn't contain any %, CTRL+Click to input text will - Drag, Sliders: if the format string doesn't contain any %, CTRL+Click to input text will
use the default format specifier for the type. Allow display/input of raw value when using use the default format specifier for the type. Allow display/input of raw value when using
"enums" patterns (display label instead of value) + allow using when value is hidden. (#6405) "enums" patterns (display label instead of value) + allow using when value is hidden. (#6405)
- Nav: Record/restore preferred position on each given axis after a movement on that axis,
then score movement on the other axis using this as a bias. This allows going up and down
between e.g. a large header spanning horizontal space and three-ways-columns, landing
on the same column as before.
- Nav: Fixed navigation within tables/columns where item boundaries goes beyond columns limits, - Nav: Fixed navigation within tables/columns where item boundaries goes beyond columns limits,
unclipped bounding boxes would interfere with other columns. (#2221) [@zzzyap, @ocornut] unclipped bounding boxes would interfere with other columns. (#2221) [@zzzyap, @ocornut]
- Nav: Fixed CTRL+Tab into a root window with only childs with _NavFlattened flags - Nav: Fixed CTRL+Tab into a root window with only childs with _NavFlattened flags

View File

@ -3688,6 +3688,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NUL
DrawList = &DrawListInst; DrawList = &DrawListInst;
DrawList->_Data = &Ctx->DrawListSharedData; DrawList->_Data = &Ctx->DrawListSharedData;
DrawList->_OwnerName = Name; DrawList->_OwnerName = Name;
NavPreferredScoringPosRel[0] = NavPreferredScoringPosRel[1] = ImVec2(FLT_MAX, FLT_MAX);
} }
ImGuiWindow::~ImGuiWindow() ImGuiWindow::~ImGuiWindow()
@ -10620,6 +10621,12 @@ void ImGui::SetNavWindow(ImGuiWindow* window)
NavUpdateAnyRequestFlag(); NavUpdateAnyRequestFlag();
} }
void ImGui::NavClearPreferredPosForAxis(ImGuiAxis axis)
{
ImGuiContext& g = *GImGui;
g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer][axis] = FLT_MAX;
}
void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel) void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -10630,6 +10637,10 @@ void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id
g.NavFocusScopeId = focus_scope_id; g.NavFocusScopeId = focus_scope_id;
g.NavWindow->NavLastIds[nav_layer] = id; g.NavWindow->NavLastIds[nav_layer] = id;
g.NavWindow->NavRectRel[nav_layer] = rect_rel; g.NavWindow->NavRectRel[nav_layer] = rect_rel;
// Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it)
NavClearPreferredPosForAxis(ImGuiAxis_X);
NavClearPreferredPosForAxis(ImGuiAxis_Y);
} }
void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
@ -10654,6 +10665,10 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
g.NavDisableMouseHover = true; g.NavDisableMouseHover = true;
else else
g.NavDisableHighlight = true; g.NavDisableHighlight = true;
// Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it)
NavClearPreferredPosForAxis(ImGuiAxis_X);
NavClearPreferredPosForAxis(ImGuiAxis_Y);
} }
ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy) ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy)
@ -10746,16 +10761,22 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result)
draw_list->AddText(cand.Min, IM_COL32(255, 255, 255, 255), buf); draw_list->AddText(cand.Min, IM_COL32(255, 255, 255, 255), buf);
} }
} }
if (IsMouseHoveringRect(cand.Min, cand.Max)) const bool debug_hovering = IsMouseHoveringRect(cand.Min, cand.Max);
const bool debug_tty = (g.IO.KeyCtrl && IsKeyPressed(ImGuiKey_Space));
if (debug_hovering || debug_tty)
{ {
ImFormatString(buf, IM_ARRAYSIZE(buf), ImFormatString(buf, IM_ARRAYSIZE(buf),
"d-box (%7.3f,%7.3f) -> %7.3f\nd-center (%7.3f,%7.3f) -> %7.3f\nd-axial (%7.3f,%7.3f) -> %7.3f\nnav %c, quadrant %c", "d-box (%7.3f,%7.3f) -> %7.3f\nd-center (%7.3f,%7.3f) -> %7.3f\nd-axial (%7.3f,%7.3f) -> %7.3f\nnav %c, quadrant %c",
dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]); dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "-WENS"[move_dir+1], "-WENS"[quadrant+1]);
ImDrawList* draw_list = GetForegroundDrawList(window); if (debug_hovering)
draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100)); {
draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200)); ImDrawList* draw_list = GetForegroundDrawList(window);
draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40,0,0,200)); draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255, 200, 0, 100));
draw_list->AddText(cand.Max, ~0U, buf); draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255, 255, 0, 200));
draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40, 0, 0, 200));
draw_list->AddText(cand.Max, ~0U, buf);
}
if (debug_tty) { IMGUI_DEBUG_LOG_NAV("id 0x%08X\n%s\n", g.LastItemData.ID, buf); }
} }
#endif #endif
@ -11322,11 +11343,11 @@ static void ImGui::NavUpdate()
// [DEBUG] // [DEBUG]
g.NavScoringDebugCount = 0; g.NavScoringDebugCount = 0;
#if IMGUI_DEBUG_NAV_RECTS #if IMGUI_DEBUG_NAV_RECTS
if (g.NavWindow) if (ImGuiWindow* debug_window = g.NavWindow)
{ {
ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow); ImDrawList* draw_list = GetForegroundDrawList(debug_window);
if (1) { for (int layer = 0; layer < 2; layer++) { ImRect r = WindowRectRelToAbs(g.NavWindow, g.NavWindow->NavRectRel[layer]); draw_list->AddRect(r.Min, r.Max, IM_COL32(255,200,0,255)); } } // [DEBUG] int layer = g.NavLayer; /* for (int layer = 0; layer < 2; layer++)*/ { ImRect r = WindowRectRelToAbs(debug_window, debug_window->NavRectRel[layer]); draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 200, 0, 255)); }
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); } //if (1) { ImU32 col = (!debug_window->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); }
} }
#endif #endif
} }
@ -11347,6 +11368,28 @@ void ImGui::NavInitRequestApplyResult()
NavRestoreHighlightAfterMove(); NavRestoreHighlightAfterMove();
} }
// Bias scoring rect ahead of scoring + update preferred pos (if missing) using source position
static void NavBiasScoringRect(ImRect& r, ImVec2& preferred_pos_rel, ImGuiDir move_dir)
{
// Bias initial rect
ImGuiContext& g = *GImGui;
const ImVec2 rel_to_abs_offset = g.NavWindow->DC.CursorStartPos;
// Initialize bias on departure if we don't have any. So mouse-click + arrow will record bias.
// - We default to L/U bias, so moving down from a large source item into several columns will land on left-most column.
// - But each successful move sets new bias on one axis, only cleared when using mouse.
if (preferred_pos_rel.x == FLT_MAX)
preferred_pos_rel.x = ImMin(r.Min.x + 1.0f, r.Max.x) - rel_to_abs_offset.x;
if (preferred_pos_rel.y == FLT_MAX)
preferred_pos_rel.y = r.GetCenter().y - rel_to_abs_offset.y;
// Apply general bias on the other axis
if (move_dir == ImGuiDir_Up || move_dir == ImGuiDir_Down)
r.Min.x = r.Max.x = preferred_pos_rel.x + rel_to_abs_offset.x;
else
r.Min.y = r.Max.y = preferred_pos_rel.y + rel_to_abs_offset.y;
}
void ImGui::NavUpdateCreateMoveRequest() void ImGui::NavUpdateCreateMoveRequest()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -11453,8 +11496,8 @@ void ImGui::NavUpdateCreateMoveRequest()
ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0); ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? window->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
scoring_rect = WindowRectRelToAbs(window, nav_rect_rel); scoring_rect = WindowRectRelToAbs(window, nav_rect_rel);
scoring_rect.TranslateY(scoring_rect_offset_y); scoring_rect.TranslateY(scoring_rect_offset_y);
scoring_rect.Min.x = ImMin(scoring_rect.Min.x + 1.0f, scoring_rect.Max.x); if (g.NavMoveSubmitted)
scoring_rect.Max.x = scoring_rect.Min.x; NavBiasScoringRect(scoring_rect, window->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer], g.NavMoveDir);
IM_ASSERT(!scoring_rect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allow us to remove extraneous ImFabs() calls in NavScoreItem(). IM_ASSERT(!scoring_rect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allow us to remove extraneous ImFabs() calls in NavScoreItem().
//GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG] //GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG]
//if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG] //if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG]
@ -11508,12 +11551,14 @@ void ImGui::NavMoveRequestApplyResult()
result = &g.NavTabbingResultFirst; result = &g.NavTabbingResultFirst;
// In a situation when there are no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result) // In a situation when there are no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result)
const ImGuiAxis axis = (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X;
if (result == NULL) if (result == NULL)
{ {
if (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) if (g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing)
g.NavMoveFlags |= ImGuiNavMoveFlags_DontSetNavHighlight; g.NavMoveFlags |= ImGuiNavMoveFlags_DontSetNavHighlight;
if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_DontSetNavHighlight) == 0) if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_DontSetNavHighlight) == 0)
NavRestoreHighlightAfterMove(); NavRestoreHighlightAfterMove();
NavClearPreferredPosForAxis(axis); // On a failed move, clear preferred pos for this axis.
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveSubmitted but not led to a result!\n"); IMGUI_DEBUG_LOG_NAV("[nav] NavMoveSubmitted but not led to a result!\n");
return; return;
} }
@ -11558,10 +11603,19 @@ void ImGui::NavMoveRequestApplyResult()
g.NavJustMovedToKeyMods = g.NavMoveKeyMods; g.NavJustMovedToKeyMods = g.NavMoveKeyMods;
} }
// Focus // Apply new NavID/Focus
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name); IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name);
ImVec2 preferred_scoring_pos_rel = g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer];
SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel); SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);
// Restore last preferred position for current axis
// (storing in RootWindowForNav-> as the info is desirable at the beginning of a Move Request. In theory all storage should use RootWindowForNav..)
if ((g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) == 0)
{
preferred_scoring_pos_rel[axis] = result->RectRel.GetCenter()[axis];
g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer] = preferred_scoring_pos_rel;
}
// Tabbing: Activates Inputable or Focus non-Inputable // Tabbing: Activates Inputable or Focus non-Inputable
if ((g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) && (result->InFlags & ImGuiItemFlags_Inputable)) if ((g.NavMoveFlags & ImGuiNavMoveFlags_Tabbing) && (result->InFlags & ImGuiItemFlags_Inputable))
{ {
@ -11775,6 +11829,8 @@ static void ImGui::NavUpdateCreateWrappingRequest()
if (!do_forward) if (!do_forward)
return; return;
window->NavRectRel[g.NavLayer] = bb_rel; window->NavRectRel[g.NavLayer] = bb_rel;
NavClearPreferredPosForAxis(ImGuiAxis_X);
NavClearPreferredPosForAxis(ImGuiAxis_Y);
NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags, g.NavMoveScrollFlags); NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags, g.NavMoveScrollFlags);
} }
@ -14285,6 +14341,9 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y); BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y);
DebugLocateItemOnHover(window->NavLastIds[layer]); DebugLocateItemOnHover(window->NavLastIds[layer]);
} }
const ImVec2* pr = window->NavPreferredScoringPosRel;
for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++)
BulletText("NavPreferredScoringPosRel[%d] = {%.1f,%.1f)", layer, (pr[layer].x == FLT_MAX ? -99999.0f : pr[layer].x), (pr[layer].y == FLT_MAX ? -99999.0f : pr[layer].y)); // Display as 99999.0f so it looks neater.
BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL"); BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); } if (window->RootWindow != window) { DebugNodeWindow(window->RootWindow, "RootWindow"); }
if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); } if (window->ParentWindow != NULL) { DebugNodeWindow(window->ParentWindow, "ParentWindow"); }

View File

@ -23,7 +23,7 @@
// Library Version // Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345') // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345')
#define IMGUI_VERSION "1.89.6 WIP" #define IMGUI_VERSION "1.89.6 WIP"
#define IMGUI_VERSION_NUM 18955 #define IMGUI_VERSION_NUM 18956
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE
/* /*

View File

@ -2366,6 +2366,7 @@ struct IMGUI_API ImGuiWindow
ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.) ImGuiWindow* NavLastChildNavWindow; // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.)
ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1) ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1)
ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space
ImVec2 NavPreferredScoringPosRel[ImGuiNavLayer_COUNT]; // Preferred X/Y position updated when moving on a given axis, reset to FLT_MAX.
ImGuiID NavRootFocusScopeId; // Focus Scope ID at the time of Begin() ImGuiID NavRootFocusScopeId; // Focus Scope ID at the time of Begin()
int MemoryDrawListIdxCapacity; // Backup of last idx/vtx count, so when waking up the window we can preallocate and avoid iterative alloc/copy int MemoryDrawListIdxCapacity; // Backup of last idx/vtx count, so when waking up the window we can preallocate and avoid iterative alloc/copy
@ -2761,6 +2762,7 @@ namespace ImGui
IMGUI_API void SetWindowHiddendAndSkipItemsForCurrentFrame(ImGuiWindow* window); IMGUI_API void SetWindowHiddendAndSkipItemsForCurrentFrame(ImGuiWindow* window);
inline ImRect WindowRectAbsToRel(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y); } inline ImRect WindowRectAbsToRel(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y); }
inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); } inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); }
inline ImVec2 WindowPosRelToAbs(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x + off.x, p.y + off.y); }
// Windows: Display Order and Focus Order // Windows: Display Order and Focus Order
IMGUI_API void FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags = 0); IMGUI_API void FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags = 0);
@ -2908,6 +2910,7 @@ namespace ImGui
IMGUI_API void NavMoveRequestCancel(); IMGUI_API void NavMoveRequestCancel();
IMGUI_API void NavMoveRequestApplyResult(); IMGUI_API void NavMoveRequestApplyResult();
IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags);
IMGUI_API void NavClearPreferredPosForAxis(ImGuiAxis axis);
IMGUI_API void NavUpdateCurrentWindowIsScrollPushableX(); IMGUI_API void NavUpdateCurrentWindowIsScrollPushableX();
IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again. IMGUI_API void ActivateItem(ImGuiID id); // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again.
IMGUI_API void SetNavWindow(ImGuiWindow* window); IMGUI_API void SetNavWindow(ImGuiWindow* window);

View File

@ -6219,11 +6219,13 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
if (g.NavId == id && g.NavMoveDir == ImGuiDir_Left && is_open) if (g.NavId == id && g.NavMoveDir == ImGuiDir_Left && is_open)
{ {
toggled = true; toggled = true;
NavClearPreferredPosForAxis(ImGuiAxis_X);
NavMoveRequestCancel(); NavMoveRequestCancel();
} }
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? 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?
{ {
toggled = true; toggled = true;
NavClearPreferredPosForAxis(ImGuiAxis_X);
NavMoveRequestCancel(); NavMoveRequestCancel();
} }