Stack Tool: Added Stack Tool (ShowStackToolWindow() function and available from Demo and Metrics window). (#4631)

This commit is contained in:
ocornut 2021-09-30 12:15:34 +02:00
parent e443ea139d
commit 2de96c4bd5
8 changed files with 274 additions and 76 deletions

View File

@ -42,6 +42,10 @@ Breaking Changes:
Other Changes: Other Changes:
- Debug: Stack Tool: Added "Stack Tool" available in "Demo->Examples->Stack Tool", "Metrics->Tools",
or by calling the ShowStackToolWindow() function. The tool run queries on hovered id to display
details about individual components that were hashed to create an ID. It helps understanding
the ID stack system and debugging potential ID collisions. (#4631) [@ocornut, @rokups]
- Windows: Fixed background order of overlapping childs submitted sequentially. (#4493) - Windows: Fixed background order of overlapping childs submitted sequentially. (#4493)
- IsWindowFocused: Added ImGuiFocusedFlags_NoPopupHierarchy flag allowing to exclude child popups - IsWindowFocused: Added ImGuiFocusedFlags_NoPopupHierarchy flag allowing to exclude child popups
from the tested windows when combined with _ChildWindows. from the tested windows when combined with _ChildWindows.

View File

@ -33,7 +33,7 @@
// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp. // It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended. //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
//#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty. //#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger and other debug tools: ShowMetricsWindow() and ShowStackToolWindow() will be empty.
//---- Don't implement some functions to reduce linkage requirements. //---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a) //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)

290
imgui.cpp
View File

@ -82,6 +82,7 @@ CODE
// [SECTION] VIEWPORTS // [SECTION] VIEWPORTS
// [SECTION] PLATFORM DEPENDENT HELPERS // [SECTION] PLATFORM DEPENDENT HELPERS
// [SECTION] METRICS/DEBUGGER WINDOW // [SECTION] METRICS/DEBUGGER WINDOW
// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)
*/ */
@ -924,16 +925,17 @@ static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window);
static void NavRestoreLayer(ImGuiNavLayer layer); static void NavRestoreLayer(ImGuiNavLayer layer);
static int FindWindowFocusIndex(ImGuiWindow* window); static int FindWindowFocusIndex(ImGuiWindow* window);
// Error Checking // Error Checking and Debug Tools
static void ErrorCheckNewFrameSanityChecks(); static void ErrorCheckNewFrameSanityChecks();
static void ErrorCheckEndFrameSanityChecks(); static void ErrorCheckEndFrameSanityChecks();
static void UpdateDebugToolItemPicker();
static void UpdateDebugToolStackQueries();
// Misc // Misc
static void UpdateSettings(); static void UpdateSettings();
static void UpdateMouseInputs(); static void UpdateMouseInputs();
static void UpdateMouseWheel(); static void UpdateMouseWheel();
static void UpdateTabFocus(); static void UpdateTabFocus();
static void UpdateDebugToolItemPicker();
static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect);
static void RenderWindowOuterBorders(ImGuiWindow* window); static void RenderWindowOuterBorders(ImGuiWindow* window);
static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
@ -2967,10 +2969,9 @@ ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
ImGuiID seed = IDStack.back(); ImGuiID seed = IDStack.back();
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
ImGui::KeepAliveID(id); ImGui::KeepAliveID(id);
#ifdef IMGUI_ENABLE_TEST_ENGINE
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end); if (g.DebugHookIdInfo == id)
#endif ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
return id; return id;
} }
@ -2979,10 +2980,9 @@ ImGuiID ImGuiWindow::GetID(const void* ptr)
ImGuiID seed = IDStack.back(); ImGuiID seed = IDStack.back();
ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
ImGui::KeepAliveID(id); ImGui::KeepAliveID(id);
#ifdef IMGUI_ENABLE_TEST_ENGINE
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr); if (g.DebugHookIdInfo == id)
#endif ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL);
return id; return id;
} }
@ -2991,10 +2991,9 @@ ImGuiID ImGuiWindow::GetID(int n)
ImGuiID seed = IDStack.back(); ImGuiID seed = IDStack.back();
ImGuiID id = ImHashData(&n, sizeof(n), seed); ImGuiID id = ImHashData(&n, sizeof(n), seed);
ImGui::KeepAliveID(id); ImGui::KeepAliveID(id);
#ifdef IMGUI_ENABLE_TEST_ENGINE
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n); if (g.DebugHookIdInfo == id)
#endif ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
return id; return id;
} }
@ -3002,10 +3001,9 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
{ {
ImGuiID seed = IDStack.back(); ImGuiID seed = IDStack.back();
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
#ifdef IMGUI_ENABLE_TEST_ENGINE
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end); if (g.DebugHookIdInfo == id)
#endif ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
return id; return id;
} }
@ -3013,10 +3011,9 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr)
{ {
ImGuiID seed = IDStack.back(); ImGuiID seed = IDStack.back();
ImGuiID id = ImHashData(&ptr, sizeof(void*), seed); ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
#ifdef IMGUI_ENABLE_TEST_ENGINE
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr); if (g.DebugHookIdInfo == id)
#endif ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL);
return id; return id;
} }
@ -3024,10 +3021,9 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n)
{ {
ImGuiID seed = IDStack.back(); ImGuiID seed = IDStack.back();
ImGuiID id = ImHashData(&n, sizeof(n), seed); ImGuiID id = ImHashData(&n, sizeof(n), seed);
#ifdef IMGUI_ENABLE_TEST_ENGINE
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n); if (g.DebugHookIdInfo == id)
#endif ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
return id; return id;
} }
@ -4159,8 +4155,9 @@ void ImGui::NewFrame()
g.ItemFlagsStack.push_back(ImGuiItemFlags_None); g.ItemFlagsStack.push_back(ImGuiItemFlags_None);
g.GroupStack.resize(0); g.GroupStack.resize(0);
// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack. // [DEBUG] Update debug features
UpdateDebugToolItemPicker(); UpdateDebugToolItemPicker();
UpdateDebugToolStackQueries();
// Create implicit/fallback window - which we will only render it if the user has added something to it. // Create implicit/fallback window - which we will only render it if the user has added something to it.
// We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags. // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
@ -4173,31 +4170,6 @@ void ImGui::NewFrame()
CallContextHooks(&g, ImGuiContextHookType_NewFramePost); CallContextHooks(&g, ImGuiContextHookType_NewFramePost);
} }
// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
void ImGui::UpdateDebugToolItemPicker()
{
ImGuiContext& g = *GImGui;
g.DebugItemPickerBreakId = 0;
if (g.DebugItemPickerActive)
{
const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
SetMouseCursor(ImGuiMouseCursor_Hand);
if (IsKeyPressedMap(ImGuiKey_Escape))
g.DebugItemPickerActive = false;
if (IsMouseClicked(0) && hovered_id)
{
g.DebugItemPickerBreakId = hovered_id;
g.DebugItemPickerActive = false;
}
SetNextWindowBgAlpha(0.60f);
BeginTooltip();
Text("HoveredId: 0x%08X", hovered_id);
Text("Press ESC to abort picking.");
TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
EndTooltip();
}
}
void ImGui::Initialize(ImGuiContext* context) void ImGui::Initialize(ImGuiContext* context)
{ {
ImGuiContext& g = *context; ImGuiContext& g = *context;
@ -7184,6 +7156,8 @@ void ImGui::PushOverrideID(ImGuiID id)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
if (g.DebugHookIdInfo == id)
DebugHookIdInfo(id, ImGuiDataType_ID, NULL, NULL);
window->IDStack.push_back(id); window->IDStack.push_back(id);
} }
@ -7193,11 +7167,10 @@ void ImGui::PushOverrideID(ImGuiID id)
ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed) ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed)
{ {
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed); ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
ImGui::KeepAliveID(id); KeepAliveID(id);
#ifdef IMGUI_ENABLE_TEST_ENGINE
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end); if (g.DebugHookIdInfo == id)
#endif DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
return id; return id;
} }
@ -11226,22 +11199,23 @@ namespace ImGui { void ShowFontAtlas(ImFontAtlas* atlas); }
void ImGui::ShowMetricsWindow(bool* p_open) void ImGui::ShowMetricsWindow(bool* p_open)
{ {
ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
if (cfg->ShowStackTool)
ShowStackToolWindow(&cfg->ShowStackTool);
if (!Begin("Dear ImGui Metrics/Debugger", p_open)) if (!Begin("Dear ImGui Metrics/Debugger", p_open))
{ {
End(); End();
return; return;
} }
ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
// Basic info // Basic info
Text("Dear ImGui %s", GetVersion()); Text("Dear ImGui %s", GetVersion());
Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3); Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows); Text("%d visible windows, %d active allocations", io.MetricsRenderWindows, io.MetricsActiveAllocations);
Text("%d active allocations", io.MetricsActiveAllocations);
//SameLine(); if (SmallButton("GC")) { g.GcCompactAll = true; } //SameLine(); if (SmallButton("GC")) { g.GcCompactAll = true; }
Separator(); Separator();
@ -11295,11 +11269,10 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// Tools // Tools
if (TreeNode("Tools")) if (TreeNode("Tools"))
{ {
// The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted. // Stack Tool is your best friend!
if (Button("Item Picker..")) Checkbox("Show stack tool", &cfg->ShowStackTool);
DebugStartItemPicker();
SameLine(); SameLine();
MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash."); MetricsHelpMarker("You can also call ImGui::ShowStackToolWindow() from your code.");
Checkbox("Show windows begin order", &cfg->ShowWindowsBeginOrder); Checkbox("Show windows begin order", &cfg->ShowWindowsBeginOrder);
Checkbox("Show windows rectangles", &cfg->ShowWindowsRects); Checkbox("Show windows rectangles", &cfg->ShowWindowsRects);
@ -11317,8 +11290,6 @@ void ImGui::ShowMetricsWindow(bool* p_open)
} }
Unindent(); Unindent();
} }
Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh);
Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes);
Checkbox("Show tables rectangles", &cfg->ShowTablesRects); Checkbox("Show tables rectangles", &cfg->ShowTablesRects);
SameLine(); SameLine();
@ -11365,6 +11336,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
} }
} }
// The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
if (Button("Item Picker.."))
DebugStartItemPicker();
SameLine();
MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash.");
TreePop(); TreePop();
} }
@ -11378,6 +11355,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
drawlist_count += g.Viewports[viewport_i]->DrawDataBuilder.GetDrawListCount(); drawlist_count += g.Viewports[viewport_i]->DrawDataBuilder.GetDrawListCount();
if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count)) if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count))
{ {
Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh);
Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes);
for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++) for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++)
{ {
ImGuiViewportP* viewport = g.Viewports[viewport_i]; ImGuiViewportP* viewport = g.Viewports[viewport_i];
@ -12002,6 +11981,186 @@ void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* la
TreePop(); TreePop();
} }
//-----------------------------------------------------------------------------
// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)
//-----------------------------------------------------------------------------
// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
void ImGui::UpdateDebugToolItemPicker()
{
ImGuiContext& g = *GImGui;
g.DebugItemPickerBreakId = 0;
if (!g.DebugItemPickerActive)
return;
const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
SetMouseCursor(ImGuiMouseCursor_Hand);
if (IsKeyPressedMap(ImGuiKey_Escape))
g.DebugItemPickerActive = false;
if (IsMouseClicked(0) && hovered_id)
{
g.DebugItemPickerBreakId = hovered_id;
g.DebugItemPickerActive = false;
}
SetNextWindowBgAlpha(0.60f);
BeginTooltip();
Text("HoveredId: 0x%08X", hovered_id);
Text("Press ESC to abort picking.");
TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
EndTooltip();
}
// [DEBUG] Stack Tool: update queries. Called by NewFrame()
void ImGui::UpdateDebugToolStackQueries()
{
ImGuiContext& g = *GImGui;
ImGuiStackTool* tool = &g.DebugStackTool;
// Clear hook when stack tool is not visible
g.DebugHookIdInfo = 0;
if (g.FrameCount != tool->LastActiveFrame + 1)
return;
// Update queries. The steps are: -1: query Stack, >= 0: query each stack item
// We can only perform 1 ID Info query every frame. This is designed so the GetID() tests are cheap and constant-time
const ImGuiID query_id = g.ActiveId ? g.ActiveId : g.HoveredIdPreviousFrame;
if (tool->QueryId != query_id)
{
tool->QueryId = query_id;
tool->StackLevel = -1;
tool->Results.resize(0);
}
if (query_id == 0)
return;
// Advance to next stack level when we got our result, or after 2 frames (in case we never get a result)
int stack_level = tool->StackLevel;
if (stack_level >= 0 && stack_level < tool->Results.Size)
if (tool->Results[stack_level].QuerySuccess || tool->Results[stack_level].QueryFrameCount > 2)
tool->StackLevel++;
// Update hook
stack_level = tool->StackLevel;
if (stack_level == -1)
g.DebugHookIdInfo = query_id;
if (stack_level >= 0 && stack_level < tool->Results.Size)
{
g.DebugHookIdInfo = tool->Results[stack_level].ID;
tool->Results[stack_level].QueryFrameCount++;
}
}
// [DEBUG] Stack tool: hooks called by GetID() family functions
void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiStackTool* tool = &g.DebugStackTool;
// Step 0: stack query
// This assume that the ID was computed with the current ID stack, which tends to be the case for our widget.
if (tool->StackLevel == -1)
{
tool->StackLevel++;
tool->Results.resize(window->IDStack.Size + 1, ImGuiStackLevelInfo());
for (int n = 0; n < window->IDStack.Size + 1; n++)
tool->Results[n].ID = (n < window->IDStack.Size) ? window->IDStack[n] : id;
return;
}
// Step 1+: query for individual level
IM_ASSERT(tool->StackLevel >= 0);
if (tool->StackLevel != window->IDStack.Size)
return;
ImGuiStackLevelInfo* info = &tool->Results[tool->StackLevel];
IM_ASSERT(info->ID == id && info->QueryFrameCount > 0);
int data_len;
switch (data_type)
{
case ImGuiDataType_S32:
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%d", (int)(intptr_t)data_id);
break;
case ImGuiDataType_String:
data_len = data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)strlen((const char*)data_id);
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "\"%.*s\"", data_len, (const char*)data_id);
break;
case ImGuiDataType_Pointer:
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "(void*)0x%p", data_id);
break;
case ImGuiDataType_ID:
if (info->Desc[0] == 0) // PushOverrideID() is often used to avoid hashing twice, which would lead to 2 calls to DebugHookIdInfo(). We prioritize the first one.
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "0x%08X [override]", id);
break;
default:
IM_ASSERT(0);
}
info->QuerySuccess = true;
}
// Stack Tool: Display UI
void ImGui::ShowStackToolWindow(bool* p_open)
{
if (!Begin("Dear ImGui Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1)
{
End();
return;
}
// Display hovered/active status
ImGuiContext& g = *GImGui;
const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
const ImGuiID active_id = g.ActiveId;
#ifdef IMGUI_ENABLE_TEST_ENGINE
Text("HoveredId: 0x%08X (\"%s\"), ActiveId: 0x%08X (\"%s\")", hovered_id, hovered_id ? ImGuiTestEngine_FindItemDebugLabel(&g, hovered_id) : "", active_id, active_id ? ImGuiTestEngine_FindItemDebugLabel(&g, active_id) : "");
#else
Text("HoveredId: 0x%08X, ActiveId: 0x%08X", hovered_id, active_id);
#endif
SameLine();
MetricsHelpMarker("Hover an item with the mouse to display elements of the ID Stack leading to the item's final ID.\nEach level of the stack correspond to a PushID() call.\nAll levels of the stack are hashed together to make the final ID of a widget (ID displayed at the bottom level of the stack).\nRead FAQ entry about the ID stack for details.");
// Display decorated stack
ImGuiStackTool* tool = &g.DebugStackTool;
tool->LastActiveFrame = g.FrameCount;
if (tool->Results.Size > 0 && BeginTable("##table", 3, ImGuiTableFlags_Borders))
{
const float id_width = CalcTextSize("0xDDDDDDDD").x;
TableSetupColumn("Seed", ImGuiTableColumnFlags_WidthFixed, id_width);
TableSetupColumn("PushID", ImGuiTableColumnFlags_WidthStretch);
TableSetupColumn("Result", ImGuiTableColumnFlags_WidthFixed, id_width);
TableHeadersRow();
for (int n = 0; n < tool->Results.Size; n++)
{
ImGuiStackLevelInfo* info = &tool->Results[n];
TableNextColumn();
Text("0x%08X", (n > 0) ? tool->Results[n - 1].ID : 0);
TableNextColumn();
ImGuiWindow* window = (info->Desc[0] == 0 && n == 0) ? FindWindowByID(info->ID) : NULL;
if (window) // Source: window name (because the root ID don't call GetID() and so doesn't get hooked)
Text("\"%s\" [window]", window->Name);
else if (info->QuerySuccess) // Source: GetID() hooks (prioritize over ItemInfo() because we frequently use patterns like: PushID(str), Button("") where they both have same id)
TextUnformatted(info->Desc);
else if (tool->StackLevel >= tool->Results.Size) // Only start using fallback below when all queries are done, so during queries we don't flickering ??? markers.
{
#ifdef IMGUI_ENABLE_TEST_ENGINE
if (const char* label = ImGuiTestEngine_FindItemDebugLabel(&g, info->ID)) // Source: ImGuiTestEngine's ItemInfo()
Text("??? \"%s\"", label);
else
#endif
TextUnformatted("???");
}
TableNextColumn();
Text("0x%08X", info->ID);
if (n == tool->Results.Size - 1)
TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_Header));
}
EndTable();
}
End();
}
#else #else
void ImGui::ShowMetricsWindow(bool*) {} void ImGui::ShowMetricsWindow(bool*) {}
@ -12017,7 +12176,12 @@ void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings*) {}
void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>*, const char*) {} void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>*, const char*) {}
void ImGui::DebugNodeViewport(ImGuiViewportP*) {} void ImGui::DebugNodeViewport(ImGuiViewportP*) {}
#endif void ImGui::ShowStackToolWindow(bool*) {}
void ImGui::DebugHookIdInfo(ImGuiID, ImGuiDataType, const void*, const void*) {}
void ImGui::UpdateDebugToolItemPicker() {}
void ImGui::UpdateDebugToolStackQueries() {}
#endif // #ifndef IMGUI_DISABLE_METRICS_WINDOW
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -64,7 +64,7 @@ Index of this file:
// Version // Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens)
#define IMGUI_VERSION "1.85 WIP" #define IMGUI_VERSION "1.85 WIP"
#define IMGUI_VERSION_NUM 18418 #define IMGUI_VERSION_NUM 18419
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE
@ -307,6 +307,7 @@ namespace ImGui
// Demo, Debug, Information // Demo, Debug, Information
IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window. demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window. demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application!
IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Metrics/Debugger window. display Dear ImGui internals: windows, draw commands, various internal state, etc. IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Metrics/Debugger window. display Dear ImGui internals: windows, draw commands, various internal state, etc.
IMGUI_API void ShowStackToolWindow(bool* p_open = NULL); // create Stack Tool window. hover items with mouse to query information about the source of their unique ID.
IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information. IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information.
IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style) IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style)
IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles. IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles.

View File

@ -294,10 +294,12 @@ void ImGui::ShowDemoWindow(bool* p_open)
// Dear ImGui Apps (accessible from the "Tools" menu) // Dear ImGui Apps (accessible from the "Tools" menu)
static bool show_app_metrics = false; static bool show_app_metrics = false;
static bool show_app_stack_tool = false;
static bool show_app_style_editor = false; static bool show_app_style_editor = false;
static bool show_app_about = false; static bool show_app_about = false;
if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); } if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); }
if (show_app_stack_tool) { ImGui::ShowStackToolWindow(&show_app_stack_tool); }
if (show_app_about) { ImGui::ShowAboutWindow(&show_app_about); } if (show_app_about) { ImGui::ShowAboutWindow(&show_app_about); }
if (show_app_style_editor) if (show_app_style_editor)
{ {
@ -382,7 +384,10 @@ void ImGui::ShowDemoWindow(bool* p_open)
//if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar! //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar!
if (ImGui::BeginMenu("Tools")) if (ImGui::BeginMenu("Tools"))
{ {
#ifndef IMGUI_DISABLE_METRICS_WINDOW
ImGui::MenuItem("Metrics/Debugger", NULL, &show_app_metrics); ImGui::MenuItem("Metrics/Debugger", NULL, &show_app_metrics);
ImGui::MenuItem("Stack Tool", NULL, &show_app_stack_tool);
#endif
ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor); ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor);
ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about); ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about);
ImGui::EndMenu(); ImGui::EndMenu();

View File

@ -24,7 +24,7 @@ Index of this file:
// [SECTION] Docking support // [SECTION] Docking support
// [SECTION] Viewport support // [SECTION] Viewport support
// [SECTION] Settings support // [SECTION] Settings support
// [SECTION] Metrics, Debug // [SECTION] Metrics, Debug tools
// [SECTION] Generic context hooks // [SECTION] Generic context hooks
// [SECTION] ImGuiContext (main imgui context) // [SECTION] ImGuiContext (main imgui context)
// [SECTION] ImGuiWindowTempData, ImGuiWindow // [SECTION] ImGuiWindowTempData, ImGuiWindow
@ -1382,11 +1382,12 @@ struct ImGuiSettingsHandler
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] Metrics, Debug // [SECTION] Metrics, Debug Tools
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
struct ImGuiMetricsConfig struct ImGuiMetricsConfig
{ {
bool ShowStackTool;
bool ShowWindowsRects; bool ShowWindowsRects;
bool ShowWindowsBeginOrder; bool ShowWindowsBeginOrder;
bool ShowTablesRects; bool ShowTablesRects;
@ -1397,6 +1398,7 @@ struct ImGuiMetricsConfig
ImGuiMetricsConfig() ImGuiMetricsConfig()
{ {
ShowStackTool = false;
ShowWindowsRects = false; ShowWindowsRects = false;
ShowWindowsBeginOrder = false; ShowWindowsBeginOrder = false;
ShowTablesRects = false; ShowTablesRects = false;
@ -1407,6 +1409,27 @@ struct ImGuiMetricsConfig
} }
}; };
struct ImGuiStackLevelInfo
{
ImGuiID ID;
ImS8 QueryFrameCount; // >= 1: Query in progress
bool QuerySuccess; // Obtained result from DebugHookIdInfo()
char Desc[58]; // Arbitrarily sized buffer to hold a result (FIXME: could replace Results[] with a chunk stream?)
ImGuiStackLevelInfo() { memset(this, 0, sizeof(*this)); }
};
// State for Stack tool queries
struct ImGuiStackTool
{
int LastActiveFrame;
int StackLevel; // -1: query stack and resize Results, >= 0: individual stack level
ImGuiID QueryId; // ID to query details for
ImVector<ImGuiStackLevelInfo> Results;
ImGuiStackTool() { memset(this, 0, sizeof(*this)); }
};
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] Generic context hooks // [SECTION] Generic context hooks
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1448,7 +1471,6 @@ struct ImGuiContext
bool WithinEndChild; // Set within EndChild() bool WithinEndChild; // Set within EndChild()
bool GcCompactAll; // Request full GC bool GcCompactAll; // Request full GC
bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log() bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log()
ImGuiID TestEngineHookIdInfo; // Will call test engine hooks: ImGuiTestEngineHook_IdInfo() from GetID()
void* TestEngine; // Test engine user data void* TestEngine; // Test engine user data
// Windows state // Windows state
@ -1468,6 +1490,7 @@ struct ImGuiContext
float WheelingWindowTimer; float WheelingWindowTimer;
// Item/widgets state and tracking information // Item/widgets state and tracking information
ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line]
ImGuiID HoveredId; // Hovered widget, filled during the frame ImGuiID HoveredId; // Hovered widget, filled during the frame
ImGuiID HoveredIdPreviousFrame; ImGuiID HoveredIdPreviousFrame;
bool HoveredIdAllowOverlap; bool HoveredIdAllowOverlap;
@ -1671,8 +1694,9 @@ struct ImGuiContext
// Debug Tools // Debug Tools
bool DebugItemPickerActive; // Item picker is active (started with DebugStartItemPicker()) bool DebugItemPickerActive; // Item picker is active (started with DebugStartItemPicker())
ImGuiID DebugItemPickerBreakId; // Will call IM_DEBUG_BREAK() when encountering this id ImGuiID DebugItemPickerBreakId; // Will call IM_DEBUG_BREAK() when encountering this ID
ImGuiMetricsConfig DebugMetricsConfig; ImGuiMetricsConfig DebugMetricsConfig;
ImGuiStackTool DebugStackTool;
// Misc // Misc
float FramerateSecPerFrame[120]; // Calculate estimate of framerate for user over the last 2 seconds. float FramerateSecPerFrame[120]; // Calculate estimate of framerate for user over the last 2 seconds.
@ -1697,7 +1721,6 @@ struct ImGuiContext
WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false; WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false;
GcCompactAll = false; GcCompactAll = false;
TestEngineHookItems = false; TestEngineHookItems = false;
TestEngineHookIdInfo = 0;
TestEngine = NULL; TestEngine = NULL;
WindowsActiveCount = 0; WindowsActiveCount = 0;
@ -1708,6 +1731,7 @@ struct ImGuiContext
WheelingWindow = NULL; WheelingWindow = NULL;
WheelingWindowTimer = 0.0f; WheelingWindowTimer = 0.0f;
DebugHookIdInfo = 0;
HoveredId = HoveredIdPreviousFrame = 0; HoveredId = HoveredIdPreviousFrame = 0;
HoveredIdAllowOverlap = false; HoveredIdAllowOverlap = false;
HoveredIdUsingMouseWheel = HoveredIdPreviousFrameUsingMouseWheel = false; HoveredIdUsingMouseWheel = HoveredIdPreviousFrameUsingMouseWheel = false;
@ -2713,6 +2737,7 @@ namespace ImGui
inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; } inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; }
IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas);
IMGUI_API void DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end);
IMGUI_API void DebugNodeColumns(ImGuiOldColumns* columns); IMGUI_API void DebugNodeColumns(ImGuiOldColumns* columns);
IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label); IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label);
IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb);
@ -2758,14 +2783,12 @@ IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table
#ifdef IMGUI_ENABLE_TEST_ENGINE #ifdef IMGUI_ENABLE_TEST_ENGINE
extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id);
extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags); extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags);
extern void ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id);
extern void ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id, const void* data_id_end);
extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...); extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...);
extern const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext* ctx, ImGuiID id);
#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _BB, _ID) // Register item bounding box #define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _BB, _ID) // Register item bounding box
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional) #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional)
#define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log #define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log
#define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA) if (g.TestEngineHookIdInfo == _ID) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA));
#define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2) if (g.TestEngineHookIdInfo == _ID) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA), (const void*)(_DATA2));
#else #else
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) ((void)0) #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) ((void)0)
#endif #endif

View File

@ -564,6 +564,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// + 0 (for ImGuiTable instance, we are pooling allocations in g.Tables) // + 0 (for ImGuiTable instance, we are pooling allocations in g.Tables)
// + 1 (for table->RawData allocated below) // + 1 (for table->RawData allocated below)
// + 1 (for table->ColumnsNames, if names are used) // + 1 (for table->ColumnsNames, if names are used)
// Shared allocations per number of nested tables
// + 1 (for table->Splitter._Channels) // + 1 (for table->Splitter._Channels)
// + 2 * active_channels_count (for ImDrawCmd and ImDrawIdx buffers inside channels) // + 2 * active_channels_count (for ImDrawCmd and ImDrawIdx buffers inside channels)
// Where active_channels_count is variable but often == columns_count or columns_count + 1, see TableSetupDrawChannels() for details. // Where active_channels_count is variable but often == columns_count or columns_count + 1, see TableSetupDrawChannels() for details.

View File

@ -1799,7 +1799,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
bool value_changed = false; bool value_changed = false;
for (int i = 0; i < items_count; i++) for (int i = 0; i < items_count; i++)
{ {
PushID((void*)(intptr_t)i); PushID(i);
const bool item_selected = (i == *current_item); const bool item_selected = (i == *current_item);
const char* item_text; const char* item_text;
if (!items_getter(data, i, &item_text)) if (!items_getter(data, i, &item_text))
@ -6017,7 +6017,7 @@ void ImGui::TreePushOverrideID(ImGuiID id)
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
Indent(); Indent();
window->DC.TreeDepth++; window->DC.TreeDepth++;
window->IDStack.push_back(id); PushOverrideID(id);
} }
void ImGui::TreePop() void ImGui::TreePop()