diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index d915d9510..35c4c6743 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -43,6 +43,25 @@ Breaking changes:
Other changes:
+- Added io.ConfigDebugHighlightIdConflicts debug feature! (#7961, #7669)
+ THIS DETECTS THE MOST COMMON USER ERROR BY FIRST-TIME DEAR IMGUI PROGRAMMERS!
+ - The tool detects when multiple items are sharing the same identifier, due to not
+ using PushID/PopID in loops, or not using ID stack facilities such as "##" suffixes.
+ Very frequently it happens when using empty "" labels.
+ - When hovering an item with a conflicting ID, all visible items with the same ID will
+ be highlighted and an explanatory tooltip is made visible.
+ - The feature may be disabled and is exposed in Demo->Tools menu.
+ - I've been wanting to add this tool for a long time, but was stalled by finding a way to
+ not make it spammy + make it practically zero cost. After @pthom made various proposals to
+ solve the same problem (thanks for pushing me!), I decided it was time to finish it.
+ - Added ImGuiItemFlags_AllowDuplicateId to use with PushItemFlag/PopItemFlag() if for some
+ reason you intend to have duplicate identifiers.
+ - (#74, #96, #480, #501, #647, #654, #719, #843, #894, #1057, #1173, #1390, #1414, #1556, #1768,
+ #2041, #2116, #2330, #2475, #2562, #2667, #2807, #2885, #3102, #3375, #3526, #3964, #4008,
+ #4070, #4158, #4172, #4199, #4375, #4395, #4471, #4548, #4612, #4631, #4657, #4796, #5210,
+ #5303, #5360, #5393, #5533, #5692, #5707, #5729, #5773, #5787, #5884, #6046, #6093, #6186,
+ #6223, #6364, #6387, #6567, #6692, #6724, #6939, #6984, #7246, #7270, #7375, #7421, #7434,
+ #7472, #7581, #7724, #7926, #7937 and probably more..)
- Nav: pressing any keyboard key while holding Alt disable toggling nav layer on Alt release. (#4439)
- InputText: added CJK double-width punctuation to list of separators considered for CTRL+Arrow.
- TextLinkOpenURL(): modified tooltip to display a verb "Open 'xxxx'". (#7885, #7660)
diff --git a/docs/FAQ.md b/docs/FAQ.md
index d53a5a099..4e2a42576 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -204,10 +204,11 @@ ctx->RSSetScissorRects(1, &r);
### Q: How can I have multiple widgets with the same label?
### Q: How can I have multiple windows with the same label?
-**USING THE SAME LABEL+ID IS THE MOST COMMON USER MISTAKE:**
+**USING THE SAME LABEL+ID IS THE MOST COMMON USER MISTAKE!**
+
**USING AN EMPTY LABEL IS THE SAME AS USING THE SAME LABEL AS YOUR PARENT WIDGET!**
+ |
ImGui::Begin("Incorrect!");
diff --git a/imgui.cpp b/imgui.cpp
index 1d9d8b899..e6cf5ca45 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -1395,6 +1395,8 @@ ImGuiIO::ImGuiIO()
ConfigWindowsResizeFromEdges = true;
ConfigWindowsMoveFromTitleBarOnly = false;
ConfigMemoryCompactTimer = 60.0f;
+ ConfigDebugIsDebuggerPresent = false;
+ ConfigDebugHighlightIdConflicts = true;
ConfigDebugBeginReturnValueOnce = false;
ConfigDebugBeginReturnValueLoop = false;
@@ -4290,6 +4292,17 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
+
+ // Detect ID conflicts
+#ifndef IMGUI_DISABLE_DEBUG_TOOLS
+ if (id != 0 && g.HoveredIdPreviousFrame == id && (item_flags & ImGuiItemFlags_AllowDuplicateId) == 0)
+ {
+ g.HoveredIdPreviousFrameItemCount++;
+ if (g.DebugDrawIdConflicts == id)
+ window->DrawList->AddRect(bb.Min - ImVec2(1,1), bb.Max + ImVec2(1,1), IM_COL32(255, 0, 0, 255), 0.0f, ImDrawFlags_None, 2.0f);
+ }
+#endif
+
if (g.HoveredWindow != window)
return false;
if (!IsMouseHoveringRect(bb.Min, bb.Max))
@@ -4833,6 +4846,11 @@ void ImGui::NewFrame()
if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId)
KeepAliveID(g.DragDropPayload.SourceId);
+ // [DEBUG]
+ g.DebugDrawIdConflicts = 0;
+ if (g.IO.ConfigDebugHighlightIdConflicts && g.HoveredIdPreviousFrameItemCount > 1)
+ g.DebugDrawIdConflicts = g.HoveredIdPreviousFrame;
+
// Update HoveredId data
if (!g.HoveredIdPreviousFrame)
g.HoveredIdTimer = 0.0f;
@@ -4843,6 +4861,7 @@ void ImGui::NewFrame()
if (g.HoveredId && g.ActiveId != g.HoveredId)
g.HoveredIdNotActiveTimer += g.IO.DeltaTime;
g.HoveredIdPreviousFrame = g.HoveredId;
+ g.HoveredIdPreviousFrameItemCount = 0;
g.HoveredId = 0;
g.HoveredIdAllowOverlap = false;
g.HoveredIdIsDisabled = false;
@@ -5235,6 +5254,29 @@ void ImGui::EndFrame()
return;
IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?");
+#ifndef IMGUI_DISABLE_DEBUG_TOOLS
+ if (g.DebugDrawIdConflicts != 0)
+ {
+ PushStyleColor(ImGuiCol_PopupBg, ImLerp(g.Style.Colors[ImGuiCol_PopupBg], ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 0.10f));
+ if (g.DebugItemPickerActive == false && BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None))
+ {
+ SeparatorText("MESSAGE FROM DEAR IMGUI");
+ Text("Programmer error: %d visible items with conflicting ID!", g.HoveredIdPreviousFrameItemCount);
+ BulletText("Code should use PushID()/PopID() in loops, or append \"##xx\" to same-label identifiers!");
+ BulletText("Empty label e.g. Button(\"\") == same ID as parent widget/node. Use Button(\"##xx\") instead!");
+ BulletText("Press F1 to open \"FAQ -> About the ID Stack System\" and read details.");
+ BulletText("Press CTRL+P to activate Item Picker and debug-break in item call-stack.");
+ BulletText("Set io.ConfigDebugDetectIdConflicts=false to disable this warning in non-programmers builds.");
+ EndTooltip();
+ }
+ PopStyleColor();
+ if (Shortcut(ImGuiMod_Ctrl | ImGuiKey_P, ImGuiInputFlags_RouteGlobal))
+ DebugStartItemPicker();
+ if (Shortcut(ImGuiKey_F1, ImGuiInputFlags_RouteGlobal) && g.PlatformIO.Platform_OpenInShellFn != NULL)
+ g.PlatformIO.Platform_OpenInShellFn(&g, "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#qa-usage");
+ }
+#endif
+
CallContextHooks(&g, ImGuiContextHookType_EndFramePre);
ErrorCheckEndFrameSanityChecks();
diff --git a/imgui.h b/imgui.h
index 18efaff42..ebb156d4b 100644
--- a/imgui.h
+++ b/imgui.h
@@ -29,7 +29,7 @@
// Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.91.2 WIP"
-#define IMGUI_VERSION_NUM 19112
+#define IMGUI_VERSION_NUM 19113
#define IMGUI_HAS_TABLE
/*
@@ -1135,6 +1135,7 @@ enum ImGuiItemFlags_
ImGuiItemFlags_NoNavDefaultFocus = 1 << 2, // false // Disable item being a candidate for default focus (e.g. used by title bar items).
ImGuiItemFlags_ButtonRepeat = 1 << 3, // false // Any button-like behavior will have repeat mode enabled (based on io.KeyRepeatDelay and io.KeyRepeatRate values). Note that you can also call IsItemActive() after any button to tell if it is being held.
ImGuiItemFlags_AutoClosePopups = 1 << 4, // true // MenuItem()/Selectable() automatically close their parent popup window.
+ ImGuiItemFlags_AllowDuplicateId = 1 << 5, // false // Allow submitting an item with the same identifier as an item already submitted this frame without triggering a warning tooltip if io.ConfigDebugHighlightIdConflicts is set.
};
// Flags for ImGui::InputText()
@@ -2231,6 +2232,7 @@ struct ImGuiIO
const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified).
void* UserData; // = NULL // Store your own data.
+ // Font system
ImFontAtlas*Fonts; // |