Popups: Added ImGuiPopupFlags type, ImGuiPopupFlags_AnyPopupId and ImGuiPopupFlags_AnyPopupLevel flags for IsPopupOpen().
# Conflicts:
# docs/CHANGELOG.txt
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index 00dbbce..8882f0a 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -54,6 +54,9 @@
Set to an intermediary value to toggle behavior based on width (same as Firefox).
- Tab: Added a ImGuiTabItemFlags_NoTooltip flag to disable the tooltip for individual tab item
(vs ImGuiTabBarFlags_NoTooltip for entire tab bar). [@Xipiryon]
+- Popups: Added ImGuiPopupFlags_AnyPopupId and ImGuiPopupFlags_AnyPopupLevel flags for IsPopupOpen(),
+ allowing to check if any popup is open at the current level, if a given popup is open at any popup
+ level, if any popup is open at all.
- Popups: Fix an edge case where programatically closing a popup while clicking on its empty space
would attempt to focus it and close other popups. (#2880)
- Popups: Fix BeginPopupContextVoid() when clicking over the area made unavailable by a modal. (#1636)
diff --git a/imgui.cpp b/imgui.cpp
index bb5d8a9..f2e77c7 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -3468,7 +3468,7 @@
// Handle the edge case of a popup being closed while clicking in its empty space.
// If we try to focus it, FocusWindow() > ClosePopupsOverWindow() will accidentally close any parent popups because they are not linked together any more.
ImGuiWindow* root_window = g.HoveredRootWindow;
- const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpenAtAnyLevel(root_window->PopupId);
+ const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel);
if (root_window != NULL && !is_closed_popup)
{
@@ -7619,35 +7619,45 @@
// [SECTION] POPUPS
//-----------------------------------------------------------------------------
-// Return true if the popup is open at the current BeginPopup() level of the popup stack
-bool ImGui::IsPopupOpen(ImGuiID id)
+// Supported flags: ImGuiPopupFlags_AnyPopupId, ImGuiPopupFlags_AnyPopupLevel
+bool ImGui::IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags)
{
ImGuiContext& g = *GImGui;
- return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;
+ if (popup_flags & ImGuiPopupFlags_AnyPopupId)
+ {
+ // Return true if any popup is open at the current BeginPopup() level of the popup stack
+ // This may be used to e.g. test for another popups already opened to handle popups priorities at the same level.
+ IM_ASSERT(id == 0);
+ if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
+ return g.OpenPopupStack.Size > 0;
+ else
+ return g.OpenPopupStack.Size > g.BeginPopupStack.Size;
+ }
+ else
+ {
+ if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
+ {
+ // Return true if the popup is open anywhere in the popup stack
+ for (int n = 0; n < g.OpenPopupStack.Size; n++)
+ if (g.OpenPopupStack[n].PopupId == id)
+ return true;
+ return false;
+ }
+ else
+ {
+ // Return true if the popup is open at the current BeginPopup() level of the popup stack (this is the most-common query)
+ return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;
+ }
+ }
}
-// Return true if the popup is open at the current BeginPopup() level of the popup stack
-bool ImGui::IsPopupOpen(const char* str_id)
+bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags)
{
ImGuiContext& g = *GImGui;
- return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
-}
-
-bool ImGui::IsPopupOpenAtAnyLevel(ImGuiID id)
-{
- ImGuiContext& g = *GImGui;
- for (int n = 0; n < g.OpenPopupStack.Size; n++)
- if (g.OpenPopupStack[n].PopupId == id)
- return true;
- return false;
-}
-
-// Return true if any popup is open at the current BeginPopup() level of the popup stack
-// This may be used to e.g. test for another popups already opened in the same frame to handle popups priorities at the same level.
-bool ImGui::IsAnyPopupOpen()
-{
- ImGuiContext& g = *GImGui;
- return g.OpenPopupStack.Size > g.BeginPopupStack.Size;
+ ImGuiID id = (popup_flags & ImGuiPopupFlags_AnyPopupId) ? 0 : g.CurrentWindow->GetID(str_id);
+ if ((popup_flags & ImGuiPopupFlags_AnyPopupLevel) && id != 0)
+ IM_ASSERT(0 && "Cannot use IsPopupOpen() with a string id and ImGuiPopupFlags_AnyPopupLevel."); // But non-string version is legal and used internally
+ return IsPopupOpen(id, popup_flags);
}
ImGuiWindow* ImGui::GetTopMostPopupModal()
@@ -7674,7 +7684,7 @@
{
ImGuiContext& g = *GImGui;
ImGuiWindow* parent_window = g.CurrentWindow;
- int current_stack_size = g.BeginPopupStack.Size;
+ const int current_stack_size = g.BeginPopupStack.Size;
ImGuiPopupData 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;
@@ -7811,7 +7821,7 @@
bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags)
{
ImGuiContext& g = *GImGui;
- if (!IsPopupOpen(id))
+ if (!IsPopupOpen(id, ImGuiPopupFlags_None))
{
g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
return false;
@@ -7850,7 +7860,7 @@
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
const ImGuiID id = window->GetID(name);
- if (!IsPopupOpen(id))
+ if (!IsPopupOpen(id, ImGuiPopupFlags_None))
{
g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
return false;
diff --git a/imgui.h b/imgui.h
index cedc861..63bfc27 100644
--- a/imgui.h
+++ b/imgui.h
@@ -161,6 +161,7 @@
typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc.
typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText(), InputTextMultiline()
typedef int ImGuiKeyModFlags; // -> enum ImGuiKeyModFlags_ // Flags: for io.KeyMods (Ctrl/Shift/Alt/Super)
+typedef int ImGuiPopupFlags; // -> enum ImGuiPopupFlags_ // Flags: for OpenPopup*(), BeginPopupContext*(), IsPopupOpen()
typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable()
typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar()
typedef int ImGuiTabItemFlags; // -> enum ImGuiTabItemFlags_ // Flags: for BeginTabItem()
@@ -612,13 +613,17 @@
IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!).
IMGUI_API bool OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mouse_b = 1); // helper to open popup when clicked on last item. return true when just opened. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors)
IMGUI_API void CloseCurrentPopup(); // manually close the popup we have begin-ed into.
- IMGUI_API bool IsPopupOpen(const char* str_id); // return true if the popup is open at the current BeginPopup() level of the popup stack
// Popups: open+begin combined functions helpers
// - Helpers to do OpenPopup+BeginPopup where the Open action is triggered by e.g. hovering an item and right-clicking.
// - They are convenient to easily create context menus, hence the name.
IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mouse_b = 1); // open+begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp!
IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, ImGuiMouseButton mouse_b = 1, bool also_over_items = true); // open+begin popup when clicked on current window.
IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, ImGuiMouseButton mouse_b = 1); // open+begin popup when clicked in void (where there are no windows).
+ // Popups: test function
+ // - IsPopupOpen(): return true if the popup is open at the current BeginPopup() level of the popup stack.
+ // - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId: return true if any popup is open at the current BeginPopup() level of the popup stack.
+ // - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId + ImGuiPopupFlags_AnyPopupLevel: return true if any popup is open.
+ IMGUI_API bool IsPopupOpen(const char* str_id, ImGuiPopupFlags flags = 0); // return true if the popup is open.
// Columns
// - You can also use SameLine(pos_x) to mimic simplified columns.
@@ -865,6 +870,15 @@
ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog
};
+// Flags for IsPopupOpen() function.
+enum ImGuiPopupFlags_
+{
+ ImGuiPopupFlags_None = 0,
+ ImGuiPopupFlags_AnyPopupId = 1 << 7, // For IsPopupOpen(): ignore the ImGuiID parameter and test for any popup.
+ ImGuiPopupFlags_AnyPopupLevel = 1 << 8, // For IsPopupOpen(): search/test at any level of the popup stack (default test in the current level)
+ ImGuiPopupFlags_AnyPopup = ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel
+};
+
// Flags for ImGui::Selectable()
enum ImGuiSelectableFlags_
{
diff --git a/imgui_internal.h b/imgui_internal.h
index a00a341..d0c8bbc 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -1853,9 +1853,7 @@
IMGUI_API void OpenPopupEx(ImGuiID id);
IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup);
IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup);
- IMGUI_API bool IsPopupOpen(ImGuiID id); // Test for id at the current BeginPopup() level of the popup stack (this doesn't scan the whole popup stack!)
- IMGUI_API bool IsPopupOpenAtAnyLevel(ImGuiID id);
- IMGUI_API bool IsAnyPopupOpen(); // Return true if any popup is open at the current BeginPopup() level of the popup stack
+ IMGUI_API bool IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags);
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);
IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags);
IMGUI_API ImGuiWindow* GetTopMostPopupModal();
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp
index bda694a..79144ee 100644
--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -1492,7 +1492,7 @@
bool hovered, held;
bool pressed = ButtonBehavior(frame_bb, id, &hovered, &held);
- bool popup_open = IsPopupOpen(id);
+ bool popup_open = IsPopupOpen(id, ImGuiPopupFlags_None);
const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
const float value_x2 = ImMax(frame_bb.Min.x, frame_bb.Max.x - arrow_size);
@@ -6288,7 +6288,7 @@
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
- bool menu_is_open = IsPopupOpen(id);
+ bool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None);
// Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu)
ImGuiWindowFlags flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus;
@@ -6414,7 +6414,7 @@
if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }'
want_close = true;
- if (want_close && IsPopupOpen(id))
+ if (want_close && IsPopupOpen(id, ImGuiPopupFlags_None))
ClosePopupToLevel(g.BeginPopupStack.Size, true);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0));