Is there any easier way to detect duplicate widget IDs than randomly stumbling upon them and getting a tooltip warning?
Version/Branch of Dear ImGui:
Version 1.89.2, Branch: docking
Back-ends:
glfw, rust bindings
Compiler, OS:
Irrelevant
Full config/build information:
No response
Details:
When one creates a widget with the same ID, these days imgui will very helpfully generate a big red tooltip informing the user about it. It even very helpfully puts borders around the elements. Lovely.
The downside is that it can be a bit hard to find. We have an application with tens of windows and probably the number of elements is into thousands. Many of these aren't frequently used and even fewer are clicked.
Is there a way for imgui to inform us about duplicate IDs in some way that doesn't involve us randomly stumbling upon it and getting a tooltip? It doesn't have to be amazing: highlighting the elements would be more than enough. At this point I'd even take an (optional) crash so that I could work backwards from the stack trace to find the location.
This way we could open all the windows in the application and have extra confidence that we don't have duplicates. Of course it's not fool-proof and dynamic elements can slip through, but it'd be a lot better than having to hover over everything.
Thank you!
Screenshots/Video:
No response
Minimal, Complete and Verifiable Example code:
No response
There's no easy way, no.
The reason the detection is done on hovering is that the logic for conflict detection is carefully tailored to avoid expensive searches (e.g. O(N^2) or O(Log N)). Doing it on hovering allows us to implement a O(N) variation with a very trivial u32 compare that requires no search and no storage and no allocation.
Technically we could decide to implement a compile-time opt-in variation that did a fancier scan, but it would need to be compile-time because I don't want to interfere with adding non-trivial code in lowest-level functions.
Another possibility might be to leverage imgui_test_engine automation to e.g. hover every item or every reachable location in a window, but it would take some work.
Technically we could decide to implement a compile-time opt-in variation that did a fancier scan, but it would need to be compile-time because I don't want to interfere with adding non-trivial code in lowest-level functions.
Was just looking into that, using ImGuiStorage for the set of known ids to avoid new dependencies. But compared to f.e. std::set, it uses sorted linear storage which makes it even more expensive. But maybe that's OK for a check that's optional and deactivated by default.
As an alternative, it could be as simple as a debug hook that can be defined in imconfig.h, something like IMGUI_ITEMADD_HOOK. If defined, must be defined to the name of a function (along a declaration) to be called. Something like that could be used to facilitate advanced debugging like in the following suggestion, but without users having to modify source files.
@Fuuzetsu:
If you don't mind a small code customization, you could add a call to a custom hook function in ImGui::ItemAdd() and give it the item id and flags. 2 lines in imgui.cpp basically, a declaration of your hook function and the call itself. In your own source files you could then define that function. If ImGuiItemFlags_AllowDuplicateId isn't set, assert that the id is not in a set of known ids, then add it to the set. Clear the set on new frames and the duplicate check is already done.
I have added a compile-time feature for this in 0ba02a4
//---- Debug Tools: Enable highlight ID conflicts _before_ hovering items. When io.ConfigDebugHighlightIdConflicts is set.
// (THIS WILL SLOW DOWN DEAR IMGUI. Only use occasionally and disable after use)
//#define IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS
It is intentionally compile time and it will spit logs to discourage you to keep this enabled:
// Print a debug message when running with debug feature IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS because it is very slow.
// DO NOT COMMENT OUT THIS MESSAGE. IT IS DESIGNED TO REMIND YOU THAT IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS SHOULD ONLY BE TEMPORARILY ENABLED.
#ifdef IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS
DebugLog("IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS is enabled.\nMust disable after use! Otherwise Dear ImGui will run slower.\n");
#ifdef IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS
TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS is enabled.\nMust disable after use! Otherwise Dear ImGui will run slower.\n");
#endif
If I spot one codebase with this kept enabled I swear I'm adding blinking red text everywhere.
Awesome, I'll try it out when I get the chance! Thanks.