Navigation: Tap NavMenu to access menu and close buttons, hold to focus/resize (#323)

Introducing a concept of NavLayer to filter navigable items
This commit is contained in:
ocornut 2016-07-24 14:56:14 +02:00
parent c3aa36d9ab
commit aeabda5a5f
2 changed files with 133 additions and 56 deletions

168
imgui.cpp
View File

@ -1837,6 +1837,8 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window = NULL)
g.NavDisableHighlight = true;
g.NavId = id;
if (window)
g.NavLayer = window->DC.NavLayerCurrent;
if (window && window->DC.NavLayerCurrent == 0) // (Assume that id correspond to the current NavLayer, which should be the case)
window->NavLastId = id;
}
}
@ -1914,8 +1916,12 @@ static float NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
static bool NavScoreItem(ImRect cand)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (g.NavLayer != window->DC.NavLayerCurrent)
return false;
const ImRect& curr = g.NavScoringRectScreen; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having lots of items with varied width)
cand.Clip(g.CurrentWindow->ClipRect);
cand.Clip(window->ClipRect);
// Compute distance between boxes
// FIXME-NAVIGATION: Introducing various biases toward typical imgui uses cases, but we don't have any rigorous proof of their effect now.
@ -1952,7 +1958,7 @@ static bool NavScoreItem(ImRect cand)
else
{
// Degenerate case: two overlapping buttons with same center, break ties using order
quadrant = (g.CurrentWindow->DC.LastItemId < g.NavId) ? ImGuiNavDir_W : ImGuiNavDir_E;
quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiNavDir_W : ImGuiNavDir_E;
}
#if 0 // [DEBUG]
@ -2030,8 +2036,9 @@ bool ImGui::ItemAdd(const ImRect& bb, const ImGuiID* id, const ImRect* nav_bb_ar
window->DC.LastItemId = id ? *id : 0;
window->DC.LastItemRect = bb;
window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false;
if (id != NULL) window->DC.NavHasItemsNext = true;
const bool is_clipped = IsClippedEx(bb, id, false);
if (id != NULL)
window->DC.NavLayerActiveFlagsNext |= (1 << window->DC.NavLayerCurrent);
// Navigation processing runs prior to clipping early-out
// (a) So that NavInitDefaultRequest can be honored, for newly opened windows to select a default widget
@ -2042,32 +2049,31 @@ bool ImGui::ItemAdd(const ImRect& bb, const ImGuiID* id, const ImRect* nav_bb_ar
// So eventually we would like to provide the user will the primitives to be able to implement that sort of customized/efficient navigation handling whenever necessary.
if (id != NULL && g.NavWindow == window && g.IO.NavUsable)
{
if (g.NavInitDefaultRequest && window->DC.AllowNavDefaultFocus)
const ImRect& nav_bb = nav_bb_arg ? *nav_bb_arg : bb;
const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
if (g.NavInitDefaultRequest && g.NavLayer == window->DC.NavLayerCurrent && window->DC.AllowNavDefaultFocus)
{
g.NavInitDefaultRequest = g.NavInitDefaultResultExplicit = false; // Clear flag immediately, first item gets default, also simplify the if() in ItemAdd()
g.NavInitDefaultResultId = *id;
g.NavInitDefaultResultRectRel = nav_bb_rel;
}
const bool DEBUG_NAV = false; // [DEBUG] Enable to test scoring on all items.
if ((g.NavMoveRequest || DEBUG_NAV) && g.NavId != *id)
{
//if (DEBUG_NAV && !g.NavMoveRequest) g.NavMoveDir = ImGuiNavDir_N;
const ImRect& nav_bb = nav_bb_arg ? *nav_bb_arg : bb;
if (NavScoreItem(nav_bb)) //if (!DEBUG || g.NavMoveRequest)
{
g.NavMoveResultId = *id;
g.NavMoveResultRectRel = ImRect(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
//g.OverlayDrawList.AddRectFilled(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max+ImVec2(2,2), IM_COL32(255,255,0,255)); // [DEBUG]
//g.OverlayDrawList.AddRectFilled(nav_bb.Min, nav_bb.Max, IM_COL32(255,0,255,100)); // [DEBUG]
//g.OverlayDrawList.AddText(nav_bb.Min, ~0U, "new_best"); // [DEBUG]
g.NavMoveResultRectRel = nav_bb_rel;
}
}
// Update window-relative bounding box of navigated item
if (g.NavId == *id)
{
const ImRect& nav_bb = nav_bb_arg ? *nav_bb_arg : bb;
g.NavRefRectRel = ImRect(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
g.NavRefRectRel = nav_bb_rel;
g.NavIdIsAlive = true;
g.NavIdTabCounter = window->FocusIdxTabCounter;
}
@ -2266,21 +2272,24 @@ int ImGui::GetFrameCount()
}
// This needs to be called before we submit any widget (aka in or before Begin)
static void NavInitWindow(ImGuiWindow* window)
static void NavInitWindow(ImGuiWindow* window, bool force_reinit)
{
ImGuiContext& g = *GImGui;
if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastId == 0))
IM_ASSERT(window == g.NavWindow);
if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastId == 0) || force_reinit)
{
g.NavId = window->NavLastId = 0;
g.NavId = 0;
if (g.NavLayer == 0)
window->NavLastId = 0;
g.NavInitDefaultRequest = true;
g.NavInitDefaultResultExplicit = false;
g.NavInitDefaultResultId = 0;
g.NavInitDefaultResultExplicit = false;
g.NavInitDefaultResultRectRel = ImRect();
}
else
{
g.NavId = window->NavLastId;
}
g.NavWindow = window;
}
static ImVec2 NavCalcPreferredMousePos()
@ -2293,6 +2302,18 @@ static ImVec2 NavCalcPreferredMousePos()
return ImClamp(p, r.Min, r.Max);
}
static void SetNavIdMoveMouse(ImGuiID id, const ImRect& rect_rel)
{
ImGuiContext& g = *GImGui;
g.NavId = id;
if (g.NavLayer == 0)
g.NavWindow->NavLastId = g.NavId;
g.NavRefRectRel = rect_rel;
g.NavMousePosDirty = true;
g.NavDisableHighlight = false;
g.NavDisableMouseHover = true;
}
static void NavUpdate()
{
ImGuiContext& g = *GImGui;
@ -2303,8 +2324,15 @@ static void NavUpdate()
{
// Apply result from previous navigation init request (typically select the first item, unless SetItemDefaultFocus() has been called)
IM_ASSERT(g.NavWindow);
g.NavId = g.NavWindow->NavLastId = g.NavInitDefaultResultId;
g.NavId = g.NavInitDefaultResultId;
g.NavRefRectRel = g.NavInitDefaultResultRectRel;
g.NavMousePosDirty = true;
if (g.NavLayer == 0)
g.NavWindow->NavLastId = g.NavId;
}
g.NavInitDefaultRequest = false;
g.NavInitDefaultResultExplicit = false;
g.NavInitDefaultResultId = 0;
// Apply application mouse position movement
if (g.NavMousePosDirty && g.NavIdIsAlive)
@ -2329,7 +2357,7 @@ static void NavUpdate()
ImRect window_rect_rel(g.NavWindow->InnerRect.Min - g.NavWindow->Pos, g.NavWindow->InnerRect.Max - g.NavWindow->Pos);
window_rect_rel.Expand(1.0f);
//g.OverlayDrawList.AddRect(g.NavWindow->Pos + window_rect_rel.Min, g.NavWindow->Pos + window_rect_rel.Max, IM_COL32_WHITE); // [DEBUG]
if (!window_rect_rel.Contains(g.NavMoveResultRectRel))
if (g.NavLayer == 0 && !window_rect_rel.Contains(g.NavMoveResultRectRel))
{
if (g.NavWindow->ScrollbarX && g.NavMoveResultRectRel.Min.x < window_rect_rel.Min.x)
{
@ -2354,20 +2382,24 @@ static void NavUpdate()
}
// Apply result from previous navigation directional move request
IM_ASSERT(g.NavWindow);
ImGui::SetActiveID(0);
g.NavId = g.NavWindow->NavLastId = g.NavMoveResultId;
g.NavRefRectRel = g.NavMoveResultRectRel;
g.NavMousePosDirty = true;
g.NavDisableHighlight = false;
g.NavDisableMouseHover = true;
SetNavIdMoveMouse(g.NavMoveResultId, g.NavMoveResultRectRel);
}
// Navigation windowing mode (change focus, move/resize window)
if (!g.NavWindowingTarget && g.NavWindow && IsKeyPressedMap(ImGuiKey_NavMenu, false))
{
g.NavWindowingTarget = g.NavWindow->RootNonPopupWindow;
g.NavWindowingDisplayAlpha = 0.0f;
g.NavWindowingToggleLayer = true;
}
if (g.NavWindowingTarget)
{
// Visuals only appears after a brief time holding the button, so that a fast tap (to toggle NavLayer) doesn't add visual noise
const float pressed_duration = g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_NavMenu]];
g.NavWindowingDisplayAlpha = ImMax(g.NavWindowingDisplayAlpha, ImSaturate((pressed_duration - 0.20f) / 0.05f));
g.NavWindowingToggleLayer &= (g.NavWindowingDisplayAlpha < 1.0f); // Once button is held long enough we don't consider it a tag-to-toggle-layer press anymore.
// Select window to focus
// FIXME-NAVIGATION: Need to clarify input semantic, naming is misleading/incorrect here.
int focus_change_dir = IsKeyPressedMap(ImGuiKey_NavTweakFaster, true) ? -1 : IsKeyPressedMap(ImGuiKey_NavTweakSlower, true) ? +1 : 0;
@ -2387,14 +2419,35 @@ static void NavUpdate()
i_target = i;
if (i_target != -1 && i_target != i_current) // i_target might be == i_current in rare situation where we only have 1 navigable window
g.NavWindowingTarget = g.Windows[i_target];
g.NavWindowingToggleLayer = false;
g.NavWindowingDisplayAlpha = 1.0f;
}
// Apply actual focus only when leaving NavWindowing mode (until then the window was merely rendered front-most)
if (!IsKeyDownMap(ImGuiKey_NavMenu))
{
if (g.NavWindowingTarget)
if (!g.FocusedWindow || (g.NavWindowingTarget->RootNonPopupWindow != g.FocusedWindow->RootNonPopupWindow))
ImGui::FocusWindow(g.NavWindowingTarget->RootNonPopupWindow);
// Apply actual focus only when releasing the NavMenu button (until then the window was merely rendered front-most)
if (g.NavWindowingTarget && (!g.FocusedWindow || g.NavWindowingTarget != g.FocusedWindow->RootNonPopupWindow))
{
ImGui::FocusWindow(g.NavWindowingTarget);
g.NavDisableHighlight = false;
g.NavDisableMouseHover = true;
if (g.NavWindowingTarget->NavLastId == 0)
NavInitWindow(g.NavWindowingTarget, false);
}
// Single press toggles NavLayer
if (g.NavWindowingToggleLayer)
{
if ((g.NavWindow->DC.NavLayerActiveFlags & (1<<1)) == 0 && (g.NavWindow->RootWindow->DC.NavLayerActiveFlags & (1<<1)) != 0)
ImGui::FocusWindow(g.NavWindow->RootWindow);
g.NavLayer = (g.NavWindow->DC.NavLayerActiveFlags & (1<<1)) ? (g.NavLayer ^ 1) : 0;
g.NavDisableHighlight = false;
g.NavDisableMouseHover = true;
if (g.NavLayer == 0 && g.NavWindow->NavLastId)
SetNavIdMoveMouse(g.NavWindow->NavLastId, ImRect());
else
NavInitWindow(g.NavWindow, true);
}
g.NavWindowingTarget = NULL;
}
}
@ -2415,6 +2468,14 @@ static void NavUpdate()
// Close open popup or move back to parent window
ClosePopupToLevel(g.OpenPopupStack.Size - 1);
}
else if (g.NavLayer != 0)
{
g.NavLayer = 0;
if (g.NavWindow->NavLastId)
SetNavIdMoveMouse(g.NavWindow->NavLastId, ImRect());
else
NavInitWindow(g.NavWindow, true);
}
else
{
// Clear NavId for popups but keep it for regular child window so we can leave one and come back where we were
@ -2427,7 +2488,9 @@ static void NavUpdate()
ImGuiWindow* child_window = g.FocusedWindow;
ImGuiWindow* parent_window = g.FocusedWindow->ParentWindow;
ImGui::FocusWindow(parent_window);
g.NavId = parent_window->NavLastId = parent_window->GetChildID(child_window);
g.NavId = parent_window->GetChildID(child_window);
if (g.NavLayer == 0)
parent_window->NavLastId = g.NavId;
g.NavIdIsAlive = false;
if (g.NavDisableMouseHover)
g.NavMousePosDirty = true;
@ -2447,9 +2510,6 @@ static void NavUpdate()
g.NavDisableHighlight = true;
}
g.NavMoveRequest = false;
g.NavInitDefaultRequest = false;
g.NavInitDefaultResultExplicit = false;
g.NavInitDefaultResultId = 0;
// Initiate directional inputs request
g.NavMoveDir = ImGuiNavDir_None;
@ -2467,7 +2527,7 @@ static void NavUpdate()
}
// Fallback manual-scroll with NavUp/NavDown when window has no navigable item
if (g.FocusedWindow && !g.FocusedWindow->DC.NavHasItems && g.FocusedWindow->DC.NavHasScroll && !(g.FocusedWindow->Flags & ImGuiWindowFlags_NoNav) && g.NavMoveRequest && (g.NavMoveDir == ImGuiNavDir_N || g.NavMoveDir == ImGuiNavDir_S))
if (g.FocusedWindow && !g.FocusedWindow->DC.NavLayerActiveFlags && g.FocusedWindow->DC.NavHasScroll && !(g.FocusedWindow->Flags & ImGuiWindowFlags_NoNav) && g.NavMoveRequest && (g.NavMoveDir == ImGuiNavDir_N || g.NavMoveDir == ImGuiNavDir_S))
{
float scroll_speed = ImFloor(g.FocusedWindow->CalcFontSize() * 100 * g.IO.DeltaTime + 0.5f); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
SetWindowScrollY(g.FocusedWindow, ImFloor(g.FocusedWindow->Scroll.y + ((g.NavMoveDir == ImGuiNavDir_N) ? -1.0f : +1.0f) * scroll_speed));
@ -3760,7 +3820,8 @@ void ImGui::SetItemDefaultFocus()
{
g.NavInitDefaultRequest = false;
g.NavInitDefaultResultExplicit = true;
g.NavInitDefaultResultId = g.CurrentWindow->DC.LastItemId;
g.NavInitDefaultResultId = g.NavWindow->DC.LastItemId;
g.NavInitDefaultResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos);
if (!IsItemVisible())
SetScrollHere();
}
@ -4077,10 +4138,10 @@ bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border,
// Process navigation-in immediately so NavInit can run on first frame
const ImGuiID id = parent_window->GetChildID(child_window);
if ((child_window->DC.NavHasItems || child_window->DC.NavHasScroll) && GImGui->NavActivateId == id)
if ((child_window->DC.NavLayerActiveFlags != 0 || child_window->DC.NavHasScroll) && GImGui->NavActivateId == id)
{
FocusWindow(child_window);
NavInitWindow(child_window);
NavInitWindow(child_window, false);
SetActiveIDNoNav(id+1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item
}
@ -4118,8 +4179,8 @@ void ImGui::EndChild()
ImGuiID id = parent_window->GetChildID(window);
ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
ItemSize(sz);
ItemAdd(bb, (window->DC.NavHasItems || window->DC.NavHasScroll) ? &id : NULL);
if (window->DC.NavHasItems || window->DC.NavHasScroll)
ItemAdd(bb, (window->DC.NavLayerActiveFlags != 0 || window->DC.NavHasScroll) ? &id : NULL);
if (window->DC.NavLayerActiveFlags != 0 || window->DC.NavHasScroll)
{
//if (!window->DC.NavHasItems && window->DC.NavHasScroll && g.NavWindow == window) // As a special case, we render nav highlight of child when inside when only scrolling is possible
//{
@ -4634,8 +4695,8 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
{
ImRect bb = window->Rect();
bb.Expand(g.FontSize);
window->DrawList->AddRectFilled(bb.Min, bb.Max, IM_COL32(255,255,255,30)/*ImGui::GetColorU32(ImGuiCol_HeaderHovered, 0.15f)*/, g.Style.WindowRounding);
window->DrawList->AddRect(bb.Min, bb.Max, ImGui::GetColorU32(ImGuiCol_HeaderHovered), g.Style.WindowRounding);
window->DrawList->AddRectFilled(bb.Min, bb.Max, IM_COL32(255,255,255,(int)(30 * g.NavWindowingDisplayAlpha))/*ImGui::GetColorU32(ImGuiCol_HeaderHovered, 0.15f)*/, g.Style.WindowRounding);
window->DrawList->AddRect(bb.Min, bb.Max, ImGui::GetColorU32(ImGuiCol_HeaderHovered, g.NavWindowingDisplayAlpha), g.Style.WindowRounding);
}
// Draw window + handle manual resize
@ -4682,6 +4743,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
else if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f)
{
// FIXME-NAVIGATION: Should store and accumulate into a separate size buffer to handle sizing constraints properly
g.NavWindowingToggleLayer = false;
size_target = window->SizeFull + nav_resize_delta;
held = true; // For coloring
}
@ -4781,8 +4843,8 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
window->DC.CursorMaxPos = window->DC.CursorStartPos;
window->DC.CurrentLineHeight = window->DC.PrevLineHeight = 0.0f;
window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
window->DC.NavHasItems = window->DC.NavHasItemsNext;
window->DC.NavHasItemsNext = false;
window->DC.NavLayerActiveFlags = window->DC.NavLayerActiveFlagsNext;
window->DC.NavLayerActiveFlagsNext = 0x00;
window->DC.NavHasScroll = (GetScrollMaxY() > 0.0f);
window->DC.MenuBarAppending = false;
window->DC.MenuBarOffsetX = ImMax(window->WindowPadding.x, style.ItemSpacing.x);
@ -4791,8 +4853,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
window->DC.LayoutType = ImGuiLayoutType_Vertical;
window->DC.ItemWidth = window->ItemWidthDefault;
window->DC.TextWrapPos = -1.0f; // disabled
window->DC.AllowKeyboardFocus = true;
window->DC.AllowNavDefaultFocus = true;
window->DC.AllowKeyboardFocus = window->DC.AllowNavDefaultFocus = true;
window->DC.ButtonRepeat = false;
window->DC.ItemWidthStack.resize(0);
window->DC.TextWrapPosStack.resize(0);
@ -4818,8 +4879,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
if (!(flags & (ImGuiWindowFlags_ChildWindow|ImGuiWindowFlags_Tooltip)) || (flags & ImGuiWindowFlags_Popup))
{
FocusWindow(window);
IM_ASSERT(g.NavWindow == window);
NavInitWindow(window);
NavInitWindow(window, false);
}
// Title bar
@ -4829,8 +4889,10 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us
{
const float pad = 2.0f;
const float rad = (window->TitleBarHeight() - pad*2.0f) * 0.5f;
window->DC.NavLayerCurrent++;
if (CloseButton(window->GetID("#CLOSE"), window->Rect().GetTR() + ImVec2(-pad - rad, pad + rad), rad))
*p_open = false;
window->DC.NavLayerCurrent--;
}
const ImVec2 text_size = CalcTextSize(name, NULL, true);
@ -5041,8 +5103,9 @@ void ImGui::FocusWindow(ImGuiWindow* window)
if (g.FocusedWindow != window)
{
g.NavId = window ? window->NavLastId : 0;
g.NavId = window ? window->NavLastId : 0; // Restore NavId
g.NavIdIsAlive = false;
g.NavLayer = 0;
if (window && g.NavDisableMouseHover)
g.NavMousePosDirty = true;
g.NavRefRectRel.Min = g.NavRefRectRel.Max = window ? (window->DC.CursorStartPos - window->Pos) : ImVec2(0,0);
@ -6210,7 +6273,8 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius)
const ImRect bb(pos - ImVec2(radius,radius), pos + ImVec2(radius,radius));
const bool backup_allow_nav_default_focus = window->DC.AllowNavDefaultFocus; // We could exposethis as a flag to ItemAdd() but it is such a unique case for now
window->DC.AllowNavDefaultFocus = false;
if (window->Flags & ImGuiWindowFlags_MenuBar)
window->DC.AllowNavDefaultFocus = false;
const bool added = ItemAdd(bb, &id); // To allow navigation
window->DC.AllowNavDefaultFocus = backup_allow_nav_default_focus;
if (!added)
@ -9107,7 +9171,8 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
}
else
{
window->NavLastId = id;
if (window->DC.NavLayerCurrent == 0)
window->NavLastId = id;
FocusWindow(window);
OpenPopup(label);
popup_open = true;
@ -9428,6 +9493,7 @@ bool ImGui::BeginMenuBar()
PushClipRect(ImVec2(ImFloor(rect.Min.x+0.5f), ImFloor(rect.Min.y + window->BorderSize + 0.5f)), ImVec2(ImFloor(rect.Max.x+0.5f), ImFloor(rect.Max.y+0.5f)), false);
window->DC.CursorPos = ImVec2(rect.Min.x + window->DC.MenuBarOffsetX, rect.Min.y);// + g.Style.FramePadding.y);
window->DC.LayoutType = ImGuiLayoutType_Horizontal;
window->DC.NavLayerCurrent++;
window->DC.MenuBarAppending = true;
AlignFirstTextHeightToWidgets();
return true;
@ -9447,6 +9513,7 @@ void ImGui::EndMenuBar()
window->DC.GroupStack.back().AdvanceCursor = false;
EndGroup();
window->DC.LayoutType = ImGuiLayoutType_Vertical;
window->DC.NavLayerCurrent--;
window->DC.MenuBarAppending = false;
}
@ -10327,6 +10394,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Text("%d vertices, %d indices (%d triangles)", ImGui::GetIO().MetricsRenderVertices, ImGui::GetIO().MetricsRenderIndices, ImGui::GetIO().MetricsRenderIndices / 3);
ImGui::Text("%d allocations", ImGui::GetIO().MetricsAllocs);
ImGui::Text("sizeof(ImGuiContext) = %u, sizeof(ImGuiWindow) = %u", sizeof(ImGuiContext), sizeof(ImGuiWindow));
static bool show_clip_rects = true;
ImGui::Checkbox("Show clipping rectangles when hovering a ImDrawCmd", &show_clip_rects);
ImGui::Separator();
@ -10407,7 +10475,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
NodeDrawList(window->DrawList, "DrawList");
ImGui::BulletText("Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y);
ImGui::BulletText("Scroll: (%.2f,%.2f)", window->Scroll.x, window->Scroll.y);
ImGui::BulletText("NavLastId: 0x%08x, NavHasItems: %d", window->NavLastId, window->DC.NavHasItems);
ImGui::BulletText("NavLastId: 0x%08x, NavLayerActiveFlags: %02X", window->NavLastId, window->DC.NavLayerActiveFlags);
if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows");
ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair));

View File

@ -410,6 +410,9 @@ struct ImGuiContext
ImRect NavRefRectRel, NavScoringRectScreen;// Reference rectangle, in window space. Modified rectangle for directional navigation scoring, in screen space.
ImGuiWindow* NavWindow; //
ImGuiWindow* NavWindowingTarget;
float NavWindowingDisplayAlpha;
bool NavWindowingToggleLayer;
int NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later.
int NavIdTabCounter; // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing
bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRefRectRel is valid
bool NavMousePosDirty;
@ -417,6 +420,7 @@ struct ImGuiContext
bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we disable mouse hovering until mouse is touched again
bool NavInitDefaultRequest; // Init request for appearing window to select first item
ImGuiID NavInitDefaultResultId;
ImRect NavInitDefaultResultRectRel;
bool NavInitDefaultResultExplicit; // Whether the result was explicitly requested with SetItemDefaultFocus()
bool NavMoveRequest; // Move request for this frame
ImGuiNavDir NavMoveDir; // West/East/North/South
@ -514,6 +518,8 @@ struct ImGuiContext
NavRefRectRel = NavScoringRectScreen = ImRect();
NavWindow = NULL;
NavWindowingTarget = NULL;
NavWindowingDisplayAlpha = 0.0f;
NavWindowingToggleLayer = false;
NavIdTabCounter = INT_MAX;
NavIdIsAlive = false;
NavMousePosDirty = false;
@ -586,10 +592,11 @@ struct IMGUI_API ImGuiDrawContext
int TreeDepth;
ImGuiID LastItemId;
ImRect LastItemRect;
bool LastItemHoveredAndUsable; // Item rectangle is hovered, and its window is currently interactable with (not blocked by a popup preventing access to the window)
bool LastItemHoveredRect; // Item rectangle is hovered, but its window may or not be currently interactable with (might be blocked by a popup preventing access to the window)
bool NavHasItems, NavHasItemsNext; // Set when has any navigatable item
bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f)
bool LastItemHoveredAndUsable; // Item rectangle is hovered, and its window is currently interactable with (not blocked by a popup preventing access to the window)
bool LastItemHoveredRect; // Item rectangle is hovered, but its window may or not be currently interactable with (might be blocked by a popup preventing access to the window)
bool NavHasScroll; // Set when scrolling can be used (ScrollMax > 0.0f)
int NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1)
int NavLayerActiveFlags, NavLayerActiveFlagsNext; // Which layer have been written to.
bool MenuBarAppending;
float MenuBarOffsetX;
ImVector<ImGuiWindow*> ChildWindows;
@ -633,7 +640,9 @@ struct IMGUI_API ImGuiDrawContext
LastItemId = 0;
LastItemRect = ImRect(0.0f,0.0f,0.0f,0.0f);
LastItemHoveredAndUsable = LastItemHoveredRect = false;
NavHasItems = NavHasItemsNext = NavHasScroll = false;
NavHasScroll = false;
NavLayerActiveFlags = NavLayerActiveFlagsNext = 0x00;
NavLayerCurrent = 0;
MenuBarAppending = false;
MenuBarOffsetX = 0.0f;
StateStorage = NULL;
@ -686,7 +695,7 @@ struct IMGUI_API ImGuiWindow
bool SkipItems; // == Visible && !Collapsed
int BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs)
ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling)
ImGuiID NavLastId; // Last known NavId for this window
ImGuiID NavLastId; // Last known NavId for this window, for nav layer 0 only.
int AutoFitFramesX, AutoFitFramesY;
bool AutoFitOnlyGrows;
int AutoPosLastDirection;