# Dear ImGui — User Guide

Dear ImGui is a bloat-free graphical user interface library for C++. It outputs optimized vertex buffers that you can render anytime in your 3D-pipeline-enabled application. It is fast, portable, renderer-agnostic, and self-contained (no external dependencies). Dear ImGui is designed to enable fast iterations and to empower programmers to create content creation tools, visualization/debug tools, and any UI for games or real-time applications.

Dear ImGui is particularly suited to integration in game engines (for tooling), real-time 3D applications, fullscreen applications, embedded applications, or any application where operating-system features are non-standard.

---

## 1. Quick Start

### What Is Dear ImGui?

Dear ImGui (short for "Dear Immediate Mode Graphical User Interface") is a C++ library that makes it trivially easy to add debug UIs, tools, and overlays to any application that already has a rendering pipeline. Unlike retained-mode GUI frameworks (Qt, wxWidgets, GTK), Dear ImGui redraws the entire UI every frame from your code — there is no hidden widget state to synchronize. You describe the UI, Dear ImGui draws it, and returns interaction results immediately.

### Key Features

- **Immediate mode** — no widget objects, no callbacks, no synchronization. UI code lives alongside your logic.
- **Renderer agnostic** — outputs vertex buffers (ImDrawList) that you feed to any GPU API: OpenGL, DirectX 9/10/11/12, Vulkan, Metal, WebGPU, SDL_GPU, or your own.
- **Self-contained** — no external dependencies. STB-style single-header libraries for font rasterization and text editing are bundled.
- **Keyboard & gamepad navigation** — full navigation support without a mouse, including tabbing, directional movement, and activation.
- **Tables** — feature-rich table widget with sorting, reordering, hiding columns, horizontal scrolling, and freeze rows/columns.
- **Multi-select** — beta API for multi-selection in lists, tables, and tree nodes with range-select and Ctrl+click.
- **Drag and drop** — built-in drag-and-drop system with typed payloads between any widgets.
- **Extensive widget library** — text inputs, sliders, drags, color pickers, trees, tabs, menus, popups, modals, plots, images, and more.

### Prerequisites

| Requirement | Minimum | Recommended |
|---|---|---|
| C++ standard | C++11 | C++14 or later |
| Operating system | Any (Windows, macOS, Linux, iOS, Android, Emscripten) | — |
| Graphics API | Any (or software rasterizer) | OpenGL 3+, DirectX 11, Vulkan |
| Build system | Any (add `.cpp` files to your project) | — |

### Minimal Code Example

```cpp
#include "imgui.h"
#include "imgui_impl_allegro5.h"
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>

int main()
{
    // Platform/renderer setup (Allegro5 example)
    al_init();
    al_init_primitives_addon();
    ALLEGRO_DISPLAY* display = al_create_display(1280, 720);

    // Initialize Dear ImGui
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO();

    // Setup platform/renderer backends
    ImGui_ImplAllegro5_Init(display);

    // Style
    ImGui::StyleColorsDark();

    bool running = true;
    while (running)
    {
        // Poll events...
        ImGui_ImplAllegro5_NewFrame();
        ImGui::NewFrame();

        // Your UI code — this is the entire API pattern:
        ImGui::Begin("My Tool");
        ImGui::Text("Hello, Dear ImGui!");
        static float value = 0.0f;
        ImGui::SliderFloat("Value", &value, 0.0f, 1.0f);
        if (ImGui::Button("Press Me"))
        {
            // React to button press
        }
        ImGui::End();

        // Render
        ImGui::Render();
        al_clear_to_color(al_map_rgb(0, 0, 0));
        ImGui_ImplAllegro5_RenderDrawData(ImGui::GetDrawData());
        al_flip_display();
    }

    // Cleanup
    ImGui_ImplAllegro5_Shutdown();
    ImGui::DestroyContext();
    al_destroy_display(display);
    return 0;
}
```

### What to Try Next

1. **ShowDemoWindow()** — call `ImGui::ShowDemoWindow()` anywhere in your frame loop to see every widget in action with source code.
2. **Examples** — the `examples/` folder contains 26 ready-to-build projects for every major platform/renderer combination.
3. **Wiki** — the [Dear ImGui Wiki](https://github.com/ocornut/imgui/wiki) covers integration, third-party bindings, and community resources.

> [!TIP]
> `ImGui::ShowDemoWindow()` is the single best learning resource for Dear ImGui. Every widget, layout technique, and API pattern is demonstrated with inline code. You can Ctrl+click on any demo code in the Demo window to jump to the corresponding source in `imgui_demo.cpp`. Treat it as a living, interactive reference manual.

---

## 2. Installation

Dear ImGui is a **source-level library** — there is no package manager install, no pre-built binaries, and no `cmake install` target. You add the source files directly to your project.

### System Requirements

| Component | Requirement |
|---|---|
| Language | C++11 or later |
| OS | Windows, macOS, Linux, iOS, Android, Emscripten, consoles |
| GPU API | Any — Dear ImGui outputs vertex buffers; you provide the renderer |
| Dependencies | None — all dependencies are bundled |
| Build system | Any — Visual Studio, Make, CMake, Meson, Premake, Xcode, etc. |

### Step 1: Add Core Files

Copy these files into your project (or add them as includes from the imgui directory):

| File | Purpose |
|---|---|
| `imgui.cpp` | Core library (context, windows, widgets, navigation) |
| `imgui_draw.cpp` | Drawing, font atlas, ImDrawList |
| `imgui_tables.cpp` | Table widget |
| `imgui_widgets.cpp` | Standard widgets (buttons, sliders, inputs, trees, etc.) |
| `imgui.h` | Main header — include this in your code |
| `imgui_internal.h` | Internal header (included by imgui.cpp; rarely needed by users) |
| `imconfig.h` | Compile-time configuration (user-editable) |
| `imstb_rectpack.h` | STB rect packing for font atlas |
| `imstb_textedit.h` | STB text editing for InputText |
| `imstb_truetype.h` | STB TrueType rasterizer (unless using FreeType) |

### Step 2: Pick a Platform + Renderer Backend

Backends live in the `backends/` folder. You need **one platform backend** (handles window creation, input, clipboard) and **one renderer backend** (handles drawing via GPU API).

#### Backend Combinations

| Platform ↓ / Renderer → | OpenGL2 | OpenGL3 | DirectX9 | DirectX10 | DirectX11 | DirectX12 | Vulkan | Metal | WebGPU | SDL_GPU | SDL_Renderer | Allegro5 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| **GLFW** | Yes | Yes | — | — | — | — | Yes | Yes | Yes | — | — | — |
| **SDL2** | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | — | — | Yes (2) | — |
| **SDL3** | — | Yes | — | — | — | — | Yes | Yes | Yes | Yes | Yes (3) | — |
| **Win32** | — | — | Yes | Yes | Yes | Yes | Yes | — | — | — | — | — |
| **GLUT** | — | Yes | — | — | — | — | — | — | — | — | — | — |
| **OSX (Cocoa)** | — | Yes | — | — | — | — | — | Metal | — | — | — | — |
| **Android** | — | Yes | — | — | — | — | — | — | — | — | — | — |
| **Allegro5** | — | — | — | — | — | — | — | — | — | — | — | Yes |

Backend files follow the naming convention `imgui_impl_<name>.h` and `imgui_impl_<name>.cpp`. For example, to use GLFW + OpenGL3:

```cpp
// Add these files to your build:
// backends/imgui_impl_glfw.cpp
// backends/imgui_impl_glfw.h
// backends/imgui_impl_opengl3.cpp
// backends/imgui_impl_opengl3.h

#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
```

### Step 3: Review Example Applications

The `examples/` folder contains ready-to-build projects for every supported backend combination:

| Example | Platform | Renderer |
|---|---|---|
| `example_allegro5/` | Allegro5 | Allegro5 |
| `example_android_opengl3/` | Android | OpenGL ES 3 |
| `example_apple_metal/` | OSX (Cocoa) | Metal |
| `example_apple_opengl2/` | OSX (Cocoa) | OpenGL 2 |
| `example_emscripten_wgpu/` | Emscripten + GLFW | WebGPU |
| `example_glfw_metal/` | GLFW | Metal |
| `example_glfw_opengl2/` | GLFW | OpenGL 2 |
| `example_glfw_opengl3/` | GLFW | OpenGL 3 |
| `example_glfw_vulkan/` | GLFW | Vulkan |
| `example_glfw_wgpu/` | GLFW | WebGPU |
| `example_glut_opengl2/` | GLUT | OpenGL 2 |
| `example_null/` | Null | Null (no rendering) |
| `example_sdl2_directx11/` | SDL2 | DirectX 11 |
| `example_sdl2_metal/` | SDL2 | Metal |
| `example_sdl2_opengl2/` | SDL2 | OpenGL 2 |
| `example_sdl2_opengl3/` | SDL2 | OpenGL 3 |
| `example_sdl2_sdlrenderer2/` | SDL2 | SDL_Renderer (SDL2) |
| `example_sdl2_vulkan/` | SDL2 | Vulkan |
| `example_sdl3_opengl3/` | SDL3 | OpenGL 3 |
| `example_sdl3_sdlgpu3/` | SDL3 | SDL_GPU |
| `example_sdl3_sdlrenderer3/` | SDL3 | SDL_Renderer (SDL3) |
| `example_sdl3_vulkan/` | SDL3 | Vulkan |
| `example_win32_directx9/` | Win32 | DirectX 9 |
| `example_win32_directx10/` | Win32 | DirectX 10 |
| `example_win32_directx11/` | Win32 | DirectX 11 |
| `example_win32_directx12/` | Win32 | DirectX 12 |
| `example_win32_opengl3/` | Win32 | OpenGL 3 |
| `example_win32_vulkan/` | Win32 | Vulkan |

Each example directory contains a `main.cpp` and platform-specific project files (`.vcxproj`, `Makefile`, `build_win32.bat`, etc.).

### Step 4: Build

Add the `.cpp` files to your existing build system. No special build process is required — no code generation, no pre-processing, no configure step.

**Visual Studio:** Add the `.cpp` files to your project. Add the `imgui/` and `imgui/backends/` directories to your include paths.

**CMake:**
```cmake
add_executable(my_app
    main.cpp
    imgui/imgui.cpp
    imgui/imgui_draw.cpp
    imgui/imgui_tables.cpp
    imgui/imgui_widgets.cpp
    imgui/backends/imgui_impl_glfw.cpp
    imgui/backends/imgui_impl_opengl3.cpp
)
target_include_directories(my_app PRIVATE imgui imgui/backends)
```

**Makefile:**
```makefile
IMGUI_SRCS = imgui/imgui.cpp imgui/imgui_draw.cpp imgui/imgui_tables.cpp imgui/imgui_widgets.cpp
BACKEND_SRCS = imgui/backends/imgui_impl_glfw.cpp imgui/backends/imgui_impl_opengl3.cpp
```

### Step 5: Verify

```cpp
// In your initialization code:
IMGUI_CHECKVERSION();  // Verify header/library version match
ImGui::CreateContext();
ImGui::ShowDemoWindow(); // Should display the demo window
```

> [!IMPORTANT]
> `imconfig.h` is a **compile-time** configuration file. If you modify it, you must recompile ALL translation units that include `imgui.h`. Inconsistent `imconfig.h` across translation units causes subtle memory corruption and crashes. If Dear ImGui is compiled as a static library or DLL, the same `imconfig.h` must be used for both the library build and your application.

### Optional: FreeType Font Rasterizer

For higher-quality font rendering, enable FreeType:

1. `#define IMGUI_ENABLE_FREETYPE` in `imconfig.h`
2. Add `misc/freetype/imgui_freetype.cpp` to your build
3. Link against FreeType library

For SVG-in-font support (color emoji, icon fonts), additionally define `IMGUI_ENABLE_FREETYPE_PLUTOSVG` or `IMGUI_ENABLE_FREETYPE_LUNASVG` and link the corresponding library.

### Optional: std::string Support

```cpp
// Add to your build:
// misc/cpp/imgui_stdlib.cpp
// misc/cpp/imgui_stdlib.h

#include "misc/cpp/imgui_stdlib.h"

std::string my_text = "Hello";
ImGui::InputText("Input", &my_text);  // Works with std::string directly
```

### Optional: Debugger Helpers

| File | Debugger | Purpose |
|---|---|---|
| `misc/debuggers/imgui.natvis` | Visual Studio | Pretty-print ImVector, ImGuiID, ImGuiCol, etc. |
| `misc/debuggers/imgui.gdb` | GDB | Pretty-print ImVector |
| `misc/debuggers/imgui.natstepfilter` | Visual Studio | Skip internal functions when stepping |
| `misc/debuggers/imgui.py` | LLDB | Pretty-print for LLDB |

### Optional: Single-File Build

For projects that prefer a single compilation unit:

```cpp
// imgui_single_file.h is provided in misc/single_file/
#include "misc/single_file/imgui_single_file.h"
```

This `#include`s all four core `.cpp` files into a single translation unit.

---

## 3. Configuration

### Compile-Time Configuration (imconfig.h)

These `#define`s must be set in `imconfig.h` before compiling. They cannot be changed at runtime.

| Define | Default | Purpose |
|---|---|---|
| `IM_ASSERT(EXPR)` | `assert(EXPR)` | Override assertion macro. Define to your own crash/log handler. |
| `IMGUI_API` | (empty) | Decorate public symbols for DLL export/import (`__declspec(dllexport)`, etc.) |
| `IMGUI_DISABLE_OBSOLETE_FUNCTIONS` | Not set | Remove deprecated functions to catch outdated usage at compile time |
| `IMGUI_DISABLE_OBSOLETE_KEYIO` | Not set | Remove legacy key mapping (pre-1.87 backends) |
| `IMGUI_DISABLE` | Not set | Stub out all functions (for conditional compilation) |
| `IMGUI_DISABLE_DEMO_WINDOWS` | Not set | Remove `ShowDemoWindow()` and `imgui_demo.cpp` code |
| `IMGUI_DISABLE_DEBUG_TOOLS` | Not set | Remove debug/metrics tools |
| `IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS` | Not set | Disable Win32 clipboard handling |
| `IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS` | Not set | Disable Win32 IME handling |
| `IMGUI_DISABLE_WIN32_FUNCTIONS` | Not set | Disable all Win32-specific functions |
| `IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS` | Not set | Disable default `ImGui::PlatformOpenInShellFn` |
| `IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS` | Not set | Disable default `ImFileOpen`/`ImFileClose`/`ImFileRead`/`ImFileWrite` |
| `IMGUI_DISABLE_DEFAULT_ALLOCATORS` | Not set | Disable default `malloc`/`free`-based allocators |
| `IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS` | Not set | Disable bundled `ImFormatString`/`ImFormatStringV` |
| `IMGUI_ENABLE_TEST_ENGINE` | Not set | Enable hooks for Dear ImGui Test Engine |
| `IMGUI_USE_BGRA_PACKED_COLOR` | Not set | Use BGRA color packing (for some Direct3D backends) |
| `IMGUI_USE_WCHAR32` | Not set | Use 32-bit `ImWchar` for full Unicode support beyond BMP |
| `IMGUI_ENABLE_FREETYPE` | Not set | Use FreeType for font rasterization instead of stb_truetype |
| `IMGUI_ENABLE_FREETYPE_PLUTOSVG` | Not set | Enable PlutoSVG for SVG-in-font support (requires FreeType) |
| `IMGUI_ENABLE_FREETYPE_LUNASVG` | Not set | Enable LunaSVG for SVG-in-font support (requires FreeType) |
| `IMGUI_DEFINE_MATH_OPERATORS` | Not set | Enable `+`, `-`, `*`, `/` operators on ImVec2/ImVec4 |
| `ImDrawIdx` | `unsigned short` | Set to `unsigned int` for 32-bit draw indices (meshes >64K vertices) |
| `IM_VEC2_CLASS_EXTRA` | Not set | Inject methods/operators into ImVec2 (e.g., conversion to your math type) |
| `IM_VEC4_CLASS_EXTRA` | Not set | Inject methods/operators into ImVec4 |
| `IMGUI_STB_TRUETYPE_FILENAME` | `"imstb_truetype.h"` | Override bundled stb_truetype |
| `IMGUI_STB_RECT_PACK_FILENAME` | `"imstb_rectpack.h"` | Override bundled stb_rectpack |
| `IMGUI_STB_SPRINTF_FILENAME` | Not set | Use stb_sprintf instead of system snprintf |

**Math type interop example:**

```cpp
// In imconfig.h — let ImVec2 convert to/from your engine's Vector2:
#define IM_VEC2_CLASS_EXTRA \
    constexpr ImVec2(const MyEngine::Vector2& v) : x(v.x), y(v.y) {} \
    operator MyEngine::Vector2() const { return MyEngine::Vector2(x, y); }
```

### Runtime Configuration (ImGuiIO)

After `CreateContext()`, configure behavior through `ImGui::GetIO()`:

```cpp
ImGuiIO& io = ImGui::GetIO();

// Navigation
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;  // Keyboard navigation
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;    // Gamepad navigation

// Behavior
io.ConfigInputTextCursorBlink = true;          // Blinking cursor in text inputs
io.ConfigWindowsResizeFromEdges = true;        // Resize from window edges (not just corner)
io.ConfigWindowsMoveFromTitleBarOnly = false;   // If true, only title bar drags windows
io.ConfigScrollbarScrollByPage = true;         // Page-scroll when clicking scrollbar track

// Persistence
io.IniFilename = "imgui.ini";  // Set to NULL to disable auto-save/load

// Display
io.FontGlobalScale = 1.0f;    // Global font scale multiplier
```

Key `ImGuiConfigFlags`:

| Flag | Purpose |
|---|---|
| `ImGuiConfigFlags_NavEnableKeyboard` | Enable keyboard navigation |
| `ImGuiConfigFlags_NavEnableGamepad` | Enable gamepad navigation |
| `ImGuiConfigFlags_NoMouseCursorChange` | Prevent Dear ImGui from changing the OS cursor shape |
| `ImGuiConfigFlags_NoMouse` | Disable mouse input |
| `ImGuiConfigFlags_NavNoCaptureKeyboard` | Do not set `io.WantCaptureKeyboard` during navigation |

### Built-In Styles

```cpp
ImGui::StyleColorsDark();     // Dark theme (default) — best for most tools
ImGui::StyleColorsLight();    // Light theme
ImGui::StyleColorsClassic();  // Classic ImGui theme (gray with blue highlights)
```

> [!TIP]
> Call `ImGui::ShowStyleEditor()` anywhere in your frame loop to open an interactive style editor. You can tweak every color, size, and rounding value in real time and export the result as code. This is the fastest way to create a custom theme.

For a complete reference of all configuration options, style variables, and color IDs, see the Admin Guide.

---

## 4. Core Usage

Dear ImGui follows a consistent pattern: every frame, you call functions that describe your UI, and Dear ImGui handles layout, drawing, and interaction. This section covers every widget category organized by what you want to accomplish.

### 4.1 Creating Windows

Every piece of Dear ImGui content lives inside a window created with `Begin()`/`End()`:

```cpp
ImGui::Begin("My Window");
// ... widgets go here ...
ImGui::End();
```

`Begin()` returns `false` when the window is collapsed, but you **must always call `End()`** regardless. For optimization, skip widget code when collapsed:

```cpp
if (ImGui::Begin("My Window"))
{
    ImGui::Text("Visible content");
}
ImGui::End();  // Always required
```

#### Window Flags

Pass flags as the third parameter to `Begin()`:

```cpp
ImGui::Begin("My Window", &show_window, ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoResize);
```

| Flag | Effect |
|---|---|
| `ImGuiWindowFlags_NoTitleBar` | No title bar |
| `ImGuiWindowFlags_NoResize` | User cannot resize |
| `ImGuiWindowFlags_NoMove` | User cannot move |
| `ImGuiWindowFlags_NoScrollbar` | No scrollbar (content clips) |
| `ImGuiWindowFlags_NoScrollWithMouse` | Disable mouse wheel scrolling |
| `ImGuiWindowFlags_NoCollapse` | No collapse button |
| `ImGuiWindowFlags_AlwaysAutoResize` | Resize to fit content every frame |
| `ImGuiWindowFlags_NoBackground` | No background fill |
| `ImGuiWindowFlags_NoSavedSettings` | Never save/load position/size in .ini |
| `ImGuiWindowFlags_MenuBar` | Has a menu bar (use with `BeginMenuBar()`) |
| `ImGuiWindowFlags_HorizontalScrollbar` | Enable horizontal scrollbar |
| `ImGuiWindowFlags_NoFocusOnAppearing` | Don't take focus when appearing |
| `ImGuiWindowFlags_NoBringToFrontOnFocus` | Don't raise to front when focused |
| `ImGuiWindowFlags_AlwaysVerticalScrollbar` | Always show vertical scrollbar |
| `ImGuiWindowFlags_AlwaysHorizontalScrollbar` | Always show horizontal scrollbar |
| `ImGuiWindowFlags_NoNavInputs` | No navigation within this window |
| `ImGuiWindowFlags_NoNavFocus` | No focusing via navigation |
| `ImGuiWindowFlags_NoNav` | Shorthand for NoNavInputs + NoNavFocus |
| `ImGuiWindowFlags_NoDecoration` | Shorthand for NoTitleBar + NoResize + NoScrollbar + NoCollapse |
| `ImGuiWindowFlags_NoInputs` | Shorthand for NoMouseInputs + NoNavInputs + NoNavFocus |

#### Window Manipulation

Set properties for the **next** `Begin()` call:

```cpp
ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowSize(ImVec2(400, 300), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowCollapsed(false, ImGuiCond_Once);
ImGui::SetNextWindowFocus();
ImGui::SetNextWindowBgAlpha(0.8f);
```

Condition flags (`ImGuiCond_`):

| Flag | When applied |
|---|---|
| `ImGuiCond_Always` | Every frame |
| `ImGuiCond_Once` | First time only (per session) |
| `ImGuiCond_FirstUseEver` | First time ever (across .ini sessions) |
| `ImGuiCond_Appearing` | Each time window appears after being hidden |

#### Child Windows

Create scrollable sub-regions within a window:

```cpp
// With explicit size
ImGui::BeginChild("ScrollRegion", ImVec2(0, 300), ImGuiChildFlags_Borders);
for (int i = 0; i < 100; i++)
    ImGui::Text("Item %d", i);
ImGui::EndChild();

// Auto-sizing child
ImGui::BeginChild("AutoChild", ImVec2(0, 0), ImGuiChildFlags_AutoResizeY);
ImGui::Text("This child sizes to its content vertically");
ImGui::EndChild();
```

#### Window Queries

```cpp
bool focused = ImGui::IsWindowFocused();
bool hovered = ImGui::IsWindowHovered();
ImVec2 pos   = ImGui::GetWindowPos();
ImVec2 size  = ImGui::GetWindowSize();
```

### 4.2 Displaying Text and Basic Widgets

#### Text Display

```cpp
ImGui::Text("Simple text");
ImGui::Text("Formatted: %d items, %.2f seconds", count, elapsed);
ImGui::TextColored(ImVec4(1,0,0,1), "Red warning text");
ImGui::TextDisabled("Grayed out hint");
ImGui::TextWrapped("This long text will wrap to the available width "
                   "of the current window or column.");
ImGui::BulletText("Bulleted item");
ImGui::SeparatorText("Section Header");
```

#### Buttons

```cpp
if (ImGui::Button("Click Me"))
{
    // Action happens on the frame the button is clicked
}

if (ImGui::Button("Sized Button", ImVec2(200, 40)))
{
    // Button with explicit size
}

ImGui::SmallButton("Compact");          // Small, no frame padding
ImGui::ArrowButton("##left", ImGuiDir_Left);  // Directional arrow

// Invisible button — a clickable region with no visual
if (ImGui::InvisibleButton("zone", ImVec2(100, 100)))
{
    // Clicked in the invisible region
}

// Hyperlinks
ImGui::TextLink("Open Documentation");     // Returns true when clicked
ImGui::TextLinkOpenURL("Visit GitHub", "https://github.com/ocornut/imgui");
```

#### Checkboxes and Radio Buttons

```cpp
static bool enabled = true;
ImGui::Checkbox("Enable Feature", &enabled);

static int mode = 0;
ImGui::RadioButton("Mode A", &mode, 0); ImGui::SameLine();
ImGui::RadioButton("Mode B", &mode, 1); ImGui::SameLine();
ImGui::RadioButton("Mode C", &mode, 2);
```

#### Progress Bar

```cpp
ImGui::ProgressBar(0.65f, ImVec2(0, 0), "65%");
```

### 4.3 Input Widgets

#### Text Input

```cpp
static char buf[256] = "";
if (ImGui::InputText("Name", buf, sizeof(buf)))
{
    // Text changed this frame
}

static char multiline[1024] = "";
ImGui::InputTextMultiline("Description", multiline, sizeof(multiline),
                          ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 8));

static char search[128] = "";
ImGui::InputTextWithHint("##search", "Search...", search, sizeof(search));
```

Key `ImGuiInputTextFlags`:

| Flag | Effect |
|---|---|
| `ImGuiInputTextFlags_CharsDecimal` | Allow `0123456789.+-*/` |
| `ImGuiInputTextFlags_CharsHexadecimal` | Allow `0123456789ABCDEFabcdef` |
| `ImGuiInputTextFlags_CharsScientific` | Allow `0123456789.+-*/eE` |
| `ImGuiInputTextFlags_CharsUppercase` | Force uppercase |
| `ImGuiInputTextFlags_CharsNoBlank` | Filter spaces and tabs |
| `ImGuiInputTextFlags_EnterReturnsTrue` | Return true on Enter instead of on every edit |
| `ImGuiInputTextFlags_CallbackCompletion` | Tab key triggers callback |
| `ImGuiInputTextFlags_CallbackHistory` | Up/Down triggers callback |
| `ImGuiInputTextFlags_CallbackResize` | Callback when buffer needs to grow (for std::string) |
| `ImGuiInputTextFlags_Password` | Mask display with `*` |
| `ImGuiInputTextFlags_ReadOnly` | Display only, no editing |
| `ImGuiInputTextFlags_AutoSelectAll` | Select all on focus |
| `ImGuiInputTextFlags_NoHorizontalScroll` | Disable horizontal scrolling |
| `ImGuiInputTextFlags_EscapeClearsAll` | Escape clears the field |

#### Numeric Input

```cpp
static float f = 0.5f;
static int i = 42;

// Drag widgets — click and drag to adjust
ImGui::DragFloat("Speed", &f, 0.01f, 0.0f, 1.0f, "%.3f");
ImGui::DragInt("Count", &i, 1, 0, 100);

// Slider widgets — slide within a fixed range
ImGui::SliderFloat("Volume", &f, 0.0f, 1.0f, "%.2f");
ImGui::SliderInt("Quality", &i, 0, 10);
ImGui::SliderAngle("Rotation", &f);  // Displays in degrees, stores radians

// Direct numeric input
ImGui::InputFloat("Value", &f, 0.1f, 1.0f, "%.3f");
ImGui::InputInt("Count", &i, 1, 10);
ImGui::InputDouble("Precision", &d, 0.001, 0.01, "%.6f");

// Multi-component
static float vec3[3] = {0, 0, 0};
ImGui::DragFloat3("Position", vec3, 0.1f);
ImGui::SliderFloat3("Color", vec3, 0.0f, 1.0f);
ImGui::InputFloat3("Coords", vec3);
```

> [!NOTE]
> **Ctrl+Click** on any `SliderFloat`, `SliderInt`, `DragFloat`, or `DragInt` widget to convert it into a direct text input box. This lets users type exact values when precision matters. The behavior is automatic and requires no extra code.

#### Color Editing

```cpp
static float col3[3] = {1.0f, 0.5f, 0.0f};
static float col4[4] = {1.0f, 0.5f, 0.0f, 1.0f};

ImGui::ColorEdit3("Color", col3);           // RGB
ImGui::ColorEdit4("Color+Alpha", col4);     // RGBA
ImGui::ColorPicker3("Pick Color", col3);    // Full picker widget
ImGui::ColorPicker4("Pick Color+A", col4);  // Full picker with alpha

// Color button (shows a color swatch, opens picker on click)
ImGui::ColorButton("Preview", ImVec4(col4[0], col4[1], col4[2], col4[3]));
```

#### std::string Support

```cpp
#include "misc/cpp/imgui_stdlib.h"

std::string name = "Default";
ImGui::InputText("Name", &name);  // Automatically resizes the string
```

### 4.4 Layout and Positioning

#### Cursor and Content Region

```cpp
// The two most important layout functions:
ImVec2 pos = ImGui::GetCursorScreenPos();     // Where the next widget will be drawn (screen coords)
ImVec2 avail = ImGui::GetContentRegionAvail(); // Remaining space in current region
```

#### Horizontal Layout

```cpp
ImGui::Button("A"); ImGui::SameLine();
ImGui::Button("B"); ImGui::SameLine();
ImGui::Button("C");
// Result: [A] [B] [C] on one line

ImGui::SameLine(200);    // Position next item at x=200 within the window
ImGui::SameLine(0, 20);  // Default position, but with 20px spacing
```

#### Spacing and Separators

```cpp
ImGui::NewLine();        // Empty line
ImGui::Spacing();        // Small vertical gap
ImGui::Dummy(ImVec2(0, 20));  // Explicit spacer of given size
ImGui::Separator();      // Horizontal line
ImGui::SeparatorText("Section");  // Line with centered text
```

#### Indentation

```cpp
ImGui::Text("Root");
ImGui::Indent();
ImGui::Text("Indented");
ImGui::Indent();
ImGui::Text("More indented");
ImGui::Unindent(2 * ImGui::GetTreeNodeToLabelSpacing());  // Reset
```

#### Groups

Groups let you treat multiple widgets as a single item for layout purposes:

```cpp
ImGui::BeginGroup();
ImGui::Text("Label:");
ImGui::Text("Value:");
ImGui::EndGroup();

ImGui::SameLine();

ImGui::BeginGroup();
ImGui::Text("Name");
ImGui::Text("42");
ImGui::EndGroup();
```

#### Item Width

```cpp
// Set width for the next widget
ImGui::SetNextItemWidth(200);
ImGui::InputFloat("##val", &val);

// Push width for multiple widgets
ImGui::PushItemWidth(200);
ImGui::InputFloat("A", &a);
ImGui::InputFloat("B", &b);
ImGui::PopItemWidth();

// Negative width: relative to right edge
ImGui::PushItemWidth(-100);  // Leave 100px on the right for labels
```

#### Text Wrapping

```cpp
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 300); // Wrap at 300px from cursor
ImGui::TextWrapped("This text wraps within the specified width...");
ImGui::PopTextWrapPos();

// Wrap to window edge:
ImGui::PushTextWrapPos(0.0f);
ImGui::TextWrapped("Wraps to the window edge.");
ImGui::PopTextWrapPos();
```

### 4.5 Trees and Hierarchies

```cpp
if (ImGui::TreeNode("Root Node"))
{
    ImGui::Text("Leaf content");
    if (ImGui::TreeNode("Child Node"))
    {
        ImGui::Text("Nested content");
        ImGui::TreePop();
    }
    ImGui::TreePop();  // Required for every TreeNode that returns true
}
```

#### TreeNodeEx with Flags

```cpp
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow
                         | ImGuiTreeNodeFlags_OpenOnDoubleClick
                         | ImGuiTreeNodeFlags_SpanAvailWidth;

// Leaf node (no arrow, not expandable)
ImGuiTreeNodeFlags leaf_flags = flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen;

if (ImGui::TreeNodeEx("Parent", flags))
{
    ImGui::TreeNodeEx("Leaf Item", leaf_flags);
    ImGui::TreePop();
}
```

#### CollapsingHeader

Unlike `TreeNode`, `CollapsingHeader` does **not** require `TreePop()`:

```cpp
if (ImGui::CollapsingHeader("Settings"))
{
    ImGui::SliderFloat("Volume", &volume, 0.0f, 1.0f);
    ImGui::Checkbox("Mute", &mute);
}

// With close button:
static bool show_header = true;
if (ImGui::CollapsingHeader("Closeable", &show_header))
{
    ImGui::Text("Content");
}
```

#### Controlling Open State

```cpp
ImGui::SetNextItemOpen(true, ImGuiCond_Once);  // Open by default
if (ImGui::TreeNode("Open by default"))
{
    // ...
    ImGui::TreePop();
}
```

### 4.6 Tables

The table widget is one of Dear ImGui's most powerful features, supporting sorting, reordering, column hiding, freezing, and more.

```cpp
// Basic table
if (ImGui::BeginTable("my_table", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
{
    // Setup columns (optional but recommended)
    ImGui::TableSetupColumn("Name");
    ImGui::TableSetupColumn("Type");
    ImGui::TableSetupColumn("Value");
    ImGui::TableHeadersRow();

    // Rows
    for (int row = 0; row < 5; row++)
    {
        ImGui::TableNextRow();
        ImGui::TableSetColumnIndex(0);
        ImGui::Text("Item %d", row);
        ImGui::TableSetColumnIndex(1);
        ImGui::Text("Type A");
        ImGui::TableSetColumnIndex(2);
        ImGui::Text("%.2f", row * 1.5f);
    }
    ImGui::EndTable();
}
```

Alternative row traversal using `TableNextColumn()`:

```cpp
if (ImGui::BeginTable("table2", 3))
{
    for (int row = 0; row < 5; row++)
    {
        ImGui::TableNextColumn(); ImGui::Text("Cell %d,0", row);
        ImGui::TableNextColumn(); ImGui::Text("Cell %d,1", row);
        ImGui::TableNextColumn(); ImGui::Text("Cell %d,2", row);
    }
    ImGui::EndTable();
}
```

#### Table Flags

| Flag | Effect |
|---|---|
| `ImGuiTableFlags_Resizable` | Columns can be resized |
| `ImGuiTableFlags_Reorderable` | Columns can be reordered by dragging headers |
| `ImGuiTableFlags_Hideable` | Columns can be hidden via context menu |
| `ImGuiTableFlags_Sortable` | Enable sorting (click headers) |
| `ImGuiTableFlags_SortMulti` | Allow sorting on multiple columns (Shift+click) |
| `ImGuiTableFlags_RowBg` | Alternate row background colors |
| `ImGuiTableFlags_Borders` | All borders (alias for BordersInner + BordersOuter) |
| `ImGuiTableFlags_BordersV` | Vertical borders |
| `ImGuiTableFlags_BordersH` | Horizontal borders |
| `ImGuiTableFlags_NoBordersInBody` | No borders in body (headers only) |
| `ImGuiTableFlags_ScrollX` | Enable horizontal scrolling |
| `ImGuiTableFlags_ScrollY` | Enable vertical scrolling (requires outer size) |
| `ImGuiTableFlags_SizingFixedFit` | Columns default to fixed width |
| `ImGuiTableFlags_SizingStretchSame` | Columns stretch with equal weight |
| `ImGuiTableFlags_SizingStretchProp` | Columns stretch proportionally |

#### Sorting

```cpp
if (ImGui::BeginTable("sortable", 3, ImGuiTableFlags_Sortable))
{
    ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort);
    ImGui::TableSetupColumn("Name");
    ImGui::TableSetupColumn("Score");
    ImGui::TableHeadersRow();

    if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
    {
        if (sort_specs->SpecsDirty)
        {
            // Re-sort your data based on sort_specs->Specs[0].ColumnIndex
            // and sort_specs->Specs[0].SortDirection
            sort_specs->SpecsDirty = false;
        }
    }

    // ... render sorted rows ...
    ImGui::EndTable();
}
```

#### Freeze Rows/Columns

```cpp
if (ImGui::BeginTable("frozen", 3, ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY,
                      ImVec2(0, 300)))
{
    ImGui::TableSetupScrollFreeze(1, 1);  // Freeze 1 column, 1 row
    ImGui::TableSetupColumn("Frozen Col");
    ImGui::TableSetupColumn("Col 2");
    ImGui::TableSetupColumn("Col 3");
    ImGui::TableHeadersRow();
    // ...
    ImGui::EndTable();
}
```

> [!WARNING]
> The legacy `Columns()` API is deprecated. Use the `BeginTable()`/`EndTable()` API instead. The table widget offers vastly superior features including sorting, column reordering, column hiding, scrolling, and freeze rows/columns. The old `Columns()` API is retained only for backward compatibility and will be removed in a future version.

### 4.7 Tab Bars

```cpp
if (ImGui::BeginTabBar("Tabs"))
{
    if (ImGui::BeginTabItem("General"))
    {
        ImGui::Text("General settings");
        ImGui::EndTabItem();
    }
    if (ImGui::BeginTabItem("Graphics"))
    {
        ImGui::Text("Graphics settings");
        ImGui::EndTabItem();
    }
    if (ImGui::BeginTabItem("Audio"))
    {
        ImGui::Text("Audio settings");
        ImGui::EndTabItem();
    }
    ImGui::EndTabBar();
}
```

Closeable tabs:

```cpp
static bool show_tab = true;
if (ImGui::BeginTabItem("Closeable", &show_tab))
{
    ImGui::Text("This tab can be closed");
    ImGui::EndTabItem();
}
```

Tab bar utilities:

```cpp
ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing);  // Add-tab button
ImGui::SetTabItemClosed("Tab Name");  // Programmatically close
```

### 4.8 Menus

#### Window Menu Bar

```cpp
ImGui::Begin("Editor", nullptr, ImGuiWindowFlags_MenuBar);
if (ImGui::BeginMenuBar())
{
    if (ImGui::BeginMenu("File"))
    {
        if (ImGui::MenuItem("New", "Ctrl+N"))  { /* action */ }
        if (ImGui::MenuItem("Open", "Ctrl+O")) { /* action */ }
        ImGui::Separator();
        if (ImGui::MenuItem("Quit", "Alt+F4")) { /* action */ }
        ImGui::EndMenu();
    }
    if (ImGui::BeginMenu("Edit"))
    {
        if (ImGui::MenuItem("Undo", "Ctrl+Z", false, has_undo)) { /* action */ }
        if (ImGui::MenuItem("Redo", "Ctrl+Y", false, has_redo)) { /* action */ }
        ImGui::EndMenu();
    }
    ImGui::EndMenuBar();
}
ImGui::End();
```

#### Main Menu Bar (top of screen)

```cpp
if (ImGui::BeginMainMenuBar())
{
    if (ImGui::BeginMenu("File")) { /* ... */ ImGui::EndMenu(); }
    if (ImGui::BeginMenu("Edit")) { /* ... */ ImGui::EndMenu(); }
    ImGui::EndMainMenuBar();
}
```

#### Submenus and Toggle Items

```cpp
if (ImGui::BeginMenu("View"))
{
    ImGui::MenuItem("Show Grid", nullptr, &show_grid);     // Toggle
    ImGui::MenuItem("Show FPS", nullptr, &show_fps);       // Toggle
    if (ImGui::BeginMenu("Layout"))                        // Submenu
    {
        ImGui::MenuItem("Horizontal");
        ImGui::MenuItem("Vertical");
        ImGui::EndMenu();
    }
    ImGui::EndMenu();
}
```

### 4.9 Popups and Modals

#### Basic Popup

```cpp
if (ImGui::Button("Open Popup"))
    ImGui::OpenPopup("my_popup");

if (ImGui::BeginPopup("my_popup"))
{
    ImGui::Text("Popup content");
    if (ImGui::Button("Close"))
        ImGui::CloseCurrentPopup();
    ImGui::EndPopup();
}
```

#### Modal Dialog

```cpp
if (ImGui::Button("Delete"))
    ImGui::OpenPopup("Confirm Delete");

if (ImGui::BeginPopupModal("Confirm Delete", nullptr, ImGuiWindowFlags_AlwaysAutoResize))
{
    ImGui::Text("Are you sure you want to delete this item?");
    ImGui::Separator();
    if (ImGui::Button("OK", ImVec2(120, 0)))
    {
        // Perform delete
        ImGui::CloseCurrentPopup();
    }
    ImGui::SameLine();
    if (ImGui::Button("Cancel", ImVec2(120, 0)))
    {
        ImGui::CloseCurrentPopup();
    }
    ImGui::EndPopup();
}
```

#### Context Menus

```cpp
// Context menu on the last item
ImGui::Text("Right-click me");
if (ImGui::BeginPopupContextItem("item_context"))
{
    if (ImGui::MenuItem("Copy"))  { /* ... */ }
    if (ImGui::MenuItem("Paste")) { /* ... */ }
    ImGui::EndPopup();
}

// Context menu on window background
if (ImGui::BeginPopupContextWindow())
{
    if (ImGui::MenuItem("Add Item"))  { /* ... */ }
    ImGui::EndPopup();
}

// Context menu on void (no window hovered)
if (ImGui::BeginPopupContextVoid())
{
    if (ImGui::MenuItem("Settings")) { /* ... */ }
    ImGui::EndPopup();
}
```

> [!WARNING]
> In Dear ImGui 1.92.6, the default popup trigger changed to **right-click** (`ImGuiPopupFlags_MouseButtonRight`). If you relied on left-click to open popups via `OpenPopupOnItemClick()`, you must now explicitly pass `ImGuiPopupFlags_MouseButtonLeft`. The `BeginPopupContextItem/Window/Void` helpers already default to right-click and are unaffected.

### 4.10 Tooltips

```cpp
// Simple tooltip on hover
ImGui::Button("Hover me");
if (ImGui::IsItemHovered())
    ImGui::SetTooltip("This is a tooltip");

// Rich tooltip with multiple widgets
ImGui::Button("Rich tooltip");
if (ImGui::BeginItemTooltip())
{
    ImGui::Text("Detailed information:");
    ImGui::BulletText("Point 1");
    ImGui::BulletText("Point 2");
    ImGui::ProgressBar(0.7f);
    ImGui::EndTooltip();
}

// Shorthand for text-only item tooltip
ImGui::Button("Short");
ImGui::SetItemTooltip("Tooltip text for the preceding item");
```

### 4.11 Images

Dear ImGui can render application textures via `Image()` and `ImageButton()`. You must create the texture using your graphics API and pass its handle.

```cpp
// ImTextureRef wraps a texture identifier + size information (new in 1.92)
ImTextureRef tex = ...; // Backend-specific: e.g., (ImTextureID)(intptr_t)opengl_texture_id

ImGui::Image(tex, ImVec2(256, 256));                        // Display at 256x256
ImGui::Image(tex, ImVec2(128, 128), ImVec2(0,0), ImVec2(1,1)); // With UV coords

// Image with background color (for transparent images)
ImGui::ImageWithBg(tex, ImVec2(256, 256), ImVec2(0,0), ImVec2(1,1),
                   ImVec4(0,0,0,1));  // Black background

// Image button
if (ImGui::ImageButton("btn_id", tex, ImVec2(32, 32)))
{
    // Clicked
}
```

The exact type of `ImTextureID` depends on your renderer backend:

| Backend | ImTextureID value |
|---|---|
| OpenGL | `(ImTextureID)(intptr_t)gl_texture` |
| DirectX9 | `(ImTextureID)d3d9_texture_ptr` |
| DirectX11 | `(ImTextureID)srv_ptr` |
| DirectX12 | `(ImTextureID)gpu_descriptor_handle.ptr` |
| Vulkan | `(ImTextureID)vk_descriptor_set` |
| Metal | `(ImTextureID)mtl_texture` |

### 4.12 Selectables and Multi-Select

#### Selectable

```cpp
static int selected = -1;
const char* items[] = { "Apple", "Banana", "Cherry", "Date" };
for (int i = 0; i < 4; i++)
{
    if (ImGui::Selectable(items[i], selected == i))
        selected = i;
}
```

#### Multi-Select (Beta)

```cpp
static ImGuiSelectionBasicStorage selection;
ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape;
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, selection.Size, item_count);
selection.ApplyRequests(ms_io);

for (int i = 0; i < item_count; i++)
{
    ImGui::SetNextItemSelectionUserData(i);
    bool is_selected = selection.Contains((ImGuiID)i);
    ImGui::Selectable(items[i], is_selected);
}

ms_io = ImGui::EndMultiSelect();
selection.ApplyRequests(ms_io);
```

### 4.13 List Boxes and Combo Boxes

#### Combo Box

```cpp
static int current_item = 0;
const char* items[] = { "Option A", "Option B", "Option C" };

// Simple version
ImGui::Combo("Combo", &current_item, items, IM_ARRAYSIZE(items));

// Begin/End version (custom content)
if (ImGui::BeginCombo("Custom Combo", items[current_item]))
{
    for (int i = 0; i < IM_ARRAYSIZE(items); i++)
    {
        bool is_selected = (current_item == i);
        if (ImGui::Selectable(items[i], is_selected))
            current_item = i;
        if (is_selected)
            ImGui::SetItemDefaultFocus();
    }
    ImGui::EndCombo();
}
```

#### List Box

```cpp
static int current = 0;
if (ImGui::BeginListBox("Items", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing())))
{
    for (int i = 0; i < item_count; i++)
    {
        bool is_selected = (current == i);
        if (ImGui::Selectable(items[i], is_selected))
            current = i;
        if (is_selected)
            ImGui::SetItemDefaultFocus();
    }
    ImGui::EndListBox();
}
```

### 4.14 Data Plotting

```cpp
static float values[100];
// ... fill values ...

ImGui::PlotLines("Signal", values, IM_ARRAYSIZE(values), 0, "overlay text",
                 -1.0f, 1.0f, ImVec2(0, 80));

ImGui::PlotHistogram("Distribution", values, IM_ARRAYSIZE(values), 0, nullptr,
                     0.0f, 1.0f, ImVec2(0, 80));
```

For advanced plotting (axes, legends, multiple series, heatmaps), use the companion library [ImPlot](https://github.com/epezent/implot).

### 4.15 Drag and Drop

```cpp
// Source: the widget you drag FROM
if (ImGui::Button("Drag me"))
{
}
if (ImGui::BeginDragDropSource())
{
    int payload_data = 42;
    ImGui::SetDragDropPayload("MY_TYPE", &payload_data, sizeof(int));
    ImGui::Text("Dragging value: %d", payload_data);  // Preview tooltip
    ImGui::EndDragDropSource();
}

// Target: the region you drop INTO
ImGui::Button("Drop here");
if (ImGui::BeginDragDropTarget())
{
    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_TYPE"))
    {
        int received = *(const int*)payload->Data;
        // Handle the drop
    }
    ImGui::EndDragDropTarget();
}
```

The payload type string (`"MY_TYPE"`) acts as a type filter — only matching payloads are accepted.

### 4.16 Keyboard and Gamepad Navigation

#### Enabling Navigation

```cpp
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;  // Arrow keys, Tab, Enter, Escape
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;    // D-pad, face buttons, triggers
```

#### Keyboard Shortcuts

```cpp
// Global shortcut (works when Dear ImGui has focus)
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_S))
{
    // Save
}

// Shortcut bound to a menu item
if (ImGui::MenuItem("Save", "Ctrl+S"))
{
    // Save action
}

// Shortcut assigned to a specific widget
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_Z);
if (ImGui::Button("Undo"))
{
    // Undo action — also triggered by Ctrl+Z
}
```

Modifier keys: `ImGuiMod_Ctrl`, `ImGuiMod_Shift`, `ImGuiMod_Alt`, `ImGuiMod_Super`.

### 4.17 Fonts

#### Default Fonts

```cpp
ImGuiIO& io = ImGui::GetIO();

// Vector-based default font (scalable, new approach)
io.Fonts->AddFontDefaultVector();

// Bitmap-based default font (ProggyClean 13px)
io.Fonts->AddFontDefaultBitmap();
```

#### Loading Custom Fonts

```cpp
// From file
ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/Roboto-Regular.ttf", 16.0f);

// From memory (e.g., embedded font data)
ImFont* font2 = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 16.0f);

// With specific glyph ranges
ImFont* font_jp = io.Fonts->AddFontFromFileTTF("fonts/NotoSansJP.ttf", 18.0f,
    nullptr, io.Fonts->GetGlyphRangesJapanese());
```

#### Dynamic Font Sizing (New in 1.92)

```cpp
ImFont* font = io.Fonts->AddFontFromFileTTF("Roboto.ttf", 0);  // Base size 0 = vector font

// In your frame loop:
ImGui::PushFont(font, 24.0f);  // Render at 24px
ImGui::Text("Large text");
ImGui::PopFont();

ImGui::PushFont(font, 12.0f);  // Render at 12px
ImGui::Text("Small text");
ImGui::PopFont();
```

#### Font Merging (Icon Fonts)

```cpp
// Load primary font
io.Fonts->AddFontFromFileTTF("Roboto.ttf", 16.0f);

// Merge icon font into primary font
ImFontConfig config;
config.MergeMode = true;
config.GlyphMinAdvanceX = 16.0f;
static const ImWchar icon_ranges[] = { 0xf000, 0xf3ff, 0 };
io.Fonts->AddFontFromFileTTF("FontAwesome.ttf", 16.0f, &config, icon_ranges);
```

#### Available Glyph Ranges

| Method | Coverage |
|---|---|
| `GetGlyphRangesDefault()` | Basic Latin + supplement (U+0020–U+00FF) |
| `GetGlyphRangesGreek()` | Greek and Coptic |
| `GetGlyphRangesCyrillic()` | Cyrillic |
| `GetGlyphRangesKorean()` | Korean (Hangul) |
| `GetGlyphRangesJapanese()` | Hiragana, Katakana, CJK Unified |
| `GetGlyphRangesChineseFull()` | Full Chinese character set |
| `GetGlyphRangesChineseSimplifiedCommon()` | ~2500 most common simplified Chinese |
| `GetGlyphRangesThai()` | Thai |
| `GetGlyphRangesVietnamese()` | Vietnamese |

### 4.18 Drawing API (ImDrawList)

The low-level drawing API lets you render arbitrary shapes. Every window has a draw list, and there are global background and foreground draw lists.

```cpp
ImDrawList* draw_list = ImGui::GetWindowDrawList();

ImVec2 p = ImGui::GetCursorScreenPos();  // Use as origin
ImU32 col = IM_COL32(255, 255, 0, 255);  // Yellow, fully opaque

// Lines
draw_list->AddLine(ImVec2(p.x, p.y), ImVec2(p.x + 100, p.y + 50), col, 2.0f);

// Rectangles
draw_list->AddRect(ImVec2(p.x, p.y), ImVec2(p.x + 80, p.y + 40), col);
draw_list->AddRectFilled(ImVec2(p.x, p.y), ImVec2(p.x + 80, p.y + 40), col);
draw_list->AddRectFilled(ImVec2(p.x, p.y), ImVec2(p.x + 80, p.y + 40), col, 10.0f);  // Rounded

// Circles
draw_list->AddCircle(ImVec2(p.x + 40, p.y + 40), 30.0f, col, 0, 2.0f);
draw_list->AddCircleFilled(ImVec2(p.x + 40, p.y + 40), 30.0f, col);

// Triangles
draw_list->AddTriangle(ImVec2(p.x, p.y + 60), ImVec2(p.x + 60, p.y + 60),
                       ImVec2(p.x + 30, p.y), col, 2.0f);
draw_list->AddTriangleFilled(ImVec2(p.x, p.y + 60), ImVec2(p.x + 60, p.y + 60),
                             ImVec2(p.x + 30, p.y), col);

// Text
draw_list->AddText(ImVec2(p.x, p.y), col, "Hello");

// Bezier curves
draw_list->AddBezierCubic(ImVec2(p.x, p.y), ImVec2(p.x+50, p.y-50),
                          ImVec2(p.x+100, p.y+50), ImVec2(p.x+150, p.y), col, 2.0f);
draw_list->AddBezierQuadratic(ImVec2(p.x, p.y), ImVec2(p.x+75, p.y-50),
                              ImVec2(p.x+150, p.y), col, 2.0f);

// N-gons (regular polygons)
draw_list->AddNgon(ImVec2(p.x+40, p.y+40), 30.0f, col, 6, 2.0f);       // Hexagon outline
draw_list->AddNgonFilled(ImVec2(p.x+40, p.y+40), 30.0f, col, 6);       // Filled hexagon

// Ellipses
draw_list->AddEllipse(ImVec2(p.x+50, p.y+30), ImVec2(50, 30), col, 0.0f, 0, 2.0f);
draw_list->AddEllipseFilled(ImVec2(p.x+50, p.y+30), ImVec2(50, 30), col);

// Images
draw_list->AddImage(tex_id, ImVec2(p.x, p.y), ImVec2(p.x + 100, p.y + 100));

// Polyline
ImVec2 points[] = { {p.x,p.y}, {p.x+30,p.y-20}, {p.x+60,p.y+10}, {p.x+90,p.y-5} };
draw_list->AddPolyline(points, 4, col, ImDrawFlags_None, 2.0f);

// Convex filled polygon
draw_list->AddConvexPolyFilled(points, 4, col);
```

#### Draw List Layers

```cpp
ImDrawList* bg = ImGui::GetBackgroundDrawList();   // Behind all windows
ImDrawList* fg = ImGui::GetForegroundDrawList();   // In front of all windows
ImDrawList* wl = ImGui::GetWindowDrawList();       // Current window's draw list
```

### 4.19 ID System

Dear ImGui uses IDs to track widget state (open/closed, active, edited, scroll position). Understanding IDs is essential to avoid bugs.

#### How IDs Work

Every widget needs a unique ID within its parent window/tree scope. By default, the ID is derived from the label string:

```cpp
ImGui::Button("OK");    // ID = hash of "OK" in current scope
ImGui::Button("OK");    // BUG: duplicate ID — second button won't work
```

#### Solving ID Conflicts

**Method 1: `##` separator** — text after `##` is part of the ID but not displayed:

```cpp
ImGui::Button("OK##save");    // Displays "OK", ID includes "save"
ImGui::Button("OK##cancel");  // Displays "OK", different ID
```

**Method 2: `###` separator** — only text after `###` forms the ID:

```cpp
// Useful when label changes but you want stable widget state
char buf[64];
sprintf(buf, "Frame %d###AnimatingTitle", frame_count);
ImGui::Begin(buf);  // Window ID stays the same even as title changes
ImGui::End();
```

**Method 3: `PushID()`/`PopID()`** — create a unique ID scope:

```cpp
for (int i = 0; i < items.size(); i++)
{
    ImGui::PushID(i);          // Push integer as ID scope
    ImGui::Button("Delete");   // "Delete" is now unique within this scope
    ImGui::SameLine();
    ImGui::Button("Edit");
    ImGui::PopID();
}
```

`PushID()` accepts `int`, `const char*`, `const void*`, or a string range.

### 4.20 Disabling Widgets

```cpp
bool can_edit = user_has_permission();
ImGui::BeginDisabled(!can_edit);
ImGui::InputText("Name", buf, sizeof(buf));
ImGui::Button("Save");
ImGui::EndDisabled();
// When disabled: widgets are grayed out and do not respond to input
```

### 4.21 Clipping

```cpp
ImGui::PushClipRect(ImVec2(100, 100), ImVec2(300, 300), true);
// Only content within the rectangle is visible
ImGui::Text("This text may be clipped");
ImGui::PopClipRect();
```

### 4.22 Logging and Capture

Dear ImGui can capture UI output as text — useful for copying widget content to the clipboard or a file.

```cpp
ImGui::LogToClipboard();   // Start capturing to clipboard
ImGui::LogToFile(-1, "output.txt");  // Capture to file
ImGui::LogToTTY();         // Capture to stdout

// All subsequent widget output is captured as text...

ImGui::LogFinish();        // Stop capturing

// Convenience: show buttons for all log targets
ImGui::LogButtons();
```

### 4.23 Settings Persistence

Dear ImGui automatically saves and loads window positions, sizes, collapsed states, and table column settings to an `.ini` file.

```cpp
// Default behavior: saves to "imgui.ini" on exit
ImGuiIO& io = ImGui::GetIO();
io.IniFilename = "my_app_layout.ini";  // Custom filename
io.IniFilename = nullptr;              // Disable auto-save/load

// Manual control
ImGui::LoadIniSettingsFromDisk("layout.ini");
ImGui::SaveIniSettingsToDisk("layout.ini");

// In-memory (useful for custom storage)
const char* ini_data = ImGui::SaveIniSettingsToMemory();
ImGui::LoadIniSettingsFromMemory(ini_data);

// Detect when settings need saving (useful for custom persistence)
if (io.WantSaveIniSettings)
{
    const char* data = ImGui::SaveIniSettingsToMemory();
    // Save 'data' to your custom storage
    io.WantSaveIniSettings = false;
}
```

### 4.24 Item Queries

After any widget call, you can query its state:

```cpp
ImGui::InputFloat("Value", &val);

// Hover and focus
bool hovered   = ImGui::IsItemHovered();          // Mouse is over it
bool focused   = ImGui::IsItemFocused();           // Has keyboard focus
bool active    = ImGui::IsItemActive();            // Being interacted with (held, editing)

// Interaction events
bool clicked   = ImGui::IsItemClicked();           // Was clicked this frame
bool edited    = ImGui::IsItemEdited();            // Value was changed this frame
bool activated = ImGui::IsItemActivated();         // Became active this frame
bool deacted   = ImGui::IsItemDeactivated();       // Stopped being active this frame
bool deact_edit = ImGui::IsItemDeactivatedAfterEdit(); // Stopped being active AND value changed

// Useful for commit-on-deactivate patterns (undo/redo):
ImGui::DragFloat("Position", &pos);
if (ImGui::IsItemActivated())
    undo_stack.push(pos);           // Save old value when editing starts
if (ImGui::IsItemDeactivatedAfterEdit())
    redo_stack.clear();             // Commit when editing ends with a change
```

#### Input Dispatch

```cpp
// Check if Dear ImGui wants to capture input (critical for game/app integration):
ImGuiIO& io = ImGui::GetIO();

if (io.WantCaptureMouse)
{
    // Dear ImGui is using the mouse — do NOT pass mouse events to your game
}
if (io.WantCaptureKeyboard)
{
    // Dear ImGui is using the keyboard — do NOT pass key events to your game
}
```

---

## 5. Common Tasks

### 5.1 Build a Property Editor

**Goal:** Display and edit properties of a selected object in a two-column layout.

**Steps:**

```cpp
void DrawPropertyEditor(GameObject* obj)
{
    if (!obj) return;

    ImGui::Text("Editing: %s", obj->name.c_str());
    ImGui::Separator();

    if (ImGui::BeginTable("properties", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersInnerV))
    {
        ImGui::TableSetupColumn("Property", ImGuiTableColumnFlags_WidthFixed, 150.0f);
        ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch);

        // Transform section
        ImGui::TableNextRow();
        ImGui::TableSetColumnIndex(0); ImGui::Text("Position");
        ImGui::TableSetColumnIndex(1);
        ImGui::SetNextItemWidth(-FLT_MIN);
        ImGui::DragFloat3("##pos", &obj->position.x, 0.1f);

        ImGui::TableNextRow();
        ImGui::TableSetColumnIndex(0); ImGui::Text("Rotation");
        ImGui::TableSetColumnIndex(1);
        ImGui::SetNextItemWidth(-FLT_MIN);
        ImGui::DragFloat3("##rot", &obj->rotation.x, 1.0f);

        ImGui::TableNextRow();
        ImGui::TableSetColumnIndex(0); ImGui::Text("Scale");
        ImGui::TableSetColumnIndex(1);
        ImGui::SetNextItemWidth(-FLT_MIN);
        ImGui::DragFloat3("##scale", &obj->scale.x, 0.01f, 0.01f, 100.0f);

        ImGui::TableNextRow();
        ImGui::TableSetColumnIndex(0); ImGui::Text("Visible");
        ImGui::TableSetColumnIndex(1);
        ImGui::Checkbox("##visible", &obj->visible);

        ImGui::TableNextRow();
        ImGui::TableSetColumnIndex(0); ImGui::Text("Color");
        ImGui::TableSetColumnIndex(1);
        ImGui::SetNextItemWidth(-FLT_MIN);
        ImGui::ColorEdit4("##color", &obj->color.x);

        ImGui::EndTable();
    }
}
```

**Verify:** Run the property editor, change values, confirm they apply to the object in real time.

**If it fails:** Check that `PushID`/`PopID` scopes are correct if multiple objects share property names. The `##` prefix on labels avoids duplicate IDs within the table.

### 5.2 Create a Dockable Tool Window with Menu Bar

**Goal:** A standalone tool window with its own menu bar.

```cpp
static bool show_tool = true;

void DrawToolWindow()
{
    if (!show_tool) return;

    ImGui::Begin("Asset Browser", &show_tool, ImGuiWindowFlags_MenuBar);

    if (ImGui::BeginMenuBar())
    {
        if (ImGui::BeginMenu("View"))
        {
            static bool show_thumbnails = true;
            ImGui::MenuItem("Thumbnails", nullptr, &show_thumbnails);
            static bool show_details = false;
            ImGui::MenuItem("Details", nullptr, &show_details);
            ImGui::EndMenu();
        }
        if (ImGui::BeginMenu("Sort"))
        {
            if (ImGui::MenuItem("By Name"))  { /* sort */ }
            if (ImGui::MenuItem("By Date"))  { /* sort */ }
            if (ImGui::MenuItem("By Size"))  { /* sort */ }
            ImGui::EndMenu();
        }
        ImGui::EndMenuBar();
    }

    // Content
    static char filter[128] = "";
    ImGui::InputTextWithHint("##filter", "Filter assets...", filter, sizeof(filter));

    ImGui::BeginChild("AssetList", ImVec2(0, 0), ImGuiChildFlags_Borders);
    for (int i = 0; i < asset_count; i++)
    {
        if (filter[0] && !strstr(assets[i].name, filter))
            continue;
        ImGui::Selectable(assets[i].name);
    }
    ImGui::EndChild();

    ImGui::End();
}
```

### 5.3 Add a File Browser Dialog

**Goal:** Let the user pick a file path using Dear ImGui widgets.

```cpp
struct FileBrowser
{
    char current_path[512] = ".";
    char selected_file[256] = "";
    bool is_open = false;

    void Draw()
    {
        if (!is_open) return;
        ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
        if (ImGui::BeginPopupModal("Select File", &is_open))
        {
            ImGui::InputText("Path", current_path, sizeof(current_path));
            ImGui::Separator();

            ImGui::BeginChild("FileList", ImVec2(0, -ImGui::GetFrameHeightWithSpacing()));
            // List directory contents here using your OS API
            // For each entry:
            //   if (ImGui::Selectable(entry_name, is_selected))
            //       strncpy(selected_file, entry_name, sizeof(selected_file));
            ImGui::EndChild();

            if (ImGui::Button("Open", ImVec2(120, 0)))
            {
                // Process selected_file
                ImGui::CloseCurrentPopup();
            }
            ImGui::SameLine();
            if (ImGui::Button("Cancel", ImVec2(120, 0)))
            {
                selected_file[0] = '\0';
                ImGui::CloseCurrentPopup();
            }
            ImGui::EndPopup();
        }
    }

    void Open() { is_open = true; ImGui::OpenPopup("Select File"); }
};
```

### 5.4 Implement Undo/Redo with IsItemDeactivatedAfterEdit

**Goal:** Track value changes for undo/redo with proper commit semantics.

```cpp
struct UndoEntry { float old_value; float new_value; };
std::vector<UndoEntry> undo_stack;
int undo_index = -1;

static float value = 0.0f;
static float value_before_edit = 0.0f;

ImGui::DragFloat("Value", &value, 0.01f);

if (ImGui::IsItemActivated())
{
    value_before_edit = value;  // Snapshot before editing begins
}
if (ImGui::IsItemDeactivatedAfterEdit())
{
    // Editing ended and value changed — commit to undo stack
    undo_stack.resize(undo_index + 1);  // Truncate any redo entries
    undo_stack.push_back({ value_before_edit, value });
    undo_index = (int)undo_stack.size() - 1;
}

// Undo
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_Z) && undo_index >= 0)
{
    value = undo_stack[undo_index].old_value;
    undo_index--;
}
// Redo
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_Y) && undo_index < (int)undo_stack.size() - 1)
{
    undo_index++;
    value = undo_stack[undo_index].new_value;
}
```

### 5.5 Create a Log/Console Window with Filtering

**Goal:** Scrollable, filterable log display with auto-scroll.

```cpp
struct AppLog
{
    ImGuiTextBuffer buf;
    ImGuiTextFilter filter;
    ImVector<int>   line_offsets;
    bool            auto_scroll = true;

    void Clear() { buf.clear(); line_offsets.clear(); line_offsets.push_back(0); }

    void AddLog(const char* fmt, ...)
    {
        int old_size = buf.size();
        va_list args;
        va_start(args, fmt);
        buf.appendfv(fmt, args);
        va_end(args);
        for (int i = old_size; i < buf.size(); i++)
            if (buf[i] == '\n')
                line_offsets.push_back(i + 1);
    }

    void Draw(const char* title, bool* p_open = nullptr)
    {
        ImGui::Begin(title, p_open);

        // Options
        ImGui::Checkbox("Auto-scroll", &auto_scroll);
        ImGui::SameLine();
        if (ImGui::Button("Clear")) Clear();
        ImGui::SameLine();
        filter.Draw("Filter", -100.0f);
        ImGui::Separator();

        // Log content
        ImGui::BeginChild("scrolling", ImVec2(0, 0), ImGuiChildFlags_None,
                          ImGuiWindowFlags_HorizontalScrollbar);

        const char* buf_begin = buf.begin();
        const char* buf_end = buf.end();

        if (filter.IsActive())
        {
            for (int i = 0; i < line_offsets.Size - 1; i++)
            {
                const char* line_start = buf_begin + line_offsets[i];
                const char* line_end = (i + 1 < line_offsets.Size)
                    ? buf_begin + line_offsets[i + 1] - 1 : buf_end;
                if (filter.PassFilter(line_start, line_end))
                    ImGui::TextUnformatted(line_start, line_end);
            }
        }
        else
        {
            // Use clipper for large logs
            ImGuiListClipper clipper;
            clipper.Begin(line_offsets.Size - 1);
            while (clipper.Step())
            {
                for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
                {
                    const char* line_start = buf_begin + line_offsets[i];
                    const char* line_end = (i + 1 < line_offsets.Size)
                        ? buf_begin + line_offsets[i + 1] - 1 : buf_end;
                    ImGui::TextUnformatted(line_start, line_end);
                }
            }
            clipper.End();
        }

        if (auto_scroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
            ImGui::SetScrollHereY(1.0f);

        ImGui::EndChild();
        ImGui::End();
    }
};
```

### 5.6 Build a Color Theme Editor

**Goal:** Interactive theme editor that exports code.

```cpp
void DrawThemeEditor()
{
    ImGuiStyle& style = ImGui::GetStyle();

    // Preset buttons
    if (ImGui::Button("Dark"))    ImGui::StyleColorsDark();
    ImGui::SameLine();
    if (ImGui::Button("Light"))   ImGui::StyleColorsLight();
    ImGui::SameLine();
    if (ImGui::Button("Classic")) ImGui::StyleColorsClassic();

    ImGui::Separator();

    // Sizes
    ImGui::SliderFloat("Window Rounding", &style.WindowRounding, 0.0f, 12.0f);
    ImGui::SliderFloat("Frame Rounding", &style.FrameRounding, 0.0f, 12.0f);
    ImGui::SliderFloat2("Window Padding", (float*)&style.WindowPadding, 0.0f, 20.0f);
    ImGui::SliderFloat2("Frame Padding", (float*)&style.FramePadding, 0.0f, 20.0f);

    ImGui::Separator();

    // Colors
    if (ImGui::BeginChild("Colors", ImVec2(0, 0), ImGuiChildFlags_Borders))
    {
        for (int i = 0; i < ImGuiCol_COUNT; i++)
        {
            const char* name = ImGui::GetStyleColorName(i);
            ImGui::PushID(i);
            ImGui::ColorEdit4("##color", (float*)&style.Colors[i],
                            ImGuiColorEditFlags_AlphaBar);
            ImGui::SameLine();
            ImGui::TextUnformatted(name);
            ImGui::PopID();
        }
    }
    ImGui::EndChild();

    // Export button
    if (ImGui::Button("Export to Clipboard"))
    {
        ImGui::LogToClipboard();
        ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;\n");
        for (int i = 0; i < ImGuiCol_COUNT; i++)
        {
            const ImVec4& c = style.Colors[i];
            ImGui::LogText("colors[ImGuiCol_%s] = ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);\n",
                          ImGui::GetStyleColorName(i), c.x, c.y, c.z, c.w);
        }
        ImGui::LogFinish();
    }
}
```

### 5.7 Display an Image/Texture from Your Application

**Goal:** Load and display a texture (OpenGL example).

```cpp
// Step 1: Create texture using your graphics API
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
             GL_RGBA, GL_UNSIGNED_BYTE, pixels);

// Step 2: Display in Dear ImGui
ImGui::Begin("Image Viewer");
ImGui::Image((ImTextureID)(intptr_t)texture, ImVec2((float)width, (float)height));

// With UV coordinates (display a sub-region):
ImGui::Image((ImTextureID)(intptr_t)texture,
             ImVec2(128, 128),       // display size
             ImVec2(0.0f, 0.0f),     // UV top-left
             ImVec2(0.5f, 0.5f));    // UV bottom-right
ImGui::End();
```

### 5.8 Create a Sortable Data Table

**Goal:** Display tabular data with clickable column headers for sorting.

```cpp
struct Employee { int id; const char* name; float salary; };
static Employee employees[] = {
    {1, "Alice", 75000}, {2, "Bob", 82000}, {3, "Carol", 91000},
    {4, "Dave", 68000},  {5, "Eve", 95000}
};

void DrawEmployeeTable()
{
    ImGuiTableFlags flags = ImGuiTableFlags_Sortable | ImGuiTableFlags_Resizable
                          | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders
                          | ImGuiTableFlags_ScrollY;

    if (ImGui::BeginTable("employees", 3, flags, ImVec2(0, 300)))
    {
        ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort);
        ImGui::TableSetupColumn("Name");
        ImGui::TableSetupColumn("Salary", ImGuiTableColumnFlags_PreferSortDescending);
        ImGui::TableSetupScrollFreeze(0, 1);
        ImGui::TableHeadersRow();

        if (ImGuiTableSortSpecs* specs = ImGui::TableGetSortSpecs())
        {
            if (specs->SpecsDirty)
            {
                auto& s = specs->Specs[0];
                std::sort(std::begin(employees), std::end(employees),
                    [&](const Employee& a, const Employee& b) {
                        int cmp = 0;
                        switch (s.ColumnIndex) {
                            case 0: cmp = a.id - b.id; break;
                            case 1: cmp = strcmp(a.name, b.name); break;
                            case 2: cmp = (a.salary > b.salary) ? 1 : -1; break;
                        }
                        return (s.SortDirection == ImGuiSortDirection_Ascending) ? cmp < 0 : cmp > 0;
                    });
                specs->SpecsDirty = false;
            }
        }

        for (auto& e : employees)
        {
            ImGui::TableNextRow();
            ImGui::TableSetColumnIndex(0); ImGui::Text("%d", e.id);
            ImGui::TableSetColumnIndex(1); ImGui::Text("%s", e.name);
            ImGui::TableSetColumnIndex(2); ImGui::Text("$%.0f", e.salary);
        }
        ImGui::EndTable();
    }
}
```

### 5.9 Implement Keyboard Shortcuts

**Goal:** Add application-wide and widget-specific keyboard shortcuts.

```cpp
// Global shortcuts (evaluated every frame)
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_N)) NewDocument();
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_O)) OpenDocument();
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_S)) SaveDocument();

// Widget-bound shortcut (activates the button via keyboard)
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_Z);
if (ImGui::Button("Undo")) Undo();

ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_Y);
if (ImGui::Button("Redo")) Redo();

// Menu items with shortcut display
if (ImGui::BeginMainMenuBar())
{
    if (ImGui::BeginMenu("File"))
    {
        if (ImGui::MenuItem("New", "Ctrl+N"))  NewDocument();
        if (ImGui::MenuItem("Open", "Ctrl+O")) OpenDocument();
        if (ImGui::MenuItem("Save", "Ctrl+S")) SaveDocument();
        ImGui::EndMenu();
    }
    ImGui::EndMainMenuBar();
}
```

### 5.10 Create a Search/Filter Widget

**Goal:** Filterable list using ImGuiTextFilter.

```cpp
static ImGuiTextFilter filter;
filter.Draw("Search", -100.0f);

ImGui::Separator();

const char* items[] = { "Apple", "Banana", "Cherry", "Date", "Elderberry", "Fig" };
for (int i = 0; i < IM_ARRAYSIZE(items); i++)
{
    if (filter.PassFilter(items[i]))
        ImGui::BulletText("%s", items[i]);
}
```

`ImGuiTextFilter` supports comma-separated include terms and `-` prefix for exclusion (e.g., `apple,banana,-rotten`).

### 5.11 Build a Tree View with Drag-and-Drop

**Goal:** Hierarchical tree where items can be rearranged via drag-and-drop.

```cpp
struct TreeNode { const char* name; int id; std::vector<TreeNode> children; };

void DrawTreeNode(TreeNode& node)
{
    ImGui::PushID(node.id);

    ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow
                             | ImGuiTreeNodeFlags_SpanAvailWidth;
    if (node.children.empty())
        flags |= ImGuiTreeNodeFlags_Leaf;

    bool open = ImGui::TreeNodeEx(node.name, flags);

    // Drag source
    if (ImGui::BeginDragDropSource())
    {
        ImGui::SetDragDropPayload("TREE_NODE", &node.id, sizeof(int));
        ImGui::Text("Move: %s", node.name);
        ImGui::EndDragDropSource();
    }

    // Drop target
    if (ImGui::BeginDragDropTarget())
    {
        if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("TREE_NODE"))
        {
            int dropped_id = *(const int*)payload->Data;
            // Reparent the node with dropped_id under this node
        }
        ImGui::EndDragDropTarget();
    }

    if (open)
    {
        for (auto& child : node.children)
            DrawTreeNode(child);
        ImGui::TreePop();
    }
    ImGui::PopID();
}
```

### 5.12 Create a Right-Click Context Menu

**Goal:** Show a context menu when right-clicking items in a list.

```cpp
for (int i = 0; i < item_count; i++)
{
    ImGui::PushID(i);
    ImGui::Selectable(items[i], selected == i);

    if (ImGui::BeginPopupContextItem())
    {
        ImGui::Text("Actions for: %s", items[i]);
        ImGui::Separator();
        if (ImGui::MenuItem("Rename")) { /* start rename */ }
        if (ImGui::MenuItem("Duplicate")) { /* duplicate item */ }
        ImGui::Separator();
        if (ImGui::MenuItem("Delete")) { /* delete item */ }
        ImGui::EndPopup();
    }
    ImGui::PopID();
}
```

### 5.13 Modal Confirmation Dialog

**Goal:** Block all other interaction until the user confirms or cancels.

```cpp
// Trigger
static bool pending_delete = false;
if (ImGui::Button("Delete All"))
{
    pending_delete = true;
    ImGui::OpenPopup("Confirm Deletion");
}

// Modal
if (ImGui::BeginPopupModal("Confirm Deletion", nullptr,
                           ImGuiWindowFlags_AlwaysAutoResize))
{
    ImGui::Text("This will permanently delete all items.");
    ImGui::Text("This action cannot be undone.");
    ImGui::Separator();

    if (ImGui::Button("Delete", ImVec2(120, 0)))
    {
        // Perform deletion
        pending_delete = false;
        ImGui::CloseCurrentPopup();
    }
    ImGui::SameLine();
    if (ImGui::Button("Cancel", ImVec2(120, 0)))
    {
        pending_delete = false;
        ImGui::CloseCurrentPopup();
    }
    ImGui::EndPopup();
}
```

### 5.14 Build a Node Editor Canvas (Using ImDrawList)

**Goal:** Draggable nodes connected by curves on a scrollable canvas.

```cpp
struct Node { int id; ImVec2 pos; const char* name; };

void DrawNodeEditor(std::vector<Node>& nodes)
{
    ImGui::Begin("Node Editor");
    ImDrawList* draw_list = ImGui::GetWindowDrawList();
    ImVec2 canvas_pos = ImGui::GetCursorScreenPos();
    ImVec2 canvas_size = ImGui::GetContentRegionAvail();

    // Canvas background
    draw_list->AddRectFilled(canvas_pos,
        ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y),
        IM_COL32(40, 40, 40, 255));

    // Grid
    float grid_step = 32.0f;
    for (float x = 0; x < canvas_size.x; x += grid_step)
        draw_list->AddLine(ImVec2(canvas_pos.x + x, canvas_pos.y),
                           ImVec2(canvas_pos.x + x, canvas_pos.y + canvas_size.y),
                           IM_COL32(200, 200, 200, 40));
    for (float y = 0; y < canvas_size.y; y += grid_step)
        draw_list->AddLine(ImVec2(canvas_pos.x, canvas_pos.y + y),
                           ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + y),
                           IM_COL32(200, 200, 200, 40));

    // Draw nodes
    for (auto& node : nodes)
    {
        ImGui::PushID(node.id);
        ImVec2 node_pos = ImVec2(canvas_pos.x + node.pos.x, canvas_pos.y + node.pos.y);
        ImVec2 node_size = ImVec2(120, 60);

        // Node box
        draw_list->AddRectFilled(node_pos,
            ImVec2(node_pos.x + node_size.x, node_pos.y + node_size.y),
            IM_COL32(60, 60, 60, 255), 4.0f);
        draw_list->AddRect(node_pos,
            ImVec2(node_pos.x + node_size.x, node_pos.y + node_size.y),
            IM_COL32(100, 100, 100, 255), 4.0f);
        draw_list->AddText(ImVec2(node_pos.x + 8, node_pos.y + 8),
                          IM_COL32(255, 255, 255, 255), node.name);

        // Invisible button for dragging
        ImGui::SetCursorScreenPos(node_pos);
        ImGui::InvisibleButton("node", node_size);
        if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0))
        {
            node.pos.x += ImGui::GetIO().MouseDelta.x;
            node.pos.y += ImGui::GetIO().MouseDelta.y;
        }
        ImGui::PopID();
    }

    // Draw connections (Bezier curves between nodes)
    // draw_list->AddBezierCubic(start, cp1, cp2, end, color, thickness);

    ImGui::End();
}
```

### 5.15 Create a Multi-Select List

**Goal:** List with Ctrl+click, Shift+click, and range selection.

```cpp
static ImGuiSelectionBasicStorage selection;
const char* items[] = { "Item A", "Item B", "Item C", "Item D", "Item E",
                        "Item F", "Item G", "Item H", "Item I", "Item J" };
int item_count = IM_ARRAYSIZE(items);

ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape
                            | ImGuiMultiSelectFlags_BoxSelect1d;
ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, item_count);
selection.ApplyRequests(ms_io);

for (int i = 0; i < item_count; i++)
{
    ImGui::SetNextItemSelectionUserData(i);
    bool is_selected = selection.Contains((ImGuiID)i);
    ImGui::Selectable(items[i], is_selected);
}

ms_io = ImGui::EndMultiSelect();
selection.ApplyRequests(ms_io);

ImGui::Text("Selected: %d items", selection.Size);
```

### 5.16 Load Custom Fonts with Specific Glyph Ranges

**Goal:** Display Chinese and icon glyphs alongside Latin text.

```cpp
ImGuiIO& io = ImGui::GetIO();

// Primary font (Latin)
ImFont* font_main = io.Fonts->AddFontFromFileTTF("fonts/Roboto-Regular.ttf", 16.0f);

// Chinese font merged into primary
ImFontConfig cfg;
cfg.MergeMode = true;
io.Fonts->AddFontFromFileTTF("fonts/NotoSansSC-Regular.ttf", 16.0f,
    &cfg, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());

// Icon font merged into primary
cfg.GlyphMinAdvanceX = 16.0f;
static const ImWchar icon_ranges[] = { 0xf000, 0xf3ff, 0 };
io.Fonts->AddFontFromFileTTF("fonts/FontAwesome5.ttf", 16.0f, &cfg, icon_ranges);

// Build atlas
io.Fonts->Build();
// Upload atlas texture to GPU (backend-specific)
```

### 5.17 Create a Toolbar with Image Buttons

**Goal:** Horizontal toolbar with icon buttons.

```cpp
void DrawToolbar(ImTextureID icons_texture)
{
    ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4, 4));
    ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 2));

    ImVec2 btn_size(24, 24);
    float icon_w = 1.0f / 8.0f;  // 8 icons in texture atlas

    // Each button uses a different UV region of the icon atlas
    if (ImGui::ImageButton("##new",  icons_texture, btn_size, ImVec2(0,0), ImVec2(icon_w,1)))
        NewFile();
    ImGui::SameLine();
    if (ImGui::ImageButton("##open", icons_texture, btn_size, ImVec2(icon_w,0), ImVec2(icon_w*2,1)))
        OpenFile();
    ImGui::SameLine();
    if (ImGui::ImageButton("##save", icons_texture, btn_size, ImVec2(icon_w*2,0), ImVec2(icon_w*3,1)))
        SaveFile();

    ImGui::SameLine();
    ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
    ImGui::SameLine();

    if (ImGui::ImageButton("##undo", icons_texture, btn_size, ImVec2(icon_w*3,0), ImVec2(icon_w*4,1)))
        Undo();
    ImGui::SameLine();
    if (ImGui::ImageButton("##redo", icons_texture, btn_size, ImVec2(icon_w*4,0), ImVec2(icon_w*5,1)))
        Redo();

    ImGui::PopStyleVar(2);
}
```

### 5.18 Build a Status Bar

**Goal:** Fixed-height bar at the bottom of a window showing status information.

```cpp
void DrawStatusBar()
{
    // Reserve space at the bottom
    float status_height = ImGui::GetFrameHeightWithSpacing();
    ImVec2 window_size = ImGui::GetWindowSize();

    ImGui::SetCursorPosY(window_size.y - status_height - ImGui::GetStyle().WindowPadding.y);
    ImGui::Separator();

    ImGui::Text("Ready");
    ImGui::SameLine(200);
    ImGui::Text("Line: %d, Col: %d", cursor_line, cursor_col);
    ImGui::SameLine(400);
    ImGui::Text("FPS: %.1f", ImGui::GetIO().Framerate);
}
```

### 5.19 Implement Value Editing with DragFloat

**Goal:** Precise value editing with variable-speed dragging.

```cpp
static float position[3] = {0, 0, 0};
static float rotation = 0.0f;
static float scale = 1.0f;

// Speed parameter controls sensitivity
ImGui::DragFloat3("Position", position, 0.1f);         // 0.1 units per pixel
ImGui::DragFloat("Rotation", &rotation, 1.0f, 0, 360, "%.1f deg");  // 1 degree per pixel
ImGui::DragFloat("Scale", &scale, 0.01f, 0.01f, 100.0f, "%.2fx");   // Clamped range

// Format string controls display
ImGui::DragFloat("Speed", &speed, 0.1f, 0.0f, FLT_MAX, "%.1f m/s");
ImGui::DragFloat("Opacity", &opacity, 0.005f, 0.0f, 1.0f, "%.0f%%",
                 ImGuiSliderFlags_AlwaysClamp);

// Integer drag
static int count = 10;
ImGui::DragInt("Count", &count, 1, 0, 1000);

// Range drag (two values)
static float range[2] = {20.0f, 80.0f};
ImGui::DragFloatRange2("Range", &range[0], &range[1], 0.5f, 0.0f, 100.0f);
```

### 5.20 Create Animated Widgets Using GetTime()

**Goal:** Widgets that animate smoothly using Dear ImGui's built-in time.

```cpp
// Pulsing button
float pulse = 0.5f + 0.5f * sinf((float)ImGui::GetTime() * 3.0f);
ImGui::PushStyleColor(ImGuiCol_Button,
    ImVec4(pulse * 0.8f, 0.2f, 0.2f, 1.0f));
ImGui::Button("Alert!", ImVec2(100, 40));
ImGui::PopStyleColor();

// Animated progress bar
float progress = fmodf((float)ImGui::GetTime() * 0.3f, 1.0f);
ImGui::ProgressBar(progress, ImVec2(0, 0), "Loading...");

// Spinning indicator using ImDrawList
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 center = ImGui::GetCursorScreenPos();
center.x += 20; center.y += 20;
float radius = 15.0f;
float t = (float)ImGui::GetTime();
int segments = 12;
for (int i = 0; i < segments; i++)
{
    float a = (float)i / segments * IM_PI * 2.0f + t * 4.0f;
    float alpha = (float)i / segments;
    draw_list->AddCircleFilled(
        ImVec2(center.x + cosf(a) * radius, center.y + sinf(a) * radius),
        3.0f, IM_COL32(255, 255, 255, (int)(alpha * 255)));
}
ImGui::Dummy(ImVec2(40, 40));  // Reserve space

// Smooth scrolling
static float target_scroll = 0.0f;
static float current_scroll = 0.0f;
current_scroll += (target_scroll - current_scroll) * ImGui::GetIO().DeltaTime * 10.0f;
```

### 5.21 Custom Widget Background Colors

**Goal:** Highlight table rows or widget backgrounds conditionally.

```cpp
if (ImGui::BeginTable("colored_table", 3, ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders))
{
    for (int row = 0; row < 10; row++)
    {
        ImGui::TableNextRow();

        // Highlight rows conditionally
        if (data[row].has_error)
            ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, IM_COL32(255, 0, 0, 50));
        else if (data[row].is_selected)
            ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, IM_COL32(0, 120, 255, 50));

        ImGui::TableSetColumnIndex(0); ImGui::Text("%d", row);
        ImGui::TableSetColumnIndex(1); ImGui::Text("%s", data[row].name);
        ImGui::TableSetColumnIndex(2); ImGui::Text("%.2f", data[row].value);
    }
    ImGui::EndTable();
}
```

### 5.22 Using ImGuiListClipper for Large Lists

**Goal:** Efficiently render lists with thousands of items.

```cpp
ImGui::BeginChild("LargeList", ImVec2(0, 400));
ImGuiListClipper clipper;
clipper.Begin(100000);  // 100,000 items
while (clipper.Step())
{
    for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
    {
        ImGui::Text("Item %d: data here", i);
    }
}
clipper.End();
ImGui::EndChild();
```

The clipper calculates which items are visible and only calls your code for those items, making even million-item lists performant.

---

## 6. Troubleshooting

### Error: `Assertion failed: thickness > 0.0f`

**Cause:** A draw call (e.g., `AddLine`, `AddRect`, `AddCircle`) was given a zero or negative thickness value.

**Solution:**
1. Search your code for draw calls passing `0.0f` as the thickness parameter.
2. Ensure thickness variables are initialized to a positive value.
3. If thickness comes from user input, clamp it: `ImMax(thickness, 1.0f)`.

**Prevention:** Always validate draw parameters before passing them. Use a minimum thickness of `1.0f` for visible lines.

---

### Error: `Assertion failed: g.CurrentWindow != NULL`

**Cause:** You called a widget function (e.g., `ImGui::Text()`, `ImGui::Button()`) outside of a `Begin()`/`End()` block, or after calling `End()` without a matching `Begin()`.

**Solution:**
1. Ensure every widget call is between a `Begin()`/`End()` pair.
2. Check for early returns that skip the `End()` call.
3. Never call widget functions before `NewFrame()` or after `Render()`.

**Prevention:** Structure your code so `End()` is always called — even when `Begin()` returns false:
```cpp
if (ImGui::Begin("Window")) { /* widgets */ }
ImGui::End();  // Always called
```

---

### Error: `Assertion failed: (flags & ImGuiWindowFlags_NoInputs) == 0`

**Cause:** Attempted to focus or interact with a window that has `ImGuiWindowFlags_NoInputs` set.

**Solution:**
1. Remove `ImGuiWindowFlags_NoInputs` if the window needs interaction.
2. If using `NoInputs` intentionally (overlay windows), ensure no code tries to focus or interact with it.

**Prevention:** Only use `NoInputs` for purely visual overlay windows.

---

### Error: Duplicate widget IDs causing interaction failures

**Cause:** Two or more widgets in the same scope share the same label, producing the same ID. Only the first widget receives interactions.

**Solution:**
1. Add unique suffixes with `##`: `Button("Delete##item1")`, `Button("Delete##item2")`.
2. Use `PushID(i)` / `PopID()` in loops.
3. Use the ID Stack Debugger: `ImGui::ShowIDStackToolWindow()` to inspect active IDs.

**Prevention:** Use `##` or `PushID` whenever creating widgets in a loop or with repeated labels. This is the most common beginner mistake.

---

### Error: `WantCaptureMouse` not preventing game input

**Cause:** The application is not checking `io.WantCaptureMouse` / `io.WantCaptureKeyboard` before dispatching input to the game layer.

**Solution:**
1. After `ImGui::NewFrame()`, check the flags before processing input:
```cpp
if (!io.WantCaptureMouse)
{
    // Process mouse for game
}
if (!io.WantCaptureKeyboard)
{
    // Process keyboard for game
}
```
2. Ensure you are checking the flags **after** `NewFrame()`, not before.

**Prevention:** Always gate your application's input handling behind these flags.

---

### Error: Font atlas texture fails to build

**Cause:** The combined size of all fonts exceeds the maximum texture dimensions, or a font file path is incorrect.

**Solution:**
1. Verify font file paths exist and are readable.
2. Reduce the number of glyph ranges or fonts.
3. Increase atlas size: `io.Fonts->TexDesiredWidth = 4096;`
4. Check return value of `AddFontFromFileTTF()` — it returns `nullptr` on failure.

**Prevention:** Build the font atlas early in initialization and check the return values. Use `GetGlyphRangesChineseSimplifiedCommon()` instead of `GetGlyphRangesChineseFull()` when full CJK is not needed.

---

### Error: Linker errors — undefined reference to `ImGui::*`

**Cause:** The imgui `.cpp` files are not compiled and linked into your application.

**Solution:**
1. Ensure all four core files are in your build: `imgui.cpp`, `imgui_draw.cpp`, `imgui_tables.cpp`, `imgui_widgets.cpp`.
2. Ensure backend `.cpp` files are also compiled: `imgui_impl_<platform>.cpp` and `imgui_impl_<renderer>.cpp`.
3. If using a static library, ensure it was built with the same `imconfig.h`.

**Prevention:** Add all required `.cpp` files to your build system at setup time.

---

### Error: `Assertion failed: g.FrameCount > 0` or `NewFrame not called`

**Cause:** You called `Render()` or widget functions without first calling `NewFrame()`, or called `NewFrame()` twice without an intervening `Render()`.

**Solution:**
1. Ensure every frame follows the pattern: `NewFrame()` → widgets → `Render()`.
2. Check that backend `_NewFrame()` calls happen before `ImGui::NewFrame()`.

**Prevention:** Use the standard frame structure from the example applications.

---

### Error: Window positions reset every launch

**Cause:** The `.ini` file is not being saved or loaded. Common causes: `IniFilename` set to `nullptr`, working directory changes between runs, file permissions.

**Solution:**
1. Check `io.IniFilename` is set (default is `"imgui.ini"`).
2. Verify the working directory is consistent.
3. Use an absolute path: `io.IniFilename = "C:/myapp/imgui.ini";`
4. If using manual persistence, call `SaveIniSettingsToDisk()` before destroying the context.

**Prevention:** Set `IniFilename` to an absolute path in a known-writable directory.

---

### Error: DLL boundary crashes when using Dear ImGui across DLL boundaries

**Cause:** Each DLL gets its own copy of Dear ImGui's global state (`GImGui`). Widgets called from a DLL use a different context than the main application.

**Solution:**
1. Use `ImGui::SetCurrentContext()` at the start of DLL functions to set the context created by the host application.
2. Pass the context pointer from the host to the DLL via an initialization function.
3. Alternatively, configure `IMGUI_API` to export/import symbols so all code shares one copy.

**Prevention:** Design your architecture so all Dear ImGui calls share a single context. Pass the `ImGuiContext*` across DLL boundaries.

---

### Error: Text renders as rectangles or question marks

**Cause:** The requested glyphs are not in the font atlas. The default font only covers Basic Latin (U+0020–U+00FF).

**Solution:**
1. Load a font with the required glyph ranges: `AddFontFromFileTTF("font.ttf", size, nullptr, io.Fonts->GetGlyphRangesJapanese())`.
2. For custom ranges, build an `ImWchar` array: `{ 0x4e00, 0x9fff, 0 }`.
3. Merge icon fonts using `ImFontConfig::MergeMode = true`.

**Prevention:** Plan your glyph requirements at initialization time. Test with the target language immediately.

---

### Error: Colors look wrong (swapped red and blue channels)

**Cause:** Your renderer expects BGRA color packing but Dear ImGui outputs RGBA by default (or vice versa).

**Solution:**
1. Define `IMGUI_USE_BGRA_PACKED_COLOR` in `imconfig.h` if your renderer expects BGRA.
2. Alternatively, swap channels in your pixel shader.

**Prevention:** Check your renderer's expected color format and configure `imconfig.h` accordingly.

---

### Error: `Assertion failed: draw_list->CmdBuffer.Size > 0` or empty draw data

**Cause:** `Render()` was called without any `Begin()`/`End()` pairs, or the Dear ImGui context is not properly initialized.

**Solution:**
1. Ensure at least one window exists (even an empty one) before rendering.
2. Check that `CreateContext()` was called before any other Dear ImGui function.
3. Verify the backend initialization order: platform init → renderer init → main loop.

**Prevention:** Follow the initialization order from the example applications.

---

### Error: `ImGui::TableNextRow() called without calling ImGui::TableNextColumn()`

**Cause:** Incorrect table traversal pattern — you must call `TableNextColumn()` or `TableSetColumnIndex()` after `TableNextRow()` before emitting content.

**Solution:**
```cpp
// Correct pattern:
ImGui::TableNextRow();
ImGui::TableNextColumn();  // Move to column 0
ImGui::Text("Content");
```

**Prevention:** Use either the `TableNextRow()` + `TableSetColumnIndex()` pattern or the simpler `TableNextColumn()` flow consistently.

---

### Error: Scrollbar appears but content is not scrollable

**Cause:** The `BeginChild()` region has no height limit, so the child auto-sizes to fit content and never needs scrolling.

**Solution:**
1. Specify an explicit height: `BeginChild("list", ImVec2(0, 300))`.
2. Or use `ImGui::BeginChild("list", ImVec2(0, -ImGui::GetFrameHeightWithSpacing()))` to fill remaining space minus a footer.

**Prevention:** Always specify a height for scrollable child regions.

---

### Error: `Assertion failed: user_callback != NULL` in ImDrawCmd

**Cause:** A draw command has a user callback set but the function pointer is null or invalid. This can happen with corrupted draw lists.

**Solution:**
1. If using custom draw callbacks, ensure the callback pointer is valid for the lifetime of the frame.
2. Check for memory corruption in your draw list manipulation code.

**Prevention:** Only use `AddCallback()` when necessary, and ensure callbacks survive until `Render()` completes.

---

### Error: Mouse cursor is offset or in the wrong position

**Cause:** Display scaling (HiDPI), multiple monitors with different DPIs, or incorrect `io.DisplayFramebufferScale`.

**Solution:**
1. Ensure `io.DisplaySize` matches your window's client area in screen coordinates.
2. Set `io.DisplayFramebufferScale` to the ratio of framebuffer pixels to screen coordinates (typically 2.0 on Retina displays).
3. Use the backend's built-in handling (most backends handle this automatically).

**Prevention:** Use the platform backend's DPI handling. Check `ImGui_ImplXxx_NewFrame()` in your backend for DPI-related code.

---

### Error: Widgets stop responding after a popup is closed unexpectedly

**Cause:** A popup was opened but never properly closed (e.g., the code path that calls `EndPopup()` was skipped).

**Solution:**
1. Ensure `EndPopup()` is always called when `BeginPopup()` / `BeginPopupModal()` returns true.
2. Check for early returns between `BeginPopup()` and `EndPopup()`.

**Prevention:** Structure popup code as:
```cpp
if (ImGui::BeginPopup("name"))
{
    // All code here
    ImGui::EndPopup();
}
```
Never place returns or conditionals between `BeginPopup` and `EndPopup`.

---

### Error: Table column widths reset unexpectedly

**Cause:** The table ID changed between frames (dynamic label, different scope), or `.ini` settings are not being persisted.

**Solution:**
1. Use a stable string ID for `BeginTable()`.
2. If the table is in a loop, use `PushID()` to create a stable scope.
3. Check that `io.IniFilename` is set and writable.

**Prevention:** Use fixed table identifiers and ensure `.ini` persistence is working.

---

### Error: `ImGui::Shortcut()` does not trigger

**Cause:** Another window or widget has focus and is consuming the key. Or `ImGuiConfigFlags_NavEnableKeyboard` is not set.

**Solution:**
1. Enable keyboard navigation: `io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard`.
2. Use `ImGuiInputFlags_RouteGlobal` if you want the shortcut to fire regardless of focus:
   `ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_S, ImGuiInputFlags_RouteGlobal)`.

**Prevention:** Plan your shortcut routing strategy. Use route flags to control priority.

---

### Error: `Assertion failed: "Mismatched Begin/End calls"` or stack mismatch

**Cause:** A `Begin*` call (e.g., `BeginChild`, `BeginGroup`, `BeginTable`, `BeginMenu`, `PushStyleColor`) does not have a matching `End*` / `Pop*` call, or vice versa.

**Solution:**
1. Use the Metrics/Debug window (`ShowMetricsWindow()`) — it displays the active stack and highlights mismatches.
2. Search your code for all `Begin*` / `Push*` calls and verify matching `End*` / `Pop*` calls.
3. Pay attention to conditional logic — if `BeginChild()` is inside an `if`, `EndChild()` must be in the same `if` block.

**Prevention:** Keep `Begin*`/`End*` pairs at the same indentation level and in the same scope. Never conditionally skip an `End*` call.

---

### Error: `IMGUI_CHECKVERSION()` assertion fails

**Cause:** The Dear ImGui version compiled into your application does not match the version compiled into a library or DLL you are linking against. This typically means mismatched headers and `.cpp` files.

**Solution:**
1. Ensure all translation units use the same version of Dear ImGui headers.
2. If using a precompiled library, rebuild it with the same `imgui.h` as your application.

**Prevention:** Always compile Dear ImGui from source as part of your project rather than using prebuilt binaries.

---

### Error: `AddFontFromFileTTF` returns nullptr

**Cause:** The font file path is invalid, the file cannot be read, or memory allocation failed.

**Solution:**
1. Verify the file exists at the specified path.
2. Use an absolute path or verify the working directory.
3. On mobile platforms, ensure the font is bundled in the app's assets.
4. Check that `ImFileOpen` works for your platform (override via `IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS` if needed).

**Prevention:** Check the return value of `AddFontFromFileTTF()`. Log the attempted path if it fails.

---

### Error: Draw list generates too many vertices (overflow with 16-bit indices)

**Cause:** A single draw call generated more than 65,535 vertices, which exceeds the range of `ImDrawIdx` (default `unsigned short`).

**Solution:**
1. Define `ImDrawIdx` as `unsigned int` in `imconfig.h` for 32-bit indices.
2. Or reduce the complexity of your drawing (fewer segments in circles, fewer items per draw list).

**Prevention:** For complex applications with lots of drawing, use 32-bit indices from the start: `#define ImDrawIdx unsigned int` in `imconfig.h`.

---

## 7. FAQ

### General

**Q: Which version should I use — master or docking branch?**
The `master` branch is the stable, mainline version. The `docking` branch adds multi-window docking and multi-viewport support but is experimental. For new projects, start with `master`. If you specifically need window docking (tabbing windows together like an IDE), use the `docking` branch and be prepared for occasional API changes.

**Q: How do I integrate Dear ImGui into my existing application?**
Add the source files to your project, pick a platform+renderer backend from `backends/`, and call the initialization functions once. In your main loop, add the three-phase pattern: `NewFrame()` → widget calls → `Render()` + backend draw. Dear ImGui does not take over your main loop or event handling — you keep full control. See the `examples/` folder for complete working integrations.

**Q: Is Dear ImGui thread-safe?**
No. All Dear ImGui calls must happen on the same thread. The library uses global state (`GImGui`) that is not protected by locks. If you need to update the UI from another thread, collect the data on that thread and read it on the main thread during UI rendering.

**Q: Can I use Dear ImGui with language X?**
Dear ImGui is a C++ library, but there are third-party bindings for many languages: Python (`pyimgui`, `imgui-bundle`), C# (`ImGui.NET`), Rust (`imgui-rs`), Go, Java, Lua, and others. The C binding (`cimgui`) enables integration with most languages that support C FFI. See the Wiki for a list of bindings.

**Q: How do I handle high-DPI / Retina displays?**
Load fonts at the appropriate size for the display (e.g., 2x the normal size for a 2x Retina display), and set `io.FontGlobalScale` if you want to uniformly scale all text. Most backends handle `io.DisplayFramebufferScale` automatically. With the new dynamic font sizing in 1.92, you can load a single vector font and render it at any size, which simplifies DPI handling.

**Q: Does Dear ImGui support Unicode?**
Yes. Dear ImGui uses UTF-8 for all text. The default font covers Basic Latin. For other scripts (CJK, Cyrillic, Thai, etc.), load a font with the appropriate glyph ranges. Define `IMGUI_USE_WCHAR32` for characters outside the Basic Multilingual Plane (above U+FFFF).

**Q: What is the performance overhead of Dear ImGui?**
Minimal. Dear ImGui generates vertex buffers and draw commands, which are very fast to produce. The GPU cost is typically negligible compared to your application's own rendering. The main cost is the `Render()` call, which flattens the draw lists. For large UIs with thousands of items, use `ImGuiListClipper` to cull off-screen items.

### Windows

**Q: How do I make a window that fills the entire screen?**
```cpp
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->WorkPos);
ImGui::SetNextWindowSize(viewport->WorkSize);
ImGui::Begin("Fullscreen", nullptr,
    ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove
    | ImGuiWindowFlags_NoBringToFrontOnFocus);
// Content...
ImGui::End();
```

**Q: How do I create a window that cannot be closed?**
Do not pass a `p_open` pointer (second parameter) to `Begin()`. Without it, no close button is shown.

**Q: How do I prevent a window from being moved or resized?**
Use `ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize`.

**Q: How can I have a window with no title bar?**
Use `ImGuiWindowFlags_NoTitleBar`. The window still needs a unique string name for identification — this name is used as the ID, not displayed.

### Widgets

**Q: Why is my widget not reacting when I click on it?**
Most likely a duplicate ID conflict. Two widgets with the same label in the same scope will share an ID, and only the first one receives interactions. Use `##unique_suffix` to differentiate or `PushID()` in loops. Use `ShowIDStackToolWindow()` to debug.

**Q: How can I have widgets with empty labels?**
Use `##` with a unique ID: `ImGui::Button("##hidden_button")`. The label is empty but the ID is derived from `"hidden_button"`. You can also use `""` as a label, but then you must ensure uniqueness via `PushID()`.

**Q: How can I have multiple widgets with the same visible label?**
Use the `##` separator: `ImGui::Button("OK##dialog1")` and `ImGui::Button("OK##dialog2")` both display "OK" but have different IDs.

**Q: How do I make a button that fills the available width?**
```cpp
ImGui::SetNextItemWidth(-FLT_MIN);
// or for buttons specifically:
if (ImGui::Button("Full Width", ImVec2(-FLT_MIN, 0))) { }
```

**Q: How do I change a widget's color temporarily?**
```cpp
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.1f, 0.1f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.9f, 0.2f, 0.2f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 0.1f, 0.1f, 1.0f));
ImGui::Button("Red Button");
ImGui::PopStyleColor(3);
```

**Q: How do I get the text height for layout calculations?**
Use `ImGui::GetTextLineHeight()` for a single line or `ImGui::GetTextLineHeightWithSpacing()` for a line including the spacing between lines.

### Input

**Q: How do I dispatch inputs between Dear ImGui and my application?**
Check `io.WantCaptureMouse` and `io.WantCaptureKeyboard` after `NewFrame()`. When they are `true`, Dear ImGui needs the input — do not pass it to your application. When `false`, Dear ImGui does not need it.

**Q: How do I handle text input (character input) correctly?**
Use `io.AddInputCharacter()` or `io.AddInputCharactersUTF8()` for text input. Do not convert key presses to characters yourself — that misses dead keys, IME, and system-specific text input. Most backends handle this automatically.

**Q: How does navigation (keyboard/gamepad) work?**
Enable it with `io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard`. Then Arrow keys move between widgets, Enter activates, Escape cancels/closes. Tab cycles through input fields. Ctrl+Tab switches between windows. The system works automatically with all standard widgets.

**Q: Can I detect when a slider value has been committed (not just changed)?**
Yes. Use `IsItemDeactivatedAfterEdit()` — it returns true on the frame the user releases the slider (or confirms input), and only if the value changed during the interaction.

### Fonts

**Q: How do I load a custom font?**
```cpp
ImGuiIO& io = ImGui::GetIO();
ImFont* font = io.Fonts->AddFontFromFileTTF("my_font.ttf", 18.0f);
// In your frame loop, to use it:
ImGui::PushFont(font, 18.0f);
ImGui::Text("Custom font text");
ImGui::PopFont();
```

**Q: How do I display an icon font alongside text?**
Load the icon font with `MergeMode = true` so it merges into the previous font. Then use the icon's Unicode codepoint inline: `ImGui::Text("Save " ICON_FA_SAVE)` (where `ICON_FA_SAVE` is a define for the Unicode codepoint string like `"\xef\x83\x87"`).

**Q: Why is my font blurry?**
Bitmap fonts look best at their native size. If you need crisp text at various sizes, use the new vector font support (`AddFontDefaultVector()` or `PushFont(font, size)`) or enable FreeType with `IMGUI_ENABLE_FREETYPE`. Also ensure `io.FontGlobalScale` is 1.0 and that you are loading fonts at the correct size for your display DPI.

**Q: How do I use the new dynamic font sizing (1.92)?**
Load a font without specifying a pixel size (or with 0), then use `PushFont(font, desired_size)` and `PopFont()` at render time. This allows a single font to be drawn at different sizes without reloading.

### Performance

**Q: How do I render a large scrollable list efficiently?**
Use `ImGuiListClipper` to skip off-screen items:
```cpp
ImGuiListClipper clipper;
clipper.Begin(10000);
while (clipper.Step())
    for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
        ImGui::Text("Item %d", i);
```
Without the clipper, Dear ImGui would process all 10,000 items even if only 20 are visible.

**Q: Is there a limit to how many widgets I can have per frame?**
No hard limit. Practically, thousands of visible widgets per frame is fine. For tens of thousands of items, use `ImGuiListClipper` or virtual scrolling. The CPU cost is proportional to the number of visible widgets, not the total data size.

**Q: How do I reduce Dear ImGui's draw call count?**
Dear ImGui automatically batches draw calls by texture. To minimize draw calls: avoid switching fonts/textures frequently, merge icon fonts into your text font, and use a single texture atlas. The Metrics window (`ShowMetricsWindow()`) shows draw call counts per window.

### Integration

**Q: How do I display a texture/image from my application?**
Create the texture using your graphics API, then pass its identifier as `ImTextureID` to `ImGui::Image()`. The exact cast depends on your backend (see section 4.11). The texture must remain valid until `Render()` completes.

**Q: How do I add Dear ImGui to a project that uses CMake?**
Add the source files directly — there is no `CMakeLists.txt` provided by Dear ImGui (by design). Create your own `add_library(imgui STATIC ...)` or add the files to your executable's source list. Add the `imgui/` and `imgui/backends/` directories to your include path.

**Q: How do I render Dear ImGui on top of my 3D scene?**
Dear ImGui's render output (`ImGui::GetDrawData()`) is just a list of draw commands with vertex buffers. Render it after your 3D scene in your main render pass. Most backends handle this automatically — you just call `ImGui_ImplXxx_RenderDrawData(ImGui::GetDrawData())` at the end of your frame.

**Q: Can I use Dear ImGui without a window/display (headless)?**
Yes. Use the Null backend (`example_null/`). This is useful for testing, generating screenshots from a CI pipeline, or running the test engine.

### Building

**Q: Do I need CMake to build Dear ImGui?**
No. Dear ImGui has no build system of its own. Add the `.cpp` files to whatever build system you use. It works with Visual Studio, Make, CMake, Meson, Premake, Xcode, Ninja, or any build tool that can compile C++.

**Q: I get linker errors about undefined ImGui symbols. What am I missing?**
You need to compile and link all four core files: `imgui.cpp`, `imgui_draw.cpp`, `imgui_tables.cpp`, `imgui_widgets.cpp`. Also compile the backend files you are using. If you added the headers but not the source files, you will get linker errors.

**Q: How do I compile Dear ImGui as a DLL/shared library?**
Define `IMGUI_API` as `__declspec(dllexport)` when building the DLL and `__declspec(dllimport)` when consuming it. Use the same `imconfig.h` for both. Pass `ImGuiContext*` across the DLL boundary using `ImGui::SetCurrentContext()`.

**Q: What compiler warnings should I expect?**
Dear ImGui compiles cleanly with most compilers at high warning levels. If you use `-Wall -Wextra` (GCC/Clang) or `/W4` (MSVC), you may see a few warnings in the STB headers — these are safe to suppress with pragmas or by excluding them from high-warning-level builds.

---

_Generated May 2026 from ocornut/imgui at bda4982. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
