From 4ebec38a915f451b80e255110f14f47047603667 Mon Sep 17 00:00:00 2001 From: Soufiane KHIAT Date: Wed, 1 Jul 2026 23:28:37 +0200 Subject: [PATCH 1/2] Metrics/Debugger: Added io.DebugDrawCmdCallback + ImGuiDebugDrawCmdCallbackFn. When set, callback draw commands in the Metrics/Debugger's draw-list viewer show a descriptive TreeNode and optionally render mesh/bounding-box overlays on hover, instead of the opaque "Callback %p, user_data %p" bullet. The callback receives the draw list, the draw command, the two overlay toggles (mesh / bbox) already exposed by the Metrics config, and a text buffer to fill with a short description for the tree label. - Add ImGuiDebugDrawCmdCallbackFn typedef in imgui.h. - Add DebugDrawCmdCallback field on ImGuiIO (defaults to NULL). - In DebugNodeDrawList(), branch on the callback: descriptive TreeNode when set, previous BulletText fallback otherwise. Behaviour is unchanged for users that don't set the callback. --- imgui.cpp | 15 ++++++++++++++- imgui.h | 6 ++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index a7d03caa4..166c370a2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -17384,7 +17384,20 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, con { if (pcmd->UserCallback) { - BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); + if (g.IO.DebugDrawCmdCallback) + { + char buf[300]; + g.IO.DebugDrawCmdCallback(NULL, draw_list, pcmd, false, false, buf, IM_ARRAYSIZE(buf)); + bool cb_node_open = TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Callback: %s", buf); + if (IsItemHovered() && (cfg->ShowDrawCmdMesh || cfg->ShowDrawCmdBoundingBoxes) && fg_draw_list) + g.IO.DebugDrawCmdCallback(fg_draw_list, draw_list, pcmd, cfg->ShowDrawCmdMesh, cfg->ShowDrawCmdBoundingBoxes, NULL, 0); + if (cb_node_open) + TreePop(); + } + else + { + BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); + } continue; } diff --git a/imgui.h b/imgui.h index 0d4995699..9ae47c9bc 100644 --- a/imgui.h +++ b/imgui.h @@ -287,6 +287,7 @@ typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints() typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() +typedef void (*ImGuiDebugDrawCmdCallbackFn)(ImDrawList* overlay_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb, char* out_text, int text_size); // Debug callback for custom draw commands // ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type] // - This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type. @@ -2510,6 +2511,11 @@ struct ImGuiIO // Option to audit .ini data bool ConfigDebugIniSettings; // = false // Save .ini data with extra comments (particularly helpful for Docking, but makes saving slower) + // Debug callback for custom draw commands (callbacks) in the Metrics/Debugger draw list viewer. + // When set, callback draw commands will show a tree node with descriptive text and mesh/bbox overlay on hover, + // instead of just "Callback %p, user_data %p". See ImGuiDebugDrawCmdCallbackFn typedef for parameters. + ImGuiDebugDrawCmdCallbackFn DebugDrawCmdCallback; // = NULL + //------------------------------------------------------------------ // Platform Identifiers // (the imgui_impl_xxxx backend files are setting those up for you) From 6561fdccbb900d7453e45aa9eed3453aa0287a82 Mon Sep 17 00:00:00 2001 From: Soufiane KHIAT Date: Wed, 14 Oct 2026 23:38:38 +0200 Subject: [PATCH 2/2] Metrics/Debugger: replaced io.DebugDrawCmdCallback with chainable DebugAddDrawCmdHook() / DebugRemoveDrawCmdHook(). (#9459) As suggested in review: a list of hooks instead of a single ImGuiIO field, so several libraries can register. For every user callback command in DebugNodeDrawList(), hooks are tried in registration order; the first one returning true has fully displayed the command (TreeNode + contents, overlay on hover in 'fg_draw_list'). If none handles it, the default "Callback %p, user_data %p" bullet is shown. - No change to the public API (imgui.h): the ImGuiIO field and its typedef are removed. - imgui_internal.h: ImGuiDebugDrawCmdHookFn, ImGuiDebugDrawCmdHook, ImGuiContext::DebugDrawCmdHooks, DebugAddDrawCmdHook(), DebugRemoveDrawCmdHook(), and IMGUI_HAS_DEBUG_DRAWCMD_HOOKS for feature detection. - No arbitrary text buffer or mesh/bbox parameters: hooks draw their own node and read DebugMetricsConfig / call DebugNodeDrawCmdShowMeshAndBoundingBox() as needed. --- imgui.cpp | 43 ++++++++++++++++++++++++++++++------------- imgui.h | 6 ------ imgui_internal.h | 16 ++++++++++++++++ 3 files changed, 46 insertions(+), 19 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 166c370a2..a30547d80 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4590,6 +4590,28 @@ ImGuiID ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook) return g.HookIdNext; } +// Metrics/Debugger: register a hook describing user draw callbacks (see ImGuiDebugDrawCmdHookFn). +void ImGui::DebugAddDrawCmdHook(ImGuiDebugDrawCmdHookFn hook, void* user_data) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(hook != NULL); + ImGuiDebugDrawCmdHook entry; + entry.Callback = hook; + entry.UserData = user_data; + g.DebugDrawCmdHooks.push_back(entry); +} + +void ImGui::DebugRemoveDrawCmdHook(ImGuiDebugDrawCmdHookFn hook, void* user_data) +{ + ImGuiContext& g = *GImGui; + for (int n = 0; n < g.DebugDrawCmdHooks.Size; n++) + if (g.DebugDrawCmdHooks[n].Callback == hook && g.DebugDrawCmdHooks[n].UserData == user_data) + { + g.DebugDrawCmdHooks.erase(g.DebugDrawCmdHooks.Data + n); + return; + } +} + // Deferred removal, avoiding issue with changing vector while iterating it void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id) { @@ -17384,20 +17406,15 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, con { if (pcmd->UserCallback) { - if (g.IO.DebugDrawCmdCallback) - { - char buf[300]; - g.IO.DebugDrawCmdCallback(NULL, draw_list, pcmd, false, false, buf, IM_ARRAYSIZE(buf)); - bool cb_node_open = TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Callback: %s", buf); - if (IsItemHovered() && (cfg->ShowDrawCmdMesh || cfg->ShowDrawCmdBoundingBoxes) && fg_draw_list) - g.IO.DebugDrawCmdCallback(fg_draw_list, draw_list, pcmd, cfg->ShowDrawCmdMesh, cfg->ShowDrawCmdBoundingBoxes, NULL, 0); - if (cb_node_open) - TreePop(); - } - else - { + bool handled = false; + for (ImGuiDebugDrawCmdHook& hook : g.DebugDrawCmdHooks) + if (hook.Callback(draw_list, pcmd, fg_draw_list, hook.UserData)) + { + handled = true; + break; + } + if (!handled) BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData); - } continue; } diff --git a/imgui.h b/imgui.h index 9ae47c9bc..0d4995699 100644 --- a/imgui.h +++ b/imgui.h @@ -287,7 +287,6 @@ typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints() typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() -typedef void (*ImGuiDebugDrawCmdCallbackFn)(ImDrawList* overlay_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb, char* out_text, int text_size); // Debug callback for custom draw commands // ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type] // - This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type. @@ -2511,11 +2510,6 @@ struct ImGuiIO // Option to audit .ini data bool ConfigDebugIniSettings; // = false // Save .ini data with extra comments (particularly helpful for Docking, but makes saving slower) - // Debug callback for custom draw commands (callbacks) in the Metrics/Debugger draw list viewer. - // When set, callback draw commands will show a tree node with descriptive text and mesh/bbox overlay on hover, - // instead of just "Callback %p, user_data %p". See ImGuiDebugDrawCmdCallbackFn typedef for parameters. - ImGuiDebugDrawCmdCallbackFn DebugDrawCmdCallback; // = NULL - //------------------------------------------------------------------ // Platform Identifiers // (the imgui_impl_xxxx backend files are setting those up for you) diff --git a/imgui_internal.h b/imgui_internal.h index 299287e65..6d93c3c06 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2195,6 +2195,19 @@ struct ImGuiIDStackTool typedef void (*ImGuiContextHookCallback)(ImGuiContext* ctx, ImGuiContextHook* hook); enum ImGuiContextHookType { ImGuiContextHookType_NewFramePre, ImGuiContextHookType_NewFramePost, ImGuiContextHookType_EndFramePre, ImGuiContextHookType_EndFramePost, ImGuiContextHookType_RenderPre, ImGuiContextHookType_RenderPost, ImGuiContextHookType_Shutdown, ImGuiContextHookType_PendingRemoval_ }; +// Metrics/Debugger: hooks describing user draw callbacks (ImDrawCmd::UserCallback) in DebugNodeDrawList(). +// Hooks are tried in registration order for every callback command; the first one returning true has fully +// displayed the command (typically a TreeNode() and its contents, and an overlay on hover drawn in +// 'fg_draw_list', which may be NULL). If none handles it, the default "Callback %p, user_data %p" is shown. +#define IMGUI_HAS_DEBUG_DRAWCMD_HOOKS // DebugAddDrawCmdHook() / DebugRemoveDrawCmdHook() are available +typedef bool (*ImGuiDebugDrawCmdHookFn)(const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, ImDrawList* fg_draw_list, void* user_data); + +struct ImGuiDebugDrawCmdHook +{ + ImGuiDebugDrawCmdHookFn Callback; + void* UserData; +}; + struct ImGuiContextHook { ImGuiID HookId; // A unique ID assigned by AddContextHook() @@ -2590,6 +2603,7 @@ struct ImGuiContext float DebugFlashStyleColorTime; ImVec4 DebugFlashStyleColorBackup; ImGuiMetricsConfig DebugMetricsConfig; + ImVector DebugDrawCmdHooks; // Metrics/Debugger: user draw callback hooks (DebugAddDrawCmdHook) ImGuiDebugItemPathQuery DebugItemPathQuery; ImGuiIDStackTool DebugIDStackTool; ImGuiDebugAllocInfo DebugAllocInfo; @@ -3818,6 +3832,8 @@ namespace ImGui IMGUI_API void DebugNodeColumns(ImGuiOldColumns* columns); IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, 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 DebugAddDrawCmdHook(ImGuiDebugDrawCmdHookFn hook, void* user_data = NULL); + IMGUI_API void DebugRemoveDrawCmdHook(ImGuiDebugDrawCmdHookFn hook, void* user_data = NULL); IMGUI_API void DebugNodeFont(ImFont* font); IMGUI_API void DebugNodeFontGlyphsForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask); IMGUI_API void DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph);