From d7598aa84fa0b803c3548d0982dc9af5ee2c4301 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 15 Jan 2026 16:07:07 +0100 Subject: [PATCH 01/22] Backends: SDL2, SDL3: changed GetClipboardText() handler to return NULL on error aka clipboard contents is not text. (#9168) Consistent with other backends. --- backends/imgui_impl_sdl2.cpp | 6 +++++- backends/imgui_impl_sdl3.cpp | 6 +++++- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 3 ++- imgui.h | 2 +- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 371b1dac4..2049f117b 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-01-15: Changed GetClipboardText() handler to return nullptr on error aka clipboard contents is not text. Consistent with other backends. (#9168) // 2025-09-24: Skip using the SDL_GetGlobalMouseState() state when one of our window is hovered, as the SDL_MOUSEMOTION data is reliable. Fix macOS notch mouse coordinates issue in fullscreen mode + better perf on X11. (#7919, #7786) // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. // 2025-09-15: Content Scales are always reported as 1.0 on Wayland. (#8921) @@ -178,7 +179,10 @@ static const char* ImGui_ImplSDL2_GetClipboardText(ImGuiContext*) ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); if (bd->ClipboardTextData) SDL_free(bd->ClipboardTextData); - bd->ClipboardTextData = SDL_GetClipboardText(); + if (SDL_HasClipboardText()) + bd->ClipboardTextData = SDL_GetClipboardText(); + else + bd->ClipboardTextData = nullptr; return bd->ClipboardTextData; } diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index ffd9f8a59..a1a3eeb86 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-01-15: Changed GetClipboardText() handler to return nullptr on error aka clipboard contents is not text. Consistent with other backends. (#9168) // 2025-11-05: Fixed an issue with missing characters events when an already active text field changes viewports. (#9054) // 2025-10-22: Fixed Platform_OpenInShellFn() return value (unused in core). // 2025-09-24: Skip using the SDL_GetGlobalMouseState() state when one of our window is hovered, as the SDL_EVENT_MOUSE_MOTION data is reliable. Fix macOS notch mouse coordinates issue in fullscreen mode + better perf on X11. (#7919, #7786) @@ -151,7 +152,10 @@ static const char* ImGui_ImplSDL3_GetClipboardText(ImGuiContext*) ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); if (bd->ClipboardTextData) SDL_free(bd->ClipboardTextData); - bd->ClipboardTextData = SDL_GetClipboardText(); + if (SDL_HasClipboardText()) + bd->ClipboardTextData = SDL_GetClipboardText(); + else + bd->ClipboardTextData = nullptr; return bd->ClipboardTextData; } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6de32507b..61798aa86 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -195,6 +195,8 @@ Other Changes: forcefully disable either. (#9109, #9116) - OpenGL3: Fixed embedded loader multiple init/shutdown cycles broken on some platforms. (#8792, #9112) + - SDL2, SDL3: changed GetClipboardText() handler to return NULL on error aka + clipboard contents is not text. Consistent with other backends. (#9168) - SDL_GPU3: macOS version can use MSL shaders in order to support macOS 10.14+ (vs Metallib shaders requiring macOS 14+). Requires application calling SDL_CreateGPUDevice() with SDL_GPU_SHADERFORMAT_MSL. (#9076) [@Niminem] diff --git a/imgui.cpp b/imgui.cpp index 105041d18..4743838c3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5091,10 +5091,11 @@ void ImGui::DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr } } +// A conformant backend should return NULL on failure (e.g. clipboard data is not text). const char* ImGui::GetClipboardText() { ImGuiContext& g = *GImGui; - return g.PlatformIO.Platform_GetClipboardTextFn ? g.PlatformIO.Platform_GetClipboardTextFn(&g) : ""; + return g.PlatformIO.Platform_GetClipboardTextFn ? g.PlatformIO.Platform_GetClipboardTextFn(&g) : NULL; } void ImGui::SetClipboardText(const char* text) diff --git a/imgui.h b/imgui.h index 33c642b00..448221dce 100644 --- a/imgui.h +++ b/imgui.h @@ -3956,7 +3956,7 @@ struct ImGuiPlatformIO // Optional: Access OS clipboard // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) - const char* (*Platform_GetClipboardTextFn)(ImGuiContext* ctx); + const char* (*Platform_GetClipboardTextFn)(ImGuiContext* ctx); // Should return NULL on failure (e.g. clipboard data is not text). void (*Platform_SetClipboardTextFn)(ImGuiContext* ctx, const char* text); void* Platform_ClipboardUserData; From 21d3299e588b5c702dcca0f448b4f937af369b4a Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 15 Jan 2026 16:08:40 +0100 Subject: [PATCH 02/22] Backends: fixed reappearing uses to NULL to favor nullptr. --- backends/imgui_impl_allegro5.cpp | 2 +- backends/imgui_impl_allegro5.h | 2 +- backends/imgui_impl_dx10.h | 2 +- backends/imgui_impl_dx11.h | 2 +- backends/imgui_impl_dx12.cpp | 2 +- backends/imgui_impl_dx12.h | 2 +- backends/imgui_impl_dx9.h | 2 +- backends/imgui_impl_glfw.cpp | 4 ++-- backends/imgui_impl_metal.h | 4 ++-- backends/imgui_impl_opengl2.h | 2 +- backends/imgui_impl_opengl3.cpp | 2 +- backends/imgui_impl_opengl3.h | 2 +- backends/imgui_impl_sdl2.cpp | 2 +- backends/imgui_impl_sdl3.cpp | 4 ++-- backends/imgui_impl_sdlgpu3.h | 2 +- backends/imgui_impl_sdlrenderer2.h | 2 +- backends/imgui_impl_sdlrenderer3.h | 2 +- backends/imgui_impl_vulkan.cpp | 2 +- backends/imgui_impl_vulkan.h | 2 +- backends/imgui_impl_wgpu.h | 2 +- 20 files changed, 23 insertions(+), 23 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index bb6660d88..6ee88a184 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -524,7 +524,7 @@ void ImGui_ImplAllegro5_SetDisplay(ALLEGRO_DISPLAY* display) if (bd->VertexDecl) { al_destroy_vertex_decl(bd->VertexDecl); - bd->VertexDecl = NULL; + bd->VertexDecl = nullptr; } if (bd->Display && !bd->VertexDecl) diff --git a/backends/imgui_impl_allegro5.h b/backends/imgui_impl_allegro5.h index 622430432..135c4ff8a 100644 --- a/backends/imgui_impl_allegro5.h +++ b/backends/imgui_impl_allegro5.h @@ -38,7 +38,7 @@ IMGUI_IMPL_API void ImGui_ImplAllegro5_SetDisplay(ALLEGRO_DISPLAY* display); IMGUI_IMPL_API bool ImGui_ImplAllegro5_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplAllegro5_InvalidateDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplAllegro5_UpdateTexture(ImTextureData* tex); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_dx10.h b/backends/imgui_impl_dx10.h index 38ecbdfe3..9d7fb68ae 100644 --- a/backends/imgui_impl_dx10.h +++ b/backends/imgui_impl_dx10.h @@ -32,7 +32,7 @@ IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplDX10_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks. diff --git a/backends/imgui_impl_dx11.h b/backends/imgui_impl_dx11.h index c120bf093..1df4f3695 100644 --- a/backends/imgui_impl_dx11.h +++ b/backends/imgui_impl_dx11.h @@ -34,7 +34,7 @@ IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplDX11_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks. diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 14c0fc60f..056d23a6c 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -875,7 +875,7 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) init_info = &bd->InitInfo; bd->pd3dDevice = init_info->Device; - IM_ASSERT(init_info->CommandQueue != NULL); + IM_ASSERT(init_info->CommandQueue != nullptr); bd->pCommandQueue = init_info->CommandQueue; bd->RTVFormat = init_info->RTVFormat; bd->DSVFormat = init_info->DSVFormat; diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index 3bb66c1fb..8d61dae77 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -64,7 +64,7 @@ IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks. diff --git a/backends/imgui_impl_dx9.h b/backends/imgui_impl_dx9.h index 600f0a750..021439b9a 100644 --- a/backends/imgui_impl_dx9.h +++ b/backends/imgui_impl_dx9.h @@ -31,7 +31,7 @@ IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplDX9_UpdateTexture(ImTextureData* tex); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 82c512fee..f166b45d2 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -251,10 +251,10 @@ static bool ImGui_ImplGlfw_IsWayland() return glfwGetPlatform() == GLFW_PLATFORM_WAYLAND; #else const char* version = glfwGetVersionString(); - if (strstr(version, "Wayland") == NULL) // e.g. Ubuntu 22.04 ships with GLFW 3.3.6 compiled without Wayland + if (strstr(version, "Wayland") == nullptr) // e.g. Ubuntu 22.04 ships with GLFW 3.3.6 compiled without Wayland return false; #ifdef GLFW_EXPOSE_NATIVE_X11 - if (glfwGetX11Display() != NULL) + if (glfwGetX11Display() != nullptr) return false; #endif return true; diff --git a/backends/imgui_impl_metal.h b/backends/imgui_impl_metal.h index 2a9a26a02..8af2c8b6b 100644 --- a/backends/imgui_impl_metal.h +++ b/backends/imgui_impl_metal.h @@ -39,7 +39,7 @@ IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id device); IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex); #endif @@ -67,7 +67,7 @@ IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device); IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex); #endif diff --git a/backends/imgui_impl_opengl2.h b/backends/imgui_impl_opengl2.h index 014a03aca..65b0fe0b4 100644 --- a/backends/imgui_impl_opengl2.h +++ b/backends/imgui_impl_opengl2.h @@ -37,7 +37,7 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 133b0ed27..6348b01b0 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -41,7 +41,7 @@ // 2023-05-09: OpenGL: Support for glBindSampler() backup/restore on ES3. (#6375) // 2023-04-18: OpenGL: Restore front and back polygon mode separately when supported by context. (#6333) // 2023-03-23: OpenGL: Properly restoring "no shader program bound" if it was the case prior to running the rendering function. (#6267, #6220, #6224) -// 2023-03-15: OpenGL: Fixed GL loader crash when GL_VERSION returns NULL. (#6154, #4445, #3530) +// 2023-03-15: OpenGL: Fixed GL loader crash when GL_VERSION returns nullptr. (#6154, #4445, #3530) // 2023-03-06: OpenGL: Fixed restoration of a potentially deleted OpenGL program, by calling glIsProgram(). (#6220, #6224) // 2022-11-09: OpenGL: Reverted use of glBufferSubData(), too many corruptions issues + old issues seemingly can't be reproed with Intel drivers nowadays (revert 2021-12-15 and 2022-05-23 changes). // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. diff --git a/backends/imgui_impl_opengl3.h b/backends/imgui_impl_opengl3.h index b72b5c887..aabe04b07 100644 --- a/backends/imgui_impl_opengl3.h +++ b/backends/imgui_impl_opengl3.h @@ -40,7 +40,7 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex); // Configuration flags to add in your imconfig file: diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 2049f117b..4fb9c4d99 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -684,7 +684,7 @@ static void ImGui_ImplSDL2_UpdateMouseData() // Note that SDL_GetGlobalMouseState() is in theory slow on X11, but this only runs on rather specific cases. If a problem we may provide a way to opt-out this feature. SDL_Window* hovered_window = SDL_GetMouseFocus(); const bool is_relative_mouse_mode = SDL_GetRelativeMouseMode() != 0; - if (hovered_window == NULL && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) + if (hovered_window == nullptr && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) { // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) int mouse_x, mouse_y; diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index a1a3eeb86..f8bacc51b 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -191,7 +191,7 @@ static void ImGui_ImplSDL3_UpdateIme() SDL_StopTextInput(bd->ImeWindow); bd->ImeWindow = nullptr; } - if ((!bd->ImeDirty && bd->ImeWindow == window) || (window == NULL)) + if ((!bd->ImeDirty && bd->ImeWindow == window) || (window == nullptr)) return; // Start/update current input @@ -663,7 +663,7 @@ static void ImGui_ImplSDL3_UpdateMouseData() // Note that SDL_GetGlobalMouseState() is in theory slow on X11, but this only runs on rather specific cases. If a problem we may provide a way to opt-out this feature. SDL_Window* hovered_window = SDL_GetMouseFocus(); const bool is_relative_mouse_mode = SDL_GetWindowRelativeMouseMode(bd->Window); - if (hovered_window == NULL && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) + if (hovered_window == nullptr && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) { // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) float mouse_x, mouse_y; diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h index cde9c5fe7..12b6528f3 100644 --- a/backends/imgui_impl_sdlgpu3.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -48,7 +48,7 @@ IMGUI_IMPL_API void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, IMGUI_IMPL_API void ImGui_ImplSDLGPU3_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplSDLGPU3_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks. diff --git a/backends/imgui_impl_sdlrenderer2.h b/backends/imgui_impl_sdlrenderer2.h index a62e60927..860e95507 100644 --- a/backends/imgui_impl_sdlrenderer2.h +++ b/backends/imgui_impl_sdlrenderer2.h @@ -39,7 +39,7 @@ IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_d IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks. diff --git a/backends/imgui_impl_sdlrenderer3.h b/backends/imgui_impl_sdlrenderer3.h index 618cc2430..f5f53b9d2 100644 --- a/backends/imgui_impl_sdlrenderer3.h +++ b/backends/imgui_impl_sdlrenderer3.h @@ -39,7 +39,7 @@ IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_d IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_DestroyDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks. diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index f01d2145d..8f4bd5a62 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -1156,7 +1156,7 @@ void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_ImplVulkan_PipelineInfo* pi #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING VkPipelineRenderingCreateInfoKHR* pipeline_rendering_create_info = &pipeline_info->PipelineRenderingCreateInfo; - if (v->UseDynamicRendering && pipeline_rendering_create_info->pColorAttachmentFormats != NULL) + if (v->UseDynamicRendering && pipeline_rendering_create_info->pColorAttachmentFormats != nullptr) { // Deep copy buffer to reduce error-rate for end user (#8282) ImVector formats; diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 0ebe1d42d..4ad33b8f3 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -142,7 +142,7 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_i // Else, the pipeline can be created, or re-created, using ImGui_ImplVulkan_CreateMainPipeline() before rendering. IMGUI_IMPL_API void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_ImplVulkan_PipelineInfo* info); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex); // Register a texture (VkDescriptorSet == ImTextureID) diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index f17fe6c25..7ab3dd31f 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -72,7 +72,7 @@ IMGUI_IMPL_API void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURen IMGUI_IMPL_API bool ImGui_ImplWGPU_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplWGPU_InvalidateDeviceObjects(); -// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplWGPU_UpdateTexture(ImTextureData* tex); // [BETA] Selected render state data shared with callbacks. From 5dde06b32759faf1da252426688b8a04a1d6df61 Mon Sep 17 00:00:00 2001 From: E Date: Sun, 18 Jan 2026 17:45:38 -0500 Subject: [PATCH 03/22] Docs: fixed 'Tearaway' link in credits section (#9176) --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index c1b413629..a2d140734 100644 --- a/docs/README.md +++ b/docs/README.md @@ -209,7 +209,7 @@ Dear ImGui is using software and services provided free of charge for open sourc Credits ------- -Developed by [Omar Cornut](https://www.miracleworld.net) and every direct or indirect [contributors](https://github.com/ocornut/imgui/graphs/contributors) to the GitHub. The early version of this library was developed with the support of [Media Molecule](https://www.mediamolecule.com) and first used internally on the game [Tearaway](https://tearaway.mediamolecule.com) (PS Vita). +Developed by [Omar Cornut](https://www.miracleworld.net) and every direct or indirect [contributors](https://github.com/ocornut/imgui/graphs/contributors) to the GitHub. The early version of this library was developed with the support of [Media Molecule](https://www.mediamolecule.com) and first used internally on the game [Tearaway](https://youtu.be/w0oxBviRGlU) (PS Vita). Recurring contributors include Rokas Kupstys [@rokups](https://github.com/rokups) (2020-2022): a good portion of work on automation system and regression tests now available in [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine). From 14dfd5bf6ba3b555fd79b0d42ef714f0c3d40aab Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Jan 2026 11:42:08 +0100 Subject: [PATCH 04/22] Examples: DX12: update to VS2019 so it supports WIndows SDK 10.0 simplified versioning. --- .../example_win32_directx12.vcxproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/example_win32_directx12/example_win32_directx12.vcxproj b/examples/example_win32_directx12/example_win32_directx12.vcxproj index bb98c4141..c4b81e76f 100644 --- a/examples/example_win32_directx12/example_win32_directx12.vcxproj +++ b/examples/example_win32_directx12/example_win32_directx12.vcxproj @@ -21,34 +21,34 @@ {b4cf9797-519d-4afe-a8f4-5141a6b521d3} example_win32_directx12 - 10.0.20348.0 + 10.0 Application true Unicode - v140 + v142 Application true Unicode - v140 + v142 Application false true Unicode - v140 + v142 Application false true Unicode - v140 + v142 From ea122de913e087f77d68672a8810dee1960e2ea2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Jan 2026 11:49:11 +0100 Subject: [PATCH 05/22] Error handling: Improve error handling and recovery for TableSetupColumn(). --- docs/CHANGELOG.txt | 1 + imgui_tables.cpp | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 61798aa86..6dd87e848 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -184,6 +184,7 @@ Other Changes: activated by SetNextItemShortcut(). (#9138) - Error Handling: - Improve error handling and recovery for EndMenu()/EndCombo(). (#1651, #9165, #8499) + - Improve error handling and recovery for TableSetupColumn(). - Debug Tools: - Debug Log: fixed incorrectly printing characters in IO log when submitting non-ASCII values to io.AddInputCharacter(). (#9099) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index af97b2e96..f5048e505 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1606,11 +1606,11 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); return; } - IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!"); + IM_ASSERT(table->IsLayoutLocked == false && "TableSetupColumn(): need to call before first row!"); IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()"); if (table->DeclColumnsCount >= table->ColumnsCount) { - IM_ASSERT_USER_ERROR(table->DeclColumnsCount < table->ColumnsCount, "Called TableSetupColumn() too many times!"); + IM_ASSERT_USER_ERROR(table->DeclColumnsCount < table->ColumnsCount, "TableSetupColumn(): called too many times!"); return; } @@ -1620,7 +1620,10 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo // Assert when passing a width or weight if policy is entirely left to default, to avoid storing width into weight and vice-versa. // Give a grace to users of ImGuiTableFlags_ScrollX. if (table->IsDefaultSizingPolicy && (flags & ImGuiTableColumnFlags_WidthMask_) == 0 && (flags & ImGuiTableFlags_ScrollX) == 0) - IM_ASSERT(init_width_or_weight <= 0.0f && "Can only specify width/weight if sizing policy is set explicitly in either Table or Column."); + { + IM_ASSERT_USER_ERROR(init_width_or_weight <= 0.0f, "TableSetupColumn(): can only specify width/weight if sizing policy is set explicitly in either Table or Column."); + return; + } // When passing a width automatically enforce WidthFixed policy // (whereas TableSetupColumnFlags would default to WidthAuto if table is not resizable) From 12223cc3e93fec65ef3b7ca3627bb125b23ddaa1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Jan 2026 12:04:43 +0100 Subject: [PATCH 06/22] Error handling: rework macros, add IM_ASSERT_USER_ERROR_RET(), IM_ASSERT_USER_ERROR_RETV() to simplify code. --- imgui.cpp | 72 ++++++++--------------------------------------- imgui_internal.h | 4 ++- imgui_tables.cpp | 70 +++++++++------------------------------------ imgui_widgets.cpp | 47 ++++++------------------------- 4 files changed, 36 insertions(+), 157 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 4743838c3..151a17308 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3635,11 +3635,7 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { ImGuiContext& g = *GImGui; const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 1) - { - IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); - return; - } + IM_ASSERT_USER_ERROR_RET(var_info->DataType == ImGuiDataType_Float && var_info->Count == 1, "Calling PushStyleVar() variant with wrong type!"); float* pvar = (float*)var_info->GetVarPtr(&g.Style); g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); *pvar = val; @@ -3649,11 +3645,7 @@ void ImGui::PushStyleVarX(ImGuiStyleVar idx, float val_x) { ImGuiContext& g = *GImGui; const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 2) - { - IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); - return; - } + IM_ASSERT_USER_ERROR_RET(var_info->DataType == ImGuiDataType_Float && var_info->Count == 2, "Calling PushStyleVar() variant with wrong type!"); ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); pvar->x = val_x; @@ -3663,11 +3655,7 @@ void ImGui::PushStyleVarY(ImGuiStyleVar idx, float val_y) { ImGuiContext& g = *GImGui; const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 2) - { - IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); - return; - } + IM_ASSERT_USER_ERROR_RET(var_info->DataType == ImGuiDataType_Float && var_info->Count == 2, "Calling PushStyleVar() variant with wrong type!"); ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); pvar->y = val_y; @@ -3677,11 +3665,7 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { ImGuiContext& g = *GImGui; const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 2) - { - IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); - return; - } + IM_ASSERT_USER_ERROR_RET(var_info->DataType == ImGuiDataType_Float && var_info->Count == 2, "Calling PushStyleVar() variant with wrong type!"); ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); *pvar = val; @@ -5941,11 +5925,7 @@ void ImGui::EndFrame() // Don't process EndFrame() multiple times. if (g.FrameCountEnded == g.FrameCount) return; - if (!g.WithinFrameScope) - { - IM_ASSERT_USER_ERROR(g.WithinFrameScope, "Forgot to call ImGui::NewFrame()?"); - return; - } + IM_ASSERT_USER_ERROR_RET(g.WithinFrameScope, "Forgot to call ImGui::NewFrame()?"); CallContextHooks(&g, ImGuiContextHookType_EndFramePre); @@ -8221,11 +8201,7 @@ void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) void ImGui::PopItemFlag() { ImGuiContext& g = *GImGui; - if (g.ItemFlagsStack.Size <= 1) - { - IM_ASSERT_USER_ERROR(0, "Calling PopItemFlag() too many times!"); - return; - } + IM_ASSERT_USER_ERROR_RET(g.ItemFlagsStack.Size > 1, "Calling PopItemFlag() too many times!"); g.ItemFlagsStack.pop_back(); g.CurrentItemFlags = g.ItemFlagsStack.back(); } @@ -8255,11 +8231,7 @@ void ImGui::BeginDisabled(bool disabled) void ImGui::EndDisabled() { ImGuiContext& g = *GImGui; - if (g.DisabledStackSize <= 0) - { - IM_ASSERT_USER_ERROR(0, "Calling EndDisabled() too many times!"); - return; - } + IM_ASSERT_USER_ERROR_RET(g.DisabledStackSize > 0, "Calling EndDisabled() too many times!"); g.DisabledStackSize--; bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; //PopItemFlag(); @@ -8306,11 +8278,7 @@ void ImGui::PopTextWrapPos() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - if (window->DC.TextWrapPosStack.Size <= 0) - { - IM_ASSERT_USER_ERROR(0, "Calling PopTextWrapPos() too many times!"); - return; - } + IM_ASSERT_USER_ERROR_RET(window->DC.TextWrapPosStack.Size > 0, "Calling PopTextWrapPos() too many times!"); window->DC.TextWrapPos = window->DC.TextWrapPosStack.back(); window->DC.TextWrapPosStack.pop_back(); } @@ -8709,11 +8677,7 @@ void ImGui::PushFocusScope(ImGuiID id) void ImGui::PopFocusScope() { ImGuiContext& g = *GImGui; - if (g.FocusScopeStack.Size <= g.StackSizesInBeginForCurrentWindow->SizeOfFocusScopeStack) - { - IM_ASSERT_USER_ERROR(0, "Calling PopFocusScope() too many times!"); - return; - } + IM_ASSERT_USER_ERROR_RET(g.FocusScopeStack.Size > g.StackSizesInBeginForCurrentWindow->SizeOfFocusScopeStack, "Calling PopFocusScope() too many times!"); g.FocusScopeStack.pop_back(); g.CurrentFocusScopeId = g.FocusScopeStack.Size ? g.FocusScopeStack.back().ID : 0; } @@ -9104,11 +9068,7 @@ void ImGui::PushFont(ImFont* font, float font_size_base) void ImGui::PopFont() { ImGuiContext& g = *GImGui; - if (g.FontStack.Size <= 0) - { - IM_ASSERT_USER_ERROR(0, "Calling PopFont() too many times!"); - return; - } + IM_ASSERT_USER_ERROR_RET(g.FontStack.Size > 0, "Calling PopFont() too many times!"); ImFontStackData* font_stack_data = &g.FontStack.back(); SetCurrentFont(font_stack_data->Font, font_stack_data->FontSizeBeforeScaling, font_stack_data->FontSizeAfterScaling); g.FontStack.pop_back(); @@ -9248,11 +9208,7 @@ ImGuiID ImGui::GetIDWithSeed(int n, ImGuiID seed) void ImGui::PopID() { ImGuiWindow* window = GImGui->CurrentWindow; - if (window->IDStack.Size <= 1) - { - IM_ASSERT_USER_ERROR(0, "Calling PopID() too many times!"); - return; - } + IM_ASSERT_USER_ERROR_RET(window->IDStack.Size > 1, "Calling PopID() too many times!"); window->IDStack.pop_back(); } @@ -12457,11 +12413,7 @@ void ImGui::EndPopup() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - if ((window->Flags & ImGuiWindowFlags_Popup) == 0 || g.BeginPopupStack.Size == 0) - { - IM_ASSERT_USER_ERROR(0, "Calling EndPopup() in wrong window!"); - return; - } + IM_ASSERT_USER_ERROR_RET((window->Flags & ImGuiWindowFlags_Popup) != 0 && g.BeginPopupStack.Size > 0, "Calling EndPopup() in wrong window!"); // Make all menus and popups wrap around for now, may need to expose that policy (e.g. focus scope could include wrap/loop policy flags used by new move requests) if (g.NavWindow == window) diff --git a/imgui_internal.h b/imgui_internal.h index 6af67614e..5a1816547 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2056,7 +2056,9 @@ struct ImGuiLocEntry // - See 'Demo->Configuration->Error Handling' and ImGuiIO definitions for details on error handling. // - Read https://github.com/ocornut/imgui/wiki/Error-Handling for details on error handling. #ifndef IM_ASSERT_USER_ERROR -#define IM_ASSERT_USER_ERROR(_EXPR,_MSG) do { if (!(_EXPR) && ImGui::ErrorLog(_MSG)) { IM_ASSERT((_EXPR) && _MSG); } } while (0) // Recoverable User Error +#define IM_ASSERT_USER_ERROR(_EXPR,_MSG) do { if (!(_EXPR)) { if (ImGui::ErrorLog(_MSG)) { IM_ASSERT((_EXPR) && _MSG); } } } while (0) // Recoverable User Error +#define IM_ASSERT_USER_ERROR_RET(_EXPR,_MSG) do { if (!(_EXPR)) { if (ImGui::ErrorLog(_MSG)) { IM_ASSERT((_EXPR) && _MSG); } return; } } while (0) // Recoverable User Error +#define IM_ASSERT_USER_ERROR_RETV(_EXPR,_RETV,_MSG) do { if (!(_EXPR)) { if (ImGui::ErrorLog(_MSG)) { IM_ASSERT((_EXPR) && _MSG); } return _RETV; } } while (0) // Recoverable User Error #endif // The error callback is currently not public, as it is expected that only advanced users will rely on it. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index f5048e505..bb2be7631 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1348,11 +1348,7 @@ void ImGui::EndTable() { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "EndTable() call should only be done while in BeginTable() scope!"); - return; - } + IM_ASSERT_USER_ERROR_RET(table != NULL, "EndTable() call should only be done while in BeginTable() scope!"); // This assert would be very useful to catch a common error... unfortunately it would probably trigger in some // cases, and for consistency user may sometimes output empty tables (and still benefit from e.g. outer border) @@ -1601,18 +1597,10 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); - return; - } - IM_ASSERT(table->IsLayoutLocked == false && "TableSetupColumn(): need to call before first row!"); + IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!"); + IM_ASSERT_USER_ERROR_RET(table->DeclColumnsCount < table->ColumnsCount, "TableSetupColumn(): called too many times!"); + IM_ASSERT_USER_ERROR_RET(table->IsLayoutLocked == false, "TableSetupColumn(): need to call before first row!"); IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()"); - if (table->DeclColumnsCount >= table->ColumnsCount) - { - IM_ASSERT_USER_ERROR(table->DeclColumnsCount < table->ColumnsCount, "TableSetupColumn(): called too many times!"); - return; - } ImGuiTableColumn* column = &table->Columns[table->DeclColumnsCount]; table->DeclColumnsCount++; @@ -1620,10 +1608,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo // Assert when passing a width or weight if policy is entirely left to default, to avoid storing width into weight and vice-versa. // Give a grace to users of ImGuiTableFlags_ScrollX. if (table->IsDefaultSizingPolicy && (flags & ImGuiTableColumnFlags_WidthMask_) == 0 && (flags & ImGuiTableFlags_ScrollX) == 0) - { - IM_ASSERT_USER_ERROR(init_width_or_weight <= 0.0f, "TableSetupColumn(): can only specify width/weight if sizing policy is set explicitly in either Table or Column."); - return; - } + IM_ASSERT_USER_ERROR_RET(init_width_or_weight <= 0.0f, "TableSetupColumn(): can only specify width/weight if sizing policy is set explicitly in either Table or Column."); // When passing a width automatically enforce WidthFixed policy // (whereas TableSetupColumnFlags would default to WidthAuto if table is not resizable) @@ -1665,12 +1650,8 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows) { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); - return; - } - IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!"); + IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!"); + IM_ASSERT(table->IsLayoutLocked == false && "TableSetupColumn(): need to call before first row!"); IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS); IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit @@ -1746,11 +1727,7 @@ void ImGui::TableSetColumnEnabled(int column_n, bool enabled) { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); - return; - } + IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!"); IM_ASSERT(table->Flags & ImGuiTableFlags_Hideable); // See comments above if (column_n < 0) column_n = table->CurrentColumn; @@ -1828,12 +1805,8 @@ void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; + IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!"); IM_ASSERT(target != ImGuiTableBgTarget_None); - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); - return; - } if (color == IM_COL32_DISABLE) color = 0; @@ -2131,11 +2104,7 @@ bool ImGui::TableSetColumnIndex(int column_n) { if (table->CurrentColumn != -1) TableEndCell(table); - if ((column_n >= 0 && column_n < table->ColumnsCount) == false) - { - IM_ASSERT_USER_ERROR(column_n >= 0 && column_n < table->ColumnsCount, "TableSetColumnIndex() invalid column index!"); - return false; - } + IM_ASSERT_USER_ERROR_RETV(column_n >= 0 && column_n < table->ColumnsCount, false, "TableSetColumnIndex() invalid column index!"); TableBeginCell(table, column_n); } @@ -3121,11 +3090,7 @@ void ImGui::TableHeadersRow() { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); - return; - } + IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!"); // Call layout if not already done. This is automatically done by TableNextRow: we do it here _only_ to make // it easier to debug-step in TableUpdateLayout(). Your own version of this function doesn't need this. @@ -3170,12 +3135,7 @@ void ImGui::TableHeader(const char* label) return; ImGuiTable* table = g.CurrentTable; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); - return; - } - + IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!"); IM_ASSERT(table->CurrentColumn != -1); const int column_n = table->CurrentColumn; ImGuiTableColumn* column = &table->Columns[column_n]; @@ -3350,11 +3310,7 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label ImGuiTable* table = g.CurrentTable; ImGuiWindow* window = g.CurrentWindow; ImDrawList* draw_list = window->DrawList; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); - return; - } + IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!"); IM_ASSERT(table->CurrentRow == -1 && "Must be first row"); if (max_label_width == 0.0f) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 0a044a97b..e64c59eac 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2065,10 +2065,7 @@ void ImGui::EndCombo() char name[16]; ImFormatString(name, IM_COUNTOF(name), "##Combo_%02d", g.BeginComboDepth); // FIXME: Move those to helpers? if (strcmp(g.CurrentWindow->Name, name) != 0) - { - IM_ASSERT_USER_ERROR(0, "Calling EndCombo() in wrong window!"); - return; - } + IM_ASSERT_USER_ERROR_RET(0, "Calling EndCombo() in wrong window!"); EndPopup(); } @@ -9150,11 +9147,7 @@ bool ImGui::BeginMainMenuBar() void ImGui::EndMainMenuBar() { ImGuiContext& g = *GImGui; - if (!g.CurrentWindow->DC.MenuBarAppending) - { - IM_ASSERT_USER_ERROR(0, "Calling EndMainMenuBar() not from a menu-bar!"); // Not technically testing that it is the main menu bar - return; - } + IM_ASSERT_USER_ERROR_RET(g.CurrentWindow->DC.MenuBarAppending, "Calling EndMainMenuBar() not from a menu-bar!"); // Not technically testing that it is the main menu bar EndMenuBar(); g.CurrentWindow->Flags |= ImGuiWindowFlags_NoSavedSettings; // Restore _NoSavedSettings (#8356) @@ -9414,12 +9407,8 @@ void ImGui::EndMenu() // Nav: When a left move request our menu failed, close ourselves. ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT_USER_ERROR_RET((window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu), "Calling EndMenu() in wrong window!"); - if ((window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) != (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) - { - IM_ASSERT_USER_ERROR(0, "Calling EndMenu() in wrong window!"); - return; - } ImGuiWindow* parent_window = window->ParentWindow; // Should always be != NULL is we passed assert. if (window->BeginCount == window->BeginCountPreviousFrame) if (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet()) @@ -9716,11 +9705,7 @@ void ImGui::EndTabBar() return; ImGuiTabBar* tab_bar = g.CurrentTabBar; - if (tab_bar == NULL) - { - IM_ASSERT_USER_ERROR(tab_bar != NULL, "Mismatched BeginTabBar()/EndTabBar()!"); - return; - } + IM_ASSERT_USER_ERROR_RET(tab_bar != NULL, "Mismatched BeginTabBar()/EndTabBar()!"); // Fallback in case no TabItem have been submitted if (tab_bar->WantLayout) @@ -10361,11 +10346,7 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f return false; ImGuiTabBar* tab_bar = g.CurrentTabBar; - if (tab_bar == NULL) - { - IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); - return false; - } + IM_ASSERT_USER_ERROR_RETV(tab_bar != NULL, false, "Needs to be called between BeginTabBar() and EndTabBar()!"); IM_ASSERT((flags & ImGuiTabItemFlags_Button) == 0); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead! bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL); @@ -10385,11 +10366,7 @@ void ImGui::EndTabItem() return; ImGuiTabBar* tab_bar = g.CurrentTabBar; - if (tab_bar == NULL) - { - IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); - return; - } + IM_ASSERT_USER_ERROR_RET(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); IM_ASSERT(tab_bar->LastTabItemIdx >= 0); ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx]; if (!(tab->Flags & ImGuiTabItemFlags_NoPushId)) @@ -10404,11 +10381,7 @@ bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags) return false; ImGuiTabBar* tab_bar = g.CurrentTabBar; - if (tab_bar == NULL) - { - IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); - return false; - } + IM_ASSERT_USER_ERROR_RETV(tab_bar != NULL, false, "Needs to be called between BeginTabBar() and EndTabBar()!"); return TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder, NULL); } @@ -10420,11 +10393,7 @@ void ImGui::TabItemSpacing(const char* str_id, ImGuiTabItemFlags flags, float return; ImGuiTabBar* tab_bar = g.CurrentTabBar; - if (tab_bar == NULL) - { - IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); - return; - } + IM_ASSERT_USER_ERROR_RET(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); SetNextItemWidth(width); TabItemEx(tab_bar, str_id, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder | ImGuiTabItemFlags_Invisible, NULL); } From b933599f00c1ec3a9c4fe0ab34710bad10063aa6 Mon Sep 17 00:00:00 2001 From: thedmd Date: Sat, 27 Sep 2025 15:09:52 +0200 Subject: [PATCH 07/22] Backends: DirectX12: added helpers to switch to Linear sampler (yet not made public, but intended to be forward declared). (#9173) --- backends/imgui_impl_dx12.cpp | 63 +++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 12 deletions(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 056d23a6c..a5420782a 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -93,8 +93,10 @@ struct ImGui_ImplDX12_Data ImGui_ImplDX12_InitInfo InitInfo; IDXGIFactory5* pdxgiFactory; ID3D12Device* pd3dDevice; - ID3D12RootSignature* pRootSignature; - ID3D12PipelineState* pPipelineState; + ID3D12RootSignature* pRootSignatureLinear; + ID3D12RootSignature* pRootSignatureNearest; + ID3D12PipelineState* pPipelineStateLinear; + ID3D12PipelineState* pPipelineStateNearest; ID3D12CommandQueue* pCommandQueue; bool commandQueueOwned; DXGI_FORMAT RTVFormat; @@ -140,11 +142,27 @@ struct VERTEX_CONSTANT_BUFFER_DX12 float mvp[4][4]; }; +// FIXME-WIP: Allow user to forward declare those two, for until we come up with a backend agnostic API to do this. (#9173) +void ImGui_ImplDX12_SetupSamplerLinear(ID3D12GraphicsCommandList* command_list); +void ImGui_ImplDX12_SetupSamplerNearest(ID3D12GraphicsCommandList* command_list); + // Functions -static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* command_list, ImGui_ImplDX12_RenderBuffers* fr) +void ImGui_ImplDX12_SetupSamplerLinear(ID3D12GraphicsCommandList* command_list) { ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); + command_list->SetPipelineState(bd->pPipelineStateLinear); + command_list->SetGraphicsRootSignature(bd->pRootSignatureLinear); +} +void ImGui_ImplDX12_SetupSamplerNearest(ID3D12GraphicsCommandList* command_list) +{ + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); + command_list->SetPipelineState(bd->pPipelineStateNearest); + command_list->SetGraphicsRootSignature(bd->pRootSignatureNearest); +} + +static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* command_list, ImGui_ImplDX12_RenderBuffers* fr) +{ // Setup orthographic projection matrix into our constant buffer // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). VERTEX_CONSTANT_BUFFER_DX12 vertex_constant_buffer; @@ -186,8 +204,7 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; command_list->IASetIndexBuffer(&ibv); command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - command_list->SetPipelineState(bd->pPipelineState); - command_list->SetGraphicsRootSignature(bd->pRootSignature); + ImGui_ImplDX12_SetupSamplerLinear(command_list); command_list->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0); // Setup blend factor @@ -555,7 +572,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects() ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); if (!bd || !bd->pd3dDevice) return false; - if (bd->pPipelineState) + if (bd->pPipelineStateLinear) ImGui_ImplDX12_InvalidateDeviceObjects(); HRESULT hr = ::CreateDXGIFactory1(IID_PPV_ARGS(&bd->pdxgiFactory)); @@ -644,7 +661,15 @@ bool ImGui_ImplDX12_CreateDeviceObjects() if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, nullptr) != S_OK) return false; - bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignature)); + bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignatureLinear)); + blob->Release(); + + // Root Signature for ImDrawCallback_SetSamplerNearest + staticSampler[0].Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; + if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, nullptr) != S_OK) + return false; + + bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignatureNearest)); blob->Release(); } @@ -657,7 +682,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects() D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.NodeMask = 1; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - psoDesc.pRootSignature = bd->pRootSignature; + psoDesc.pRootSignature = bd->pRootSignatureLinear; psoDesc.SampleMask = UINT_MAX; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = bd->RTVFormat; @@ -780,7 +805,18 @@ bool ImGui_ImplDX12_CreateDeviceObjects() desc.BackFace = desc.FrontFace; } - HRESULT result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineState)); + HRESULT result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineStateLinear)); + if (result_pipeline_state != S_OK) + { + vertexShaderBlob->Release(); + pixelShaderBlob->Release(); + return false; + } + + // Pipeline State for ImDrawCallback_SetSamplerNearest + psoDesc.pRootSignature = bd->pRootSignatureNearest; + + result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineStateNearest)); vertexShaderBlob->Release(); pixelShaderBlob->Release(); if (result_pipeline_state != S_OK) @@ -813,8 +849,11 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() if (bd->commandQueueOwned) SafeRelease(bd->pCommandQueue); bd->commandQueueOwned = false; - SafeRelease(bd->pRootSignature); - SafeRelease(bd->pPipelineState); + SafeRelease(bd->pRootSignatureLinear); + SafeRelease(bd->pRootSignatureNearest); + SafeRelease(bd->pPipelineStateLinear); + SafeRelease(bd->pPipelineStateNearest); + if (bd->pTexUploadBufferMapped) { D3D12_RANGE range = { 0, bd->pTexUploadBufferSize }; @@ -961,7 +1000,7 @@ void ImGui_ImplDX12_NewFrame() ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX12_Init()?"); - if (!bd->pPipelineState) + if (!bd->pPipelineStateLinear) if (!ImGui_ImplDX12_CreateDeviceObjects()) IM_ASSERT(0 && "ImGui_ImplDX12_CreateDeviceObjects() failed!"); } From 8b86c939c7eb5346784d1030102f2236a3bd547c Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Sep 2025 16:26:58 +0200 Subject: [PATCH 08/22] Backends: DirectX10, DirectX11, SDLGPU3: added nearest sampler in ImGui_ImplDX10_RenderState/ImGui_ImplDX11_RenderState/ImGui_ImplSDLGPU3_RenderState struct. (#6969, #5834, #7468, #3590, #9173, #8926, #7230, #5118, #3590, #2973, #6969) --- backends/imgui_impl_dx10.cpp | 8 +++++++- backends/imgui_impl_dx10.h | 3 ++- backends/imgui_impl_dx11.cpp | 8 +++++++- backends/imgui_impl_dx11.h | 3 ++- backends/imgui_impl_sdlgpu3.cpp | 11 +++++++++-- backends/imgui_impl_sdlgpu3.h | 3 ++- docs/CHANGELOG.txt | 5 +++++ 7 files changed, 34 insertions(+), 7 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 5650a3c85..118798325 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -16,6 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-01-19: DirectX11: Added 'SamplerNearest' in ImGui_ImplDX11_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'. // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: DirectX10: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. // 2025-05-07: DirectX10: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). @@ -75,6 +76,7 @@ struct ImGui_ImplDX10_Data ID3D10Buffer* pVertexConstantBuffer; ID3D10PixelShader* pPixelShader; ID3D10SamplerState* pTexSamplerLinear; + ID3D10SamplerState* pTexSamplerNearest; ID3D10RasterizerState* pRasterizerState; ID3D10BlendState* pBlendState; ID3D10DepthStencilState* pDepthStencilState; @@ -258,7 +260,8 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplDX10_RenderState render_state; render_state.Device = bd->pd3dDevice; - render_state.SamplerDefault = bd->pTexSamplerLinear; + render_state.SamplerLinear = bd->pTexSamplerLinear; + render_state.SamplerNearest = bd->pTexSamplerNearest; render_state.VertexConstantBuffer = bd->pVertexConstantBuffer; platform_io.Renderer_RenderState = &render_state; @@ -565,6 +568,8 @@ bool ImGui_ImplDX10_CreateDeviceObjects() desc.MinLOD = 0.f; desc.MaxLOD = 0.f; bd->pd3dDevice->CreateSamplerState(&desc, &bd->pTexSamplerLinear); + desc.Filter = D3D10_FILTER_MIN_MAG_MIP_POINT; + bd->pd3dDevice->CreateSamplerState(&desc, &bd->pTexSamplerNearest); } return true; @@ -581,6 +586,7 @@ void ImGui_ImplDX10_InvalidateDeviceObjects() if (tex->RefCount == 1) ImGui_ImplDX10_DestroyTexture(tex); if (bd->pTexSamplerLinear) { bd->pTexSamplerLinear->Release(); bd->pTexSamplerLinear = nullptr; } + if (bd->pTexSamplerNearest) { bd->pTexSamplerNearest->Release(); bd->pTexSamplerNearest = nullptr; } if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; } diff --git a/backends/imgui_impl_dx10.h b/backends/imgui_impl_dx10.h index 9d7fb68ae..87945d64e 100644 --- a/backends/imgui_impl_dx10.h +++ b/backends/imgui_impl_dx10.h @@ -41,7 +41,8 @@ IMGUI_IMPL_API void ImGui_ImplDX10_UpdateTexture(ImTextureData* tex); struct ImGui_ImplDX10_RenderState { ID3D10Device* Device; - ID3D10SamplerState* SamplerDefault; + ID3D10SamplerState* SamplerLinear; + ID3D10SamplerState* SamplerNearest; ID3D10Buffer* VertexConstantBuffer; }; diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 878930404..193127b4e 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -17,6 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-01-19: DirectX11: Added 'SamplerNearest' in ImGui_ImplDX11_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'. // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: DirectX11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. // 2025-05-07: DirectX11: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). @@ -78,6 +79,7 @@ struct ImGui_ImplDX11_Data ID3D11Buffer* pVertexConstantBuffer; ID3D11PixelShader* pPixelShader; ID3D11SamplerState* pTexSamplerLinear; + ID3D11SamplerState* pTexSamplerNearest; ID3D11RasterizerState* pRasterizerState; ID3D11BlendState* pBlendState; ID3D11DepthStencilState* pDepthStencilState; @@ -272,7 +274,8 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) ImGui_ImplDX11_RenderState render_state; render_state.Device = bd->pd3dDevice; render_state.DeviceContext = bd->pd3dDeviceContext; - render_state.SamplerDefault = bd->pTexSamplerLinear; + render_state.SamplerLinear = bd->pTexSamplerLinear; + render_state.SamplerNearest = bd->pTexSamplerNearest; render_state.VertexConstantBuffer = bd->pVertexConstantBuffer; platform_io.Renderer_RenderState = &render_state; @@ -580,6 +583,8 @@ bool ImGui_ImplDX11_CreateDeviceObjects() desc.MinLOD = 0.f; desc.MaxLOD = 0.f; bd->pd3dDevice->CreateSamplerState(&desc, &bd->pTexSamplerLinear); + desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + bd->pd3dDevice->CreateSamplerState(&desc, &bd->pTexSamplerNearest); } return true; @@ -597,6 +602,7 @@ void ImGui_ImplDX11_InvalidateDeviceObjects() ImGui_ImplDX11_DestroyTexture(tex); if (bd->pTexSamplerLinear) { bd->pTexSamplerLinear->Release(); bd->pTexSamplerLinear = nullptr; } + if (bd->pTexSamplerNearest) { bd->pTexSamplerNearest->Release(); bd->pTexSamplerNearest = nullptr; } if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; } diff --git a/backends/imgui_impl_dx11.h b/backends/imgui_impl_dx11.h index 1df4f3695..338e0093f 100644 --- a/backends/imgui_impl_dx11.h +++ b/backends/imgui_impl_dx11.h @@ -44,7 +44,8 @@ struct ImGui_ImplDX11_RenderState { ID3D11Device* Device; ID3D11DeviceContext* DeviceContext; - ID3D11SamplerState* SamplerDefault; + ID3D11SamplerState* SamplerLinear; + ID3D11SamplerState* SamplerNearest; ID3D11Buffer* VertexConstantBuffer; }; diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index e5934c302..9019c7de3 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -62,6 +62,7 @@ struct ImGui_ImplSDLGPU3_Data SDL_GPUShader* FragmentShader = nullptr; SDL_GPUGraphicsPipeline* Pipeline = nullptr; SDL_GPUSampler* TexSamplerLinear = nullptr; + SDL_GPUSampler* TexSamplerNearest = nullptr; SDL_GPUTransferBuffer* TexTransferBuffer = nullptr; uint32_t TexTransferBufferSize = 0; @@ -236,7 +237,8 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplSDLGPU3_RenderState render_state; render_state.Device = bd->InitInfo.Device; - render_state.SamplerDefault = render_state.SamplerCurrent = bd->TexSamplerLinear; + render_state.SamplerLinear = render_state.SamplerCurrent = bd->TexSamplerLinear; + render_state.SamplerNearest = bd->TexSamplerNearest; platform_io.Renderer_RenderState = &render_state; ImGui_ImplSDLGPU3_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, render_pass, fd, fb_width, fb_height); @@ -592,9 +594,14 @@ void ImGui_ImplSDLGPU3_CreateDeviceObjects() sampler_info.enable_anisotropy = false; sampler_info.max_anisotropy = 1.0f; sampler_info.enable_compare = false; - bd->TexSamplerLinear = SDL_CreateGPUSampler(v->Device, &sampler_info); IM_ASSERT(bd->TexSamplerLinear != nullptr && "Failed to create sampler, call SDL_GetError() for more information"); + + sampler_info.min_filter = SDL_GPU_FILTER_NEAREST; + sampler_info.mag_filter = SDL_GPU_FILTER_NEAREST; + sampler_info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST; + bd->TexSamplerNearest = SDL_CreateGPUSampler(v->Device, &sampler_info); + IM_ASSERT(bd->TexSamplerNearest != nullptr && "Failed to create sampler, call SDL_GetError() for more information"); } ImGui_ImplSDLGPU3_CreateGraphicsPipeline(); diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h index 12b6528f3..1c73dfd71 100644 --- a/backends/imgui_impl_sdlgpu3.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -57,7 +57,8 @@ IMGUI_IMPL_API void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex); struct ImGui_ImplSDLGPU3_RenderState { SDL_GPUDevice* Device; - SDL_GPUSampler* SamplerDefault; // Default sampler (bilinear filtering) + SDL_GPUSampler* SamplerLinear; // Bilinear filtering sampler + SDL_GPUSampler* SamplerNearest; // Nearest/point filtering sampler SDL_GPUSampler* SamplerCurrent; // Current sampler (may be changed by callback) }; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6dd87e848..e8ff5aa0d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -190,6 +190,10 @@ Other Changes: non-ASCII values to io.AddInputCharacter(). (#9099) - Debug Log: can output to debugger on Windows. (#5855) - Backends: + - DirectX10: added 'SamplerNearest' in ImGui_ImplDX10_RenderState. + (+renamed 'SamplerDefault' to 'SamplerLinear', which was tagged as beta API) + - DirectX11: added 'SamplerNearest' in ImGui_ImplDX11_RenderState. + (+renamed 'SamplerDefault' to 'SamplerLinear', which was tagged as beta API) - GLFW: Avoid repeated glfwSetCursor()/glfwSetInputMode() calls when unnecessary. Lowers overhead for very high framerates (e.g. 10k+ FPS). [@maxliani] - GLFW: Added IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND to @@ -198,6 +202,7 @@ Other Changes: platforms. (#8792, #9112) - SDL2, SDL3: changed GetClipboardText() handler to return NULL on error aka clipboard contents is not text. Consistent with other backends. (#9168) + - SDL_GPU3: added 'TexSamplerNearest' in ImGui_ImplSDLGPU3_RenderState. - SDL_GPU3: macOS version can use MSL shaders in order to support macOS 10.14+ (vs Metallib shaders requiring macOS 14+). Requires application calling SDL_CreateGPUDevice() with SDL_GPU_SHADERFORMAT_MSL. (#9076) [@Niminem] From 8c0b41037151d3b3c0f81d8dbcb508bda8b0b6f5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 Jan 2026 16:18:18 +0100 Subject: [PATCH 09/22] Docs: tweaks. --- backends/imgui_impl_win32.cpp | 2 +- backends/imgui_impl_win32.h | 4 ++-- docs/CHANGELOG.txt | 22 +++++++++++----------- examples/example_android_opengl3/main.cpp | 6 ------ 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index de3c6fbd6..c344a1417 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -830,7 +830,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA // - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps. // - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc. // but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime, -// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. +// neither of which we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. //--------------------------------------------------------------------------------------------------------- // This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable. // ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically. diff --git a/backends/imgui_impl_win32.h b/backends/imgui_impl_win32.h index 5ae399e0e..d2a960059 100644 --- a/backends/imgui_impl_win32.h +++ b/backends/imgui_impl_win32.h @@ -26,7 +26,7 @@ IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd); IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame(); -// Win32 message handler your application need to call. +// Win32 message handler your application needs to call. // - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on from this helper. // - You should COPY the line below into your .cpp code to forward declare the function and then you can call it. // - Call from your application's message handler. Keep calling your message handler unless this function returns TRUE. @@ -40,7 +40,7 @@ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg // - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps. // - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc. // but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime, -// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. +// neither of which we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness(); IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e8ff5aa0d..023ae0263 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -187,33 +187,33 @@ Other Changes: - Improve error handling and recovery for TableSetupColumn(). - Debug Tools: - Debug Log: fixed incorrectly printing characters in IO log when submitting - non-ASCII values to io.AddInputCharacter(). (#9099) + non-ASCII values to `io.AddInputCharacter()`. (#9099) - Debug Log: can output to debugger on Windows. (#5855) - Backends: - - DirectX10: added 'SamplerNearest' in ImGui_ImplDX10_RenderState. - (+renamed 'SamplerDefault' to 'SamplerLinear', which was tagged as beta API) - - DirectX11: added 'SamplerNearest' in ImGui_ImplDX11_RenderState. - (+renamed 'SamplerDefault' to 'SamplerLinear', which was tagged as beta API) - - GLFW: Avoid repeated glfwSetCursor()/glfwSetInputMode() calls when unnecessary. + - DirectX10: added `SamplerNearest` in `ImGui_ImplDX10_RenderState`. + (+renamed `SamplerDefault` to `SamplerLinear`, which was tagged as beta API) + - DirectX11: added `SamplerNearest` in ImGui_ImplDX11_RenderState. + (+renamed `SamplerDefault` to `SamplerLinear`, which was tagged as beta API) + - GLFW: Avoid repeated `glfwSetCursor()` / `glfwSetInputMode()` unnecessary calls. Lowers overhead for very high framerates (e.g. 10k+ FPS). [@maxliani] - GLFW: Added IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND to forcefully disable either. (#9109, #9116) - OpenGL3: Fixed embedded loader multiple init/shutdown cycles broken on some platforms. (#8792, #9112) - - SDL2, SDL3: changed GetClipboardText() handler to return NULL on error aka + - SDL2, SDL3: changed `GetClipboardText()` handler to return NULL on error aka clipboard contents is not text. Consistent with other backends. (#9168) - - SDL_GPU3: added 'TexSamplerNearest' in ImGui_ImplSDLGPU3_RenderState. + - SDL_GPU3: added `SamplerNearest` in `ImGui_ImplSDLGPU3_RenderState`. - SDL_GPU3: macOS version can use MSL shaders in order to support macOS 10.14+ (vs Metallib shaders requiring macOS 14+). Requires application calling - SDL_CreateGPUDevice() with SDL_GPU_SHADERFORMAT_MSL. (#9076) [@Niminem] + `SDL_CreateGPUDevice()` with `SDL_GPU_SHADERFORMAT_MSL`. (#9076) [@Niminem] - Vulkan: helper for creating a swapchain (used by examples and multi-viewports) selects `VkSwapchainCreateInfoKHR`'s `compositeAlpha` value based on `cap.supportedCompositeAlpha`, which seems to be required on some Android devices. (#8784) [@FelixStach] - - Win32: handle WM_IME_CHAR/WM_IME_COMPOSITION to support Unicode inputs on + - Win32: handle `WM_IME_CHAR`/`WM_IME_COMPOSITION` to support Unicode inputs on MBCS (non-Unicode) Windows. (#9099, #3653, #5961) [@ulhc, @ocornut, @Othereum] - Examples: - - Win32+DirectX12: ignore seemingly incorrect D3D12_MESSAGE_ID_FENCE_ZERO_WAIT + - Win32+DirectX12: ignore seemingly incorrect `D3D12_MESSAGE_ID_FENCE_ZERO_WAIT` warning on startups on some setups. (#9084, #9093) [@RT2Code, @LeoGautheron] diff --git a/examples/example_android_opengl3/main.cpp b/examples/example_android_opengl3/main.cpp index 0de952dbd..7f60ac631 100644 --- a/examples/example_android_opengl3/main.cpp +++ b/examples/example_android_opengl3/main.cpp @@ -151,12 +151,6 @@ void Init(struct android_app* app) ImGui_ImplAndroid_Init(g_App->window); ImGui_ImplOpenGL3_Init("#version 300 es"); - // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - Read 'docs/FONTS.md' for more instructions and details. If you like the default font but want it to scale better, consider using the 'ProggyVector' from the same author! - // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - // Setup scaling float main_scale = 2.0f; ImGuiStyle& style = ImGui::GetStyle(); From 3803203d47c18c3a55bdb594fc59f89a8d25afc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A1draic=20Slattery?= Date: Wed, 21 Jan 2026 17:34:30 +0100 Subject: [PATCH 10/22] CI: update outdated GitHub Actions versions (#9186) --- .github/workflows/build.yml | 24 ++++++++++++------------ .github/workflows/static-analysis.yml | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 46ff68912..9bc81bf81 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,7 +28,7 @@ jobs: VS_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\ MSBUILD_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\ steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: path: ${{ github.workspace }}/imgui @@ -274,7 +274,7 @@ jobs: working-directory: ${{ github.workspace }}/imgui steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: path: ${{ github.workspace }}/imgui @@ -514,7 +514,7 @@ jobs: working-directory: ${{ github.workspace }}/imgui steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: path: ${{ github.workspace }}/imgui @@ -596,7 +596,7 @@ jobs: name: Build - iOS steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Build example_apple_metal run: | @@ -608,7 +608,7 @@ jobs: name: Build - Emscripten steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Install Dependencies run: | @@ -651,7 +651,7 @@ jobs: name: Build - Android steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Build example_android_opengl3 run: | @@ -670,11 +670,11 @@ jobs: MSBUILD_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\ steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: path: ${{ github.workspace }}/imgui - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 continue-on-error: true with: fetch-depth: 1 @@ -725,11 +725,11 @@ jobs: working-directory: ${{ github.workspace }}/imgui steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: path: ${{ github.workspace }}/imgui - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 1 repository: ocornut/imgui_test_engine @@ -763,11 +763,11 @@ jobs: # working-directory: ${{ github.workspace }}/imgui # # steps: -# - uses: actions/checkout@v5 +# - uses: actions/checkout@v6 # with: # path: ${{ github.workspace }}/imgui # -# - uses: actions/checkout@v5 +# - uses: actions/checkout@v6 # with: # fetch-depth: 1 # repository: ocornut/imgui_test_engine diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 53db04764..295628368 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -12,7 +12,7 @@ jobs: PVS-Studio: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 1 From 42b7704b70f3e19e87183160fa88cac52396fa6d Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 21 Jan 2026 18:18:55 +0100 Subject: [PATCH 11/22] InputText: add ImGuiInputTextState::SetSelection() helper + make TextSrc valid outside scope for non-read only fields. (#9174) --- imgui_internal.h | 3 ++- imgui_widgets.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 5a1816547..3cc3ef512 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1233,7 +1233,7 @@ struct IMGUI_API ImGuiInputTextState ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set. ImGuiID ID; // widget id owning the text state int TextLen; // UTF-8 length of the string in TextA (in bytes) - const char* TextSrc; // == TextA.Data unless read-only, in which case == buf passed to InputText(). Field only set and valid _inside_ the call InputText() call. + const char* TextSrc; // == TextA.Data unless read-only, in which case == buf passed to InputText(). For _ReadOnly fields, pointer will be null outside the InputText() call. ImVector TextA; // main UTF8 buffer. TextA.Size is a buffer size! Should always be >= buf_size passed by user (and of course >= CurLenA + 1). ImVector TextToRevertTo; // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered) ImVector CallbackTextBackup; // temporary storage for callback to support automatic reconcile of undo-stack @@ -1267,6 +1267,7 @@ struct IMGUI_API ImGuiInputTextState int GetCursorPos() const; int GetSelectionStart() const; int GetSelectionEnd() const; + void SetSelection(int start, int end); void SelectAll(); // Reload user buf (WIP #2890) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e64c59eac..c557ddbe6 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4304,6 +4304,7 @@ void ImGuiInputTextState::ClearSelection() { Stb->select_start int ImGuiInputTextState::GetCursorPos() const { return Stb->cursor; } int ImGuiInputTextState::GetSelectionStart() const { return Stb->select_start; } int ImGuiInputTextState::GetSelectionEnd() const { return Stb->select_end; } +void ImGuiInputTextState::SetSelection(int start, int end) { Stb->select_start = start; Stb->cursor = Stb->select_end = end; } float ImGuiInputTextState::GetPreferredOffsetX() const { return Stb->has_preferred_x ? Stb->preferred_x : -1; } void ImGuiInputTextState::SelectAll() { Stb->select_start = 0; Stb->cursor = Stb->select_end = TextLen; Stb->has_preferred_x = 0; } void ImGuiInputTextState::ReloadUserBufAndSelectAll() { WantReloadUserBuf = true; ReloadSelectionStart = 0; ReloadSelectionEnd = INT_MAX; } @@ -5630,7 +5631,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ g.LastItemData.StatusFlags = item_data_backup.StatusFlags; } } - if (state) + if (state && is_readonly) state->TextSrc = NULL; // Log as text From f21307e5c9bac40acab906ed2e8a5ce53e4d137d Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 21 Jan 2026 18:25:38 +0100 Subject: [PATCH 12/22] InputText: ImGuiInputTextCallbackData::SelectAll() sets CursorPos. Added SetSelection() helper. Context was for #9174 but not specific to it. --- docs/CHANGELOG.txt | 3 +++ imgui.h | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 023ae0263..ff21dab57 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -154,6 +154,9 @@ Other Changes: - Added ImGuiSliderFlags_ColorMarkers to opt-in adding R/G/B/A color markers next to each components, in multi-components functions. - Added a way to select a specific marker color. +- InputText: + - ImGuiInputTextCallbackData::SelectAll() also sets CursorPos to SelectionEnd. + - Added ImGuiInputTextCallbackData::SetSelection() helper. - Text, InputText: - Reworked word-wrapping logic: - Try to not wrap in the middle of contiguous punctuations. (#8139, #8439, #9094) diff --git a/imgui.h b/imgui.h index 448221dce..6baa6d746 100644 --- a/imgui.h +++ b/imgui.h @@ -2650,9 +2650,10 @@ struct ImGuiInputTextCallbackData IMGUI_API ImGuiInputTextCallbackData(); IMGUI_API void DeleteChars(int pos, int bytes_count); IMGUI_API void InsertChars(int pos, const char* text, const char* text_end = NULL); - void SelectAll() { SelectionStart = 0; SelectionEnd = BufTextLen; } - void ClearSelection() { SelectionStart = SelectionEnd = BufTextLen; } - bool HasSelection() const { return SelectionStart != SelectionEnd; } + void SelectAll() { SelectionStart = 0; CursorPos = SelectionEnd = BufTextLen; } + void SetSelection(int s, int e) { IM_ASSERT(s >= 0 && s <= BufTextLen); IM_ASSERT(e >= 0 && e <= BufTextLen); SelectionStart = s; CursorPos = SelectionEnd = e; } + void ClearSelection() { SelectionStart = SelectionEnd = BufTextLen; } + bool HasSelection() const { return SelectionStart != SelectionEnd; } }; // Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin(). From d448045669b317aa8377039e53ef801a8f697c8c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 21 Jan 2026 18:34:28 +0100 Subject: [PATCH 13/22] InputText: Added ImGuiInputTextCallbackData::ID field. --- docs/CHANGELOG.txt | 3 ++- imgui.h | 5 +++-- imgui_widgets.cpp | 22 +++++++++++++--------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ff21dab57..afa1d5534 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -155,8 +155,9 @@ Other Changes: next to each components, in multi-components functions. - Added a way to select a specific marker color. - InputText: - - ImGuiInputTextCallbackData::SelectAll() also sets CursorPos to SelectionEnd. + - Made ImGuiInputTextCallbackData::SelectAll() also sets CursorPos to SelectionEnd. - Added ImGuiInputTextCallbackData::SetSelection() helper. + - Added ImGuiInputTextCallbackData::ID field. - Text, InputText: - Reworked word-wrapping logic: - Try to not wrap in the middle of contiguous punctuations. (#8139, #8439, #9094) diff --git a/imgui.h b/imgui.h index 6baa6d746..01e5113d7 100644 --- a/imgui.h +++ b/imgui.h @@ -2629,18 +2629,19 @@ struct ImGuiInputTextCallbackData ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only void* UserData; // What user passed to InputText() // Read-only + ImGuiID ID; // Widget ID // Read-only // Arguments for the different callback events // - During Resize callback, Buf will be same as your input buffer. // - However, during Completion/History/Always callback, Buf always points to our own internal data (it is not the same as your buffer)! Changes to it will be reflected into your own buffer shortly after the callback. // - To modify the text buffer in a callback, prefer using the InsertChars() / DeleteChars() function. InsertChars() will take care of calling the resize callback if necessary. // - If you know your edits are not going to resize the underlying buffer allocation, you may modify the contents of 'Buf[]' directly. You need to update 'BufTextLen' accordingly (0 <= BufTextLen < BufSize) and set 'BufDirty'' to true so InputText can update its internal state. - ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0; ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only // [Completion,History] + ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0; + bool BufDirty; // Set if you modify Buf/BufTextLen! // Write // [Completion,History,Always] char* Buf; // Text buffer // Read-write // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer! int BufTextLen; // Text length (in bytes) // Read-write // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length() int BufSize; // Buffer size (in bytes) = capacity+1 // Read-only // [Resize,Completion,History,Always] Include zero-terminator storage. In C land: == ARRAYSIZE(my_char_array), in C++ land: string.capacity()+1 - bool BufDirty; // Set if you modify Buf/BufTextLen! // Write // [Completion,History,Always] int CursorPos; // // Read-write // [Completion,History,Always] int SelectionStart; // // Read-write // [Completion,History,Always] == to SelectionEnd when no selection int SelectionEnd; // // Read-write // [Completion,History,Always] diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c557ddbe6..17e69c3b5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -134,7 +134,7 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); //------------------------------------------------------------------------- // For InputTextEx() -static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard = false); +static bool InputTextFilterCharacter(ImGuiContext* ctx, ImGuiInputTextState* state, unsigned int* p_char, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard = false); static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end_display, const char* text_end, const char** out_remaining = NULL, ImVec2* out_offset = NULL, ImDrawTextFlags flags = 0); //------------------------------------------------------------------------- @@ -4409,9 +4409,10 @@ void ImGui::PopPasswordFont() } // Return false to discard a character. -static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard) +static bool InputTextFilterCharacter(ImGuiContext* ctx, ImGuiInputTextState* state, unsigned int* p_char, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard) { unsigned int c = *p_char; + ImGuiInputTextFlags flags = state->Flags; // Filter non-printable (NB: isprint is unreliable! see #2467) bool apply_named_filters = true; @@ -4501,9 +4502,10 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im ImGuiContext& g = *GImGui; ImGuiInputTextCallbackData callback_data; callback_data.Ctx = &g; + callback_data.ID = state->ID; + callback_data.Flags = flags; callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter; callback_data.EventChar = (ImWchar)c; - callback_data.Flags = flags; callback_data.UserData = user_data; if (callback(&callback_data) != 0) return false; @@ -5020,7 +5022,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (Shortcut(ImGuiKey_Tab, ImGuiInputFlags_Repeat, id)) { unsigned int c = '\t'; // Insert TAB - if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data)) + if (InputTextFilterCharacter(&g, state, &c, callback, callback_user_data)) state->OnCharPressed(c); } // FIXME: Implement Shift+Tab @@ -5043,7 +5045,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ unsigned int c = (unsigned int)io.InputQueueCharacters[n]; if (c == '\t') // Skip Tab, see above. continue; - if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data)) + if (InputTextFilterCharacter(&g, state, &c, callback, callback_user_data)) state->OnCharPressed(c); } @@ -5129,7 +5131,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // Insert new line unsigned int c = '\n'; - if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data)) + if (InputTextFilterCharacter(&g, state, &c, callback, callback_user_data)) state->OnCharPressed(c); } } @@ -5198,7 +5200,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ unsigned int c; int in_len = ImTextCharFromUtf8(&c, s, clipboard_end); s += in_len; - if (!InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, true)) + if (!InputTextFilterCharacter(&g, state, &c, callback, callback_user_data, true)) continue; char c_utf8[5]; ImTextCharToUtf8(c_utf8, c); @@ -5297,8 +5299,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { ImGuiInputTextCallbackData callback_data; callback_data.Ctx = &g; - callback_data.EventFlag = event_flag; + callback_data.ID = id; callback_data.Flags = flags; + callback_data.EventFlag = event_flag; callback_data.UserData = callback_user_data; // FIXME-OPT: Undo stack reconcile needs a backup of the data until we rework API, see #7925 @@ -5374,8 +5377,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { ImGuiInputTextCallbackData callback_data; callback_data.Ctx = &g; - callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; + callback_data.ID = id; callback_data.Flags = flags; + callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; callback_data.Buf = buf; callback_data.BufTextLen = apply_new_text_length; callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1); From cb3b7ff4fbdb7ff47cb81a0e78322110c8f4b2d3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 21 Jan 2026 18:46:38 +0100 Subject: [PATCH 14/22] InputText: added mGuiInputTextCallbackData::EventActive helpers. (#9174) --- docs/CHANGELOG.txt | 6 +++--- imgui.h | 1 + imgui_widgets.cpp | 3 +++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index afa1d5534..4324c69ef 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -155,9 +155,9 @@ Other Changes: next to each components, in multi-components functions. - Added a way to select a specific marker color. - InputText: - - Made ImGuiInputTextCallbackData::SelectAll() also sets CursorPos to SelectionEnd. - - Added ImGuiInputTextCallbackData::SetSelection() helper. - - Added ImGuiInputTextCallbackData::ID field. + - ImGuiInputTextCallbackData: SelectAll() also sets CursorPos to SelectionEnd. + - ImGuiInputTextCallbackData: Added SetSelection() helper. + - ImGuiInputTextCallbackData: Added ID and EventActive helpers. (#9174) - Text, InputText: - Reworked word-wrapping logic: - Try to not wrap in the middle of contiguous punctuations. (#8139, #8439, #9094) diff --git a/imgui.h b/imgui.h index 01e5113d7..4a9af9b7a 100644 --- a/imgui.h +++ b/imgui.h @@ -2638,6 +2638,7 @@ struct ImGuiInputTextCallbackData // - If you know your edits are not going to resize the underlying buffer allocation, you may modify the contents of 'Buf[]' directly. You need to update 'BufTextLen' accordingly (0 <= BufTextLen < BufSize) and set 'BufDirty'' to true so InputText can update its internal state. ImGuiKey EventKey; // Key pressed (Up/Down/TAB) // Read-only // [Completion,History] ImWchar EventChar; // Character input // Read-write // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0; + bool EventActivated; // Input field just got activated // Read-only // [Always] bool BufDirty; // Set if you modify Buf/BufTextLen! // Write // [Completion,History,Always] char* Buf; // Text buffer // Read-write // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer! int BufTextLen; // Text length (in bytes) // Read-write // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length() diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 17e69c3b5..8faf35e50 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4506,6 +4506,7 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, ImGuiInputTextState* sta callback_data.Flags = flags; callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter; callback_data.EventChar = (ImWchar)c; + callback_data.EventActivated = (g.ActiveId == state->ID && g.ActiveIdIsJustActivated); callback_data.UserData = user_data; if (callback(&callback_data) != 0) return false; @@ -5302,6 +5303,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ callback_data.ID = id; callback_data.Flags = flags; callback_data.EventFlag = event_flag; + callback_data.EventActivated = (g.ActiveId == state->ID && g.ActiveIdIsJustActivated); callback_data.UserData = callback_user_data; // FIXME-OPT: Undo stack reconcile needs a backup of the data until we rework API, see #7925 @@ -5380,6 +5382,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ callback_data.ID = id; callback_data.Flags = flags; callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize; + callback_data.EventActivated = (g.ActiveId == state->ID && g.ActiveIdIsJustActivated); callback_data.Buf = buf; callback_data.BufTextLen = apply_new_text_length; callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1); From 3aba95060ec7960e2c1c7d65163756b9d9c1e419 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 21 Jan 2026 19:53:31 +0100 Subject: [PATCH 15/22] Fonts: adding new fonts after removing all fonts mid-frame properly updates current state. --- docs/CHANGELOG.txt | 1 + imgui_draw.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4324c69ef..63235b2c2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -128,6 +128,7 @@ Other Changes: is enabled, creating side-effects when later disabling hinting or dynamically switching to stb_truetype rasterizer. - Post rescale GlyphOffset is always rounded. + - Adding new fonts after removing all fonts mid-frame properly updates current state. - Textures: - Fixed a building issue when ImTextureID is defined as a struct. - Fixed displaying texture # in Metrics/Debugger window. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 780f6b844..9889b2884 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3035,6 +3035,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) ImFontAtlasBuildInit(this); // Create new font + const bool is_first_font = (Fonts.Size == 0); ImFont* font; if (!font_cfg_in->MergeMode) { @@ -3092,6 +3093,8 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) } ImFontAtlasFontSourceAddToFont(this, font, font_cfg); + if (is_first_font) + ImFontAtlasBuildNotifySetFont(this, NULL, font); return font; } @@ -3254,6 +3257,9 @@ void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, ImFont* shared_data->Font = new_font; if (ImGuiContext* ctx = shared_data->Context) { + if (ctx->FrameCount == 0 && old_font == NULL) // While this should work either way, we save ourselves the bother / debugging confusion of running ImGui code so early when it is not needed. + continue; + if (ctx->IO.FontDefault == old_font) ctx->IO.FontDefault = new_font; if (ctx->Font == old_font) From 66bb8add7333b0fea779de5a7749198c2294d9a4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 Jan 2026 14:28:46 +0100 Subject: [PATCH 16/22] Docs: better document Shortcut() related stuff. (#9188) Better document io.ConfigDpiScaleFonts. (#9179) --- docs/FAQ.md | 4 ++-- examples/example_glfw_metal/main.mm | 2 +- examples/example_glfw_opengl2/main.cpp | 2 +- examples/example_glfw_opengl3/main.cpp | 2 +- examples/example_glfw_vulkan/main.cpp | 2 +- examples/example_glfw_wgpu/main.cpp | 2 +- examples/example_sdl2_directx11/main.cpp | 2 +- examples/example_sdl2_opengl2/main.cpp | 2 +- examples/example_sdl2_opengl3/main.cpp | 2 +- examples/example_sdl2_sdlrenderer2/main.cpp | 2 +- examples/example_sdl2_vulkan/main.cpp | 2 +- examples/example_sdl2_wgpu/main.cpp | 2 +- examples/example_sdl3_directx11/main.cpp | 2 +- examples/example_sdl3_metal/main.mm | 2 +- examples/example_sdl3_opengl3/main.cpp | 2 +- examples/example_sdl3_sdlgpu3/main.cpp | 2 +- examples/example_sdl3_sdlrenderer3/main.cpp | 2 +- examples/example_sdl3_vulkan/main.cpp | 2 +- examples/example_sdl3_wgpu/main.cpp | 2 +- examples/example_win32_directx10/main.cpp | 2 +- examples/example_win32_directx11/main.cpp | 2 +- examples/example_win32_directx12/main.cpp | 2 +- examples/example_win32_directx9/main.cpp | 2 +- examples/example_win32_opengl3/main.cpp | 2 +- examples/example_win32_vulkan/main.cpp | 2 +- imgui.cpp | 2 +- imgui.h | 25 +++++++++++++-------- 27 files changed, 43 insertions(+), 36 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 282c65c3f..6c9526aa7 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -678,8 +678,8 @@ ImGui::PushFont(new_font, 42.0f); In `docking` branch or with multi-viewports: ```cpp -io.ConfigDpiScaleFonts = true; // Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. -io.ConfigDpiScaleViewports = true; // Scale Dear ImGui and Platform Windows when Monitor DPI changes. +io.ConfigDpiScaleFonts = true; // (Docking branch only) Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. +io.ConfigDpiScaleViewports = true; // (Docking branch only) Scale Dear ImGui and Platform Windows when Monitor DPI changes. ``` **Scaling style** (paddings, spacings, thicknesses) diff --git a/examples/example_glfw_metal/main.mm b/examples/example_glfw_metal/main.mm index 9627de70e..b6a802106 100644 --- a/examples/example_glfw_metal/main.mm +++ b/examples/example_glfw_metal/main.mm @@ -52,7 +52,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) id device = MTLCreateSystemDefaultDevice(); id commandQueue = [device newCommandQueue]; diff --git a/examples/example_glfw_opengl2/main.cpp b/examples/example_glfw_opengl2/main.cpp index 4fa8b0792..52d3612d3 100644 --- a/examples/example_glfw_opengl2/main.cpp +++ b/examples/example_glfw_opengl2/main.cpp @@ -61,7 +61,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForOpenGL(window, true); diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp index af21d9094..98af19d21 100644 --- a/examples/example_glfw_opengl3/main.cpp +++ b/examples/example_glfw_opengl3/main.cpp @@ -92,7 +92,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForOpenGL(window, true); diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index ccce94fb5..2ee284044 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -397,7 +397,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForVulkan(window, true); diff --git a/examples/example_glfw_wgpu/main.cpp b/examples/example_glfw_wgpu/main.cpp index 60662b031..cea13682e 100644 --- a/examples/example_glfw_wgpu/main.cpp +++ b/examples/example_glfw_wgpu/main.cpp @@ -98,7 +98,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForOther(window, true); diff --git a/examples/example_sdl2_directx11/main.cpp b/examples/example_sdl2_directx11/main.cpp index 1018913bc..65e4ca49c 100644 --- a/examples/example_sdl2_directx11/main.cpp +++ b/examples/example_sdl2_directx11/main.cpp @@ -83,7 +83,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplSDL2_InitForD3D(window); diff --git a/examples/example_sdl2_opengl2/main.cpp b/examples/example_sdl2_opengl2/main.cpp index 59cd7ed8e..cc3cce022 100644 --- a/examples/example_sdl2_opengl2/main.cpp +++ b/examples/example_sdl2_opengl2/main.cpp @@ -72,7 +72,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplSDL2_InitForOpenGL(window, gl_context); diff --git a/examples/example_sdl2_opengl3/main.cpp b/examples/example_sdl2_opengl3/main.cpp index 43e5aad0c..dea16869c 100644 --- a/examples/example_sdl2_opengl3/main.cpp +++ b/examples/example_sdl2_opengl3/main.cpp @@ -112,7 +112,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplSDL2_InitForOpenGL(window, gl_context); diff --git a/examples/example_sdl2_sdlrenderer2/main.cpp b/examples/example_sdl2_sdlrenderer2/main.cpp index 9ede2cac8..5021039cf 100644 --- a/examples/example_sdl2_sdlrenderer2/main.cpp +++ b/examples/example_sdl2_sdlrenderer2/main.cpp @@ -74,7 +74,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplSDL2_InitForSDLRenderer(window, renderer); diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index 87a38ff90..49a6acfa9 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -403,7 +403,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplSDL2_InitForVulkan(window); diff --git a/examples/example_sdl2_wgpu/main.cpp b/examples/example_sdl2_wgpu/main.cpp index cddce3e63..1b24e1c51 100644 --- a/examples/example_sdl2_wgpu/main.cpp +++ b/examples/example_sdl2_wgpu/main.cpp @@ -81,7 +81,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplSDL2_InitForOther(window); diff --git a/examples/example_sdl3_directx11/main.cpp b/examples/example_sdl3_directx11/main.cpp index 06d8ea505..88d7189a6 100644 --- a/examples/example_sdl3_directx11/main.cpp +++ b/examples/example_sdl3_directx11/main.cpp @@ -74,7 +74,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForD3D(window); diff --git a/examples/example_sdl3_metal/main.mm b/examples/example_sdl3_metal/main.mm index 9c9eab54a..b6dc5aa60 100644 --- a/examples/example_sdl3_metal/main.mm +++ b/examples/example_sdl3_metal/main.mm @@ -70,7 +70,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplMetal_Init(layer.device); diff --git a/examples/example_sdl3_opengl3/main.cpp b/examples/example_sdl3_opengl3/main.cpp index 1b0e100e4..e5fa6d5a9 100644 --- a/examples/example_sdl3_opengl3/main.cpp +++ b/examples/example_sdl3_opengl3/main.cpp @@ -102,7 +102,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForOpenGL(window, gl_context); diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp index 3372d56b0..9d5dd31a4 100644 --- a/examples/example_sdl3_sdlgpu3/main.cpp +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -76,7 +76,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForSDLGPU(window); diff --git a/examples/example_sdl3_sdlrenderer3/main.cpp b/examples/example_sdl3_sdlrenderer3/main.cpp index e275e5f07..82ccec6ef 100644 --- a/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/examples/example_sdl3_sdlrenderer3/main.cpp @@ -64,7 +64,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForSDLRenderer(window, renderer); diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index 38c48d3a7..705d6b523 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -402,7 +402,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForVulkan(window); diff --git a/examples/example_sdl3_wgpu/main.cpp b/examples/example_sdl3_wgpu/main.cpp index b5ae84bfd..cdf819e8b 100644 --- a/examples/example_sdl3_wgpu/main.cpp +++ b/examples/example_sdl3_wgpu/main.cpp @@ -88,7 +88,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForOther(window); diff --git a/examples/example_win32_directx10/main.cpp b/examples/example_win32_directx10/main.cpp index 6a7687537..3a3b8e17e 100644 --- a/examples/example_win32_directx10/main.cpp +++ b/examples/example_win32_directx10/main.cpp @@ -65,7 +65,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp index 9ca7705fb..50fce7e98 100644 --- a/examples/example_win32_directx11/main.cpp +++ b/examples/example_win32_directx11/main.cpp @@ -65,7 +65,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 85c598fb1..bb9e8161b 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -145,7 +145,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); diff --git a/examples/example_win32_directx9/main.cpp b/examples/example_win32_directx9/main.cpp index 2fe01420c..19174d4b0 100644 --- a/examples/example_win32_directx9/main.cpp +++ b/examples/example_win32_directx9/main.cpp @@ -63,7 +63,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); diff --git a/examples/example_win32_opengl3/main.cpp b/examples/example_win32_opengl3/main.cpp index f83d693f9..d214aa93e 100644 --- a/examples/example_win32_opengl3/main.cpp +++ b/examples/example_win32_opengl3/main.cpp @@ -73,7 +73,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplWin32_InitForOpenGL(hwnd); diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp index 75c5605cf..9470ce96c 100644 --- a/examples/example_win32_vulkan/main.cpp +++ b/examples/example_win32_vulkan/main.cpp @@ -390,7 +390,7 @@ int main(int, char**) // Setup scaling ImGuiStyle& style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) - style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); diff --git a/imgui.cpp b/imgui.cpp index 151a17308..976216cb6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9010,7 +9010,7 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) // Global scale factors final_size *= g.Style.FontScaleMain; // Main global scale factor - final_size *= g.Style.FontScaleDpi; // Per-monitor/viewport DPI scale factor, automatically updated when io.ConfigDpiScaleFonts is enabled. + final_size *= g.Style.FontScaleDpi; // Per-monitor/viewport DPI scale factor (in docking branch: automatically updated when io.ConfigDpiScaleFonts is enabled). // Window scale (mostly obsolete now) if (window != NULL) diff --git a/imgui.h b/imgui.h index 4a9af9b7a..936ce0add 100644 --- a/imgui.h +++ b/imgui.h @@ -1051,19 +1051,22 @@ namespace ImGui IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v); IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); - // Inputs Utilities: Keyboard/Mouse/Gamepad + // Inputs Utilities: Raw Keyboard/Mouse/Gamepad Access + // - Consider using the Shortcut() function instead of IsKeyPressed()/IsKeyChordPressed()! Shortcut() is easier to use and better featured (can do focus routing check). // - the ImGuiKey enum contains all possible keyboard, mouse and gamepad inputs (e.g. ImGuiKey_A, ImGuiKey_MouseLeft, ImGuiKey_GamepadDpadUp...). - // - (legacy: before v1.87, we used ImGuiKey to carry native/user indices as defined by each backends. This was obsoleted in 1.87 (2022-02) and completely removed in 1.91.5 (2024-11). See https://github.com/ocornut/imgui/issues/4921) - // - (legacy: any use of ImGuiKey will assert when key < 512 to detect passing legacy native/user indices) + // - (legacy: before v1.87 (2022-02), we used ImGuiKey < 512 values to carry native/user indices as defined by each backends. This was obsoleted in 1.87 (2022-02) and completely removed in 1.91.5 (2024-11). See https://github.com/ocornut/imgui/issues/4921) IMGUI_API bool IsKeyDown(ImGuiKey key); // is key being held. - IMGUI_API bool IsKeyPressed(ImGuiKey key, bool repeat = true); // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate + IMGUI_API bool IsKeyPressed(ImGuiKey key, bool repeat = true); // was key pressed (went from !Down to Down)? Repeat rate uses io.KeyRepeatDelay / KeyRepeatRate. IMGUI_API bool IsKeyReleased(ImGuiKey key); // was key released (went from Down to !Down)? IMGUI_API bool IsKeyChordPressed(ImGuiKeyChord key_chord); // was key chord (mods + key) pressed, e.g. you can pass 'ImGuiMod_Ctrl | ImGuiKey_S' as a key-chord. This doesn't do any routing or focus check, please consider using Shortcut() function instead. IMGUI_API int GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names are provided for debugging purpose and are not meant to be saved persistently nor compared. IMGUI_API void SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard); // Override io.WantCaptureKeyboard flag next frame (said flag is left for your application to handle, typically when true it instructs your app to ignore inputs). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard"; after the next NewFrame() call. - // Inputs Utilities: Shortcut Testing & Routing [BETA] + // Inputs Utilities: Shortcut Testing & Routing + // - Typical use is e.g.: 'if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_S)) { ... }'. + // - Flags: Default route use ImGuiInputFlags_RouteFocused, but see ImGuiInputFlags_RouteGlobal and other options in ImGuiInputFlags_! + // - Flags: Use ImGuiInputFlags_Repeat to support repeat. // - ImGuiKeyChord = a ImGuiKey + optional ImGuiMod_Alt/ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Super. // ImGuiKey_C // Accepted by functions taking ImGuiKey or ImGuiKeyChord arguments // ImGuiMod_Ctrl | ImGuiKey_C // Accepted by functions taking ImGuiKeyChord arguments @@ -1075,8 +1078,10 @@ namespace ImGui // The whole system is order independent, so if Child1 makes its calls before Parent, results will be identical. // This is an important property as it facilitate working with foreign code or larger codebase. // - To understand the difference: - // - IsKeyChordPressed() compares mods and call IsKeyPressed() -> function has no side-effect. - // - Shortcut() submits a route, routes are resolved, if it currently can be routed it calls IsKeyChordPressed() -> function has (desirable) side-effects as it can prevents another call from getting the route. + // - IsKeyChordPressed() compares mods and call IsKeyPressed() + // -> the function has no side-effect. + // - Shortcut() submits a route, routes are resolved, if it currently can be routed it calls IsKeyChordPressed() + // -> the function has (desirable) side-effects as it can prevents another call from getting the route. // - Visualize registered routes in 'Metrics/Debugger->Inputs'. IMGUI_API bool Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0); IMGUI_API void SetNextItemShortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0); @@ -1126,7 +1131,9 @@ namespace ImGui IMGUI_API const char* SaveIniSettingsToMemory(size_t* out_ini_size = NULL); // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings. // Debug Utilities - // - Your main debugging friend is the ShowMetricsWindow() function, which is also accessible from Demo->Tools->Metrics Debugger + // - Your main debugging friend is the ShowMetricsWindow() function. + // - Interactive tools are all accessible from the 'Dear ImGui Demo->Tools' menu. + // - Read https://github.com/ocornut/imgui/wiki/Debug-Tools for a description of all available debug tools. IMGUI_API void DebugTextEncoding(const char* text); IMGUI_API void DebugFlashStyleColor(ImGuiCol idx); IMGUI_API void DebugStartItemPicker(); @@ -2271,7 +2278,7 @@ struct ImGuiStyle // - recap: ImGui::GetFontSize() == FontSizeBase * (FontScaleMain * FontScaleDpi * other_scaling_factors) float FontSizeBase; // Current base font size before external global factors are applied. Use PushFont(NULL, size) to modify. Use ImGui::GetFontSize() to obtain scaled value. float FontScaleMain; // Main global scale factor. May be set by application once, or exposed to end-user. - float FontScaleDpi; // Additional global scale factor from viewport/monitor contents scale. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor DPI. + float FontScaleDpi; // Additional global scale factor from viewport/monitor contents scale. In docking branch: when io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor DPI. float Alpha; // Global alpha applies to everything in Dear ImGui. float DisabledAlpha; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. From 3050f653cb5b6c79875659c4ac4bf43f9678e588 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 Jan 2026 17:33:35 +0100 Subject: [PATCH 17/22] Menus, Nav: made navigation into menu-bar auto wrap on X axis. (#9178) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 2 +- imgui_widgets.cpp | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 63235b2c2..bd7715e2c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -135,6 +135,7 @@ Other Changes: - Menus: - Fixed MenuItem() label position and BeginMenu() arrow/icon/popup positions, when used inside a line with a baseline offset. + - Made navigation into menu-bar auto wrap on X axis. (#9178) - TreeNode: - Fixed highlight position when used inside a line with a large text baseline offset. (never quite worked in this situation; but then most of the time the text diff --git a/imgui.cpp b/imgui.cpp index 976216cb6..1f7115159 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -13436,7 +13436,7 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags wra // In theory we should test for NavMoveRequestButNoResultYet() but there's no point doing it: // as NavEndFrame() will do the same test. It will end up calling NavUpdateCreateWrappingRequest(). - if (g.NavWindow == window && g.NavMoveScoringItems && g.NavLayer == ImGuiNavLayer_Main) + if (g.NavWindow == window && g.NavMoveScoringItems && g.NavLayer == window->DC.NavLayerCurrent) g.NavMoveFlags = (g.NavMoveFlags & ~ImGuiNavMoveFlags_WrapMask_) | wrap_flags; } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 8faf35e50..de19ecf28 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -9070,6 +9070,10 @@ void ImGui::EndMenuBar() NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); // Repeat } } + else + { + NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_WrapX); + } PopClipRect(); PopID(); From b015acc464655943cd9e74444b8339b4baaec348 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 Jan 2026 17:50:25 +0100 Subject: [PATCH 18/22] Viewports: added GetWindowViewport() in imgui_internal.h to increase consistency with code using this public API in docking branch. (#9140) --- imgui_internal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui_internal.h b/imgui_internal.h index 3cc3ef512..e8618ccc5 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3223,6 +3223,7 @@ namespace ImGui IMGUI_API void UpdateMouseMovingWindowEndFrame(); // Viewports + inline ImGuiViewport* GetWindowViewport() { return GetMainViewport(); } // For code consistency. This is public API in docking branch. IMGUI_API void ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale); IMGUI_API void SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport); From a117055b6b8c549be838cef73b29fd6d5d4218f1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 Jan 2026 18:24:12 +0100 Subject: [PATCH 19/22] Internals: move field for locality. --- imgui.cpp | 13 +++++++------ imgui_internal.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1f7115159..12c51ccb1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7975,13 +7975,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical; // Default item width. Make it proportional to window size if window manually resizes - if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) - window->ItemWidthDefault = ImTrunc(window->Size.x * 0.65f); + const bool is_resizable_window = (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)); + if (is_resizable_window) + window->DC.ItemWidthDefault = ImTrunc(window->Size.x * 0.65f); else - window->ItemWidthDefault = ImTrunc(g.FontSize * 16.0f); - window->DC.ItemWidth = window->ItemWidthDefault; - window->DC.TextWrapPos = -1.0f; // disabled + window->DC.ItemWidthDefault = ImTrunc(g.FontSize * 16.0f); + window->DC.ItemWidth = window->DC.ItemWidthDefault; window->DC.ItemWidthStack.resize(0); + window->DC.TextWrapPos = -1.0f; // Disabled window->DC.TextWrapPosStack.resize(0); if (flags & ImGuiWindowFlags_Modal) window->DC.ModalDimBgColor = ColorConvertFloat4ToU32(GetStyleColorVec4(ImGuiCol_ModalWindowDimBg)); @@ -11448,7 +11449,7 @@ void ImGui::PushItemWidth(float item_width) ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width - window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); + window->DC.ItemWidth = (item_width == 0.0f ? window->DC.ItemWidthDefault : item_width); g.NextItemData.HasFlags &= ~ImGuiNextItemDataFlags_HasWidth; } diff --git a/imgui_internal.h b/imgui_internal.h index e8618ccc5..0f5e5d9cd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2625,6 +2625,7 @@ struct IMGUI_API ImGuiWindowTempData // Local parameters stacks // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. float ItemWidth; // Current item width (>0.0: width in pixels, <0.0: align xx pixels to the right of window). + float ItemWidthDefault; float TextWrapPos; // Current text wrap pos. ImVector ItemWidthStack; // Store item widths to restore (attention: .back() is not == ItemWidth) ImVector TextWrapPosStack; // Store text wrap pos to restore (attention: .back() is not == TextWrapPos) @@ -2715,7 +2716,6 @@ struct IMGUI_API ImGuiWindow int LastFrameActive; // Last frame number the window was Active. float LastTimeActive; // Last timestamp the window was Active (using float as we don't need high precision there) - float ItemWidthDefault; ImGuiStorage StateStorage; ImVector ColumnsStorage; float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale() From 7250fbde2e08774b3758b784b2a9b1ad0b0a3d76 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 23 Jan 2026 14:29:20 +0100 Subject: [PATCH 20/22] Fixed warning compiling stb_truetype with MSVC, C++20 with /w15262 (#9189) --- imgui_draw.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 9889b2884..4d386e56a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -104,6 +104,7 @@ namespace IMGUI_STB_NAMESPACE #pragma warning (push) #pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration #pragma warning (disable: 6011) // (stb_rectpack) Dereferencing NULL pointer 'cur->next'. +#pragma warning (disable: 5262) // (stb_truetype) implicit fall-through occurs here; are you missing a break statement? #pragma warning (disable: 6385) // (stb_truetype) Reading invalid data from 'buffer': the readable size is '_Old_3`kernel_width' bytes, but '3' bytes may be read. #pragma warning (disable: 28182) // (stb_rectpack) Dereferencing NULL pointer. 'cur' contains the same NULL value as 'cur->next' did. #endif From e1217227b29282733ff61de21fa82d324863c8e5 Mon Sep 17 00:00:00 2001 From: RegimantasSimkus <91128330+RegimantasSimkus@users.noreply.github.com> Date: Mon, 19 Jan 2026 17:05:13 +0000 Subject: [PATCH 21/22] Tooltips, Disabled: fixed EndDisabledOverrideReenable() assertion when nesting a tooltip in a disabled block. (#9180, #7640) Amend f953ebf9ca --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bd7715e2c..d3e44bf14 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -175,6 +175,8 @@ Other Changes: noticeable by user but detected by sanitizers). (#9089) [@judicaelclair] - InvisibleButton: allow calling with size (0,0) to fit to available content size. (#9166, #7623) +- Tooltips, Disabled: fixed EndDisabledOverrideReenable() assertion when + nesting a tooltip in a disabled block. (#9180, #7640) [@RegimantasSimkus] - Added GetItemFlags() in public API for consistency and to expose generic flags of last submitted item. (#9127) - Images: diff --git a/imgui.cpp b/imgui.cpp index 12c51ccb1..6f7738195 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8259,8 +8259,8 @@ void ImGui::BeginDisabledOverrideReenable() void ImGui::EndDisabledOverrideReenable() { ImGuiContext& g = *GImGui; - g.DisabledStackSize--; IM_ASSERT(g.DisabledStackSize > 0); + g.DisabledStackSize--; g.ItemFlagsStack.pop_back(); g.CurrentItemFlags = g.ItemFlagsStack.back(); g.Style.Alpha = g.CurrentWindowStack.back().DisabledOverrideReenableAlphaBackup; From d1cf58e590226402a016cd6c1e5b53c2212b7f41 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 23 Jan 2026 16:00:28 +0100 Subject: [PATCH 22/22] Nav: fixed WrapX/LoopX handling in menu layer. (#9178) Amend 3050f653cb --- docs/CHANGELOG.txt | 1 + imgui.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d3e44bf14..e2f14edec 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -171,6 +171,7 @@ Other Changes: - Nav: - Fixed remote/shortcut InputText() not teleporting mouse cursor when nav cursor is visible and `io.ConfigNavMoveSetMousePos` is enabled. + - Fixed a looping/wrapping issue when done in menu layer. (#9178) - Scrollbar: fixed a codepath leading to a divide-by-zero (which would not be noticeable by user but detected by sanitizers). (#9089) [@judicaelclair] - InvisibleButton: allow calling with size (0,0) to fit to available content diff --git a/imgui.cpp b/imgui.cpp index 6f7738195..5a49b8918 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -14252,9 +14252,13 @@ static void ImGui::NavUpdateCreateWrappingRequest() const ImGuiNavMoveFlags move_flags = g.NavMoveFlags; //const ImGuiAxis move_axis = (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X; + + // Menu layer does not maintain scrolling / content size (#9178) + ImVec2 wrap_size = (g.NavLayer == ImGuiNavLayer_Menu) ? window->Size : window->ContentSize + window->WindowPadding; + if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX))) { - bb_rel.Min.x = bb_rel.Max.x = window->ContentSize.x + window->WindowPadding.x; + bb_rel.Min.x = bb_rel.Max.x = wrap_size.x; if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(-bb_rel.GetHeight()); // Previous row @@ -14274,7 +14278,7 @@ static void ImGui::NavUpdateCreateWrappingRequest() } if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY))) { - bb_rel.Min.y = bb_rel.Max.y = window->ContentSize.y + window->WindowPadding.y; + bb_rel.Min.y = bb_rel.Max.y = wrap_size.y; if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(-bb_rel.GetWidth()); // Previous column