Focus: start moving modal check into FocusWindow(), add ImGuiFocusRequestFlags_UnlessBelowModal (currently opt-in, should try to make opt-out). (#6357, #4317)

This commit is contained in:
ocornut
2023-04-21 17:30:05 +02:00
parent f0fe1957a8
commit 30eceaf95f
3 changed files with 36 additions and 14 deletions

View File

@ -1056,7 +1056,6 @@ static void RenderWindowDecorations(ImGuiWindow* window, const ImRec
static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col);
static void RenderDimmedBackgrounds();
static ImGuiWindow* FindBlockingModal(ImGuiWindow* window);
// Viewports
static void UpdateViewportsNewFrame();
@ -3911,7 +3910,7 @@ bool ImGui::IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flag
// Inhibit hover unless the window is within the stack of our modal/popup
if (want_inhibit)
if (!ImGui::IsWindowWithinBeginStackOf(window->RootWindow, focused_root_window))
if (!IsWindowWithinBeginStackOf(window->RootWindow, focused_root_window))
return false;
}
return true;
@ -4296,10 +4295,10 @@ void ImGui::UpdateMouseMovingWindowEndFrame()
if (g.HoveredIdDisabled)
g.MovingWindow = NULL;
}
else if (root_window == NULL && g.NavWindow != NULL && GetTopMostPopupModal() == NULL)
else if (root_window == NULL && g.NavWindow != NULL)
{
// Clicking on void disable focus
FocusWindow(NULL);
FocusWindow(NULL, ImGuiFocusRequestFlags_UnlessBelowModal);
}
}
@ -4624,7 +4623,7 @@ void ImGui::NewFrame()
// Closing the focused window restore focus to the first active root window in descending z-order
if (g.NavWindow && !g.NavWindow->WasActive)
FocusTopMostWindowUnderOne(NULL, NULL, NULL);
FocusTopMostWindowUnderOne(NULL, NULL, NULL, ImGuiFocusRequestFlags_None);
// No window should be open at the beginning of the frame.
// But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
@ -6077,7 +6076,7 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags
// - Window // .. returns Modal2
// - Window // .. returns Modal2
// - Modal2 // .. returns Modal2
static ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window)
ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
if (g.OpenPopupStack.Size <= 0)
@ -6091,6 +6090,8 @@ static ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window)
continue;
if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows.
continue;
if (window == NULL) // FindBlockingModal(NULL) test for if FocusWindow(NULL) is naturally possible via a mouse click.
return popup_window;
if (IsWindowWithinBeginStackOf(window, popup_window)) // Window is rendered over last modal, no render order change needed.
break;
for (ImGuiWindow* parent = popup_window->ParentWindowInBeginStack->RootWindow; parent != NULL; parent = parent->ParentWindowInBeginStack->RootWindow)
@ -6928,10 +6929,19 @@ int ImGui::FindWindowDisplayIndex(ImGuiWindow* window)
}
// Moving window to front of display and set focus (which happens to be back of our sorted list)
void ImGui::FocusWindow(ImGuiWindow* window)
void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags)
{
ImGuiContext& g = *GImGui;
// Modal check?
if (flags & ImGuiFocusRequestFlags_UnlessBelowModal)
if (ImGuiWindow* blocking_modal = FindBlockingModal(window))
{
IMGUI_DEBUG_LOG_FOCUS("[focus] FocusWindow(\"%s\", UnlessBelowModal): prevented by \"%s\".\n", window ? window->Name : "<NULL>", blocking_modal->Name);
return;
}
// Apply focus
if (g.NavWindow != window)
{
SetNavWindow(window);
@ -6968,7 +6978,7 @@ void ImGui::FocusWindow(ImGuiWindow* window)
BringWindowToDisplayFront(display_front_window);
}
void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport)
void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags)
{
ImGuiContext& g = *GImGui;
IM_UNUSED(filter_viewport); // Unused in master branch.
@ -6994,11 +7004,11 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind
if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs))
{
ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window);
FocusWindow(focus_window);
FocusWindow(focus_window, flags);
return;
}
}
FocusWindow(NULL);
FocusWindow(NULL, flags);
}
// Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only.
@ -10101,6 +10111,7 @@ bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags)
return IsPopupOpen(id, popup_flags);
}
// FIXME: In principle we should converge toward replacing calls to GetTopMostPopupModal() + IsWindowWithinBeginStackOf() with calls to FindBlockingModal()
ImGuiWindow* ImGui::GetTopMostPopupModal()
{
ImGuiContext& g = *GImGui;
@ -10263,7 +10274,7 @@ void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_
if (focus_window && !focus_window->WasActive && popup_window)
{
// Fallback
FocusTopMostWindowUnderOne(popup_window, NULL, NULL);
FocusTopMostWindowUnderOne(popup_window, NULL, NULL, ImGuiFocusRequestFlags_None);
}
else
{