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 authored and ocornut committed Nov 22, 2021
1 parent 4d9a3b1 commit 71e99b0
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 @@ -165,6 +165,7 @@ Other Changes:
- Backends: OSX: Use mach_absolute_time as CFAbsoluteTimeGetCurrent can jump backwards. (#4557, #4563) [@lfnoise]
- Backends: All renderers: Normalize clipping rect handling across backends. (#4464)
- Examples: Added SDL + SDL_Renderer example in "examples/example_sdl_sdlrenderer/" folder. (#3926) [@1bsyl]
- 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 @@ -3896,7 +3896,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, true))
if (modal_window && g.HoveredWindow && !IsWindowChildOfBeginStack(g.HoveredWindow->RootWindow, modal_window))
clear_hovered_windows = true;

// Disabled mouse?
Expand Down Expand Up @@ -5874,7 +5874,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 @@ -6125,7 +6128,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 @@ -6764,6 +6770,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 @@ -8436,7 +8455,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 @@ -2026,6 +2026,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 _or_ docked 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. Doesn't cross through popups/dock nodes.
ImGuiWindow* RootWindowPopupTree; // Point to ourself or first ancestor that is not a child window. Cross through popups parent<>child.
ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active.
Expand Down Expand Up @@ -2414,6 +2415,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, bool popup_hierarchy);
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 71e99b0

Please sign in to comment.