|
@@ -2658,7 +2658,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
|
|
|
window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
|
|
|
|
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
|
- ImGuiTestEngineHook_ItemAdd(id, bb);
|
|
|
+ ImGuiTestEngineHook_ItemAdd(bb, id);
|
|
|
#endif
|
|
|
|
|
|
// Clipping test
|
|
@@ -3433,7 +3433,7 @@ void ImGui::NewFrame()
|
|
|
// 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.
|
|
|
g.CurrentWindowStack.resize(0);
|
|
|
- g.CurrentPopupStack.resize(0);
|
|
|
+ g.BeginPopupStack.resize(0);
|
|
|
ClosePopupsOverWindow(g.NavWindow);
|
|
|
|
|
|
// Create implicit/fallback window - which we will only render it if the user has added something to it.
|
|
@@ -3520,7 +3520,7 @@ void ImGui::Shutdown(ImGuiContext* context)
|
|
|
g.StyleModifiers.clear();
|
|
|
g.FontStack.clear();
|
|
|
g.OpenPopupStack.clear();
|
|
|
- g.CurrentPopupStack.clear();
|
|
|
+ g.BeginPopupStack.clear();
|
|
|
g.CurrentViewport = g.MouseViewport = g.MouseLastHoveredViewport = NULL;
|
|
|
for (int i = 0; i < g.Viewports.Size; i++)
|
|
|
IM_DELETE(g.Viewports[i]);
|
|
@@ -4149,8 +4149,8 @@ ImVec2 ImGui::GetMousePos()
|
|
|
ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup()
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
- if (g.CurrentPopupStack.Size > 0)
|
|
|
- return g.OpenPopupStack[g.CurrentPopupStack.Size-1].OpenMousePos;
|
|
|
+ if (g.BeginPopupStack.Size > 0)
|
|
|
+ return g.OpenPopupStack[g.BeginPopupStack.Size-1].OpenMousePos;
|
|
|
return g.IO.MousePos;
|
|
|
}
|
|
|
|
|
@@ -4423,7 +4423,7 @@ static void CheckStacksSize(ImGuiWindow* window, bool write)
|
|
|
short* p_backup = &window->DC.StackSizesBackup[0];
|
|
|
{ int current = window->IDStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!"); p_backup++; } // Too few or too many PopID()/TreePop()
|
|
|
{ int current = window->DC.GroupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // Too few or too many EndGroup()
|
|
|
- { int current = g.CurrentPopupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup()
|
|
|
+ { int current = g.BeginPopupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup()
|
|
|
// For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them.
|
|
|
{ int current = g.ColorModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // Too few or too many PopStyleColor()
|
|
|
{ int current = g.StyleModifiers.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // Too few or too many PopStyleVar()
|
|
@@ -4852,7 +4852,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesForResize > 0);
|
|
|
if (flags & ImGuiWindowFlags_Popup)
|
|
|
{
|
|
|
- ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size];
|
|
|
+ ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
|
|
|
window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
|
|
|
window_just_activated_by_user |= (window != popup_ref.Window);
|
|
|
}
|
|
@@ -4886,9 +4886,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
CheckStacksSize(window, true);
|
|
|
if (flags & ImGuiWindowFlags_Popup)
|
|
|
{
|
|
|
- ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size];
|
|
|
+ ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
|
|
|
popup_ref.Window = window;
|
|
|
- g.CurrentPopupStack.push_back(popup_ref);
|
|
|
+ g.BeginPopupStack.push_back(popup_ref);
|
|
|
window->PopupId = popup_ref.PopupId;
|
|
|
}
|
|
|
|
|
@@ -5076,7 +5076,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
{
|
|
|
window->AutoPosLastDirection = ImGuiDir_None;
|
|
|
if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api)
|
|
|
- window->Pos = g.CurrentPopupStack.back().OpenPopupPos;
|
|
|
+ window->Pos = g.BeginPopupStack.back().OpenPopupPos;
|
|
|
}
|
|
|
|
|
|
// Position child window
|
|
@@ -5553,7 +5553,7 @@ void ImGui::End()
|
|
|
// Pop from window stack
|
|
|
g.CurrentWindowStack.pop_back();
|
|
|
if (window->Flags & ImGuiWindowFlags_Popup)
|
|
|
- g.CurrentPopupStack.pop_back();
|
|
|
+ g.BeginPopupStack.pop_back();
|
|
|
CheckStacksSize(window, false);
|
|
|
SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
|
|
|
if (g.CurrentWindow)
|
|
@@ -6781,13 +6781,13 @@ void ImGui::SetTooltip(const char* fmt, ...)
|
|
|
bool ImGui::IsPopupOpen(ImGuiID id)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
- return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id;
|
|
|
+ return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;
|
|
|
}
|
|
|
|
|
|
bool ImGui::IsPopupOpen(const char* str_id)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
- return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
|
|
|
+ return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
|
|
|
}
|
|
|
|
|
|
ImGuiWindow* ImGui::GetFrontMostPopupModal()
|
|
@@ -6814,7 +6814,7 @@ void ImGui::OpenPopupEx(ImGuiID id)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* parent_window = g.CurrentWindow;
|
|
|
- int current_stack_size = g.CurrentPopupStack.Size;
|
|
|
+ int current_stack_size = g.BeginPopupStack.Size;
|
|
|
ImGuiPopupRef popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
|
|
|
popup_ref.PopupId = id;
|
|
|
popup_ref.Window = NULL;
|
|
@@ -6873,12 +6873,13 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window)
|
|
|
|
|
|
// When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
|
|
|
// Don't close our own child popup windows.
|
|
|
- int n = 0;
|
|
|
+ int popup_count_to_keep = 0;
|
|
|
if (ref_window)
|
|
|
{
|
|
|
- for (; n < g.OpenPopupStack.Size; n++)
|
|
|
+ // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow)
|
|
|
+ for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++)
|
|
|
{
|
|
|
- ImGuiPopupRef& popup = g.OpenPopupStack[n];
|
|
|
+ ImGuiPopupRef& popup = g.OpenPopupStack[popup_count_to_keep];
|
|
|
if (!popup.Window)
|
|
|
continue;
|
|
|
IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
|
|
@@ -6886,47 +6887,60 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window)
|
|
|
continue;
|
|
|
|
|
|
// Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow)
|
|
|
- bool has_focus = false;
|
|
|
- for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++)
|
|
|
- has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow);
|
|
|
- if (!has_focus)
|
|
|
+ bool popup_or_descendent_has_focus = false;
|
|
|
+ for (int m = popup_count_to_keep; m < g.OpenPopupStack.Size && !popup_or_descendent_has_focus; m++)
|
|
|
+ if (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow)
|
|
|
+ popup_or_descendent_has_focus = true;
|
|
|
+ if (!popup_or_descendent_has_focus)
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
- if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below
|
|
|
- ClosePopupToLevel(n);
|
|
|
+ if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below
|
|
|
+ {
|
|
|
+ //IMGUI_DEBUG_LOG("ClosePopupsOverWindow(%s) -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep);
|
|
|
+ ClosePopupToLevel(popup_count_to_keep, false);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-void ImGui::ClosePopupToLevel(int remaining)
|
|
|
+void ImGui::ClosePopupToLevel(int remaining, bool apply_focus_to_window_under)
|
|
|
{
|
|
|
IM_ASSERT(remaining >= 0);
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining-1].Window : g.OpenPopupStack[0].ParentWindow;
|
|
|
- if (g.NavLayer == 0)
|
|
|
- focus_window = NavRestoreLastChildNavWindow(focus_window);
|
|
|
- FocusWindow(focus_window);
|
|
|
- focus_window->DC.NavHideHighlightOneFrame = true;
|
|
|
g.OpenPopupStack.resize(remaining);
|
|
|
-}
|
|
|
|
|
|
-void ImGui::ClosePopup(ImGuiID id)
|
|
|
-{
|
|
|
- if (!IsPopupOpen(id))
|
|
|
- return;
|
|
|
- ImGuiContext& g = *GImGui;
|
|
|
- ClosePopupToLevel(g.OpenPopupStack.Size - 1);
|
|
|
+ // FIXME: This code is faulty and we may want to eventually to replace or remove the 'apply_focus_to_window_under=true' path completely.
|
|
|
+ // Instead of using g.OpenPopupStack[remaining-1].Window etc. we should find the highest root window that is behind the popups we are closing.
|
|
|
+ // The current code will set focus to the parent of the popup window which is incorrect.
|
|
|
+ // It rarely manifested until now because UpdateMouseMovingWindow() would call FocusWindow() again on the clicked window,
|
|
|
+ // leading to a chain of focusing A (clicked window) then B (parent window of the popup) then A again.
|
|
|
+ // However if the clicked window has the _NoMove flag set we would be left with B focused.
|
|
|
+ // For now, we have disabled this path when called from ClosePopupsOverWindow() because the users of ClosePopupsOverWindow() don't need to alter focus anyway,
|
|
|
+ // but we should inspect and fix this properly.
|
|
|
+ if (apply_focus_to_window_under)
|
|
|
+ {
|
|
|
+ if (g.NavLayer == 0)
|
|
|
+ focus_window = NavRestoreLastChildNavWindow(focus_window);
|
|
|
+ FocusWindow(focus_window);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Close the popup we have begin-ed into.
|
|
|
void ImGui::CloseCurrentPopup()
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
- int popup_idx = g.CurrentPopupStack.Size - 1;
|
|
|
- if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
|
|
|
+ int popup_idx = g.BeginPopupStack.Size - 1;
|
|
|
+ if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
|
|
|
return;
|
|
|
while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu))
|
|
|
popup_idx--;
|
|
|
- ClosePopupToLevel(popup_idx);
|
|
|
+ ClosePopupToLevel(popup_idx, true);
|
|
|
+
|
|
|
+ // A common pattern is to close a popup when selecting a menu item/selectable that will open another window.
|
|
|
+ // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window.
|
|
|
+ // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic.
|
|
|
+ if (ImGuiWindow* window = g.NavWindow)
|
|
|
+ window->DC.NavHideHighlightOneFrame = true;
|
|
|
}
|
|
|
|
|
|
bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
|
|
@@ -6940,7 +6954,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
|
|
|
|
|
|
char name[20];
|
|
|
if (extra_flags & ImGuiWindowFlags_ChildMenu)
|
|
|
- ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth
|
|
|
+ ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth
|
|
|
else
|
|
|
ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
|
|
|
|
|
@@ -6954,7 +6968,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
|
|
|
bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
- if (g.OpenPopupStack.Size <= g.CurrentPopupStack.Size) // Early out for performance
|
|
|
+ if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance
|
|
|
{
|
|
|
g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
|
|
|
return false;
|
|
@@ -6963,6 +6977,8 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
|
|
|
return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags);
|
|
|
}
|
|
|
|
|
|
+// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.
|
|
|
+// Note that popup visibility status is owned by imgui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here.
|
|
|
bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui;
|
|
@@ -6985,7 +7001,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla
|
|
|
{
|
|
|
EndPopup();
|
|
|
if (is_open)
|
|
|
- ClosePopup(id);
|
|
|
+ ClosePopupToLevel(g.BeginPopupStack.Size, true);
|
|
|
return false;
|
|
|
}
|
|
|
return is_open;
|
|
@@ -6995,7 +7011,7 @@ void ImGui::EndPopup()
|
|
|
{
|
|
|
ImGuiContext& g = *GImGui; (void)g;
|
|
|
IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls
|
|
|
- IM_ASSERT(g.CurrentPopupStack.Size > 0);
|
|
|
+ IM_ASSERT(g.BeginPopupStack.Size > 0);
|
|
|
|
|
|
// Make all menus and popups wrap around for now, may need to expose that policy.
|
|
|
NavMoveRequestTryWrapping(g.CurrentWindow, ImGuiNavMoveFlags_LoopY);
|
|
@@ -7590,7 +7606,7 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window)
|
|
|
{
|
|
|
// We need to take account of the possibility that mouse may become invalid.
|
|
|
// Popups/Tooltip always set ViewportAllowPlatformMonitorExtend so GetWindowAllowedExtentRect() will return full monitor bounds.
|
|
|
- ImVec2 mouse_ref = (flags & ImGuiWindowFlags_Tooltip) ? g.IO.MousePos : g.CurrentPopupStack.back().OpenMousePos;
|
|
|
+ ImVec2 mouse_ref = (flags & ImGuiWindowFlags_Tooltip) ? g.IO.MousePos : g.BeginPopupStack.back().OpenMousePos;
|
|
|
bool use_mouse_ref = (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow);
|
|
|
bool mouse_valid = IsMousePosValid(&mouse_ref);
|
|
|
if ((window->Appearing || (flags & ImGuiWindowFlags_Tooltip)) && (!use_mouse_ref || mouse_valid))
|
|
@@ -8403,7 +8419,7 @@ static void ImGui::NavUpdate()
|
|
|
{
|
|
|
// Close open popup/menu
|
|
|
if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
|
|
|
- ClosePopupToLevel(g.OpenPopupStack.Size - 1);
|
|
|
+ ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
|
|
|
}
|
|
|
else if (g.NavLayer != 0)
|
|
|
{
|