Skip to content

Commit

Permalink
Popups: Fix popups being closed by newly appearing windows. (ocornut#…
Browse files Browse the repository at this point in the history
…4317)

* Popups/modals now remain open when new windows are created from within popup/modal begin stack.
* Modals are not closed when new window appears behind active modal.
  • Loading branch information
rokups committed Aug 25, 2021
1 parent 80ed4eb commit d8a5778
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 3 deletions.
1 change: 1 addition & 0 deletions docs/CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Other Changes:
- Backends: Metal: Fixed a crash when clipping rect larger than framebuffer is submitted via
a direct unclipped PushClipRect() call. (#4464)
- Backends: All renderers: Normalize clipping rect handling across backends. (#4464)
- Popups: Windows created from within a popup/modal will no longer close that popup/modal. (#4317) [@rokups]


-----------------------------------------------------------------------
Expand Down
25 changes: 22 additions & 3 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3879,7 +3879,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()

// Modal windows prevents mouse from hovering behind them.
ImGuiWindow* modal_window = GetTopMostPopupModal();
if (modal_window && g.HoveredWindow && !IsWindowChildOf(g.HoveredWindow->RootWindow, modal_window))
if (modal_window && g.HoveredWindow && !IsWindowChildOfBeginStack(g.HoveredWindow->RootWindow, modal_window))
clear_hovered_windows = true;

// Disabled mouse?
Expand Down Expand Up @@ -5843,7 +5843,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)

// 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
Expand Down Expand Up @@ -6094,7 +6097,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
bool want_focus = false;
if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
{
if (flags & ImGuiWindowFlags_Popup)
ImGuiWindow* modal = GetTopMostPopupModal();
if (modal != NULL && !IsWindowChildOfBeginStack(window, modal))
want_focus = false;
else if (flags & ImGuiWindowFlags_Popup)
want_focus = true;
else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0)
want_focus = true;
Expand Down Expand Up @@ -6697,6 +6703,19 @@ bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent)
return false;
}

bool ImGui::IsWindowChildOfBeginStack(ImGuiWindow* window, ImGuiWindow* potential_parent)
{
if (window->RootWindow == potential_parent)
return true;
while (window != NULL)
{
if (window == potential_parent)
return true;
window = window->ParentWindowInBeginStack;
}
return false;
}

bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below)
{
ImGuiContext& g = *GImGui;
Expand Down Expand Up @@ -8285,7 +8304,7 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to
bool ref_window_is_descendent_of_popup = false;
for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++)
if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window)
if (popup_window->RootWindow == ref_window->RootWindow)
if (IsWindowChildOfBeginStack(ref_window, popup_window))
{
ref_window_is_descendent_of_popup = true;
break;
Expand Down
2 changes: 2 additions & 0 deletions imgui_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1943,6 +1943,7 @@ struct IMGUI_API ImGuiWindow
ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer)
ImDrawList DrawListInst;
ImGuiWindow* ParentWindow; // If we are a child _or_ popup window, this is pointing to our parent. Otherwise NULL.
ImGuiWindow* ParentWindowInBeginStack;
ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window == Top-level window.
ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active.
ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag.
Expand Down Expand Up @@ -2330,6 +2331,7 @@ namespace ImGui
IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window);
IMGUI_API ImVec2 CalcWindowNextAutoFitSize(ImGuiWindow* window);
IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent);
IMGUI_API bool IsWindowChildOfBeginStack(ImGuiWindow* window, ImGuiWindow* potential_parent);
IMGUI_API bool IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below);
IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window);
IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0);
Expand Down

0 comments on commit d8a5778

Please sign in to comment.