From 420f1793417e39560ca39a4209c55a9f204fde13 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 18 Sep 2026 22:26:25 +0200 Subject: [PATCH 01/13] Backends: fixed Clang -Wold-style-cast warnings. Amend 8e17468 --- backends/imgui_impl_dx10.cpp | 5 +++++ backends/imgui_impl_dx10.h | 3 +-- backends/imgui_impl_dx11.cpp | 5 +++++ backends/imgui_impl_dx11.h | 3 +-- backends/imgui_impl_dx12.cpp | 5 +++++ backends/imgui_impl_dx12.h | 3 +-- backends/imgui_impl_opengl3.cpp | 5 +++++ backends/imgui_impl_opengl3.h | 3 +-- backends/imgui_impl_sdlgpu3.cpp | 5 +++++ backends/imgui_impl_sdlgpu3.h | 3 +-- backends/imgui_impl_sdlrenderer2.cpp | 5 +++++ backends/imgui_impl_sdlrenderer2.h | 3 +-- backends/imgui_impl_sdlrenderer3.cpp | 5 +++++ backends/imgui_impl_sdlrenderer3.h | 3 +-- backends/imgui_impl_vulkan.cpp | 5 +++++ backends/imgui_impl_vulkan.h | 3 +-- backends/imgui_impl_wgpu.cpp | 5 +++++ backends/imgui_impl_wgpu.h | 3 +-- 18 files changed, 54 insertions(+), 18 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index cb767d6ac..a81d81305 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -101,6 +101,11 @@ static ImGui_ImplDX10_Data* ImGui_ImplDX10_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplDX10_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplDX10_RenderState* ImGui_ImplDX10_GetRenderState() +{ + return (ImGui_ImplDX10_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + // Functions static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* device) { diff --git a/backends/imgui_impl_dx10.h b/backends/imgui_impl_dx10.h index 6f75693f0..3ab1669a9 100644 --- a/backends/imgui_impl_dx10.h +++ b/backends/imgui_impl_dx10.h @@ -46,7 +46,6 @@ struct ImGui_ImplDX10_RenderState //ID3D10SamplerState* SamplerLinear; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerLinear) //ID3D10SamplerState* SamplerNearest; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerNearest) }; - -static inline ImGui_ImplDX10_RenderState* ImGui_ImplDX10_GetRenderState() { return (ImGui_ImplDX10_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; } +IMGUI_IMPL_API ImGui_ImplDX10_RenderState* ImGui_ImplDX10_GetRenderState(); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index ff0a607c4..a7d2cdf73 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -103,6 +103,11 @@ static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplDX11_RenderState* ImGui_ImplDX11_GetRenderState() +{ + return (ImGui_ImplDX11_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + // Functions static void ImGui_ImplDX11_SetupRenderState(const ImDrawData* draw_data, ID3D11DeviceContext* device_ctx) { diff --git a/backends/imgui_impl_dx11.h b/backends/imgui_impl_dx11.h index 2fe392dfa..5fd8ddca9 100644 --- a/backends/imgui_impl_dx11.h +++ b/backends/imgui_impl_dx11.h @@ -48,7 +48,6 @@ struct ImGui_ImplDX11_RenderState //ID3D11SamplerState* SamplerLinear; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerLinear) //ID3D11SamplerState* SamplerNearest; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerNearest) }; - -static inline ImGui_ImplDX11_RenderState* ImGui_ImplDX11_GetRenderState() { return (ImGui_ImplDX11_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; } +IMGUI_IMPL_API ImGui_ImplDX11_RenderState* ImGui_ImplDX11_GetRenderState(); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index e5b314eb1..22a9bdc97 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -133,6 +133,11 @@ static ImGui_ImplDX12_Data* ImGui_ImplDX12_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplDX12_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplDX12_RenderState* ImGui_ImplDX12_GetRenderState() +{ + return (ImGui_ImplDX12_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + // Buffers used during the rendering of a frame struct ImGui_ImplDX12_RenderBuffers { diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index a8f3a6cf6..106b4b4d2 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -74,8 +74,7 @@ struct ImGui_ImplDX12_RenderState ID3D12Device* Device; ID3D12GraphicsCommandList* CommandList; }; - -static inline ImGui_ImplDX12_RenderState* ImGui_ImplDX12_GetRenderState() { return (ImGui_ImplDX12_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; } +IMGUI_IMPL_API ImGui_ImplDX12_RenderState* ImGui_ImplDX12_GetRenderState(); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Legacy initialization API Obsoleted in 1.91.5 diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 1d340f637..73dc349d8 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -276,6 +276,11 @@ static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplOpenGL3_RenderState* ImGui_ImplOpenGL3_GetRenderState() +{ + return (ImGui_ImplOpenGL3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + // OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only) #ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY struct ImGui_ImplOpenGL3_VtxAttribState diff --git a/backends/imgui_impl_opengl3.h b/backends/imgui_impl_opengl3.h index b5bcc7400..e1d999bd3 100644 --- a/backends/imgui_impl_opengl3.h +++ b/backends/imgui_impl_opengl3.h @@ -76,7 +76,6 @@ struct ImGui_ImplOpenGL3_RenderState unsigned int CurrentSampler; // (GLuint) Used if UseBindSampler == true (and are available), otherwise always 0 unsigned int CurrentTexParameterFilter; // (GLuint) Used if UseTexParameterFilter == true }; - -static inline ImGui_ImplOpenGL3_RenderState* ImGui_ImplOpenGL3_GetRenderState() { return (ImGui_ImplOpenGL3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; } +IMGUI_IMPL_API ImGui_ImplOpenGL3_RenderState* ImGui_ImplOpenGL3_GetRenderState(); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 53b47d434..2f6b25015 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -94,6 +94,11 @@ static ImGui_ImplSDLGPU3_Data* ImGui_ImplSDLGPU3_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplSDLGPU3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplSDLGPU3_RenderState* ImGui_ImplSDLGPU3_GetRenderState() +{ + return (ImGui_ImplSDLGPU3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, ImGui_ImplSDLGPU3_FrameData* fd, uint32_t fb_width, uint32_t fb_height) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h index ce216fef0..a517c43b1 100644 --- a/backends/imgui_impl_sdlgpu3.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -59,7 +59,6 @@ struct ImGui_ImplSDLGPU3_RenderState { SDL_GPUDevice* Device; }; - -static inline ImGui_ImplSDLGPU3_RenderState* ImGui_ImplSDLGPU3_GetRenderState() { return (ImGui_ImplSDLGPU3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; } +IMGUI_IMPL_API ImGui_ImplSDLGPU3_RenderState* ImGui_ImplSDLGPU3_GetRenderState(); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index e66150e57..d8dcfb154 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -76,6 +76,11 @@ static ImGui_ImplSDLRenderer2_Data* ImGui_ImplSDLRenderer2_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplSDLRenderer2_RenderState* ImGui_ImplSDLRenderer2_GetRenderState() +{ + return (ImGui_ImplSDLRenderer2_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + // Functions static void ImGui_ImplSDLRenderer2_SetupRenderState(SDL_Renderer* renderer) { diff --git a/backends/imgui_impl_sdlrenderer2.h b/backends/imgui_impl_sdlrenderer2.h index 0c14912db..e16b8cae9 100644 --- a/backends/imgui_impl_sdlrenderer2.h +++ b/backends/imgui_impl_sdlrenderer2.h @@ -51,7 +51,6 @@ struct ImGui_ImplSDLRenderer2_RenderState { SDL_Renderer* Renderer; }; - -static inline ImGui_ImplSDLRenderer2_RenderState* ImGui_ImplSDLRenderer2_GetRenderState() { return (ImGui_ImplSDLRenderer2_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; } +IMGUI_IMPL_API ImGui_ImplSDLRenderer2_RenderState* ImGui_ImplSDLRenderer2_GetRenderState(); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 121ce59c8..6dd4c14fe 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -81,6 +81,11 @@ static ImGui_ImplSDLRenderer3_Data* ImGui_ImplSDLRenderer3_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplSDLRenderer3_RenderState* ImGui_ImplSDLRenderer3_GetRenderState() +{ + return (ImGui_ImplSDLRenderer3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + // Functions static void ImGui_ImplSDLRenderer3_SetupRenderState(SDL_Renderer* renderer) { diff --git a/backends/imgui_impl_sdlrenderer3.h b/backends/imgui_impl_sdlrenderer3.h index 019def26a..ee701be38 100644 --- a/backends/imgui_impl_sdlrenderer3.h +++ b/backends/imgui_impl_sdlrenderer3.h @@ -51,7 +51,6 @@ struct ImGui_ImplSDLRenderer3_RenderState SDL_Renderer* Renderer; SDL_ScaleMode CurrentScaleMode; // Current scale mode during render. Set to SDL_SCALEMODE_INVALID to use "SetSamplerFromTex" mode. }; - -static inline ImGui_ImplSDLRenderer3_RenderState* ImGui_ImplSDLRenderer3_GetRenderState() { return (ImGui_ImplSDLRenderer3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; } +IMGUI_IMPL_API ImGui_ImplSDLRenderer3_RenderState* ImGui_ImplSDLRenderer3_GetRenderState(); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 9eca9a767..80b9d58ab 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -459,6 +459,11 @@ static ImGui_ImplVulkan_Data* ImGui_ImplVulkan_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplVulkan_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplVulkan_RenderState* ImGui_ImplVulkan_GetRenderState() +{ + return (ImGui_ImplVulkan_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + #ifdef IMGUI_IMPL_VULKAN_USE_LOADER // Get the Vulkan function pointers used by the current backend. // If no backend is available, return the currently loaded global function pointers (ImGuiImplVulkanFuncs). diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index a48dae3ec..0f2da5e2d 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -175,8 +175,7 @@ struct ImGui_ImplVulkan_RenderState VkPipeline Pipeline; VkPipelineLayout PipelineLayout; }; - -static inline ImGui_ImplVulkan_RenderState* ImGui_ImplVulkan_GetRenderState() { return (ImGui_ImplVulkan_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; } +IMGUI_IMPL_API ImGui_ImplVulkan_RenderState* ImGui_ImplVulkan_GetRenderState(); //------------------------------------------------------------------------- // Internal / Miscellaneous Vulkan Helpers diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index bdc4d434b..002967b92 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -129,6 +129,11 @@ static ImGui_ImplWGPU_Data* ImGui_ImplWGPU_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplWGPU_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +ImGui_ImplWGPU_RenderState* ImGui_ImplWGPU_GetRenderState() +{ + return (ImGui_ImplWGPU_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; +} + //----------------------------------------------------------------------------- // SHADERS //----------------------------------------------------------------------------- diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index a5867c923..9f206db32 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -81,8 +81,7 @@ struct ImGui_ImplWGPU_RenderState WGPUDevice Device; WGPURenderPassEncoder RenderPassEncoder; }; - -static inline ImGui_ImplWGPU_RenderState* ImGui_ImplWGPU_GetRenderState() { return (ImGui_ImplWGPU_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; } +IMGUI_IMPL_API ImGui_ImplWGPU_RenderState* ImGui_ImplWGPU_GetRenderState(); //------------------------------------------------------------------------- // Internal Helpers From d5c68c301a3d564e54051a7a78ee7858c4b821fb Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Sep 2026 14:16:55 +0200 Subject: [PATCH 02/13] ImGuiTextFilter: reworked filter to make space an AND operator. Demo: tweaked demo. Removed FilterOp, MinWordSize added a few commits ago. --- docs/CHANGELOG.txt | 6 ++-- imgui.cpp | 78 ++++++++++++++++++++++++++++------------------ imgui.h | 14 ++++----- imgui_demo.cpp | 23 +++++++++----- 4 files changed, 73 insertions(+), 48 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 82c2ffe00..ca1e27e49 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -84,8 +84,10 @@ Other Changes: hasn't been owned by another items. This is more correct and also necessary to avoid Drags/Sliders cancelling also triggering a cancel menu. (#8564, #9534) - ImGuiTextFilter: - - Added support for space ' ' as separator, which is more standard. (#2435, #30) - - Added support for quoted "xxx" blocks to e.g. match words sequences. (#2435) + - Added support for space as an "and" filter, which is the standard. (#2435, #30) + e.g. w/ filter 'hello world' (without quotes) both words needs to be in input data. + - Added support for double-quoted "xxx" blocks to e.g. match words sequences. (#2435) + e.g. w/ filter "hello world" the exact sequence needs to be in input data. - Fixed filtering when mixing "include" and "-exclude" keyword so that an "-exclude" match always filters out. (#2435) [@kudaba, @ocornut] - Added `DrawWithHint()` function. (#6206, #6395, #6447) diff --git a/imgui.cpp b/imgui.cpp index f9dc89e53..7e353df8f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3094,9 +3094,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077 { InputBuf[0] = 0; - FilterOp = '|'; - MinWordSize = 1; - _CountExclude = _CountInclude = 0; + _CountExclude = 0; if (default_filter) { ImStrncpy(InputBuf, default_filter, IM_COUNTOF(InputBuf)); @@ -3118,14 +3116,15 @@ bool ImGuiTextFilter::DrawWithHint(const char* label, const char* hint) return value_changed; } -// Parse filter and split into items +// Parse filter and split into a format optimal for PassFilter() void ImGuiTextFilter::Build() { _Items.resize(0); - _CountExclude = _CountInclude = 0; - IM_ASSERT(FilterOp == '|' || FilterOp == '&'); + _CountExclude = 0; + const char* buf_e = InputBuf + ImStrlen(InputBuf); const char* word_e; + int seq_incl_start_idx = -1; for (const char* word_b = InputBuf; word_b < buf_e; word_b = word_e + 1) { // Trim blanks @@ -3151,20 +3150,33 @@ void ImGuiTextFilter::Build() } // Min length - if (word_e - word_b < MinWordSize) - continue; + if (word_e - word_b > 0) + { + // Add to list. The '-' is not stored in items but implicitly inferred using (n < CountExclude). + // FIXME-OPT: as items are derived from user input buffer and we expect the insert() to behave sanely. + if (is_excl) + { + _Items.insert(_Items.Data + _CountExclude, ImGuiTextFilter::ImGuiTextFilterItem(word_b, word_e)); + _CountExclude++; + if (seq_incl_start_idx != -1) + seq_incl_start_idx++; + } + else + { + if (seq_incl_start_idx == -1) + seq_incl_start_idx = _Items.Size; + _Items.insert(_Items.Data + _Items.Size, ImGuiTextFilter::ImGuiTextFilterItem(word_b, word_e)); + _Items.Data[seq_incl_start_idx].CountInclude++; + } + } - // Add to list - // The '-' is not stored in items but implicitly inferred using (n < CountExclude). - // FIXME-OPT: about ~push_front(): as N is derived from user inputs we expect this to be fine. - _Items.insert(is_excl ? _Items.Data : _Items.Data + _Items.Size, ImGuiTextFilter::ImGuiTextFilterItem(word_b, word_e)); - if (is_excl) - _CountExclude++; - else - _CountInclude++; + // Next sequence + if (word_e[0] == ',') + seq_incl_start_idx = -1; } } +// FIXME: Could use a specialized ImStristr() + pre-convert our filter to uppercase. bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const { if (_Items.Size == 0) @@ -3173,24 +3185,28 @@ bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const text = text_end = ""; // Filters are sorted so that '-' ones are always leading. - int n; - for (n = 0; n < _CountExclude; n++) - if (ImStristr(text, text_end, _Items.Data[n].Begin, _Items.Data[n].End) != NULL) + ImGuiTextFilterItem* seq = _Items.Data; + ImGuiTextFilterItem* seq_excl_end = _Items.Data + _CountExclude; + for (; seq < seq_excl_end; seq++) + if (ImStristr(text, text_end, seq->Begin, seq->Begin + seq->Len) != NULL) return false; - const bool is_and_filter = (FilterOp == '&'); - for (; n < _Items.Size; n++) - { - const bool is_match = ImStristr(text, text_end, _Items.Data[n].Begin, _Items.Data[n].End) != NULL; - if (is_match && !is_and_filter) // or incl 1 -> true - return true; // or incl 0 -> continue - if (!is_match && is_and_filter) // and incl 1 -> continue - return false; // and incl 0 -> false - } - // When no inclusion are specified (only exclusions) we implicitly pass - if (_CountInclude == 0) + // Process includes + ImGuiTextFilterItem* seq_incl_end = _Items.Data + _Items.Size; + if (seq == seq_incl_end) // When no inclusion are specified (only exclusions) we implicitly pass return true; - return is_and_filter; + while (seq < seq_incl_end) + { + ImGuiTextFilterItem* seq_next = seq + seq->CountInclude; + IM_ASSERT_PARANOID(seq->CountInclude > 0 && seq_next <= seq_incl_end); + for (; seq < seq_next; seq++) + if (ImStristr(text, text_end, seq->Begin, seq->Begin + seq->Len) == NULL) + break; + if (seq == seq_next) // All matched + return true; + seq = seq_next; // Try next + } + return false; } //----------------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index 2ad3b91fb..1e0ce7dcc 100644 --- a/imgui.h +++ b/imgui.h @@ -2785,7 +2785,7 @@ struct ImGuiOnceUponAFrame operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; } }; -// Helper: Parse and apply text filters e.g. 'aaa bbb -ccc'. +// Helper: Parse and apply text filters e.g. 'aaa bbb' (all), 'aaa,bbb' (any), '-aaa' (exclude), '"Hello, world"' (exact sequence) struct ImGuiTextFilter { IMGUI_API ImGuiTextFilter(const char* default_filter = ""); @@ -2801,20 +2801,18 @@ struct ImGuiTextFilter inline bool Draw(const char* label, float width) { if (width != 0.0f) ImGui::SetNextItemWidth(width); return Draw(label); } #endif - // [Internal] Don't use! Will be replaced with ImStrv. + // [Internal] Types struct ImGuiTextFilterItem { const char* Begin; - const char* End; - ImGuiTextFilterItem(const char* b, const char* e) { Begin = b; End = e; } + int Len; + int CountInclude; // >0 when beginning of an AND chain. + ImGuiTextFilterItem(const char* b, const char* e) { IM_ASSERT(e > b); Begin = b; Len = (int)(e - b); CountInclude = 0; } }; // [Internal] Members char InputBuf[256]; // User input buffer - char FilterOp; // == '|' (any) pr '&' (all) - ImU8 MinWordSize; // == 1 - int _CountExclude; // >= 0 - int _CountInclude; // >= 0 + int _CountExclude; // >= 0 count of leading exclude ImVector _Items; // Pre-parsed, trimmed, reordered items }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5ef47f3af..0b16dab3c 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3943,15 +3943,24 @@ static void DemoWindowWidgetsTextFilter() static ImGuiTextFilter filter; ImGui::Text("Filter usage:\n" " \"\" display all lines\n" - " \"xxx\" display lines containing \"xxx\"\n" - " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" - " \"-xxx\" hide lines containing \"xxx\""); + " xxx display lines containing \"xxx\"\n" + " xxx yyy display lines containing \"xxx\" and \"yyy\"\n" + " \"xxx yyy\" display lines containing \"xxx yyy\"\n" + " xxx,yyy display lines containing \"xxx\" or \"yyy\"\n" + " -xxx hide lines containing \"xxx\""); ImGui::SetNextItemWidth(-FLT_MIN); filter.DrawWithHint("##Filter", "Filter (incl -excl)"); - const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; - for (int i = 0; i < IM_COUNTOF(lines); i++) - if (filter.PassFilter(lines[i])) - ImGui::BulletText("%s", lines[i]); + if (ImGui::BeginChild("##items", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 15), ImGuiChildFlags_FrameStyle)) + { + const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; + for (const char* item : lines) + if (filter.PassFilter(item)) + ImGui::TextUnformatted(item); + for (const char* item : ExampleNames) + if (filter.PassFilter(item)) + ImGui::TextUnformatted(item); + } + ImGui::EndChild(); ImGui::TreePop(); } } From e19fea020f69e97e420f32d80f8f1dc7e829dc2c Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Sep 2026 15:12:59 +0200 Subject: [PATCH 03/13] ImGuiTextFilter: moved ImGuiTextFilterItem to internals. (#2435) --- imgui.cpp | 4 ++-- imgui.h | 16 ++++------------ imgui_internal.h | 10 ++++++++++ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7e353df8f..b3cb17a17 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3156,7 +3156,7 @@ void ImGuiTextFilter::Build() // FIXME-OPT: as items are derived from user input buffer and we expect the insert() to behave sanely. if (is_excl) { - _Items.insert(_Items.Data + _CountExclude, ImGuiTextFilter::ImGuiTextFilterItem(word_b, word_e)); + _Items.insert(_Items.Data + _CountExclude, ImGuiTextFilterItem(word_b, word_e)); _CountExclude++; if (seq_incl_start_idx != -1) seq_incl_start_idx++; @@ -3165,7 +3165,7 @@ void ImGuiTextFilter::Build() { if (seq_incl_start_idx == -1) seq_incl_start_idx = _Items.Size; - _Items.insert(_Items.Data + _Items.Size, ImGuiTextFilter::ImGuiTextFilterItem(word_b, word_e)); + _Items.insert(_Items.Data + _Items.Size, ImGuiTextFilterItem(word_b, word_e)); _Items.Data[seq_incl_start_idx].CountInclude++; } } diff --git a/imgui.h b/imgui.h index 1e0ce7dcc..a108888a2 100644 --- a/imgui.h +++ b/imgui.h @@ -2786,6 +2786,7 @@ struct ImGuiOnceUponAFrame }; // Helper: Parse and apply text filters e.g. 'aaa bbb' (all), 'aaa,bbb' (any), '-aaa' (exclude), '"Hello, world"' (exact sequence) +struct ImGuiTextFilterItem; struct ImGuiTextFilter { IMGUI_API ImGuiTextFilter(const char* default_filter = ""); @@ -2801,19 +2802,10 @@ struct ImGuiTextFilter inline bool Draw(const char* label, float width) { if (width != 0.0f) ImGui::SetNextItemWidth(width); return Draw(label); } #endif - // [Internal] Types - struct ImGuiTextFilterItem - { - const char* Begin; - int Len; - int CountInclude; // >0 when beginning of an AND chain. - ImGuiTextFilterItem(const char* b, const char* e) { IM_ASSERT(e > b); Begin = b; Len = (int)(e - b); CountInclude = 0; } - }; - - // [Internal] Members + // Members char InputBuf[256]; // User input buffer - int _CountExclude; // >= 0 count of leading exclude - ImVector _Items; // Pre-parsed, trimmed, reordered items + int _CountExclude; // [Internal] >= 0 count of leading exclude + ImVector _Items; // [Internal] Pre-parsed, trimmed, reordered items }; // Helper: Growable text buffer for logging/accumulating text diff --git a/imgui_internal.h b/imgui_internal.h index 8b6ffb796..15d2513aa 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -368,6 +368,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer // - Helper: ImPool<> // - Helper: ImChunkStream<> // - Helper: ImGuiTextIndex +// - Helper: ImGuiTextFilterItem // - Helper: ImGuiStorage //----------------------------------------------------------------------------- @@ -836,6 +837,15 @@ struct ImGuiTextIndex void append(const char* base, int old_size, int new_size); }; +// [Internal] Types +struct ImGuiTextFilterItem +{ + const char* Begin; + int Len; + int CountInclude; // >0 when beginning of an AND chain. + ImGuiTextFilterItem(const char* b, const char* e) { IM_ASSERT(e > b); Begin = b; Len = (int)(e - b); CountInclude = 0; } +}; + // Helper: ImGuiPackedDate (sizeof() == 2) // Store a date in a way that is efficient to read/write in text form. If we stored e.g. number of days since Epoch we'd need costlier back and forth. // This is specifically designed to be able to prune old .ini data. From 6cf8332f93ac2acbba03112171d44396730a74f9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Sep 2026 16:52:48 +0200 Subject: [PATCH 04/13] ImGuiTextFilterItem: added MatchIncludesMask support field for e.g. ImGuiTextFilterMultiMatch. --- imgui_internal.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 15d2513aa..77fd38256 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -840,10 +840,11 @@ struct ImGuiTextIndex // [Internal] Types struct ImGuiTextFilterItem { - const char* Begin; - int Len; - int CountInclude; // >0 when beginning of an AND chain. - ImGuiTextFilterItem(const char* b, const char* e) { IM_ASSERT(e > b); Begin = b; Len = (int)(e - b); CountInclude = 0; } + const char* Begin; // Pointer within parent's buffer + int Len; // Length of text (non-zero terminated) + short CountInclude; // Number of consecutive items forming an end chain. >0 when beginning of an AND chain, =0 otherwise. + unsigned short MatchIncludesMask; // Storage for multi-sources versions of PassFilter(). Unused by core library. + ImGuiTextFilterItem(const char* b, const char* e) { IM_ASSERT(e > b); Begin = b; Len = (int)(e - b); CountInclude = 0; MatchIncludesMask = 0; } }; // Helper: ImGuiPackedDate (sizeof() == 2) From 58d7570b8bbbfdcade40799812da9c7162e13498 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Sep 2026 18:23:26 +0200 Subject: [PATCH 05/13] ImGuiTextFilterItem: shallow renames. --- imgui.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b3cb17a17..7bbfa72bd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3124,7 +3124,7 @@ void ImGuiTextFilter::Build() const char* buf_e = InputBuf + ImStrlen(InputBuf); const char* word_e; - int seq_incl_start_idx = -1; + int seq_start_idx = -1; for (const char* word_b = InputBuf; word_b < buf_e; word_b = word_e + 1) { // Trim blanks @@ -3158,21 +3158,21 @@ void ImGuiTextFilter::Build() { _Items.insert(_Items.Data + _CountExclude, ImGuiTextFilterItem(word_b, word_e)); _CountExclude++; - if (seq_incl_start_idx != -1) - seq_incl_start_idx++; + if (seq_start_idx != -1) + seq_start_idx++; } else { - if (seq_incl_start_idx == -1) - seq_incl_start_idx = _Items.Size; + if (seq_start_idx == -1) + seq_start_idx = _Items.Size; _Items.insert(_Items.Data + _Items.Size, ImGuiTextFilterItem(word_b, word_e)); - _Items.Data[seq_incl_start_idx].CountInclude++; + _Items.Data[seq_start_idx].CountInclude++; } } // Next sequence if (word_e[0] == ',') - seq_incl_start_idx = -1; + seq_start_idx = -1; } } @@ -3192,19 +3192,19 @@ bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const return false; // Process includes - ImGuiTextFilterItem* seq_incl_end = _Items.Data + _Items.Size; - if (seq == seq_incl_end) // When no inclusion are specified (only exclusions) we implicitly pass + ImGuiTextFilterItem* seq_end = _Items.Data + _Items.Size; + if (seq == seq_end) // When no inclusion are specified (only exclusions) we implicitly pass return true; - while (seq < seq_incl_end) + while (seq < seq_end) { - ImGuiTextFilterItem* seq_next = seq + seq->CountInclude; - IM_ASSERT_PARANOID(seq->CountInclude > 0 && seq_next <= seq_incl_end); - for (; seq < seq_next; seq++) + ImGuiTextFilterItem* seq_incl_end = seq + seq->CountInclude; + IM_ASSERT_PARANOID(seq->CountInclude > 0 && seq_incl_end <= seq_end); + for (; seq < seq_incl_end; seq++) if (ImStristr(text, text_end, seq->Begin, seq->Begin + seq->Len) == NULL) break; - if (seq == seq_next) // All matched + if (seq == seq_incl_end) // All matched return true; - seq = seq_next; // Try next + seq = seq_incl_end; // Try next } return false; } From d12321803d168099245da64fbe57e7f767f744b2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Sep 2026 15:57:40 +0200 Subject: [PATCH 06/13] Popups: reworked GetMousePosOnOpeningCurrentPopup() to be legal to call within the BeginPopup/EndPopup scope of a popup which was just closed. (#9551) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ca1e27e49..07cf3ec9c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -83,6 +83,8 @@ Other Changes: - Amended context menu right-click opening code to check that the right-click hasn't been owned by another items. This is more correct and also necessary to avoid Drags/Sliders cancelling also triggering a cancel menu. (#8564, #9534) + - Reworked `GetMousePosOnOpeningCurrentPopup()` to be legal to call within + the BeginPopup/EndPopup scope of a popup which was just closed. (#9551) [@jkunstwald] - ImGuiTextFilter: - Added support for space as an "and" filter, which is the standard. (#2435, #30) e.g. w/ filter 'hello world' (without quotes) both words needs to be in input data. diff --git a/imgui.cpp b/imgui.cpp index 7bbfa72bd..f7d9bfa91 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10269,12 +10269,11 @@ void ImGui::TeleportMousePos(const ImVec2& pos) //IMGUI_DEBUG_LOG_IO("TeleportMousePos: (%.1f,%.1f)\n", io.MousePos.x, io.MousePos.y); } -// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed! ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() { ImGuiContext& g = *GImGui; if (g.BeginPopupStack.Size > 0) - return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; + return g.BeginPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos; return g.IO.MousePos; } From 7bfc19281459c67863d4615c56152567bb98c773 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Sep 2026 16:48:51 +0200 Subject: [PATCH 07/13] Tables: tweak struct packing. --- docs/CHANGELOG.txt | 4 ++-- imgui_internal.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 07cf3ec9c..ff7c4d265 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -83,8 +83,8 @@ Other Changes: - Amended context menu right-click opening code to check that the right-click hasn't been owned by another items. This is more correct and also necessary to avoid Drags/Sliders cancelling also triggering a cancel menu. (#8564, #9534) - - Reworked `GetMousePosOnOpeningCurrentPopup()` to be legal to call within - the BeginPopup/EndPopup scope of a popup which was just closed. (#9551) [@jkunstwald] + - Reworked `GetMousePosOnOpeningCurrentPopup()` to be legal to call within the + BeginPopup/EndPopup scope of a popup which was just closed. (#9551) [@jkunstwald] - ImGuiTextFilter: - Added support for space as an "and" filter, which is the standard. (#2435, #30) e.g. w/ filter 'hello world' (without quotes) both words needs to be in input data. diff --git a/imgui_internal.h b/imgui_internal.h index 77fd38256..17925f2f8 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3137,9 +3137,9 @@ struct IMGUI_API ImGuiTable ImDrawListSplitter* DrawSplitter; // Shortcut to TempData->DrawSplitter while in table. Isolate draw commands per columns to avoid switching clip rect constantly ImGuiTableInstanceData InstanceDataFirst; ImVector InstanceDataExtra; // FIXME-OPT: Using a small-vector pattern would be good. - ImGuiTableColumnSortSpecs SortSpecsSingle; - ImVector SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would be good. ImGuiTableSortSpecs SortSpecs; // Public facing sorts specs, this is what we return in TableGetSortSpecs() + ImVector SortSpecsMulti; // FIXME-OPT: Using a small-vector pattern would be good. + ImGuiTableColumnSortSpecs SortSpecsSingle; ImGuiTableColumnIdx SortSpecsCount; ImGuiTableColumnIdx ColumnsEnabledCount; // Number of enabled columns (<= ColumnsCount) ImGuiTableColumnIdx ColumnsEnabledFixedCount; // Number of enabled columns using fixed width (<= ColumnsCount) From a6784c378fb59d0cdee51b08b09fbd8ec9d01d95 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Sep 2026 16:54:13 +0200 Subject: [PATCH 08/13] Tables: fixed reconcile path being needlessly taken on first frame of every table. (#9108) --- imgui_internal.h | 1 + imgui_tables.cpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 17925f2f8..97158497b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3171,6 +3171,7 @@ struct IMGUI_API ImGuiTable ImS8 NavLayer; // ImGuiNavLayer at the time of BeginTable(). bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row. bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow(). + bool IsNewTable; bool IsInitializing; bool IsReconcileMode; bool IsSortSpecsDirty; diff --git a/imgui_tables.cpp b/imgui_tables.cpp index fb1b998d0..eba5b12e2 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -375,7 +375,6 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG const int previous_frame_active = table->LastFrameActive; const int instance_no = (previous_frame_active != g.FrameCount) ? 0 : table->InstanceCurrent + 1; const ImGuiTableFlags previous_flags = table->Flags; - const bool is_new_table = (previous_frame_active == -1); table->ID = id; table->Flags = flags; table->LastFrameActive = g.FrameCount; @@ -384,6 +383,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->IsLayoutLocked = false; table->InnerWidth = inner_width; table->NavLayer = (ImS8)outer_window->DC.NavLayerCurrent; + table->IsNewTable = (previous_frame_active == -1); temp_data->UserOuterSize = outer_size; // Instance data (for instance 0, TableID == TableInstanceID) @@ -585,7 +585,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG if (table->IsInitializing) { // Initialize - if (is_new_table) + if (table->IsNewTable) { table->SettingsOffset = -1; table->IsSettingsRequestLoad = true; @@ -1756,7 +1756,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo ImGuiTableColumn* column = &table->Columns[column_idx]; // If topology change goes into reconcile mode - if (table->IsReconcileMode == false && column->ID != column_id) + if (table->IsReconcileMode == false && column->ID != column_id && !table->IsNewTable) { table->IsReconcileMode = true; table->TempData->ReconcileColumnsRequests.reserve(table->ColumnsCount - column_idx); From cc072ca90e525c0793ff80a152be8eeb70937261 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Sep 2026 17:13:16 +0200 Subject: [PATCH 09/13] Tables: comments for saving fix when using ImGuiTableFlags_Sortable and no user changes were made. (#9519, #9108) Because SortOrder save is gated, it doesn't guarantee every column gets an .ini entry. Amend 1d7b37dc9b. We set ImGuiTableFlags_Reorderable but technically any other field would work, tho ImGuiTableFlags_Reorderable makes more sense. --- docs/CHANGELOG.txt | 3 +++ imgui_tables.cpp | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ff7c4d265..a1170fcde 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -68,6 +68,9 @@ Other Changes: - Using <> scrolling buttons while the selected Tab is at either end of the section mid-section but not fully visible always makes it fully visible (before eventually selecting a Tab in the leading/trailing section) +- Tables: + - Fixed a bug restoring correct .ini columns order when table use is Sortable + but had no user changes. (regression from 1.92.9). (#9519, #9108) - Selectable: - Fixed `ImGuiSelectableFlags_SelectOnNav` triggering during NavInit. - Fonts: diff --git a/imgui_tables.cpp b/imgui_tables.cpp index eba5b12e2..b3e0458eb 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -3970,12 +3970,10 @@ void ImGui::TableSaveSettings(ImGuiTable* table) if (column->DisplayOrder != n) settings->SaveFlags |= ImGuiTableFlags_Reorderable; if (column->SortOrder != -1) - settings->SaveFlags |= ImGuiTableFlags_Sortable; + settings->SaveFlags |= ImGuiTableFlags_Sortable | ImGuiTableFlags_Reorderable; // Because SortOrder saving itself is gated, make sure every column is saved (#9519) if (column->IsUserEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) == 0)) settings->SaveFlags |= ImGuiTableFlags_Hideable; } - if (table->Flags & ImGuiTableFlags_Sortable) - settings->SaveFlags |= ImGuiTableFlags_Sortable | ImGuiTableFlags_Reorderable; settings->SaveFlags &= table->Flags; settings->RefScale = save_ref_scale ? table->RefScale : 0.0f; From 623ba461202d73471d65a1c2b608eecc3959a6d6 Mon Sep 17 00:00:00 2001 From: Daniel Castonguay Date: Tue, 22 Sep 2026 18:12:59 -0400 Subject: [PATCH 10/13] DrawList: fixed dangling ImDrawList::_OwnerName when using animated label. (#9552) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a1170fcde..ceb094151 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -124,6 +124,7 @@ Other Changes: - Added optional `platform_io.DrawCallback_SetSamplerFromTex` standard backend-agnostic draw callback for requesting to use the sampler associated already associated to a texture. Currently only supported by the OpenGL2/3 and SDLRenderer3 backend. (#9378) + - Fixed dangling ImDrawList::_OwnerName when using animated label. (#9552) [@ubi-dcastonguay] - Demo: - Added `Widgets->Mixed Values` section. (#5518, #5677, #6865) - Style Editor: fixed style/colors combo box applying style when opening Combo. diff --git a/imgui.cpp b/imgui.cpp index f7d9bfa91..2bc9e4c34 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7755,6 +7755,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) size_t buf_len = (size_t)window->NameBufLen; window->Name = ImStrdupcpy(window->Name, &buf_len, name); window->NameBufLen = (int)buf_len; + window->DrawList->_OwnerName = window->Name; } // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS From e7289367973e97012a247d6b0a6c4c31b2d4216c Mon Sep 17 00:00:00 2001 From: Brenton Bostick Date: Thu, 24 Sep 2026 07:48:14 -0400 Subject: [PATCH 11/13] Docs: fixed typos/repeated words. (#9555) --- backends/imgui_impl_opengl3_loader.h | 2 +- docs/CHANGELOG.txt | 8 ++++---- imgui.cpp | 4 ++-- imgui_internal.h | 4 ++-- imgui_widgets.cpp | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/backends/imgui_impl_opengl3_loader.h b/backends/imgui_impl_opengl3_loader.h index 2c485841a..34b262dff 100644 --- a/backends/imgui_impl_opengl3_loader.h +++ b/backends/imgui_impl_opengl3_loader.h @@ -114,7 +114,7 @@ extern "C" { #define GLAPI extern #endif /* glcorearb.h is for use with OpenGL core profile implementations. -** It should should be placed in the same directory as gl.h and +** It should be placed in the same directory as gl.h and ** included as . ** ** glcorearb.h includes only APIs in the latest OpenGL core profile diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ceb094151..d39b8c7b2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -145,7 +145,7 @@ Other Changes: don't have the equivalent of `SDL_SetTextureScaleMode()` and the callback won't work with them. - Vulkan: added for support for multiple Vulkan contexts with custom loaders. (#6616) [@lstalmir] - WebGPU: fixed passing non-integer sizes to `wgpuRenderPassEncoderSetViewport()` - when when `FramebufferScale` is >1.0f. (#9515, #8628) [@WayU] + when `FramebufferScale` is >1.0f. (#9515, #8628) [@WayU] - WebGPU: update to build with wgpu-native 29.0+. (#9377, #9532, #9530) [@lucascompython, @ivan-enzhaev] - Examples: - MSVC: disabled /JMC in Visual Studio projects (unnecessary overhead). @@ -1755,7 +1755,7 @@ Non-breaking Fonts/Textures related changes: - Fonts: ImFontAtlas::AddFontXXX() can fail more gracefully if error handling is configured to not assert (this will be better exposed via future font flags). - Fonts: added style.FontScaleBase scaling factor (previously called io.FontGlobalScale). -- Fonts: added style.FontScaleDpi scaling factor. This is designed to be be changed on +- Fonts: added style.FontScaleDpi scaling factor. This is designed to be changed on per-monitor/per-viewport basis, which `io.ConfigDpiScaleFonts` does automatically. (which is why it is separate from FontScaleBase). - Fonts: added optional font_size parameter to ImGui::PushFont() function. @@ -2910,7 +2910,7 @@ Other changes: - Backends: Vulkan: Remove Volk/ from volk.h #include directives. (#7722, #6582, #4854) [@martin-ejdestig] - Examples: SDL3: Remove use of SDL_HINT_IME_NATIVE_UI since new SDL_HINT_IME_IMPLEMENTED_UI - values has a more suitable default for our case case. + values has a more suitable default for our case. - Examples: GLFW+Vulkan, SDL+Vulkan: handle swap chain resize even without Vulkan returning VK_SUBOPTIMAL_KHR, which doesn't seem to happen on Wayland. (#7671) [@AndreiNego, @ocornut] @@ -4863,7 +4863,7 @@ Other Changes: - ColorPicker4: Fixed picker being unable to select exact 1.0f color when dragging toward the edges of the SV square (previously picked 0.999989986f). (#3517) [@rokups] - Menus: Fixed vertical alignments of MenuItem() calls within a menu bar (broken in 1.84). (#4538) -- Menus: Improve closing logic when moving diagonally in empty between between parent and child menus to +- Menus: Improve closing logic when moving diagonally in empty space between parent and child menus to accommodate for varying font size and dpi. - Menus: Fixed crash when navigating left inside a child window inside a sub-menu. (#4510). - Menus: Fixed an assertion happening in some situations when closing nested menus (broken in 1.83). (#4640) diff --git a/imgui.cpp b/imgui.cpp index 2bc9e4c34..d25365f16 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -230,7 +230,7 @@ CODE This is to increase compatibility, increase maintainability and facilitate use from other languages. - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types. See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that. - We can can optionally export math operators for ImVec2/ImVec4 using IMGUI_DEFINE_MATH_OPERATORS, which we use internally. + We can optionally export math operators for ImVec2/ImVec4 using IMGUI_DEFINE_MATH_OPERATORS, which we use internally. - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (so don't use ImVector in your code or at our own risk!). - Building: We don't use nor mandate a build system for the main library. @@ -12859,7 +12859,7 @@ bool ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags // This is a helper to handle the simplest case of associating one named popup to one given widget. // - To create a popup associated to the last item, you generally want to pass a NULL value to str_id. // - To create a popup with a specific identifier, pass it in str_id. -// - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call. +// - This is useful when using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call. // - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id. // - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters). // This is essentially the same as: diff --git a/imgui_internal.h b/imgui_internal.h index 97158497b..677a257c6 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -538,7 +538,7 @@ inline float ImFloor(float f) { return inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2(ImFloor(v.x), ImFloor(v.y)); } inline float ImTrunc64(float f) { return (float)(ImS64)(f); } inline float ImRound64(float f) { return (float)(ImS64)(f + 0.5f); } // FIXME: Positive values only. -inline float ImCeilFast(float f) { int i = (int)f; return (float)(i + (f > (float)i)); } // Consider using the the bit-hack version (search for "0x1p120f"). +inline float ImCeilFast(float f) { int i = (int)f; return (float)(i + (f > (float)i)); } // Consider using the bit-hack version (search for "0x1p120f"). inline int ImModPositive(int a, int b) { return (a + b) % b; } inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } @@ -905,7 +905,7 @@ struct IMGUI_API ImDrawListSharedData const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas (== FontAtlas->TexUvLines) ImFontAtlas* FontAtlas; // Current font atlas ImFont* Font; // Current font (used for simplified AddText overload) - float FontSize; // Current font size (used for for simplified AddText overload) + float FontSize; // Current font size (used for simplified AddText overload) float FontScale; // Current font scale (== FontSize / Font->FontSize) float CurveTessellationMaxError; // Tessellation tolerance when using PathBezierCurveTo() float CircleTessellationMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1f60853b6..7737a41e6 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4795,7 +4795,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ IM_ASSERT(buf != NULL && buf_size >= 0); IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) - IM_ASSERT(!((flags & ImGuiInputTextFlags_ElideLeft) && (flags & ImGuiInputTextFlags_Multiline))); // Multiline does not not work with left-trimming + IM_ASSERT(!((flags & ImGuiInputTextFlags_ElideLeft) && (flags & ImGuiInputTextFlags_Multiline))); // Multiline does not work with left-trimming IM_ASSERT((flags & ImGuiInputTextFlags_WordWrap) == 0 || (flags & ImGuiInputTextFlags_Password) == 0); // WordWrap does not work with Password mode. IM_ASSERT((flags & ImGuiInputTextFlags_WordWrap) == 0 || (flags & ImGuiInputTextFlags_Multiline) != 0); // WordWrap does not work in single-line mode. From 5c6a86a9d27d04d4274f7b25be24b38a4579facd Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 25 Sep 2026 14:07:59 +0200 Subject: [PATCH 12/13] imgui_freetype: fixed ExtraSizeScale (used by embedded ProggyForever) leading to non-pixel aligned vertical offset. (#9348, #9233) + Added ImRoundPositive64(), ImRoundSigned64(). --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 2 +- imgui_draw.cpp | 1 + imgui_internal.h | 3 ++- misc/freetype/imgui_freetype.cpp | 3 +++ 5 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d39b8c7b2..e751035ac 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -77,6 +77,8 @@ Other Changes: - Reworked `AddFontDefault()` to use `io.DisplayFrameBufferScale` as part of the heuristic to select `AddFontDefaultVector()` by default, effectively using ProggyForever instead of ProggyClean on most Apple/Retina setups by default. + - imgui_freetype: Fixed blurryness rendering `AddFontDefaultVector()`. Caused by a + non-pixel aligned offset caused by `ExtraSizeScale`. (#9348, #9233) [@redpartizan, @RDMCz] - ColorEdit: - ColorButton, ColorEdit, ColorPicker: cancel-out alpha caused by BeginDisabled() so disabled color buttons have the same color as non-disabled oness. (#9511) diff --git a/imgui.cpp b/imgui.cpp index d25365f16..57ed579af 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -12080,7 +12080,7 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window) } scroll[axis] = scroll_target - center_ratio * (window->SizeFull[axis] - decoration_size[axis]); } - scroll[axis] = ImRound64(ImMax(scroll[axis], 0.0f)); + scroll[axis] = ImRoundPositive64(ImMax(scroll[axis], 0.0f)); if (!window->Collapsed && !window->SkipItems) scroll[axis] = ImMin(scroll[axis], window->ScrollMax[axis]); } diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0e76fcefc..a4097bf38 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4776,6 +4776,7 @@ static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); baked->Ascent = ImCeil(unscaled_ascent * scale_for_layout); baked->Descent = ImFloor(unscaled_descent * scale_for_layout); + // FIXME: round to rasterizer density? (#9348) } return true; } diff --git a/imgui_internal.h b/imgui_internal.h index 677a257c6..0ffadedc3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -537,7 +537,8 @@ inline ImVec2 ImTrunc(const ImVec2& v) { return inline float ImFloor(float f) { return (float)((f >= 0 || (float)(int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2(ImFloor(v.x), ImFloor(v.y)); } inline float ImTrunc64(float f) { return (float)(ImS64)(f); } -inline float ImRound64(float f) { return (float)(ImS64)(f + 0.5f); } // FIXME: Positive values only. +inline float ImRoundPositive64(float f) { return (float)(ImS64)(f + 0.5f); } // Positive values only. +inline float ImRoundSigned64(float f) { return (float)(ImS64)(f >= 0.0f ? f + 0.5f : f - 0.5f); } inline float ImCeilFast(float f) { int i = (int)f; return (float)(i + (f > (float)i)); } // Consider using the bit-hack version (search for "0x1p120f"). inline int ImModPositive(int a, int b) { return (a + b) % b; } inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 79dff8bfb..83259bfd0 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -7,6 +7,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026/09/25: fixed handling of ExtraSizeScale. // 2025/06/11: refactored for the new ImFontLoader architecture, and ImGuiBackendFlags_RendererHasTextures support. // 2024/10/17: added plutosvg support for SVG Fonts (seems faster/better than lunasvg). Enable by using '#define IMGUI_ENABLE_FREETYPE_PLUTOSVG'. (#7927) // 2023/11/13: added support for ImFontConfig::RasterizationDensity field for scaling render density without scaling metrics. @@ -468,6 +469,8 @@ static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* s //LineSpacing = (float)FT_CEIL(metrics.height) * scale; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. //LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * scale; // The spacing in pixels between one row's descent and the next row's ascent. //MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * scale; // This field gives the maximum horizontal cursor advance for all glyphs in the font. + baked->Ascent = ImRoundSigned64(baked->Ascent * rasterizer_density) / rasterizer_density; + baked->Descent = ImRoundSigned64(baked->Descent * rasterizer_density) / rasterizer_density; } return true; } From aa0181478b182f7170378a5d8629401b77ee326e Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 25 Sep 2026 14:17:14 +0200 Subject: [PATCH 13/13] imgui_freetype: tweak rounding code. (#9348, #9233) --- misc/freetype/imgui_freetype.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 83259bfd0..2e2e78f7d 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -464,8 +464,8 @@ static bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* s // Read metrics FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; const float scale = 1.0f / (rasterizer_density * src->ExtraSizeScale); - baked->Ascent = (float)FT_CEIL(metrics.ascender) * scale; // The pixel extents above the baseline in pixels (typically positive). - baked->Descent = (float)FT_CEIL(metrics.descender) * scale; // The extents below the baseline in pixels (typically negative). + baked->Ascent = ((float)metrics.ascender / FT_SCALEFACTOR) * scale; // The pixel extents above the baseline in pixels (typically positive). + baked->Descent = ((float)metrics.descender / FT_SCALEFACTOR) * scale; // The extents below the baseline in pixels (typically negative). //LineSpacing = (float)FT_CEIL(metrics.height) * scale; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. //LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * scale; // The spacing in pixels between one row's descent and the next row's ascent. //MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * scale; // This field gives the maximum horizontal cursor advance for all glyphs in the font.