Internals: rework FocusScope system, current scope doesn't need to be in window + child doesn't inherit.

Intended as part of work for input routing + blind menu processing shortcuts. Some of this commit will be stripped by next commit.
Intent was to sort windows along with focus scope to build a hierarchy, but for our needs we'd need a persistant one, so scrapping the idea. Not squashing this with next commit to keep a bit of history for future references.
This commit is contained in:
ocornut
2022-10-19 20:54:19 +02:00
parent 1eac0024c0
commit 9f66a3a9ed
4 changed files with 68 additions and 40 deletions

View File

@ -6319,10 +6319,23 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window_stack_data.ParentLastItemDataBackup = g.LastItemData;
window_stack_data.StackSizesOnBegin.SetToCurrentState();
g.CurrentWindowStack.push_back(window_stack_data);
g.CurrentWindow = NULL;
if (flags & ImGuiWindowFlags_ChildMenu)
g.BeginMenuCount++;
// Update ->RootWindow and others pointers (before any possible call to FocusWindow)
if (first_begin_of_the_frame)
{
UpdateWindowParentAndRootLinks(window, flags, parent_window);
window->ParentWindowInBeginStack = parent_window_in_stack;
}
// Add to focus scope stack - inherited by default by child windows from parent, reset by regular window
//if (window == window->RootWindow && (window->Flags & ImGuiWindowFlags_ChildMenu) == 0)
PushFocusScope(window->ID);
window->NavRootFocusScopeId = g.CurrentFocusScopeId;
g.CurrentWindow = NULL;
// Add to popup stack
if (flags & ImGuiWindowFlags_Popup)
{
ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
@ -6332,13 +6345,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->PopupId = popup_ref.PopupId;
}
// Update ->RootWindow and others pointers (before any possible call to FocusWindow)
if (first_begin_of_the_frame)
{
UpdateWindowParentAndRootLinks(window, flags, parent_window);
window->ParentWindowInBeginStack = parent_window_in_stack;
}
// Process SetNextWindow***() calls
// (FIXME: Consider splitting the HasXXX flags into X/Y components
bool window_pos_set_by_api = false;
@ -6859,9 +6865,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
SetCurrentWindow(window);
}
// Pull/inherit current state
window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : window->GetID("#FOCUSSCOPE"); // Inherit from parent only // -V595
PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
// Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused)
@ -6939,6 +6942,8 @@ void ImGui::End()
if (window->DC.CurrentColumns)
EndColumns();
PopClipRect(); // Inner window clip rectangle
//if (window == window->RootWindow && (window->Flags & ImGuiWindowFlags_ChildMenu) == 0)
PopFocusScope();
// Stop logging
if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging
@ -7048,7 +7053,7 @@ void ImGui::FocusWindow(ImGuiWindow* window)
g.NavMousePosDirty = true;
g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
g.NavLayer = ImGuiNavLayer_Main;
g.NavFocusScopeId = 0;
g.NavFocusScopeId = window ? window->NavRootFocusScopeId : 0;
g.NavIdIsAlive = false;
// Close popups if any
@ -7619,18 +7624,24 @@ void ImGui::ActivateItem(ImGuiID id)
void ImGui::PushFocusScope(ImGuiID id)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
g.FocusScopeStack.push_back(window->DC.NavFocusScopeIdCurrent);
window->DC.NavFocusScopeIdCurrent = id;
if (g.FocusScopeStackLocked > 0)
return;
ImGuiFocusScope scope;
scope.FocusScopeId = id;
scope.Window = g.CurrentWindow;
g.FocusScopeStack.push_back(scope);
g.CurrentFocusScopeId = scope.FocusScopeId;
}
void ImGui::PopFocusScope()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
if (g.FocusScopeStackLocked > 0)
return;
IM_ASSERT(g.FocusScopeStack.Size > 0); // Too many PopFocusScope() ?
window->DC.NavFocusScopeIdCurrent = g.FocusScopeStack.back();
IM_ASSERT(g.FocusScopeStack.back().Window == g.CurrentWindow); // Mismatched pop location?
g.FocusScopeStack.pop_back();
g.CurrentFocusScopeId = g.FocusScopeStack.Size ? g.FocusScopeStack.back().FocusScopeId : 0;
}
// Note: this will likely be called ActivateItem() once we rework our Focus/Activation system!
@ -8509,7 +8520,7 @@ void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, vo
if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'", window->Name);
PopStyleVar();
}
while (g.FocusScopeStack.Size > stack_sizes->SizeOfFocusScopeStack) //-V1044
while (g.FocusScopeStack.Size > stack_sizes->SizeOfFocusScopeStack + 1) //-V1044
{
if (log_callback) log_callback(user_data, "Recovered from missing PopFocusScope() in '%s'", window->Name);
PopFocusScope();
@ -9953,12 +9964,12 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
if (g.NavWindow != window)
SetNavWindow(window);
// Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and window->DC.NavFocusScopeIdCurrent are valid.
// Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and g.CurrentFocusScopeId are valid.
// Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text)
const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent;
g.NavId = id;
g.NavLayer = nav_layer;
g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
g.NavFocusScopeId = g.CurrentFocusScopeId;
window->NavLastIds[nav_layer] = id;
if (g.LastItemData.ID == id)
window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect);
@ -10139,7 +10150,7 @@ static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result)
ImGuiWindow* window = g.CurrentWindow;
result->Window = window;
result->ID = g.LastItemData.ID;
result->FocusScopeId = window->DC.NavFocusScopeIdCurrent;
result->FocusScopeId = g.CurrentFocusScopeId;
result->InFlags = g.LastItemData.InFlags;
result->RectRel = WindowRectAbsToRel(window, g.LastItemData.NavRect);
}
@ -10206,7 +10217,7 @@ static void ImGui::NavProcessItem()
if (g.NavWindow != window)
SetNavWindow(window); // Always refresh g.NavWindow, because some operations such as FocusItem() may not have a window.
g.NavLayer = window->DC.NavLayerCurrent;
g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
g.NavFocusScopeId = g.CurrentFocusScopeId;
g.NavIdIsAlive = true;
window->NavRectRel[window->DC.NavLayerCurrent] = WindowRectAbsToRel(window, nav_bb); // Store item bounding box (relative to window position)
}
@ -10394,7 +10405,8 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
if (window->Flags & ImGuiWindowFlags_NoNavInputs)
{
g.NavId = g.NavFocusScopeId = 0;
g.NavId = 0;
g.NavFocusScopeId = window->NavRootFocusScopeId;
return;
}
@ -10404,7 +10416,7 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
if (init_for_nav)
{
SetNavID(0, g.NavLayer, 0, ImRect());
SetNavID(0, g.NavLayer, window->NavRootFocusScopeId, ImRect());
g.NavInitRequest = true;
g.NavInitRequestFromMove = false;
g.NavInitResultId = 0;
@ -10414,7 +10426,7 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
else
{
g.NavId = window->NavLastIds[0];
g.NavFocusScopeId = 0;
g.NavFocusScopeId = window->NavRootFocusScopeId;
}
}
@ -10738,7 +10750,7 @@ void ImGui::NavUpdateCreateMoveRequest()
inner_rect_rel.Min.y = clamp_y ? (inner_rect_rel.Min.y + pad_y) : -FLT_MAX;
inner_rect_rel.Max.y = clamp_y ? (inner_rect_rel.Max.y - pad_y) : +FLT_MAX;
window->NavRectRel[g.NavLayer].ClipWithFull(inner_rect_rel);
g.NavId = g.NavFocusScopeId = 0;
g.NavId = /*g.NavFocusScopeId =*/ 0;
}
}
@ -10921,7 +10933,7 @@ static void ImGui::NavUpdateCancelRequest()
// 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 = g.NavFocusScopeId = 0;
g.NavId = /*g.NavFocusScopeId =*/ 0;
}
}