Merge branch 'master' into docking

# Conflicts:
#	backends/imgui_impl_dx10.cpp
#	backends/imgui_impl_dx10.h
#	backends/imgui_impl_dx11.cpp
#	backends/imgui_impl_dx11.h
#	backends/imgui_impl_dx12.cpp
#	backends/imgui_impl_dx12.h
#	backends/imgui_impl_opengl2.cpp
#	backends/imgui_impl_opengl3.cpp
#	backends/imgui_impl_opengl3.h
#	backends/imgui_impl_sdlgpu3.cpp
#	backends/imgui_impl_sdlgpu3.h
#	backends/imgui_impl_sdlrenderer3.cpp
#	backends/imgui_impl_sdlrenderer3.h
#	backends/imgui_impl_vulkan.cpp
#	backends/imgui_impl_vulkan.h
#	backends/imgui_impl_wgpu.cpp
#	backends/imgui_impl_wgpu.h
#	imgui.cpp
#	imgui_internal.h
#	imgui_widgets.cpp
This commit is contained in:
ocornut 2026-09-18 22:19:23 +02:00
commit 730623ea35
26 changed files with 366 additions and 177 deletions

View File

@ -5,6 +5,7 @@
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX10_GetRenderState().
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.

View File

@ -5,6 +5,7 @@
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX10_GetRenderState().
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
@ -47,4 +48,6 @@ struct ImGui_ImplDX10_RenderState
//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; }
#endif // #ifndef IMGUI_DISABLE

View File

@ -5,7 +5,7 @@
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX11_GetRenderState().
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.

View File

@ -5,7 +5,7 @@
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX11_GetRenderState().
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
@ -50,4 +50,6 @@ struct ImGui_ImplDX11_RenderState
//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; }
#endif // #ifndef IMGUI_DISABLE

View File

@ -5,7 +5,7 @@
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX12_GetRenderState().
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// FIXME: The transition from removing a viewport and moving the window in an existing hosted viewport tends to flicker.

View File

@ -5,7 +5,7 @@
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX12_GetRenderState().
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification.
@ -76,6 +76,8 @@ struct ImGui_ImplDX12_RenderState
ID3D12GraphicsCommandList* CommandList;
};
static inline ImGui_ImplDX12_RenderState* ImGui_ImplDX12_GetRenderState() { return (ImGui_ImplDX12_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; }
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
// Legacy initialization API Obsoleted in 1.91.5
// - font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap'

View File

@ -28,7 +28,8 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
// 2026-09-17: OpenGL: Added support for platform_io.DrawCallback_SetSamplerFromTex. (#9378)
// 2026-09-07: OpenGL: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
// 2026-07-15: OpenGL: Backup and restore GL_UNPACK_ROW_LENGTH and GL_UNPACK_ALIGNMENT in UpdateTexture() to avoid corrupting caller GL state. (#8802, #9473)
// 2026-04-23: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
// 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295)
@ -138,6 +139,8 @@ static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_wid
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glShadeModel(GL_SMOOTH);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
bd->UseTexParameterToSetSampler = false;
bd->NextSampler = GL_LINEAR;
// If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!),
@ -164,9 +167,13 @@ static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_wid
}
// Draw callbacks
// - IMPORTANT: Using DrawCallback_SetSamplerLinear/DrawCallback_SetSamplerNearest will trash glTexParameteri() values for the texture!!
// We cannot decently backup/restore that state because glGetTexParameteriv() is slow on many setups.
// - Using DrawCallback_SetSamplerFromTex will basically instruct the backend to use existing glTexParameteri() values without modifying anything, which is the initial state.
static void ImGui_ImplOpenGL2_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplOpenGL2_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_LINEAR; }
static void ImGui_ImplOpenGL2_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_NEAREST; }
static void ImGui_ImplOpenGL2_DrawCallback_SetSamplerFromTex(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); bd->UseTexParameterToSetSampler = false; }
// OpenGL2 Render function.
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
@ -369,6 +376,7 @@ bool ImGui_ImplOpenGL2_Init()
platform_io.DrawCallback_ResetRenderState = ImGui_ImplOpenGL2_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplOpenGL2_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplOpenGL2_DrawCallback_SetSamplerNearest;
platform_io.DrawCallback_SetSamplerFromTex = ImGui_ImplOpenGL2_DrawCallback_SetSamplerFromTex;
return true;
}

View File

@ -7,6 +7,7 @@
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!]
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplOpenGL3_GetRenderState().
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// About WebGL/ES:
@ -25,7 +26,8 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
// 2026-09-17: OpenGL: Added support for platform_io.DrawCallback_SetSamplerFromTex. (#9378)
// 2026-09-07: OpenGL: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
// 2026-07-15: OpenGL: Backup and restore GL_UNPACK_ROW_LENGTH and GL_UNPACK_ALIGNMENT in UpdateTexture() to avoid corrupting caller GL state. (#8802, #9473)
// 2026-06-17: OpenGL: Expose selected render state in ImGui_ImplOpenGL3_RenderState, Allowing to dynamically select between use of glBindSampler() and glTexParameter(). You can access in 'void* platform_io.Renderer_RenderState' during rendering.
// 2026-06-03: OpenGL: GLSL version detection assume GLSL 410 when GL context is 4.1. Fixes an issue running on macOS with Wine. (#9427, #6577)
@ -392,9 +394,12 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, ImGui_Impl
glUniform1i(bd->AttribLocationTex, 0);
glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
(void)render_state;
render_state->UseBindSampler = bd->HasBindSampler;
render_state->UseTexParameterFilter = false;
render_state->CurrentSampler = 0;
render_state->CurrentTexParameterFilter = 0;
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
if (render_state->UseBindSampler)
if (bd->HasBindSampler && render_state->UseBindSampler)
{
render_state->CurrentSampler = bd->TexSamplers[0];
glBindSampler(0, render_state->CurrentSampler); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise.
@ -417,16 +422,15 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, ImGui_Impl
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, col)));
}
// Draw callbacks
static void ImGui_ImplOpenGL3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*)
static void ImGui_ImplOpenGL3_DrawCallback_SetSampler(unsigned int sampler_idx, unsigned int tex_parameter_filter)
{
ImGui_ImplOpenGL3_RenderState* render_state = ImGui_ImplOpenGL3_GetRenderState();
IM_UNUSED(sampler_idx);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
if (bd->HasBindSampler)
if (bd->HasBindSampler && render_state->UseBindSampler)
{
render_state->CurrentSampler = bd->TexSamplers[0];
render_state->CurrentSampler = bd->TexSamplers[sampler_idx];
render_state->UseTexParameterFilter = false;
glBindSampler(0, render_state->CurrentSampler);
}
@ -434,26 +438,30 @@ static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, c
#endif
{
render_state->UseTexParameterFilter = true;
render_state->CurrentTexParameterFilter = GL_LINEAR;
render_state->CurrentTexParameterFilter = tex_parameter_filter;
}
}
static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*)
// Draw callbacks
// - IMPORTANT: Using DrawCallback_SetSamplerLinear/DrawCallback_SetSamplerNearest will trash glTexParameteri() values for the texture if used on a GL context not supporting glBindSampler()!!
// We cannot decently backup/restore that state because glGetTexParameteriv() is slow on many setups.
// - Using DrawCallback_SetSamplerFromTex will basically instruct the backend to use existing glTexParameteri() values without modifying anything.
static void ImGui_ImplOpenGL3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_DrawCallback_SetSampler(0, GL_LINEAR); }
static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_DrawCallback_SetSampler(1, GL_NEAREST); }
static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerFromTex(const ImDrawList*, const ImDrawCmd*)
{
ImGui_ImplOpenGL3_RenderState* render_state = ImGui_ImplOpenGL3_GetRenderState();
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
if (bd->HasBindSampler)
{
render_state->CurrentSampler = bd->TexSamplers[1];
render_state->UseTexParameterFilter = false;
glBindSampler(0, render_state->CurrentSampler);
render_state->CurrentSampler = 0;
glBindSampler(0, 0);
}
else
#endif
{
render_state->UseTexParameterFilter = true;
render_state->CurrentTexParameterFilter = GL_NEAREST;
}
render_state->UseBindSampler = false;
render_state->UseTexParameterFilter = false;
}
// OpenGL3 Render function.
@ -527,11 +535,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
// Setup render state structure (for callbacks and custom texture bindings)
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplOpenGL3_RenderState render_state;
render_state.UseBindSampler = bd->HasBindSampler;
render_state.UseTexParameterFilter = false;
render_state.CurrentSampler = 0;
render_state.CurrentTexParameterFilter = 0;
ImGui_ImplOpenGL3_RenderState render_state = {};
platform_io.Renderer_RenderState = &render_state;
ImGui_ImplOpenGL3_SetupRenderState(draw_data, &render_state, fb_width, fb_height, vertex_array_object);
@ -1102,6 +1106,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
platform_io.DrawCallback_ResetRenderState = ImGui_ImplOpenGL3_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest;
platform_io.DrawCallback_SetSamplerFromTex = ImGui_ImplOpenGL3_DrawCallback_SetSamplerFromTex;
// Store GLSL version string so we can refer to it later in case we recreate shaders.
// Note: GLSL version is NOT the same as GL version. Leave this to nullptr if unsure.

View File

@ -7,6 +7,7 @@
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!]
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplOpenGL3_GetRenderState().
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// About WebGL/ES:
@ -73,8 +74,8 @@ struct ImGui_ImplOpenGL3_RenderState
{
bool UseBindSampler;
bool UseTexParameterFilter;
unsigned int CurrentSampler; // (GLuint) Used if UseBindSampler == true, otherwise always 0
unsigned int CurrentTexParameterFilter; // (GLuint) Used if UseTexParameterToSetSampler == true
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; }

View File

@ -5,6 +5,7 @@
// [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct.
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplSDLGPU3_GetRenderState().
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification.

View File

@ -5,6 +5,7 @@
// [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct.
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplSDLGPU3_GetRenderState().
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification.
@ -60,4 +61,6 @@ struct ImGui_ImplSDLGPU3_RenderState
SDL_GPUDevice* Device;
};
static inline ImGui_ImplSDLGPU3_RenderState* ImGui_ImplSDLGPU3_GetRenderState() { return (ImGui_ImplSDLGPU3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; }
#endif // #ifndef IMGUI_DISABLE

View File

@ -56,7 +56,8 @@
#endif
// SDL
#include <SDL.h>
#include <SDL_render.h>
#include <SDL_version.h>
#if !SDL_VERSION_ATLEAST(2,0,17)
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function
#endif

View File

@ -53,4 +53,6 @@ struct ImGui_ImplSDLRenderer2_RenderState
SDL_Renderer* Renderer;
};
static inline ImGui_ImplSDLRenderer2_RenderState* ImGui_ImplSDLRenderer2_GetRenderState() { return (ImGui_ImplSDLRenderer2_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; }
#endif // #ifndef IMGUI_DISABLE

View File

@ -13,7 +13,7 @@
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplSDLRenderer3_GetRenderState().
// Missing features:
// [ ] Renderer: Multi-viewport support (multiple windows).
@ -27,6 +27,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-09-17: Restore modified texture scale modes at the end of RenderDrawData(). Added DrawCallback_SetSamplerFromTex support. Added CurrentScaleMode in ImGui_ImplSDLRenderer3_RenderState (#9543, #9378)
// 2026-07-15: Fixed default sampler state to be linear (broken 2026-04-23). (#9470, #9378)
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
// 2026-03-12: Fixed invalid assert in ImGui_ImplSDLRenderer3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295)
@ -53,19 +54,24 @@
#endif
// SDL
#include <SDL3/SDL.h>
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_version.h>
#if !SDL_VERSION_ATLEAST(3,0,0)
#error This backend requires SDL 3.0.0+
#endif
// SDL_Renderer data
struct ImGui_ImplSDLRenderer3_TexScaleModeEntry
{
SDL_Texture* Texture;
SDL_ScaleMode ScaleModeBackup;
};
struct ImGui_ImplSDLRenderer3_Data
{
SDL_Renderer* Renderer; // Main viewport's renderer
ImVector<SDL_FColor> ColorBuffer;
// Render State
SDL_ScaleMode CurrentScaleMode;
ImVector<ImGui_ImplSDLRenderer3_TexScaleModeEntry> TexScaleModeBackups; // Backup of texture scale modes
ImGui_ImplSDLRenderer3_Data() { memset((void*)this, 0, sizeof(*this)); }
};
@ -80,14 +86,13 @@ static ImGui_ImplSDLRenderer3_Data* ImGui_ImplSDLRenderer3_GetBackendData()
// Functions
static void ImGui_ImplSDLRenderer3_SetupRenderState(SDL_Renderer* renderer)
{
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
ImGui_ImplSDLRenderer3_RenderState* render_state = ImGui_ImplSDLRenderer3_GetRenderState();
// Clear out any viewports and cliprect set by the user
// FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
SDL_SetRenderViewport(renderer, nullptr);
SDL_SetRenderClipRect(renderer, nullptr);
bd->CurrentScaleMode = SDL_SCALEMODE_LINEAR;
render_state->CurrentScaleMode = SDL_SCALEMODE_LINEAR;
}
void ImGui_ImplSDLRenderer3_NewFrame()
@ -117,8 +122,61 @@ static int SDL_RenderGeometryRaw8BitColor(SDL_Renderer* renderer, ImVector<SDL_F
// Draw callbacks
static void ImGui_ImplSDLRenderer3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); bd->CurrentScaleMode = SDL_SCALEMODE_LINEAR; }
static void ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); bd->CurrentScaleMode = SDL_SCALEMODE_NEAREST; }
static void ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLRenderer3_RenderState* render_state = ImGui_ImplSDLRenderer3_GetRenderState(); render_state->CurrentScaleMode = SDL_SCALEMODE_LINEAR; }
static void ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLRenderer3_RenderState* render_state = ImGui_ImplSDLRenderer3_GetRenderState(); render_state->CurrentScaleMode = SDL_SCALEMODE_NEAREST; }
static void ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerFromTex(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLRenderer3_RenderState* render_state = ImGui_ImplSDLRenderer3_GetRenderState(); render_state->CurrentScaleMode = SDL_SCALEMODE_INVALID; } // SDL_SCALEMODE_INVALID = use/keep value in texture.
// SDLRenderer has various design issues which makes it hard to do it compared to regular graphics API.
// - scale/filtering mode is tied to a texture.
// - scale/filtering mode is not queued as part of the SDL_RenderGeometryXXX commands, so a change in one texture requires a flush.
static void ImGui_ImplSDLRenderer3_TexScaleModeUpdate(SDL_Renderer* renderer, SDL_Texture* tex, SDL_ScaleMode desired_scale_mode)
{
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
if (desired_scale_mode != SDL_SCALEMODE_INVALID)
{
// Enforce a scale mode
SDL_ScaleMode tex_scale_mode = desired_scale_mode;
if (!SDL_GetTextureScaleMode(tex, &tex_scale_mode) || tex_scale_mode == desired_scale_mode)
return;
SDL_FlushRenderer(renderer);
SDL_SetTextureScaleMode(tex, desired_scale_mode);
// Store backup of old scale mode (FIXME-OPT)
for (ImGui_ImplSDLRenderer3_TexScaleModeEntry& entry : bd->TexScaleModeBackups)
if (entry.Texture == tex)
{
if (entry.ScaleModeBackup == SDL_SCALEMODE_INVALID)
entry.ScaleModeBackup = tex_scale_mode;
return;
}
ImGui_ImplSDLRenderer3_TexScaleModeEntry entry = { tex, tex_scale_mode };
bd->TexScaleModeBackups.push_back(entry);
}
else
{
// Use scale mode that was set in texture by user. If there is an entry, restore it and clear the entry.
for (ImGui_ImplSDLRenderer3_TexScaleModeEntry& entry : bd->TexScaleModeBackups)
if (entry.Texture == tex && entry.ScaleModeBackup != SDL_SCALEMODE_INVALID)
{
SDL_FlushRenderer(renderer);
SDL_SetTextureScaleMode(tex, entry.ScaleModeBackup);
entry.ScaleModeBackup = SDL_SCALEMODE_INVALID;
return;
}
}
}
static void ImGui_ImplSDLRenderer3_TexScaleModeRestoreBackups(SDL_Renderer* renderer)
{
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
if (bd->TexScaleModeBackups.Size == 0)
return;
SDL_FlushRenderer(renderer);
for (ImGui_ImplSDLRenderer3_TexScaleModeEntry& entry : bd->TexScaleModeBackups)
if (entry.ScaleModeBackup != SDL_SCALEMODE_INVALID)
SDL_SetTextureScaleMode(entry.Texture, entry.ScaleModeBackup);
bd->TexScaleModeBackups.resize(0);
}
void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer)
{
@ -161,19 +219,19 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer*
SDL_GetRenderViewport(renderer, &old.Viewport);
SDL_GetRenderClipRect(renderer, &old.ClipRect);
// Setup desired state
ImGui_ImplSDLRenderer3_SetupRenderState(renderer);
// Setup render state structure (for callbacks and custom texture bindings)
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplSDLRenderer3_RenderState render_state;
render_state.Renderer = renderer;
platform_io.Renderer_RenderState = &render_state;
// Setup desired state
ImGui_ImplSDLRenderer3_SetupRenderState(renderer);
IM_ASSERT(bd->TexScaleModeBackups.Size == 0);
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = render_scale;
SDL_ScaleMode last_scale_mode = bd->CurrentScaleMode;
// Render command lists
for (const ImDrawList* draw_list : draw_data->CmdLists)
@ -203,20 +261,17 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer*
if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
SDL_SetRenderClipRect(renderer, &r);
// Setup texture scale/filtering mode
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
ImGui_ImplSDLRenderer3_TexScaleModeUpdate(renderer, tex, render_state.CurrentScaleMode);
// Draw
const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, pos));
const float* uv = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, uv));
const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.19+
if (last_scale_mode != bd->CurrentScaleMode)
SDL_FlushRenderer(renderer);
// Bind texture, Draw
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
SDL_SetTextureScaleMode(tex, bd->CurrentScaleMode);
const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col));
SDL_RenderGeometryRaw8BitColor(renderer, bd->ColorBuffer, tex,
xy, (int)sizeof(ImDrawVert),
color, (int)sizeof(ImDrawVert),
@ -231,6 +286,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer*
// Restore modified SDL_Renderer state
SDL_SetRenderViewport(renderer, old.ViewportEnabled ? &old.Viewport : nullptr);
SDL_SetRenderClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr);
ImGui_ImplSDLRenderer3_TexScaleModeRestoreBackups(renderer);
}
void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex)
@ -312,6 +368,7 @@ bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer)
platform_io.DrawCallback_ResetRenderState = ImGui_ImplSDLRenderer3_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerNearest;
platform_io.DrawCallback_SetSamplerFromTex = ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerFromTex;
bd->Renderer = renderer;

View File

@ -13,7 +13,7 @@
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplSDLRenderer3_GetRenderState().
// Missing features:
// [ ] Renderer: Multi-viewport support (multiple windows).
@ -29,7 +29,8 @@
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
struct SDL_Renderer;
// For SDL_ScaleMode which cannot be forward declared.
#include <SDL3/SDL_render.h>
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer);
@ -50,6 +51,9 @@ IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex)
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; }
#endif // #ifndef IMGUI_DISABLE

View File

@ -5,7 +5,7 @@
// [!] Renderer: User texture binding. Use a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions.
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplVulkan_GetRenderState().
// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.

View File

@ -5,7 +5,7 @@
// [!] Renderer: User texture binding. Use a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions.
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplVulkan_GetRenderState().
// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
@ -184,6 +184,8 @@ struct ImGui_ImplVulkan_RenderState
VkPipelineLayout PipelineLayout;
};
static inline ImGui_ImplVulkan_RenderState* ImGui_ImplVulkan_GetRenderState() { return (ImGui_ImplVulkan_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; }
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
//-------------------------------------------------------------------------

View File

@ -5,8 +5,8 @@
// Implemented features:
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplWGPU_GetRenderState().
// Missing features or Issues:
// [ ] Renderer: Multi-viewport support (multiple windows), useful for desktop.

View File

@ -17,8 +17,8 @@
// Implemented features:
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplWGPU_GetRenderState().
// Missing features or Issues:
// [ ] Renderer: Multi-viewport support (multiple windows), useful for desktop.
@ -84,6 +84,8 @@ struct ImGui_ImplWGPU_RenderState
WGPURenderPassEncoder RenderPassEncoder;
};
static inline ImGui_ImplWGPU_RenderState* ImGui_ImplWGPU_GetRenderState() { return (ImGui_ImplWGPU_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; }
//-------------------------------------------------------------------------
// Internal Helpers
// Those are currently used by our example applications.

View File

@ -45,6 +45,8 @@ Breaking Changes:
favor of `style.CurveTessellationMaxError` (default 1.12)` which is in Pixels unit. It is
easier to tweak + this allows us to easily scale error threshold on high density screens.
- style.CurveTessellationMaxError == sqrf(style.CurveTessellationTol).
- ImGuiTextFilter: removed `float width` parameter of `Draw(const char* filter, float width)`:
prefer using `SetNextItemWidth(float)` which is standard. Kept inline redirection function.
- Backends:
- DirectX12: Removed support for legacy `ImGui_ImplDX12_Init()` signature, which was
obsoleted in 1.91.6 (December 2014), because it needed to forcefully disable support
@ -60,6 +62,14 @@ Other Changes:
- TreeNode:
- Fixed issues/asserts with 32+ deep trees when using ImGuiTreeNodeFlags_DrawLinesXXX
features or other features requiring stack storage. (#9509) [@lasrod]
- TabBar:
- Improved scroll target when clicking a Tab that is larger than the scrolling
section width.
- 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)
- Selectable:
- Fixed `ImGuiSelectableFlags_SelectOnNav` triggering during NavInit.
- Fonts:
- Reworked `AddFontDefault()` to use `io.DisplayFrameBufferScale` as part of the heuristic
to select `AddFontDefaultVector()` by default, effectively using ProggyForever instead of
@ -73,6 +83,16 @@ 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)
- 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)
- 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)
- Added a "incl -excl" hint by default when the search field is empty. (#6206, #6395, #6447)
- Style:
- Inverted `ImGuiCol_TitleBgXXX` colors for `StyleColorsLight()` so that the selected
window title bar appears brighter.
- Misc:
- Added `ImGuiItemFlags_MixedValue` flag for representing mixed/indeterminate values.
Supported by: Checkbox(), RadioButton(), DragXXX(), SliderXXX(), InputXXX(), ColorXXX()
@ -87,19 +107,34 @@ Other Changes:
and various operators.
- IO: restore default clipboard/ime/shell platform handlers on ClearPlatformHandlers(), fixing
issues switching backends mid-session to one relying on default. (#9537, #8945, #2769) [@lstalmir]
- ImDrawList:
- DrawList:
- Per-viewport FramebufferScale for Apple/Retina screen is applied to draw lists:
- AA Fringe is scaled accordingly.
- Circle and Curves tessellation error are scaled accordingly.
- Reworked assert in PushTexture() to allow convenience grace period of using a
texture that was queue for destroy during the frame. Make it safe to stick to
an existing texture during the frame. (#9528, #8465)
- 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)
- Demo:
- Added `Widgets->Mixed Values` section. (#5518, #5677, #6865)
- Style Editor: fixed style/colors combo box applying style when opening Combo.
- Backends:
- QNX: added QNX Screen backend. (#9492) [@mgorchak-blackberry]
- OpenGL2, OpenGL3: added support for `platform_io.DrawCallback_SetSamplerFromTex` draw
callback to request using the sampler associated already associated to a texture. (#9378)
- OpenGL2, OpenGL3: fixed `DrawCallback_ResetRenderState` handler not reseting all states
in the glTexParameter() path. (#9378)
- SDL2: fixed querying framebuffer scale/density when using Metal without
going through a SDL_Renderer. (#5592) [@lailoken]
- SDLRenderer3: restore any temporarily modified texture scale modes at the of `RenderDrawData()`. (#9378)
- SDLRenderer3: expose CurrentScaleMode in ImGui_ImplSDLRenderer3_RenderState. (#9543, #9378) [@Clownacy]
- SDLRenderer3: added support for `platform_io.DrawCallback_SetSamplerFromTex` draw callback to request
using the sampler associated already associated to a texture via `SDL_SetTextureScaleMode()`. (#9378)
It is equivalent to setting `render_state->CurrentScaleMode = SDL_SCALEMODE_INVALID`.
Note: this callback is only supported by selected rendering backends: most other graphics API
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]

152
imgui.cpp
View File

@ -402,6 +402,8 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
you may use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos)
- likewise io.MousePos and GetMousePos() will use OS coordinates.
If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos.
- 2026/09/18 (1.93.0) - ImGuiTextFilter: removed `float width` parameter of `Draw(const char* filter, float width)`: prefer using `SetNextItemWidth(float)` which is standard. Kept inline redirection function.
- 2026/08/03 (1.93.0) - Style: obsoleted `style.CurveTessellationTol (default 1.25)` which was in Pixels² unit in favor of `style.CurveTessellationMaxError` (default 1.12)` which is in Pixels unit.
- style.CurveTessellationMaxError == sqrf(style.CurveTessellationTol).
- 2026/07/20 (1.92.9) - DragXXX, SliderXXX, InputScalar: with `ImGuiItemFlags_LiveEditOnInputScalar` now defaulting to being disabled:
@ -3154,11 +3156,13 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE
// [SECTION] ImGuiTextFilter
//-----------------------------------------------------------------------------
// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
// Helper: Parse and apply text filters e.g. 'aaa bbb -ccc'.
ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077
{
InputBuf[0] = 0;
CountGrep = 0;
FilterOp = '|';
MinWordSize = 1;
_CountExclude = _CountInclude = 0;
if (default_filter)
{
ImStrncpy(InputBuf, default_filter, IM_COUNTOF(InputBuf));
@ -3166,85 +3170,93 @@ ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077
}
}
bool ImGuiTextFilter::Draw(const char* label, float width)
bool ImGuiTextFilter::Draw(const char* label)
{
if (width != 0.0f)
ImGui::SetNextItemWidth(width);
bool value_changed = ImGui::InputText(label, InputBuf, IM_COUNTOF(InputBuf));
return DrawWithHint(label, "incl -excl");
}
// Use ImGui::SetNextItemWidth() manually if you want to use this.
bool ImGuiTextFilter::DrawWithHint(const char* label, const char* hint)
{
bool value_changed = ImGui::InputTextWithHint(label, hint, InputBuf, IM_COUNTOF(InputBuf));
if (value_changed)
Build();
return value_changed;
}
void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector<ImGuiTextRange>* out) const
{
out->resize(0);
const char* wb = b;
const char* we = wb;
while (we < e)
{
if (*we == separator)
{
out->push_back(ImGuiTextRange(wb, we));
wb = we + 1;
}
we++;
}
if (wb != we)
out->push_back(ImGuiTextRange(wb, we));
}
// Parse filter and split into items
void ImGuiTextFilter::Build()
{
Filters.resize(0);
ImGuiTextRange input_range(InputBuf, InputBuf + ImStrlen(InputBuf));
input_range.split(',', &Filters);
CountGrep = 0;
for (ImGuiTextRange& f : Filters)
_Items.resize(0);
_CountExclude = _CountInclude = 0;
IM_ASSERT(FilterOp == '|' || FilterOp == '&');
const char* buf_e = InputBuf + ImStrlen(InputBuf);
const char* word_e;
for (const char* word_b = InputBuf; word_b < buf_e; word_b = word_e + 1)
{
while (f.b < f.e && ImCharIsBlankA(f.b[0]))
f.b++;
while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
f.e--;
if (f.empty())
// Trim blanks
while (word_b < buf_e && ImCharIsBlankA(word_b[0])) // FIXME: UTF-8 support
word_b++;
const bool is_excl = (word_b < buf_e && word_b[0] == '-');
if (is_excl)
word_b++;
const bool is_quote = (word_b < buf_e && word_b[0] == '\"');
if (is_quote)
{
// Parsing quotes. Omit storing leading/trailing quotes.
word_e = ImStrchrRange(++word_b, buf_e, '\"');
if (word_e == NULL)
word_e = buf_e;
}
else
{
// Handle both ' ' and ',' separators.
for (word_e = word_b; word_e < buf_e; word_e++)
if (*word_e == ' ' || *word_e == ',')
break;
}
// Min length
if (word_e - word_b < MinWordSize)
continue;
if (f.b[0] != '-')
CountGrep += 1;
// 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++;
}
}
bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
{
if (Filters.Size == 0)
if (_Items.Size == 0)
return true;
if (text == NULL)
text = text_end = "";
for (const ImGuiTextRange& f : Filters)
{
if (f.b == f.e)
continue;
if (f.b[0] == '-')
{
// Subtract
if (ImStristr(text, text_end, f.b + 1, f.e) != NULL)
// 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)
return false;
}
else
const bool is_and_filter = (FilterOp == '&');
for (; n < _Items.Size; n++)
{
// Grep
if (ImStristr(text, text_end, f.b, f.e) != NULL)
return true;
}
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
}
// Implicit * grep
if (CountGrep == 0)
// When no inclusion are specified (only exclusions) we implicitly pass
if (_CountInclude == 0)
return true;
return false;
return is_and_filter;
}
//-----------------------------------------------------------------------------
@ -4420,7 +4432,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas)
NavJustMovedFromFocusScopeId = NavJustMovedToId = NavJustMovedToFocusScopeId = 0;
NavJustMovedToKeyMods = ImGuiMod_None;
NavJustMovedToIsTabbing = false;
NavJustMovedToIsTabbing = NavJustMovedToIsInit = false;
NavJustMovedToHasSelectionData = false;
// All platforms use Ctrl+Tab but Ctrl<>Super are swapped on Mac...
@ -14885,6 +14897,7 @@ void ImGui::NavInitRequestApplyResult()
g.NavJustMovedToFocusScopeId = result->FocusScopeId;
g.NavJustMovedToKeyMods = 0;
g.NavJustMovedToIsTabbing = false;
g.NavJustMovedToIsInit = true;
g.NavJustMovedToHasSelectionData = (result->ItemFlags & ImGuiItemFlags_HasSelectionUserData) != 0;
}
@ -15152,6 +15165,7 @@ void ImGui::NavMoveRequestApplyResult()
g.NavJustMovedToFocusScopeId = result->FocusScopeId;
g.NavJustMovedToKeyMods = g.NavMoveKeyMods;
g.NavJustMovedToIsTabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) != 0;
g.NavJustMovedToIsInit = false;
g.NavJustMovedToHasSelectionData = (result->ItemFlags & ImGuiItemFlags_HasSelectionUserData) != 0;
//IMGUI_DEBUG_LOG_NAV("[nav] NavJustMovedFromFocusScopeId = 0x%08X, NavJustMovedToFocusScopeId = 0x%08X\n", g.NavJustMovedFromFocusScopeId, g.NavJustMovedToFocusScopeId);
}
@ -16078,17 +16092,9 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop
flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that live for 1 frame)
const bool draw_target_rect = payload.Preview && !(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect);
if (draw_target_rect && g.DragDropTargetFullViewport != 0)
{
ImGuiViewport* viewport = FindViewportByID(g.DragDropTargetFullViewport);
IM_ASSERT(viewport != NULL);
ImRect bb = g.DragDropTargetRect;
bb.Expand(-3.5f);
RenderDragDropTargetRectEx(GetForegroundDrawList(viewport), bb, g.Style.DragDropTargetRounding);
}
RenderDragDropTargetRectForViewport(g.DragDropTargetFullViewport, g.DragDropTargetRect);
else if (draw_target_rect)
{
RenderDragDropTargetRectForItem(r);
}
g.DragDropAcceptFrameCount = g.FrameCount;
if ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) && g.DragDropMouseButton == -1)
@ -16119,6 +16125,16 @@ void ImGui::RenderDragDropTargetRectForItem(const ImRect& bb)
window->DrawList->PopClipRect();
}
void ImGui::RenderDragDropTargetRectForViewport(ImGuiID viewport_id, const ImRect& bb)
{
ImGuiContext& g = *GImGui;
ImGuiViewport* viewport = FindViewportByID(viewport_id);
IM_ASSERT(viewport != NULL);
ImRect bb_padded = bb;
bb_padded.Expand(-g.Style.DragDropTargetPadding);
RenderDragDropTargetRectEx(GetForegroundDrawList(viewport), bb_padded, g.Style.DragDropTargetRounding);
}
void ImGui::RenderDragDropTargetRectEx(ImDrawList* draw_list, const ImRect& bb, float rounding)
{
ImGuiContext& g = *GImGui;
@ -16898,7 +16914,7 @@ void ImGuiPlatformIO::ClearRendererHandlers()
Renderer_CreateWindow = Renderer_DestroyWindow = NULL;
Renderer_SetWindowSize = NULL;
Renderer_RenderWindow = Renderer_SwapBuffers = NULL;
DrawCallback_ResetRenderState = DrawCallback_SetSamplerLinear = DrawCallback_SetSamplerNearest = NULL;
DrawCallback_ResetRenderState = DrawCallback_SetSamplerLinear = DrawCallback_SetSamplerNearest = DrawCallback_SetSamplerFromTex = NULL;
}
ImGuiViewport* ImGui::GetMainViewport()

42
imgui.h
View File

@ -2919,30 +2919,37 @@ 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. In format "aaaaa[,bbbb][,ccccc]"
// Helper: Parse and apply text filters e.g. 'aaa bbb -ccc'.
struct ImGuiTextFilter
{
IMGUI_API ImGuiTextFilter(const char* default_filter = "");
IMGUI_API bool Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build
IMGUI_API bool PassFilter(const char* text, const char* text_end = NULL) const;
IMGUI_API void Build();
void Clear() { InputBuf[0] = 0; Build(); }
bool IsActive() const { return !Filters.empty(); }
IMGUI_API void Build(); // Update internal data when filter changes
inline void Clear() { InputBuf[0] = 0; Build(); } // Clear filter
inline bool IsActive() const { return _Items.Size != 0; } // Useful if you need e.g. an alternative code-path when there are no filters
// [Internal]
struct ImGuiTextRange
// Helper to call InputText() + Build() when buffer is changed.
IMGUI_API bool Draw(const char* label = "Filter");
IMGUI_API bool DrawWithHint(const char* label = "Filter", const char* hint = "incl -excl");
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
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.
struct ImGuiTextFilterItem
{
const char* b;
const char* e;
ImGuiTextRange() { b = e = NULL; }
ImGuiTextRange(const char* _b, const char* _e) { b = _b; e = _e; }
bool empty() const { return b == e; }
IMGUI_API void split(char separator, ImVector<ImGuiTextRange>* out) const;
const char* Begin;
const char* End;
ImGuiTextFilterItem(const char* b, const char* e) { Begin = b; End = e; }
};
char InputBuf[256];
ImVector<ImGuiTextRange>Filters;
int CountGrep;
// [Internal] Members
char InputBuf[256]; // User input buffer
char FilterOp; // == '|' (any) pr '&' (all)
ImU8 MinWordSize; // == 1
int _CountExclude; // >= 0
int _CountInclude; // >= 0
ImVector<ImGuiTextFilterItem> _Items; // Pre-parsed, trimmed, reordered items
};
// Helper: Growable text buffer for logging/accumulating text
@ -4324,6 +4331,7 @@ struct ImGuiPlatformIO
ImDrawCallback DrawCallback_ResetRenderState; // Request to reset the graphics/render state.
ImDrawCallback DrawCallback_SetSamplerLinear; // Request backend to set texture sampling to Linear.
ImDrawCallback DrawCallback_SetSamplerNearest; // Request backend to set texture sampling to Nearest/Point.
ImDrawCallback DrawCallback_SetSamplerFromTex; // Request backend to use sampler associated to texture - only available in some backends: OpenGL2/3 and SDLRenderer3.
//ImDrawCallback DrawCallback_SetSamplerCustom; // Request backend to set texture sampling using Backend Specific data.
//------------------------------------------------------------------

View File

@ -1523,7 +1523,8 @@ static void DemoWindowWidgetsComboBoxes()
filter.Clear();
}
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F);
filter.Draw("##Filter", -FLT_MIN);
ImGui::SetNextItemWidth(-FLT_MIN);
filter.DrawWithHint("##Filter", "Filter (incl -excl)");
for (int n = 0; n < IM_COUNTOF(items); n++)
{
@ -3830,11 +3831,13 @@ static void DemoWindowWidgetsTabs()
// but they tend to make more sense together)
static bool show_leading_button = true;
static bool show_trailing_button = true;
static bool show_leading_trailing_tabs = false;
ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button);
ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button);
ImGui::Checkbox("Show Leading+Trailing TabItem()", &show_leading_trailing_tabs);
// Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyShrink;
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyMixed;
EditTabBarFittingPolicyFlags(&tab_bar_flags);
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
@ -3849,6 +3852,15 @@ static void DemoWindowWidgetsTabs()
ImGui::EndPopup();
}
// Demo Leading/Trailing Tabs
if (show_leading_trailing_tabs)
{
if (ImGui::BeginTabItem("Leading", NULL, ImGuiTabItemFlags_Leading))
ImGui::EndTabItem();
if (ImGui::BeginTabItem("Trailing", NULL, ImGuiTabItemFlags_Trailing))
ImGui::EndTabItem();
}
// Demo Trailing Tabs: click the "+" button to add a new tab.
// (In your app you may want to use a font icon instead of the "+")
// We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end.
@ -4020,7 +4032,8 @@ static void DemoWindowWidgetsTextFilter()
" \"xxx\" display lines containing \"xxx\"\n"
" \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
" \"-xxx\" hide lines containing \"xxx\"");
filter.Draw();
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]))
@ -8923,9 +8936,6 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
SameLine(); SetNextItemWidth(GetFontSize() * 10); Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
SameLine(); Checkbox("Only Modified Colors", &output_only_modified);
static ImGuiTextFilter filter;
filter.Draw("Filter colors", GetFontSize() * 16);
static ImGuiColorEditFlags alpha_flags = 0;
if (RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_AlphaOpaque)) { alpha_flags = ImGuiColorEditFlags_AlphaOpaque; } SameLine();
if (RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } SameLine();
@ -8935,6 +8945,10 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
"Left-click on color square to open color picker,\n"
"Right-click to open edit options menu.");
static ImGuiTextFilter filter;
SetNextItemWidth(-FLT_MIN);
filter.DrawWithHint("##FilterColors", "Filter Colors (incl -excl)");
SetNextWindowSizeConstraints(ImVec2(0.0f, GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX));
BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
PushItemWidth(GetFontSize() * -12);
@ -9347,7 +9361,10 @@ struct ExampleAppConsole
if (ImGui::Button("Options"))
ImGui::OpenPopup("Options");
ImGui::SameLine();
Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
ImGui::SetNextItemWidth(-FLT_MIN);
Filter.DrawWithHint("##Filter", "Filter (incl -excl)");
ImGui::Separator();
// Reserve enough left-over height for 1 separator + 1 input text
@ -9682,7 +9699,8 @@ struct ExampleAppLog
ImGui::SameLine();
bool copy = ImGui::Button("Copy");
ImGui::SameLine();
Filter.Draw("Filter", -100.0f);
ImGui::SetNextItemWidth(-FLT_MIN);
Filter.DrawWithHint("##Filter", "Filter (incl -excl)");
ImGui::Separator();
@ -9877,7 +9895,7 @@ struct ExampleAppPropertyEditor
ImGui::Text("(%d root nodes)", root_node->Childs.Size);
ImGui::SetNextItemWidth(-FLT_MIN);
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_COUNTOF(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
if (ImGui::InputTextWithHint("##Filter", "incl -excl", Filter.InputBuf, IM_COUNTOF(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
Filter.Build();
ImGui::PopItemFlag();

View File

@ -340,9 +340,9 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f);
colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f);
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f);
colors[ImGuiCol_TitleBg] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f);
colors[ImGuiCol_TitleBgActive] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.43f);
colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f);
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f);

View File

@ -418,7 +418,7 @@ IMGUI_API const char* ImStrSkipBlank(const char* str);
IMGUI_API int ImStrlenW(const ImWchar* str); // Computer string length (ImWchar string)
IMGUI_API const char* ImStrbol(const char* buf_mid_line, const char* buf_begin); // Find beginning-of-line
IM_MSVC_RUNTIME_CHECKS_OFF
inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; }
inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c & ~32 : c; }
inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; }
inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; }
inline bool ImCharIsXdigitA(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); }
@ -2651,6 +2651,7 @@ struct ImGuiContext
ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest).
ImGuiKeyChord NavJustMovedToKeyMods;
bool NavJustMovedToIsTabbing; // Copy of ImGuiNavMoveFlags_IsTabbing. Maybe we should store whole flags.
bool NavJustMovedToIsInit; // Copy of ImGuiNavMoveFlags_IsTabbing. Maybe we should store whole flags.
bool NavJustMovedToHasSelectionData; // Copy of move result's ItemFlags & ImGuiItemFlags_HasSelectionUserData). Maybe we should just store ImGuiNavItemData.
// Navigation: extra config options (will be made public eventually)
@ -3588,7 +3589,7 @@ namespace ImGui
// - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal.
IMGUI_API ImGuiIO& GetIO(ImGuiContext* ctx);
IMGUI_API ImGuiPlatformIO& GetPlatformIO(ImGuiContext* ctx);
inline float GetScale() { ImGuiContext& g = *GImGui; return g.Style._MainScale; } // FIXME-DPI: I don't want to formalize this just yet. Because reasons. Please don't use.
inline float GetScale() { ImGuiContext& g = *GImGui; return g.Style._MainScale; } // FIXME-DPI: PLEASE DO NOT USE. I don't want to formalize this just yet. Because reasons.
inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; }
inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; }
IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id);
@ -3966,6 +3967,7 @@ namespace ImGui
IMGUI_API void ClearDragDrop();
IMGUI_API bool IsDragDropPayloadBeingAccepted();
IMGUI_API void RenderDragDropTargetRectForItem(const ImRect& bb);
IMGUI_API void RenderDragDropTargetRectForViewport(ImGuiID viewport_id, const ImRect& bb);
IMGUI_API void RenderDragDropTargetRectEx(ImDrawList* draw_list, const ImRect& bb, float rounding);
// Typing-Select API
@ -3999,6 +4001,7 @@ namespace ImGui
IMGUI_API ImGuiTabItem* TabBarGetCurrentTab(ImGuiTabBar* tab_bar);
inline int TabBarGetTabOrder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) { return tab_bar->Tabs.index_from_ptr(tab); }
IMGUI_API const char* TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
IMGUI_API ImVec2 TabBarGetTabPos(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
IMGUI_API void TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window);
IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id);
IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);

View File

@ -3184,18 +3184,18 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
float clicked_t = 0.0f;
if (g.ActiveIdSource == ImGuiInputSource_Mouse)
{
const float mouse_abs_pos = g.IO.MousePos[axis];
const float mouse_pos = g.IO.MousePos[axis];
if (g.ActiveIdIsJustActivated)
{
float grab_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize);
if (axis == ImGuiAxis_Y)
grab_t = 1.0f - grab_t;
const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t);
const bool clicked_around_grab = (mouse_abs_pos >= grab_pos - grab_sz * 0.5f - 1.0f) && (mouse_abs_pos <= grab_pos + grab_sz * 0.5f + 1.0f); // No harm being extra generous here.
g.SliderGrabClickOffset = (clicked_around_grab && is_floating_point) ? mouse_abs_pos - grab_pos : 0.0f;
const bool clicked_around_grab = (mouse_pos >= grab_pos - grab_sz * 0.5f - 1.0f) && (mouse_pos <= grab_pos + grab_sz * 0.5f + 1.0f); // No harm being extra generous here.
g.SliderGrabClickOffset = (clicked_around_grab && is_floating_point) ? mouse_pos - grab_pos : 0.0f;
}
if (slider_usable_sz > 0.0f)
clicked_t = ImSaturate((mouse_abs_pos - g.SliderGrabClickOffset - slider_usable_pos_min) / slider_usable_sz);
clicked_t = ImSaturate((mouse_pos - g.SliderGrabClickOffset - slider_usable_pos_min) / slider_usable_sz);
if (axis == ImGuiAxis_Y)
clicked_t = 1.0f - clicked_t;
set_new_value = true;
@ -7623,7 +7623,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
// - (1) it would require focus scope to be set, need exposing PushFocusScope() or equivalent (e.g. BeginSelection() calling PushFocusScope())
// - (2) usage will fail with clipped items
// The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API.
if ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == g.CurrentFocusScopeId)
if ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == g.CurrentFocusScopeId && !g.NavJustMovedToIsInit)
if (g.NavJustMovedToId == id && (g.NavJustMovedToKeyMods & ImGuiMod_Ctrl) == 0)
selected = pressed = auto_selected = true;
}
@ -10235,16 +10235,17 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
}
// Horizontal scrolling buttons
// Important: note that TabBarScrollButtons() will alter BarRect.Max.x.
// - Important: note that TabBarScrollButtons() will alter BarRect.Max.x.
// - Selection skips buttons and might cross through sections if there are Tabs in Leading/Trailing sections.
const bool can_scroll = (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) || (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyMixed);
const float width_all_tabs_to_use_for_scroll = (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) ? tab_bar->WidthAllTabs : width_all_tabs_after_min_width_shrink;
tab_bar->ScrollButtonEnabled = ((width_all_tabs_to_use_for_scroll > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && can_scroll);
if (tab_bar->ScrollButtonEnabled)
if (ImGuiTabItem* scroll_and_select_tab = TabBarScrollingButtons(tab_bar))
{
scroll_to_tab_id = scroll_and_select_tab->ID;
if ((scroll_and_select_tab->Flags & ImGuiTabItemFlags_Button) == 0)
tab_bar->SelectedTabId = scroll_to_tab_id;
tab_bar->SelectedTabId = scroll_and_select_tab->ID;
scroll_to_tab_id = scroll_and_select_tab->ID;
}
if (scroll_to_tab_id == 0 && scroll_to_selected_tab)
scroll_to_tab_id = tab_bar->SelectedTabId;
@ -10437,6 +10438,14 @@ const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
return tab_bar->TabsNames.Buf.Data + tab->NameOffset;
}
ImVec2 ImGui::TabBarGetTabPos(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
{
if ((tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0)
return tab_bar->BarRect.Min + ImVec2(IM_TRUNC(tab->Offset - tab_bar->ScrollingAnim), 0.0f);
else
return tab_bar->BarRect.Min + ImVec2(tab->Offset, 0.0f);
}
// The purpose of this call is to register tab in advance so we can control their order at the time they appear.
// Otherwise calling this is unnecessary as tabs are appending as needed by the BeginTabItem() function.
void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window)
@ -10505,11 +10514,20 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGui
ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id);
if (tab == NULL)
return;
// Clamp attempt to scroll to leading/trailing sections items.
// This could be done at the TabBarScrollingButtons() call site as well, but here works.
if (tab->Flags & ImGuiTabItemFlags_Leading)
tab = &tab_bar->Tabs[sections[0].TabCount];
else if (tab->Flags & ImGuiTabItemFlags_Trailing)
tab = &tab_bar->Tabs[sections[0].TabCount + sections[1].TabCount];
if (tab->Flags & ImGuiTabItemFlags_SectionMask_)
return;
// When scrolling to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar)
// Disable the margin if the scrolling section is too small for the target tab: prefer displaying a maximum of the label.
ImGuiContext& g = *GImGui;
float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar)
float margin = ImClamp(tab_bar->ScrollingRectMaxX - tab_bar->ScrollingRectMinX - tab->Width, g.Style.ItemInnerSpacing.x, g.FontSize * 1.0f);
int order = TabBarGetTabOrder(tab_bar, tab);
// Scrolling happens only in the central section (leading/trailing sections are not scrolling)
@ -10914,10 +10932,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// Layout
const bool is_central_section = (tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0;
size.x = tab->Width;
if (is_central_section)
window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_TRUNC(tab->Offset - tab_bar->ScrollingAnim), 0.0f);
else
window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(tab->Offset, 0.0f);
window->DC.CursorPos = TabBarGetTabPos(tab_bar, tab);
ImVec2 pos = window->DC.CursorPos;
ImRect bb(pos, pos + size);