Debugging Layout Issues with Dear ImGui's Built-in Metrics Window

Dear ImGui's Metrics/Debugger window exposes real-time internal UI state—including window rectangles, ID stacks, and draw-list statistics—to rapidly diagnose misplaced widgets, clipping errors, and incorrect focus behavior.

Dear ImGui (ocornut/imgui) ships with a powerful built-in debugging interface that allows developers to visualize the internal layout engine state while the application runs. Activating ImGui::ShowMetricsWindow() provides immediate access to render statistics, window hierarchies, and input routing data. This makes it the primary tool for resolving debugging layout issues with Dear ImGui's built-in metrics window.

Opening the Metrics/Debugger Window

The debugger is exposed through a single function call defined in imgui.cpp. The implementation at line 16777 handles the entire interface initialization and rendering.

bool show_metrics = true;
ImGui::ShowMetricsWindow(&show_metrics);

Pass a boolean pointer to control the window's visibility state. When the boolean is true, the window renders immediately, capturing the current frame's statistics from the ImGuiIO structure.

Visualizing Window Rectangles and Clipping

One of the most effective features for layout debugging is Show windows rectangles, accessible under Tools → Windows in the Metrics panel. Enabling this draws colored outlines around every window boundary, revealing exactly where parent and child windows extend.

If a child window clips incorrectly, the outline visibly extends beyond the parent's clipping region. This helps identify misaligned boundaries without guessing coordinates or manually checking ImVec2 calculations.

Tracking Widget Identity via the ID Stack

Layout issues often stem from ID collisions or mismatched PushID()/PopID() calls. When you hover over any UI element, the ID Stack panel (populated at line 18480 in imgui.cpp) displays the complete hierarchy of ID pushes that generated the final widget identifier.

Mismatched IDs commonly cause widgets to disappear or appear in the wrong location. The stack trace shows exactly which scope introduced the error, allowing you to verify that PopID() calls match their corresponding PushID() calls.

Analyzing Render Statistics

The Metrics window aggregates frame-level data updated at specific points in the rendering pipeline:

  • Render vertices/indices: Read from io.MetricsRenderVertices and io.MetricsRenderIndices, populated during the render loop at imgui.cpp:6225
  • Visible windows: Tracked in io.MetricsRenderWindows, incremented at the frame start (imgui.cpp:5903)
  • Active allocations: Calculated as g.DebugAllocInfo.TotalAllocCount - g.DebugAllocInfo.TotalFreeCount (see imgui.cpp:722)

An unusually high vertex count often indicates that a widget is being rendered repeatedly—such as a Begin() call missing its corresponding End()—which corrupts the layout and wastes GPU resources.

Inspecting Draw Lists and Input State

Draw List Diagnostics

Under Tools → Draw List, the debugger displays the exact number of vertices per window and texture usage statistics. This data originates from the same buffers built in imgui_draw.cpp at line 2309.

Sudden spikes in vertex counts for specific windows reveal redundant drawing operations that indicate layout logic errors, such as widgets being drawn outside their intended containers.

Input Routing Visualization

The Inputs panel shows which widget currently owns a key or mouse button. This data lives in g.KeyOwner* structures throughout the input handling code.

If a widget steals focus unintentionally, it prevents other windows from receiving input, making them appear "dead" in the layout. The visualizer highlights the active owner for each input device, revealing focus conflicts.

Detecting Font Glyph Overlaps

The Fonts sub-tab reveals overlapping glyphs from multiple font sources (implemented at imgui.cpp:532). Overlapping glyphs shift baseline metrics and cause vertical spacing glitches that appear as layout issues but originate from font atlas configuration errors.

Practical Implementation Examples

Integrate the debugger into your application using a menu toggle:

bool show_metrics = false;

if (ImGui::BeginMainMenuBar()) {
    if (ImGui::MenuItem("Metrics/Debugger"))
        show_metrics = !show_metrics;
    ImGui::EndMainMenuBar();
}

ImGui::ShowMetricsWindow(&show_metrics);

For immediate visual debugging, force the rectangle outlines via configuration flags:

ImGui::ShowMetricsWindow(&show_metrics);
ImGui::GetIO().ConfigDebugFlags |= ImGuiConfigFlags_DebugWindows;

Key Source Files

The Metrics window relies on implementation details across the codebase:

File Relevance Key Location
imgui.cpp Core ShowMetricsWindow implementation and metric counters Line 16777
imgui_draw.cpp Low-level draw-list handling and vertex buffer construction Line 2309
imgui_internal.h Internal structures like ImGuiMetricsConfig and allocation tracking Debug info structures
imgui.h Public API declaration for ShowMetricsWindow Public header

Summary

  • Dear ImGui's built-in metrics window is accessed via ImGui::ShowMetricsWindow() defined in imgui.cpp.
  • Enable Show windows rectangles to visualize clipping boundaries and parent-child relationships.
  • Use the ID Stack panel to trace mismatched PushID() calls that cause widgets to disappear or render in incorrect positions.
  • Monitor io.MetricsRenderVertices to detect redundant widget rendering that corrupts layout.
  • Inspect the Inputs panel to identify focus-stealing widgets that make other UI elements unresponsive.
  • Check the Fonts tab for glyph overlaps that cause vertical spacing issues.

Frequently Asked Questions

How do I programmatically open the Metrics window?

Call ImGui::ShowMetricsWindow(&show_metrics) where show_metrics is a boolean flag. Toggle this flag from a menu item or hotkey to show or hide the debugger at runtime. The function implementation resides at line 16777 of imgui.cpp.

Why are my child windows clipped incorrectly?

Enable Tools → Windows → Show windows rectangles in the Metrics window. If the colored outline extends beyond the parent's bounds, the child window size exceeds its available content region. Adjust the child's ImVec2 size parameters or ensure proper BeginChild()/EndChild() pairing to constrain the clipping rectangle.

What causes unusually high vertex counts in the Draw List?

High vertex counts indicate redundant rendering. This typically occurs when ImGui::Begin() is called without a matching ImGui::End(), or when widgets are drawn in a loop without proper ID scoping. Check the Draw List tab to identify which window generates excess vertices, then verify its begin/end pairs in your code.

How can I detect which widget is stealing focus?

Open the Inputs panel in the Metrics window. This displays the current owner for each keyboard key and mouse button. If a widget appears "dead" or unresponsive, check if another widget owns the input by looking for non-zero owner IDs in the shortcut routing table.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →