From e616ace74dce14f927c808cb82f2a8b21b0d392d Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 3 Jul 2026 17:48:11 +0200 Subject: [PATCH 01/19] CI, Backends: Metal4: fixed CI, added comments. (#9458) --- .github/workflows/build.yml | 4 ++-- backends/imgui_impl_metal4.h | 1 + backends/imgui_impl_metal4.mm | 1 + examples/example_sdl3_metal4/main.mm | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dd1d0d47e..3980838a4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -575,8 +575,8 @@ jobs: - name: Build macOS example_sdl2_metal run: make -C examples/example_sdl2_metal - - name: Build macOS example_sdl3_metal4 - run: make -C examples/example_sdl3_metal4 + #- name: Build macOS example_sdl3_metal4 + # run: make -C examples/example_sdl3_metal4 - name: Build macOS example_sdl2_opengl2 run: make -C examples/example_sdl2_opengl2 diff --git a/backends/imgui_impl_metal4.h b/backends/imgui_impl_metal4.h index 6bfea6e56..b5ec4ca56 100644 --- a/backends/imgui_impl_metal4.h +++ b/backends/imgui_impl_metal4.h @@ -1,5 +1,6 @@ // dear imgui: Renderer Backend for Metal 4 // This needs to be used along with a Platform Backend (e.g. OSX) +// Metal 4 requires Apple Silicon and macOS 26+. // Implemented features: // [X] Renderer: User texture binding. Use 'MTLTexture.gpuResourceID' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! diff --git a/backends/imgui_impl_metal4.mm b/backends/imgui_impl_metal4.mm index 5f8d4983a..f88d34b4e 100644 --- a/backends/imgui_impl_metal4.mm +++ b/backends/imgui_impl_metal4.mm @@ -1,5 +1,6 @@ // dear imgui: Renderer Backend for Metal 4 // This needs to be used along with a Platform Backend (e.g. OSX) +// Metal 4 requires Apple Silicon and macOS 26+. // Implemented features: // [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! diff --git a/examples/example_sdl3_metal4/main.mm b/examples/example_sdl3_metal4/main.mm index d80b4dde0..6debb5133 100644 --- a/examples/example_sdl3_metal4/main.mm +++ b/examples/example_sdl3_metal4/main.mm @@ -1,5 +1,6 @@ // Dear ImGui: standalone example application for SDL3 + Metal 4 // (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.) +// (Metal 4 requires Apple Silicon and macOS 26+.) // Learn about Dear ImGui: // - FAQ https://dearimgui.com/faq From a97714495591ebe947b9b9a87022c7e2b3bcc13a Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 3 Jul 2026 18:42:51 +0200 Subject: [PATCH 02/19] Examples: OpenGL3+GLFW,SDL2,SDL3: improve Wine compatibility by passing empty GLSL version to ImGui_ImplOpenGL3_Init(). (#9427, #6577) --- docs/CHANGELOG.txt | 3 +++ examples/example_glfw_opengl3/main.cpp | 11 ++++------- examples/example_sdl2_opengl3/main.cpp | 11 ++++------- examples/example_sdl3_opengl3/main.cpp | 11 ++++------- 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4647ca97f..8ce3d47e7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -153,6 +153,9 @@ Other Changes: to spawn multiple-thread to manage OpenGL. (#9403) - Examples: - Android: update to AGP 9.2.0 to support Gradle 9.6.0. + - OpenGL3+GLFW/SDL2/SDL3: allow Wine compatibility by passing empty GLSL version + string to ImGui_ImplOpenGL3_Init() to let backend decide of a GLSL version based + on actual GL version obtained. (#9427, #6577) [@perminovVS] - SDL2/SDL3: use `SDL_GetWindowSizeInPixels()` to create frame-buffers. Fixes issues with non-fractional framebuffer size on Wayland. (#8761, #9124) [@billtran1632001] - SDL3+Metal4: added new example. (#9458, #9451) [@AmelieHeinrich] diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp index 20d39fccc..fbcc3e595 100644 --- a/examples/example_glfw_opengl3/main.cpp +++ b/examples/example_glfw_opengl3/main.cpp @@ -41,29 +41,26 @@ int main(int, char**) if (!glfwInit()) return 1; - // Decide GL+GLSL versions + // Select GL version + let the backend select a GLSL version + const char* glsl_version = nullptr; #if defined(IMGUI_IMPL_OPENGL_ES2) // GL ES 2.0 + GLSL 100 (WebGL 1.0) - const char* glsl_version = "#version 100"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); #elif defined(IMGUI_IMPL_OPENGL_ES3) // GL ES 3.0 + GLSL 300 es (WebGL 2.0) - const char* glsl_version = "#version 300 es"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); #elif defined(__APPLE__) - // GL 3.2 + GLSL 150 - const char* glsl_version = "#version 150"; + // GL 3.2 + generally GLSL 150 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac #else - // GL 3.0 + GLSL 130 - const char* glsl_version = "#version 130"; + // GL 3.0 + generally GLSL 130 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only diff --git a/examples/example_sdl2_opengl3/main.cpp b/examples/example_sdl2_opengl3/main.cpp index 0d992d47e..e7b101087 100644 --- a/examples/example_sdl2_opengl3/main.cpp +++ b/examples/example_sdl2_opengl3/main.cpp @@ -39,31 +39,28 @@ int main(int, char**) return 1; } - // Decide GL+GLSL versions + // Select GL version + let the backend select a GLSL version + const char* glsl_version = nullptr; #if defined(IMGUI_IMPL_OPENGL_ES2) // GL ES 2.0 + GLSL 100 (WebGL 1.0) - const char* glsl_version = "#version 100"; SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #elif defined(IMGUI_IMPL_OPENGL_ES3) // GL ES 3.0 + GLSL 300 es (WebGL 2.0) - const char* glsl_version = "#version 300 es"; SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #elif defined(__APPLE__) - // GL 3.2 Core + GLSL 150 - const char* glsl_version = "#version 150"; + // GL 3.2 Core + generally GLSL 150 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); #else - // GL 3.0 + GLSL 130 - const char* glsl_version = "#version 130"; + // GL 3.0 + generally GLSL 130 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); diff --git a/examples/example_sdl3_opengl3/main.cpp b/examples/example_sdl3_opengl3/main.cpp index a36cfaba9..e7d22a40c 100644 --- a/examples/example_sdl3_opengl3/main.cpp +++ b/examples/example_sdl3_opengl3/main.cpp @@ -33,31 +33,28 @@ int main(int, char**) return 1; } - // Decide GL+GLSL versions + // Select GL version + let the backend select a GLSL version + const char* glsl_version = nullptr; #if defined(IMGUI_IMPL_OPENGL_ES2) // GL ES 2.0 + GLSL 100 (WebGL 1.0) - const char* glsl_version = "#version 100"; SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #elif defined(IMGUI_IMPL_OPENGL_ES3) // GL ES 3.0 + GLSL 300 es (WebGL 2.0) - const char* glsl_version = "#version 300 es"; SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #elif defined(__APPLE__) - // GL 3.2 Core + GLSL 150 - const char* glsl_version = "#version 150"; + // GL 3.2 Core + generally GLSL 150 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); #else - // GL 3.0 + GLSL 130 - const char* glsl_version = "#version 130"; + // GL 3.0 + generally GLSL 130 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); From 4f1ea369eae2510c85e41ef159433e19927ff14c Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 3 Jul 2026 18:57:14 +0200 Subject: [PATCH 03/19] Examples: OpenGL3+Win32: rework OpenGL initialization to allow Wine compatibility. (#9427, #6577) --- docs/CHANGELOG.txt | 1 + examples/example_win32_opengl3/main.cpp | 56 +++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8ce3d47e7..0bc0682f0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -156,6 +156,7 @@ Other Changes: - OpenGL3+GLFW/SDL2/SDL3: allow Wine compatibility by passing empty GLSL version string to ImGui_ImplOpenGL3_Init() to let backend decide of a GLSL version based on actual GL version obtained. (#9427, #6577) [@perminovVS] + - OpenGL3+Win32: rework context creation to allow Wine compatibility. (#9427, #6577) [@perminovVS] - SDL2/SDL3: use `SDL_GetWindowSizeInPixels()` to create frame-buffers. Fixes issues with non-fractional framebuffer size on Wayland. (#8761, #9124) [@billtran1632001] - SDL3+Metal4: added new example. (#9458, #9451) [@AmelieHeinrich] diff --git a/examples/example_win32_opengl3/main.cpp b/examples/example_win32_opengl3/main.cpp index d18ea0bd8..b3a4da9c6 100644 --- a/examples/example_win32_opengl3/main.cpp +++ b/examples/example_win32_opengl3/main.cpp @@ -17,12 +17,13 @@ #include #include #include +#include // Data stored per platform window struct WGL_WindowData { HDC hDC; }; // Data -static HGLRC g_hRC; +static HGLRC g_hRC; // Rendering context static WGL_WindowData g_MainWindow; static int g_Width; static int g_Height; @@ -208,8 +209,57 @@ bool CreateDeviceWGL(HWND hWnd, WGL_WindowData* data) ::ReleaseDC(hWnd, hDc); data->hDC = ::GetDC(hWnd); - if (!g_hRC) - g_hRC = wglCreateContext(data->hDC); + if (g_hRC) + return true; + + // Create legacy context + HGLRC tempRC = wglCreateContext(data->hDC); + if (!tempRC) { ::ReleaseDC(hWnd, data->hDC); return false; } + if (!wglMakeCurrent(data->hDC, tempRC)) + { + wglDeleteContext(tempRC); + ::ReleaseDC(hWnd, data->hDC); + return false; + } + + // Get context version + GLint major = 0, minor = 0; + glGetIntegerv(0x821B, &major); // GL_MAJOR_VERSION + glGetIntegerv(0x821C, &minor); // GL_MINOR_VERSION + const char* gl_version_str = (const char*)glGetString(GL_VERSION); + if (major == 0 && minor == 0) + sscanf_s(gl_version_str, "%d.%d", &major, &minor); // Query GL_VERSION in desktop GL 2.x, the string will start with "." + const GLuint gl_version = (GLuint)(major * 100 + minor * 10); + + // Keep temporary context: already OpenGL 3.0+. + g_hRC = tempRC; + //if (gl_version >= 300) + // return true; + + typedef HGLRC(WINAPI* PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int*); + const PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); + + // GL 3.0 + const int attribs[] = + { + 0x2091, 3, // WGL_CONTEXT_MAJOR_VERSION_ARB + 0x2092, 0, // WGL_CONTEXT_MINOR_VERSION_ARB + 0x9126, 0x0001, // WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB + 0 + }; + HGLRC newRC = nullptr; + if (wglCreateContextAttribsARB) + newRC = wglCreateContextAttribsARB(data->hDC, 0, attribs); + + // If we managed to create 3.0+ context: use that one and destroy the temporary OpenGL 2.x compatibility context. + if (newRC) + { + wglMakeCurrent(nullptr, nullptr); + wglDeleteContext(tempRC); + g_hRC = newRC; + wglMakeCurrent(data->hDC, g_hRC); + } + return true; } From 776bf2ab0d61e719e58f2c6d27d109ab5dcf2af1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 3 Jul 2026 18:59:37 +0200 Subject: [PATCH 04/19] Examples: OpenGL3+Win32: rework OpenGL initialization to allow Wine compatibility. Fix. (#9427, #6577) Fixed commented out test code. --- examples/example_win32_opengl3/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/example_win32_opengl3/main.cpp b/examples/example_win32_opengl3/main.cpp index b3a4da9c6..cba8301f8 100644 --- a/examples/example_win32_opengl3/main.cpp +++ b/examples/example_win32_opengl3/main.cpp @@ -233,8 +233,8 @@ bool CreateDeviceWGL(HWND hWnd, WGL_WindowData* data) // Keep temporary context: already OpenGL 3.0+. g_hRC = tempRC; - //if (gl_version >= 300) - // return true; + if (gl_version >= 300) + return true; typedef HGLRC(WINAPI* PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int*); const PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); From 0e479b95543b736143ebc815fc727ba8c035f5c2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Jul 2026 15:34:13 +0200 Subject: [PATCH 05/19] (Breaking) ColorEdit: obsoleted SetColorEditOptions() function in favor of poking to style.ColorEditFlags. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 8 +++++++- imgui.h | 11 +++++++---- imgui_demo.cpp | 12 ++++++------ imgui_internal.h | 1 - imgui_widgets.cpp | 48 +++++++++++++++++++--------------------------- 6 files changed, 43 insertions(+), 40 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0bc0682f0..c4de5cab9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking Changes: - TreeNode: commented out legacy name `ImGuiTreeNodeFlags_SpanTextWidth` which was obsoleted in 1.90.7 (May 2024). Use `ImGuiTreeNodeFlags_SpanLabelWidth`. +- ColorEdit: obsoleted SetColorEditOptions() function added in 1.51 (June 2017) in + of directly poking to style.ColorEditFlags. More consistent and easier to discover + Other Changes: diff --git a/imgui.cpp b/imgui.cpp index f1729eb84..5f7ecef50 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -395,6 +395,7 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2026/07/06 (1.92.9) - ColorEdit: obsoleted SetColorEditOptions() function added in 1.51 (June 2017) in favor of directly poking to style.ColorEditFlags. More consistent and easier to discover. - 2026/06/02 (1.92.9) - TreeNode: commented out legacy name ImGuiTreeNodeFlags_SpanTextWidth which was obsoleted in 1.90.7 (May 2024). Use ImGuiTreeNodeFlags_SpanLabelWidth instead. - 2026/05/07 (1.92.8) - DrawList: swapped the last two arguments of AddRect(), AddPolyline(), PathStroke(). - Before: void ImDrawList::AddRect(ImVec2 p_min, ImVec2 p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0, float thickness = 1.0f); @@ -1547,6 +1548,7 @@ ImGuiStyle::ImGuiStyle() DragDropTargetPadding = 3.0f; // Size to expand the drag and drop target from actual target item size. ColorMarkerSize = 3.0f; // Size of R/G/B/A color markers for ColorEdit4() and for Drags/Sliders when using ImGuiSliderFlags_ColorMarkers. ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. + ColorEditFlags = ImGuiColorEditFlags_DefaultOptions_; // Current settings for ColorEdit/ColorPicker widgets. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. InputTextCursorSize = 1.0f; // Thickness of cursor/caret in InputText(). @@ -4356,7 +4358,6 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) TempInputId = 0; memset(&DataTypeZeroValue, 0, sizeof(DataTypeZeroValue)); BeginMenuDepth = BeginComboDepth = 0; - ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_; ColorEditCurrentID = ColorEditSavedID = 0; ColorEditSavedHue = ColorEditSavedSat = 0.0f; ColorEditSavedColor = 0; @@ -11073,6 +11074,11 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() IM_ASSERT(g.Style.WindowBorderHoverPadding > 0.0f && "Invalid style setting!"); // Required otherwise cannot resize from borders. IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); IM_ASSERT(g.Style.ColorButtonPosition == ImGuiDir_Left || g.Style.ColorButtonPosition == ImGuiDir_Right); + IM_ASSERT(ImIsPowerOfTwo(g.Style.ColorEditFlags & ImGuiColorEditFlags_DisplayMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(g.Style.ColorEditFlags & ImGuiColorEditFlags_DataTypeMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(g.Style.ColorEditFlags & ImGuiColorEditFlags_PickerMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(g.Style.ColorEditFlags & ImGuiColorEditFlags_InputMask_)); // Check only 1 option is selected + IM_ASSERT(g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesNone || g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesFull || g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesToNodes); IM_ASSERT(g.IO.MouseSingleClickDelay > g.IO.MouseDoubleClickTime); diff --git a/imgui.h b/imgui.h index f6ac7773f..e38d79b59 100644 --- a/imgui.h +++ b/imgui.h @@ -30,7 +30,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.9 WIP" -#define IMGUI_VERSION_NUM 19284 +#define IMGUI_VERSION_NUM 19285 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 @@ -737,7 +737,6 @@ namespace ImGui IMGUI_API bool ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0); IMGUI_API bool ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags = 0, const float* ref_col = NULL); IMGUI_API bool ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // display a color square/button, hover for details, return true when pressed. - IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls. // Widgets: Trees // - TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents. @@ -1918,8 +1917,9 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_InputRGB = 1 << 27, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. ImGuiColorEditFlags_InputHSV = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. - // Defaults Options. You can set application defaults using SetColorEditOptions(). The intent is that you probably don't want to - // override them in most of your calls. Let the user choose via the option menu and/or call SetColorEditOptions() once during startup. + // Defaults Options copied to style.ColorEditFlags during initialization. + // The intent is that you probably don't want to override them in most of your calls. + // Let the user choose via the option menu and/or modify style.ColorEditFlags directly during startup if you want. ImGuiColorEditFlags_DefaultOptions_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar, // [Internal] Masks @@ -2343,6 +2343,7 @@ struct ImGuiStyle float DragDropTargetPadding; // Size to expand the drag and drop target from actual target item size. float ColorMarkerSize; // Size of R/G/B/A color markers for ColorEdit4() and for Drags/Sliders when using ImGuiSliderFlags_ColorMarkers. ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. + ImGuiColorEditFlags ColorEditFlags; // Current settings for ColorEdit/ColorPicker widgets. Must have one bit of ImGuiColorEditFlags_DisplayMask_, one bit of ImGuiColorEditFlags_DataTypeMask_, one bit of ImGuiColorEditFlags_PickerMask_, one bit of ImGuiColorEditFlags_InputMask_. Defaults to ImGuiColorEditFlags_DefaultOptions_. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. float InputTextCursorSize; // Thickness of cursor/caret in InputText(). @@ -4099,6 +4100,8 @@ struct ImGuiPlatformImeData #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS namespace ImGui { + // OBSOLETED in 1.92.9 (from July 2026) + IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // set current options for if you want to select a default format, picker type, etc. User will be able to change those settings, unless you pass the _NoOptions flag to your calls. // OBSOLETED in 1.92.0 (from June 2025) inline void PushFont(ImFont* font) { PushFont(font, font ? font->LegacySize : 0.0f); } IMGUI_API void SetWindowFontScale(float scale); // Set font scale factor for current window. Prefer using PushFont(NULL, style.FontSizeBase * factor) or use style.FontScaleMain to scale all windows. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 91d7e030d..f0927b899 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1334,7 +1334,7 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::SameLine(); HelpMarker( "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex " - "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); + "if you don't specify a display mode.\n\nYou can change the defaults using style.ColorEditFlags."); ImGuiColorEditFlags flags = base_flags | color_picker_flags; if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; @@ -1347,14 +1347,14 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::Text("Set defaults in code:"); ImGui::SameLine(); HelpMarker( - "SetColorEditOptions() is designed to allow you to set boot-time default.\n" + "style.ColorEditFlags is designed to allow you to set boot-time default.\n" "We don't have Push/Pop functions because you can force options on a per-widget basis if needed, " "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid " "encouraging you to persistently save values that aren't forward-compatible."); - if (ImGui::Button("Default: Uint8 + HSV + Hue Bar")) - ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar); - if (ImGui::Button("Default: Float + HDR + Hue Wheel")) - ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel); + if (ImGui::Button("Overwrite default: Uint8 + HSV + Hue Bar")) + ImGui::GetStyle().ColorEditFlags = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar; + if (ImGui::Button("Overwrite default: Float + HDR + Hue Wheel")) + ImGui::GetStyle().ColorEditFlags = ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel; // Always display a small version of both types of pickers // (that's in order to make it more visible in the demo to people who are skimming quickly through it) diff --git a/imgui_internal.h b/imgui_internal.h index 129981aa5..7f5e90dc0 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2528,7 +2528,6 @@ struct ImGuiContext ImGuiDataTypeStorage DataTypeZeroValue; // 0 for all data types int BeginMenuDepth; int BeginComboDepth; - ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets ImGuiID ColorEditCurrentID; // Set temporarily while inside of the parent-most ColorEdit4/ColorPicker4 (because they call each others). ImGuiID ColorEditSavedID; // ID we are saving/restoring HS for float ColorEditSavedHue; // Backup of last Hue associated to LastColor, so we can restore Hue in lossy RGB<>HSV round trips diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ace655d4d..dec1f74b1 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5751,7 +5751,6 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) // - RenderColorRectWithAlphaCheckerboard() [Internal] // - ColorPicker4() // - ColorButton() -// - SetColorEditOptions() // - ColorTooltip() [Internal] // - ColorEditOptionsPopup() [Internal] // - ColorPickerOptionsPopup() [Internal] @@ -5823,14 +5822,14 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag // Read stored options if (!(flags & ImGuiColorEditFlags_DisplayMask_)) - flags |= (g.ColorEditOptions & ImGuiColorEditFlags_DisplayMask_); + flags |= (g.Style.ColorEditFlags & ImGuiColorEditFlags_DisplayMask_); if (!(flags & ImGuiColorEditFlags_DataTypeMask_)) - flags |= (g.ColorEditOptions & ImGuiColorEditFlags_DataTypeMask_); + flags |= (g.Style.ColorEditFlags & ImGuiColorEditFlags_DataTypeMask_); if (!(flags & ImGuiColorEditFlags_PickerMask_)) - flags |= (g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_); + flags |= (g.Style.ColorEditFlags & ImGuiColorEditFlags_PickerMask_); if (!(flags & ImGuiColorEditFlags_InputMask_)) - flags |= (g.ColorEditOptions & ImGuiColorEditFlags_InputMask_); - flags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_)); + flags |= (g.Style.ColorEditFlags & ImGuiColorEditFlags_InputMask_); + flags |= (g.Style.ColorEditFlags & ~(ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_)); IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check that only 1 is selected IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected @@ -6099,13 +6098,13 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl // Read stored options if (!(flags & ImGuiColorEditFlags_PickerMask_)) - flags |= ((g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_) ? g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_PickerMask_; + flags |= ((g.Style.ColorEditFlags & ImGuiColorEditFlags_PickerMask_) ? g.Style.ColorEditFlags : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_PickerMask_; if (!(flags & ImGuiColorEditFlags_InputMask_)) - flags |= ((g.ColorEditOptions & ImGuiColorEditFlags_InputMask_) ? g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_InputMask_; + flags |= ((g.Style.ColorEditFlags & ImGuiColorEditFlags_InputMask_) ? g.Style.ColorEditFlags : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_InputMask_; IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check that only 1 is selected IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected if (!(flags & ImGuiColorEditFlags_NoOptions)) - flags |= (g.ColorEditOptions & ImGuiColorEditFlags_AlphaBar); + flags |= (g.Style.ColorEditFlags & ImGuiColorEditFlags_AlphaBar); // Setup int components = (flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4; @@ -6525,25 +6524,18 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl return pressed; } -// Initialize/override default color options -// FIXME: Could be moved to a simple IO field. +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// This allowed passing 0 to set default, whereas NewFrame() will assert if one of missing. Abide to old logic. void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags) { ImGuiContext& g = *GImGui; - if ((flags & ImGuiColorEditFlags_DisplayMask_) == 0) - flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DisplayMask_; - if ((flags & ImGuiColorEditFlags_DataTypeMask_) == 0) - flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DataTypeMask_; - if ((flags & ImGuiColorEditFlags_PickerMask_) == 0) - flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_PickerMask_; - if ((flags & ImGuiColorEditFlags_InputMask_) == 0) - flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_InputMask_; - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DataTypeMask_)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check only 1 option is selected - g.ColorEditOptions = flags; + if ((flags & ImGuiColorEditFlags_DisplayMask_) == 0) { flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DisplayMask_; } + if ((flags & ImGuiColorEditFlags_DataTypeMask_) == 0) { flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DataTypeMask_; } + if ((flags & ImGuiColorEditFlags_PickerMask_) == 0) { flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_PickerMask_; } + if ((flags & ImGuiColorEditFlags_InputMask_) == 0) { flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_InputMask_; } + g.Style.ColorEditFlags = flags; } +#endif // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags) @@ -6591,7 +6583,7 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) ImGuiContext& g = *GImGui; PushItemFlag(ImGuiItemFlags_NoMarkEdited, true); - ImGuiColorEditFlags opts = g.ColorEditOptions; + ImGuiColorEditFlags opts = g.Style.ColorEditFlags; if (allow_opt_inputs) { if (RadioButton("RGB", (opts & ImGuiColorEditFlags_DisplayRGB) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayRGB; @@ -6631,7 +6623,7 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) EndPopup(); } - g.ColorEditOptions = opts; + g.Style.ColorEditFlags = opts; PopItemFlag(); EndPopup(); } @@ -6659,7 +6651,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel; ImVec2 backup_pos = GetCursorScreenPos(); if (Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup - g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags_PickerMask_) | (picker_flags & ImGuiColorEditFlags_PickerMask_); + g.Style.ColorEditFlags = (g.Style.ColorEditFlags & ~ImGuiColorEditFlags_PickerMask_) | (picker_flags & ImGuiColorEditFlags_PickerMask_); SetCursorScreenPos(backup_pos); ImVec4 previewing_ref_col; memcpy(&previewing_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4)); @@ -6671,7 +6663,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl if (allow_opt_alpha_bar) { if (allow_opt_picker) Separator(); - CheckboxFlags("Alpha Bar", &g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); + CheckboxFlags("Alpha Bar", &g.Style.ColorEditFlags, ImGuiColorEditFlags_AlphaBar); } PopItemFlag(); EndPopup(); From 9f7d8086fe653cf12b8c83961effd8e53a88d4ad Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Jul 2026 16:02:17 +0200 Subject: [PATCH 06/19] (Breaking) ColorEdit: obsoleted SetColorEditOptions() function in favor of poking to io.ColorEditFlags. (Amend 0e479b9) Reordered IO fields breaks ABI backward compat which was never guaranteed. Occasional breaking is a good way to enforce that lack of guarantee! --- imgui.cpp | 21 ++++++++++++++------- imgui.h | 24 +++++++++++++----------- imgui_demo.cpp | 6 +++--- imgui_widgets.cpp | 26 +++++++++++++------------- 4 files changed, 43 insertions(+), 34 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5f7ecef50..fbbaded6d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1548,7 +1548,6 @@ ImGuiStyle::ImGuiStyle() DragDropTargetPadding = 3.0f; // Size to expand the drag and drop target from actual target item size. ColorMarkerSize = 3.0f; // Size of R/G/B/A color markers for ColorEdit4() and for Drags/Sliders when using ImGuiSliderFlags_ColorMarkers. ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. - ColorEditFlags = ImGuiColorEditFlags_DefaultOptions_; // Current settings for ColorEdit/ColorPicker widgets. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. InputTextCursorSize = 1.0f; // Thickness of cursor/caret in InputText(). @@ -1671,8 +1670,8 @@ ImGuiIO::ImGuiIO() ConfigNavCursorVisibleAuto = true; ConfigNavCursorVisibleAlways = false; - // Miscellaneous options - MouseDrawCursor = false; + // Widget options + #ifdef __APPLE__ ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag #else @@ -1682,13 +1681,21 @@ ImGuiIO::ImGuiIO() ConfigInputTextCursorBlink = true; ConfigInputTextEnterKeepActive = false; ConfigDragClickToInputText = false; + ColorEditFlags = ImGuiColorEditFlags_DefaultOptions_; // Current settings for ColorEdit/ColorPicker widgets. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. ConfigWindowsResizeFromEdges = true; ConfigWindowsMoveFromTitleBarOnly = false; ConfigWindowsCopyContentsWithCtrlC = false; ConfigScrollbarScrollByPage = true; + + // Ini Settings options ConfigIniSettingsSaveLastUsedDate = true; ConfigIniSettingsAutoDiscardMonths = 0; + ConfigDebugIniSettings = false; + + // Miscellaneous options + MouseDrawCursor = false; ConfigMemoryCompactTimer = 60.0f; + ConfigDebugIsDebuggerPresent = false; ConfigDebugHighlightIdConflicts = true; ConfigDebugHighlightIdConflictsShowItemPicker = true; @@ -11074,10 +11081,10 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() IM_ASSERT(g.Style.WindowBorderHoverPadding > 0.0f && "Invalid style setting!"); // Required otherwise cannot resize from borders. IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); IM_ASSERT(g.Style.ColorButtonPosition == ImGuiDir_Left || g.Style.ColorButtonPosition == ImGuiDir_Right); - IM_ASSERT(ImIsPowerOfTwo(g.Style.ColorEditFlags & ImGuiColorEditFlags_DisplayMask_)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(g.Style.ColorEditFlags & ImGuiColorEditFlags_DataTypeMask_)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(g.Style.ColorEditFlags & ImGuiColorEditFlags_PickerMask_)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(g.Style.ColorEditFlags & ImGuiColorEditFlags_InputMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(g.IO.ColorEditFlags & ImGuiColorEditFlags_DisplayMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(g.IO.ColorEditFlags & ImGuiColorEditFlags_DataTypeMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(g.IO.ColorEditFlags & ImGuiColorEditFlags_PickerMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(g.IO.ColorEditFlags & ImGuiColorEditFlags_InputMask_)); // Check only 1 option is selected IM_ASSERT(g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesNone || g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesFull || g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesToNodes); IM_ASSERT(g.IO.MouseSingleClickDelay > g.IO.MouseDoubleClickTime); diff --git a/imgui.h b/imgui.h index e38d79b59..bb05b0365 100644 --- a/imgui.h +++ b/imgui.h @@ -2343,7 +2343,6 @@ struct ImGuiStyle float DragDropTargetPadding; // Size to expand the drag and drop target from actual target item size. float ColorMarkerSize; // Size of R/G/B/A color markers for ColorEdit4() and for Drags/Sliders when using ImGuiSliderFlags_ColorMarkers. ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. - ImGuiColorEditFlags ColorEditFlags; // Current settings for ColorEdit/ColorPicker widgets. Must have one bit of ImGuiColorEditFlags_DisplayMask_, one bit of ImGuiColorEditFlags_DataTypeMask_, one bit of ImGuiColorEditFlags_PickerMask_, one bit of ImGuiColorEditFlags_InputMask_. Defaults to ImGuiColorEditFlags_DefaultOptions_. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. float InputTextCursorSize; // Thickness of cursor/caret in InputText(). @@ -2437,7 +2436,19 @@ struct ImGuiIO bool ConfigNavCursorVisibleAuto; // = true // Using directional navigation key makes the cursor visible. Mouse click hides the cursor. bool ConfigNavCursorVisibleAlways; // = false // Navigation cursor is always visible. - // Ini Settings + // Widget options + bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. + bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. + bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). + bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will reactivate item and select all text (single-line only). + ImGuiColorEditFlags ColorEditFlags; // // Current settings for ColorEdit/ColorPicker widgets. Must have one bit of ImGuiColorEditFlags_DisplayMask_, one bit of ImGuiColorEditFlags_DataTypeMask_, one bit of ImGuiColorEditFlags_PickerMask_, one bit of ImGuiColorEditFlags_InputMask_. Defaults to ImGuiColorEditFlags_DefaultOptions_. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. + bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. + bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) + bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. + bool ConfigWindowsCopyContentsWithCtrlC; // = false // [EXPERIMENTAL] Ctrl+C copy the contents of focused window into the clipboard. Experimental because: (1) has known issues with nested Begin/End pairs (2) text output quality varies (3) text output is in submission order rather than spatial order. + bool ConfigScrollbarScrollByPage; // = true // Enable scrolling page by page when clicking outside the scrollbar grab. When disabled, always scroll to clicked location. When enabled, Shift+Click scrolls to clicked location. + + // Ini Settings options bool ConfigIniSettingsSaveLastUsedDate;// = true // Enable loading/saving last used day (YYYYMMDD) in some .ini struct, making things easier to audit and allowing custom tools to cleanup old data. int ConfigIniSettingsAutoDiscardMonths; // = 0 // [BETA] Set number of months after which unused .ini entries are discarded on load. Require platform_io.Platform_SessionDate to be set. For systems supporting the feature, .ini entries without a LastUsed field will always be discarded! Please report if you are using this. bool ConfigDebugIniSettings; // = false // Save .ini data with extra comments (particularly helpful for Docking, but makes saving slower) @@ -2445,15 +2456,6 @@ struct ImGuiIO // Miscellaneous options // (you can visualize and interact with all options in 'Demo->Configuration') bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations. - bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. - bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. - bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). - bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will reactivate item and select all text (single-line only). - bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. - bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) - bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. - bool ConfigWindowsCopyContentsWithCtrlC; // = false // [EXPERIMENTAL] Ctrl+C copy the contents of focused window into the clipboard. Experimental because: (1) has known issues with nested Begin/End pairs (2) text output quality varies (3) text output is in submission order rather than spatial order. - bool ConfigScrollbarScrollByPage; // = true // Enable scrolling page by page when clicking outside the scrollbar grab. When disabled, always scroll to clicked location. When enabled, Shift+Click scrolls to clicked location. float ConfigMemoryCompactTimer; // = 60.0f // Timer (in seconds) to free transient windows/tables memory buffers when unused. Set to -1.0f to disable. // Inputs Behaviors diff --git a/imgui_demo.cpp b/imgui_demo.cpp index f0927b899..d0d26fa9f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1347,14 +1347,14 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::Text("Set defaults in code:"); ImGui::SameLine(); HelpMarker( - "style.ColorEditFlags is designed to allow you to set boot-time default.\n" + "io.ColorEditFlags is designed to allow you to set boot-time default.\n" "We don't have Push/Pop functions because you can force options on a per-widget basis if needed, " "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid " "encouraging you to persistently save values that aren't forward-compatible."); if (ImGui::Button("Overwrite default: Uint8 + HSV + Hue Bar")) - ImGui::GetStyle().ColorEditFlags = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar; + ImGui::GetIO().ColorEditFlags = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar; if (ImGui::Button("Overwrite default: Float + HDR + Hue Wheel")) - ImGui::GetStyle().ColorEditFlags = ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel; + ImGui::GetIO().ColorEditFlags = ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel; // Always display a small version of both types of pickers // (that's in order to make it more visible in the demo to people who are skimming quickly through it) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index dec1f74b1..aa21753de 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5822,14 +5822,14 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag // Read stored options if (!(flags & ImGuiColorEditFlags_DisplayMask_)) - flags |= (g.Style.ColorEditFlags & ImGuiColorEditFlags_DisplayMask_); + flags |= (g.IO.ColorEditFlags & ImGuiColorEditFlags_DisplayMask_); if (!(flags & ImGuiColorEditFlags_DataTypeMask_)) - flags |= (g.Style.ColorEditFlags & ImGuiColorEditFlags_DataTypeMask_); + flags |= (g.IO.ColorEditFlags & ImGuiColorEditFlags_DataTypeMask_); if (!(flags & ImGuiColorEditFlags_PickerMask_)) - flags |= (g.Style.ColorEditFlags & ImGuiColorEditFlags_PickerMask_); + flags |= (g.IO.ColorEditFlags & ImGuiColorEditFlags_PickerMask_); if (!(flags & ImGuiColorEditFlags_InputMask_)) - flags |= (g.Style.ColorEditFlags & ImGuiColorEditFlags_InputMask_); - flags |= (g.Style.ColorEditFlags & ~(ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_)); + flags |= (g.IO.ColorEditFlags & ImGuiColorEditFlags_InputMask_); + flags |= (g.IO.ColorEditFlags & ~(ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_)); IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check that only 1 is selected IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected @@ -6098,13 +6098,13 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl // Read stored options if (!(flags & ImGuiColorEditFlags_PickerMask_)) - flags |= ((g.Style.ColorEditFlags & ImGuiColorEditFlags_PickerMask_) ? g.Style.ColorEditFlags : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_PickerMask_; + flags |= ((g.IO.ColorEditFlags & ImGuiColorEditFlags_PickerMask_) ? g.IO.ColorEditFlags : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_PickerMask_; if (!(flags & ImGuiColorEditFlags_InputMask_)) - flags |= ((g.Style.ColorEditFlags & ImGuiColorEditFlags_InputMask_) ? g.Style.ColorEditFlags : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_InputMask_; + flags |= ((g.IO.ColorEditFlags & ImGuiColorEditFlags_InputMask_) ? g.IO.ColorEditFlags : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_InputMask_; IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check that only 1 is selected IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected if (!(flags & ImGuiColorEditFlags_NoOptions)) - flags |= (g.Style.ColorEditFlags & ImGuiColorEditFlags_AlphaBar); + flags |= (g.IO.ColorEditFlags & ImGuiColorEditFlags_AlphaBar); // Setup int components = (flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4; @@ -6533,7 +6533,7 @@ void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags) if ((flags & ImGuiColorEditFlags_DataTypeMask_) == 0) { flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DataTypeMask_; } if ((flags & ImGuiColorEditFlags_PickerMask_) == 0) { flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_PickerMask_; } if ((flags & ImGuiColorEditFlags_InputMask_) == 0) { flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_InputMask_; } - g.Style.ColorEditFlags = flags; + g.IO.ColorEditFlags = flags; } #endif @@ -6583,7 +6583,7 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) ImGuiContext& g = *GImGui; PushItemFlag(ImGuiItemFlags_NoMarkEdited, true); - ImGuiColorEditFlags opts = g.Style.ColorEditFlags; + ImGuiColorEditFlags opts = g.IO.ColorEditFlags; if (allow_opt_inputs) { if (RadioButton("RGB", (opts & ImGuiColorEditFlags_DisplayRGB) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayRGB; @@ -6623,7 +6623,7 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) EndPopup(); } - g.Style.ColorEditFlags = opts; + g.IO.ColorEditFlags = opts; PopItemFlag(); EndPopup(); } @@ -6651,7 +6651,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel; ImVec2 backup_pos = GetCursorScreenPos(); if (Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup - g.Style.ColorEditFlags = (g.Style.ColorEditFlags & ~ImGuiColorEditFlags_PickerMask_) | (picker_flags & ImGuiColorEditFlags_PickerMask_); + g.IO.ColorEditFlags = (g.IO.ColorEditFlags & ~ImGuiColorEditFlags_PickerMask_) | (picker_flags & ImGuiColorEditFlags_PickerMask_); SetCursorScreenPos(backup_pos); ImVec4 previewing_ref_col; memcpy(&previewing_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4)); @@ -6663,7 +6663,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl if (allow_opt_alpha_bar) { if (allow_opt_picker) Separator(); - CheckboxFlags("Alpha Bar", &g.Style.ColorEditFlags, ImGuiColorEditFlags_AlphaBar); + CheckboxFlags("Alpha Bar", &g.IO.ColorEditFlags, ImGuiColorEditFlags_AlphaBar); } PopItemFlag(); EndPopup(); From aca69173dfaf3c54c02a5f699ca4cd1211154446 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Jul 2026 16:00:01 +0200 Subject: [PATCH 07/19] (Breaking) ColorEdit: obsoleted SetColorEditOptions() function in favor of poking to io.ConfigColorEditFlags. (Amend 0e479b9, 9f7d808) Apologies, 9f7d808 was extremely flaky. --- docs/CHANGELOG.txt | 9 +++++---- imgui.cpp | 12 ++++++------ imgui.h | 6 +++--- imgui_demo.cpp | 8 ++++---- imgui_widgets.cpp | 26 +++++++++++++------------- 5 files changed, 31 insertions(+), 30 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c4de5cab9..6c4c9de19 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -44,7 +44,7 @@ Breaking Changes: - TreeNode: commented out legacy name `ImGuiTreeNodeFlags_SpanTextWidth` which was obsoleted in 1.90.7 (May 2024). Use `ImGuiTreeNodeFlags_SpanLabelWidth`. - ColorEdit: obsoleted SetColorEditOptions() function added in 1.51 (June 2017) in - of directly poking to style.ColorEditFlags. More consistent and easier to discover + of directly poking to io.ConfigColorEditFlags. More consistent and easier to discover. Other Changes: @@ -113,6 +113,9 @@ Other Changes: - Added io.MouseSingleClickDelay to configure default delayed single click delay when using GetItemClickedCountWithSingleClickDelay() or IsMouseReleasedWithDelay(). (#8337) Note that io.MouseSingleClickDelay is always > io.MouseDoubleClickTime. +- ColorEdit: + - Added `io.ConfigColorEditFlags` to read/modify current color edit/picker settings. + - ColorButton: small rendering tweak/optimization for the alpha checkerboard. - Style: - Added style.MenuItemRounding, ImGuiStyleVar_MenuItemRounding. (#7589, #9375, #9453) - Added style.SelectableRounding, ImGuiStyleVar_SelectableRounding. (#7589, #9375, #9453) @@ -134,8 +137,6 @@ Other Changes: - Minor optimization to `AddLine()`, `AddLineH()`, `AddLineV()` functions. (#4091) - Added `ImDrawListFlags_TextNoPixelSnap` to disable snapping of AddText() coordinates for a given scope. (#3437, #9417, #2291) -- ColorButton: - - Small rendering tweak/optimization for the alpha checkerboard. - Demo: - Extract 'Widgets->Tree Nodes->Selectable Nodes' out of the 'Advanced' demo for clarity (manual reimplementation of basic selection). @@ -154,7 +155,7 @@ Other Changes: - Uses `SetProcessDpiAwarenessContext()` instead of `SetThreadDpiAwarenessContext()` when available, fixing OpenGL DPI scaling issues as e.g. NVIDIA drivers tends to spawn multiple-thread to manage OpenGL. (#9403) -- Examples: +- Examples: - Android: update to AGP 9.2.0 to support Gradle 9.6.0. - OpenGL3+GLFW/SDL2/SDL3: allow Wine compatibility by passing empty GLSL version string to ImGui_ImplOpenGL3_Init() to let backend decide of a GLSL version based diff --git a/imgui.cpp b/imgui.cpp index fbbaded6d..2e76a8e92 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -395,7 +395,7 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. - - 2026/07/06 (1.92.9) - ColorEdit: obsoleted SetColorEditOptions() function added in 1.51 (June 2017) in favor of directly poking to style.ColorEditFlags. More consistent and easier to discover. + - 2026/07/06 (1.92.9) - ColorEdit: obsoleted SetColorEditOptions() function added in 1.51 (June 2017) in favor of directly poking to io.ConfigColorEditFlags. More consistent and easier to discover. - 2026/06/02 (1.92.9) - TreeNode: commented out legacy name ImGuiTreeNodeFlags_SpanTextWidth which was obsoleted in 1.90.7 (May 2024). Use ImGuiTreeNodeFlags_SpanLabelWidth instead. - 2026/05/07 (1.92.8) - DrawList: swapped the last two arguments of AddRect(), AddPolyline(), PathStroke(). - Before: void ImDrawList::AddRect(ImVec2 p_min, ImVec2 p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0, float thickness = 1.0f); @@ -1681,7 +1681,7 @@ ImGuiIO::ImGuiIO() ConfigInputTextCursorBlink = true; ConfigInputTextEnterKeepActive = false; ConfigDragClickToInputText = false; - ColorEditFlags = ImGuiColorEditFlags_DefaultOptions_; // Current settings for ColorEdit/ColorPicker widgets. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. + ConfigColorEditFlags = ImGuiColorEditFlags_DefaultOptions_; // Current settings for ColorEdit/ColorPicker widgets. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. ConfigWindowsResizeFromEdges = true; ConfigWindowsMoveFromTitleBarOnly = false; ConfigWindowsCopyContentsWithCtrlC = false; @@ -11081,10 +11081,10 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() IM_ASSERT(g.Style.WindowBorderHoverPadding > 0.0f && "Invalid style setting!"); // Required otherwise cannot resize from borders. IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); IM_ASSERT(g.Style.ColorButtonPosition == ImGuiDir_Left || g.Style.ColorButtonPosition == ImGuiDir_Right); - IM_ASSERT(ImIsPowerOfTwo(g.IO.ColorEditFlags & ImGuiColorEditFlags_DisplayMask_)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(g.IO.ColorEditFlags & ImGuiColorEditFlags_DataTypeMask_)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(g.IO.ColorEditFlags & ImGuiColorEditFlags_PickerMask_)); // Check only 1 option is selected - IM_ASSERT(ImIsPowerOfTwo(g.IO.ColorEditFlags & ImGuiColorEditFlags_InputMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(g.IO.ConfigColorEditFlags & ImGuiColorEditFlags_DisplayMask_)); // Check only 1 option is selected + IM_ASSERT(ImIsPowerOfTwo(g.IO.ConfigColorEditFlags & ImGuiColorEditFlags_DataTypeMask_)); // " + IM_ASSERT(ImIsPowerOfTwo(g.IO.ConfigColorEditFlags & ImGuiColorEditFlags_PickerMask_)); // " + IM_ASSERT(ImIsPowerOfTwo(g.IO.ConfigColorEditFlags & ImGuiColorEditFlags_InputMask_)); // " IM_ASSERT(g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesNone || g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesFull || g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesToNodes); IM_ASSERT(g.IO.MouseSingleClickDelay > g.IO.MouseDoubleClickTime); diff --git a/imgui.h b/imgui.h index bb05b0365..caae0458b 100644 --- a/imgui.h +++ b/imgui.h @@ -1917,9 +1917,9 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_InputRGB = 1 << 27, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. ImGuiColorEditFlags_InputHSV = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. - // Defaults Options copied to style.ColorEditFlags during initialization. + // Defaults Options copied to io.ConfigColorEditFlags during initialization. // The intent is that you probably don't want to override them in most of your calls. - // Let the user choose via the option menu and/or modify style.ColorEditFlags directly during startup if you want. + // Let the user choose via the option menu and/or modify io.ConfigColorEditFlags directly during startup if you want. ImGuiColorEditFlags_DefaultOptions_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar, // [Internal] Masks @@ -2441,7 +2441,7 @@ struct ImGuiIO bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will reactivate item and select all text (single-line only). - ImGuiColorEditFlags ColorEditFlags; // // Current settings for ColorEdit/ColorPicker widgets. Must have one bit of ImGuiColorEditFlags_DisplayMask_, one bit of ImGuiColorEditFlags_DataTypeMask_, one bit of ImGuiColorEditFlags_PickerMask_, one bit of ImGuiColorEditFlags_InputMask_. Defaults to ImGuiColorEditFlags_DefaultOptions_. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. + ImGuiColorEditFlags ConfigColorEditFlags; // // Current settings for ColorEdit/ColorPicker widgets. Must have one bit of ImGuiColorEditFlags_DisplayMask_, one bit of ImGuiColorEditFlags_DataTypeMask_, one bit of ImGuiColorEditFlags_PickerMask_, one bit of ImGuiColorEditFlags_InputMask_. Defaults to ImGuiColorEditFlags_DefaultOptions_. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d0d26fa9f..29822330d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1334,7 +1334,7 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::SameLine(); HelpMarker( "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex " - "if you don't specify a display mode.\n\nYou can change the defaults using style.ColorEditFlags."); + "if you don't specify a display mode.\n\nYou can change the defaults using io.ConfigColorEditFlags."); ImGuiColorEditFlags flags = base_flags | color_picker_flags; if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; @@ -1347,14 +1347,14 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::Text("Set defaults in code:"); ImGui::SameLine(); HelpMarker( - "io.ColorEditFlags is designed to allow you to set boot-time default.\n" + "io.ConfigColorEditFlags is designed to allow you to set boot-time default.\n" "We don't have Push/Pop functions because you can force options on a per-widget basis if needed, " "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid " "encouraging you to persistently save values that aren't forward-compatible."); if (ImGui::Button("Overwrite default: Uint8 + HSV + Hue Bar")) - ImGui::GetIO().ColorEditFlags = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar; + ImGui::GetIO().ConfigColorEditFlags = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar; if (ImGui::Button("Overwrite default: Float + HDR + Hue Wheel")) - ImGui::GetIO().ColorEditFlags = ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel; + ImGui::GetIO().ConfigColorEditFlags = ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel; // Always display a small version of both types of pickers // (that's in order to make it more visible in the demo to people who are skimming quickly through it) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index aa21753de..6276f7db4 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5822,14 +5822,14 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag // Read stored options if (!(flags & ImGuiColorEditFlags_DisplayMask_)) - flags |= (g.IO.ColorEditFlags & ImGuiColorEditFlags_DisplayMask_); + flags |= (g.IO.ConfigColorEditFlags & ImGuiColorEditFlags_DisplayMask_); if (!(flags & ImGuiColorEditFlags_DataTypeMask_)) - flags |= (g.IO.ColorEditFlags & ImGuiColorEditFlags_DataTypeMask_); + flags |= (g.IO.ConfigColorEditFlags & ImGuiColorEditFlags_DataTypeMask_); if (!(flags & ImGuiColorEditFlags_PickerMask_)) - flags |= (g.IO.ColorEditFlags & ImGuiColorEditFlags_PickerMask_); + flags |= (g.IO.ConfigColorEditFlags & ImGuiColorEditFlags_PickerMask_); if (!(flags & ImGuiColorEditFlags_InputMask_)) - flags |= (g.IO.ColorEditFlags & ImGuiColorEditFlags_InputMask_); - flags |= (g.IO.ColorEditFlags & ~(ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_)); + flags |= (g.IO.ConfigColorEditFlags & ImGuiColorEditFlags_InputMask_); + flags |= (g.IO.ConfigColorEditFlags & ~(ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_)); IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_)); // Check that only 1 is selected IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected @@ -6098,13 +6098,13 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl // Read stored options if (!(flags & ImGuiColorEditFlags_PickerMask_)) - flags |= ((g.IO.ColorEditFlags & ImGuiColorEditFlags_PickerMask_) ? g.IO.ColorEditFlags : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_PickerMask_; + flags |= ((g.IO.ConfigColorEditFlags & ImGuiColorEditFlags_PickerMask_) ? g.IO.ConfigColorEditFlags : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_PickerMask_; if (!(flags & ImGuiColorEditFlags_InputMask_)) - flags |= ((g.IO.ColorEditFlags & ImGuiColorEditFlags_InputMask_) ? g.IO.ColorEditFlags : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_InputMask_; + flags |= ((g.IO.ConfigColorEditFlags & ImGuiColorEditFlags_InputMask_) ? g.IO.ConfigColorEditFlags : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_InputMask_; IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_)); // Check that only 1 is selected IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_)); // Check that only 1 is selected if (!(flags & ImGuiColorEditFlags_NoOptions)) - flags |= (g.IO.ColorEditFlags & ImGuiColorEditFlags_AlphaBar); + flags |= (g.IO.ConfigColorEditFlags & ImGuiColorEditFlags_AlphaBar); // Setup int components = (flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4; @@ -6533,7 +6533,7 @@ void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags) if ((flags & ImGuiColorEditFlags_DataTypeMask_) == 0) { flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DataTypeMask_; } if ((flags & ImGuiColorEditFlags_PickerMask_) == 0) { flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_PickerMask_; } if ((flags & ImGuiColorEditFlags_InputMask_) == 0) { flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_InputMask_; } - g.IO.ColorEditFlags = flags; + g.IO.ConfigColorEditFlags = flags; } #endif @@ -6583,7 +6583,7 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) ImGuiContext& g = *GImGui; PushItemFlag(ImGuiItemFlags_NoMarkEdited, true); - ImGuiColorEditFlags opts = g.IO.ColorEditFlags; + ImGuiColorEditFlags opts = g.IO.ConfigColorEditFlags; if (allow_opt_inputs) { if (RadioButton("RGB", (opts & ImGuiColorEditFlags_DisplayRGB) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayRGB; @@ -6623,7 +6623,7 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) EndPopup(); } - g.IO.ColorEditFlags = opts; + g.IO.ConfigColorEditFlags = opts; PopItemFlag(); EndPopup(); } @@ -6651,7 +6651,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel; ImVec2 backup_pos = GetCursorScreenPos(); if (Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup - g.IO.ColorEditFlags = (g.IO.ColorEditFlags & ~ImGuiColorEditFlags_PickerMask_) | (picker_flags & ImGuiColorEditFlags_PickerMask_); + g.IO.ConfigColorEditFlags = (g.IO.ConfigColorEditFlags & ~ImGuiColorEditFlags_PickerMask_) | (picker_flags & ImGuiColorEditFlags_PickerMask_); SetCursorScreenPos(backup_pos); ImVec4 previewing_ref_col; memcpy(&previewing_ref_col, ref_col, sizeof(float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4)); @@ -6663,7 +6663,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl if (allow_opt_alpha_bar) { if (allow_opt_picker) Separator(); - CheckboxFlags("Alpha Bar", &g.IO.ColorEditFlags, ImGuiColorEditFlags_AlphaBar); + CheckboxFlags("Alpha Bar", &g.IO.ConfigColorEditFlags, ImGuiColorEditFlags_AlphaBar); } PopItemFlag(); EndPopup(); From 0785cdb2bb07e3c58e09c56ada0e3cbc74918a20 Mon Sep 17 00:00:00 2001 From: SeanTheBuilder1 Date: Tue, 31 Mar 2026 01:13:25 +0800 Subject: [PATCH 08/19] ColorPicker: added option to fix Saturation/Value triangle in wheel picker. (#9337) --- imgui.h | 5 +++-- imgui_widgets.cpp | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index caae0458b..c1a74f5c5 100644 --- a/imgui.h +++ b/imgui.h @@ -1914,8 +1914,9 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_Float = 1 << 24, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats instead of 0..255 integers. No round-trip of value via integers. ImGuiColorEditFlags_PickerHueBar = 1 << 25, // [Picker] // ColorPicker: bar for Hue, rectangle for Sat/Value. ImGuiColorEditFlags_PickerHueWheel = 1 << 26, // [Picker] // ColorPicker: wheel for Hue, triangle for Sat/Value. - ImGuiColorEditFlags_InputRGB = 1 << 27, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. - ImGuiColorEditFlags_InputHSV = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. + ImGuiColorEditFlags_FixedTriangle = 1 << 27, // [Picker] // ColorPicker: fix triangle position for PickerHueWheel. + ImGuiColorEditFlags_InputRGB = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. + ImGuiColorEditFlags_InputHSV = 1 << 29, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. // Defaults Options copied to io.ConfigColorEditFlags during initialization. // The intent is that you probably don't want to override them in most of your calls. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6276f7db4..d4e39260d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6130,6 +6130,12 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point. ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point. ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point. + if (flags & ImGuiColorEditFlags_FixedTriangle) + { + triangle_pa = ImVec2(triangle_r * +0.866025f, triangle_r * +0.5f); // Hue point. + triangle_pb = ImVec2(0.0f, -triangle_r); // Black point. + triangle_pc = ImVec2(triangle_r * -0.866025f, triangle_r * +0.5f); // White point. + } float H = col[0], S = col[1], V = col[2]; float R = col[0], G = col[1], B = col[2]; @@ -6166,6 +6172,11 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl } float cos_hue_angle = ImCos(-H * 2.0f * IM_PI); float sin_hue_angle = ImSin(-H * 2.0f * IM_PI); + if (flags & ImGuiColorEditFlags_FixedTriangle) + { + cos_hue_angle = ImCos(-0.0 * 2.0f * IM_PI); + sin_hue_angle = ImSin(-0.0 * 2.0f * IM_PI); + } if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle))) { // Interacting with SV triangle @@ -6374,6 +6385,11 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments); draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad + 1, col_midgrey, hue_cursor_segments); draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments); + if (flags & ImGuiColorEditFlags_FixedTriangle) + { + cos_hue_angle = ImCos(-0.0 * 2.0f * IM_PI); + sin_hue_angle = ImSin(-0.0 * 2.0f * IM_PI); + } // Render SV triangle (rotated according to hue) ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle); From 5d56c0943243a75de5213c9e36653ff93ed0683a Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Jun 2026 14:37:03 +0200 Subject: [PATCH 09/19] ColorPicker: added option to fix Saturation/Value triangle in wheel picker. Amends. (#9337) --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 1 + imgui.h | 15 ++++++++------- imgui_demo.cpp | 1 + imgui_widgets.cpp | 28 +++++++++------------------- 5 files changed, 22 insertions(+), 26 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6c4c9de19..4bceb3d99 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -115,6 +115,9 @@ Other Changes: Note that io.MouseSingleClickDelay is always > io.MouseDoubleClickTime. - ColorEdit: - Added `io.ConfigColorEditFlags` to read/modify current color edit/picker settings. + - ColorPicker: added `io.ConfigColorPickerRotateTriangle` to disable rotation of the + S/V triangle when in `ImGuiColorEditFlags_PickerHueWheel` mode. (#9337) [@SeanTheBuilder1] + Likely best passed to `style.ColorEditFlags` to setup globally and once. - ColorButton: small rendering tweak/optimization for the alpha checkerboard. - Style: - Added style.MenuItemRounding, ImGuiStyleVar_MenuItemRounding. (#7589, #9375, #9453) diff --git a/imgui.cpp b/imgui.cpp index 2e76a8e92..cf6ba2460 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1682,6 +1682,7 @@ ImGuiIO::ImGuiIO() ConfigInputTextEnterKeepActive = false; ConfigDragClickToInputText = false; ConfigColorEditFlags = ImGuiColorEditFlags_DefaultOptions_; // Current settings for ColorEdit/ColorPicker widgets. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. + ConfigColorPickerRotateTriangle = true; ConfigWindowsResizeFromEdges = true; ConfigWindowsMoveFromTitleBarOnly = false; ConfigWindowsCopyContentsWithCtrlC = false; diff --git a/imgui.h b/imgui.h index c1a74f5c5..5f797aba3 100644 --- a/imgui.h +++ b/imgui.h @@ -243,7 +243,7 @@ typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: f typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for InvisibleButton() typedef int ImGuiChildFlags; // -> enum ImGuiChildFlags_ // Flags: for BeginChild() -typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4() etc. +typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4(), style.ColorEditFlags etc. typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for BeginDragDropSource(), AcceptDragDropPayload() @@ -1904,7 +1904,8 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_AlphaNoBg = 1 << 13, // // ColorEdit, ColorPicker, ColorButton: disable rendering a checkerboard background behind transparent color. ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 14, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half transparent preview. - // User Options (right-click on widget to change some of them). + // User Options (right-click on widget to change some of them) + // Current settings are stored in style.ColorEditFlags. ImGuiColorEditFlags_AlphaBar = 1 << 18, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker. ImGuiColorEditFlags_HDR = 1 << 19, // // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you probably want to use ImGuiColorEditFlags_Float flag as well). ImGuiColorEditFlags_DisplayRGB = 1 << 20, // [Display] // ColorEdit: override _display_ type among RGB/HSV/Hex. ColorPicker: select any combination using one or more of RGB/HSV/Hex. @@ -1914,9 +1915,8 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_Float = 1 << 24, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats instead of 0..255 integers. No round-trip of value via integers. ImGuiColorEditFlags_PickerHueBar = 1 << 25, // [Picker] // ColorPicker: bar for Hue, rectangle for Sat/Value. ImGuiColorEditFlags_PickerHueWheel = 1 << 26, // [Picker] // ColorPicker: wheel for Hue, triangle for Sat/Value. - ImGuiColorEditFlags_FixedTriangle = 1 << 27, // [Picker] // ColorPicker: fix triangle position for PickerHueWheel. - ImGuiColorEditFlags_InputRGB = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. - ImGuiColorEditFlags_InputHSV = 1 << 29, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. + ImGuiColorEditFlags_InputRGB = 1 << 27, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. + ImGuiColorEditFlags_InputHSV = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. // Defaults Options copied to io.ConfigColorEditFlags during initialization. // The intent is that you probably don't want to override them in most of your calls. @@ -1933,8 +1933,8 @@ enum ImGuiColorEditFlags_ // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGuiColorEditFlags_AlphaPreview = 0, // Removed in 1.91.8. This is the default now. Will display a checkerboard unless ImGuiColorEditFlags_AlphaNoBg is set. -#endif //ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] +#endif }; // Flags for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. @@ -2442,7 +2442,8 @@ struct ImGuiIO bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will reactivate item and select all text (single-line only). - ImGuiColorEditFlags ConfigColorEditFlags; // // Current settings for ColorEdit/ColorPicker widgets. Must have one bit of ImGuiColorEditFlags_DisplayMask_, one bit of ImGuiColorEditFlags_DataTypeMask_, one bit of ImGuiColorEditFlags_PickerMask_, one bit of ImGuiColorEditFlags_InputMask_. Defaults to ImGuiColorEditFlags_DefaultOptions_. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. + ImGuiColorEditFlags ConfigColorEditFlags; // = // Current settings for ColorEdit/ColorPicker widgets. Must have one bit of ImGuiColorEditFlags_DisplayMask_, one bit of ImGuiColorEditFlags_DataTypeMask_, one bit of ImGuiColorEditFlags_PickerMask_, one bit of ImGuiColorEditFlags_InputMask_. Defaults to ImGuiColorEditFlags_DefaultOptions_. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. + bool ConfigColorPickerRotateTriangle;// = true // Rotate hue triangle in color picker. bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 29822330d..25cf384e5 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1326,6 +1326,7 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | base_flags); } } + ImGui::Checkbox("io.ConfigColorPickerRotate", &ImGui::GetIO().ConfigColorPickerRotateTriangle); ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0"); ImGui::SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode."); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d4e39260d..eedbb4400 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6126,16 +6126,11 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size * 0.5f); // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic. + const bool triangle_rotate = io.ConfigColorPickerRotateTriangle; float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f); - ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point. - ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point. - ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point. - if (flags & ImGuiColorEditFlags_FixedTriangle) - { - triangle_pa = ImVec2(triangle_r * +0.866025f, triangle_r * +0.5f); // Hue point. - triangle_pb = ImVec2(0.0f, -triangle_r); // Black point. - triangle_pc = ImVec2(triangle_r * -0.866025f, triangle_r * +0.5f); // White point. - } + ImVec2 triangle_pa = triangle_rotate ? ImVec2(triangle_r, 0.0f) : ImVec2(triangle_r * +0.866f, triangle_r * +0.5f); // Hue point. + ImVec2 triangle_pb = triangle_rotate ? ImVec2(triangle_r * -0.5f, triangle_r * -0.866f) : ImVec2(0.0f, -triangle_r); // Black point. + ImVec2 triangle_pc = triangle_rotate ? ImVec2(triangle_r * -0.5f, triangle_r * +0.866f) : ImVec2(triangle_r * -0.866f, triangle_r * +0.5f); // White point. float H = col[0], S = col[1], V = col[2]; float R = col[0], G = col[1], B = col[2]; @@ -6170,13 +6165,8 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl H += 1.0f; value_changed = value_changed_h = true; } - float cos_hue_angle = ImCos(-H * 2.0f * IM_PI); - float sin_hue_angle = ImSin(-H * 2.0f * IM_PI); - if (flags & ImGuiColorEditFlags_FixedTriangle) - { - cos_hue_angle = ImCos(-0.0 * 2.0f * IM_PI); - sin_hue_angle = ImSin(-0.0 * 2.0f * IM_PI); - } + float cos_hue_angle = triangle_rotate ? ImCos(-H * 2.0f * IM_PI) : 1.0f; + float sin_hue_angle = triangle_rotate ? ImSin(-H * 2.0f * IM_PI) : 0.0f; if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle))) { // Interacting with SV triangle @@ -6385,10 +6375,10 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments); draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad + 1, col_midgrey, hue_cursor_segments); draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments); - if (flags & ImGuiColorEditFlags_FixedTriangle) + if (triangle_rotate == false) { - cos_hue_angle = ImCos(-0.0 * 2.0f * IM_PI); - sin_hue_angle = ImSin(-0.0 * 2.0f * IM_PI); + cos_hue_angle = 1.0f; + sin_hue_angle = 0.0f; } // Render SV triangle (rotated according to hue) From f626c1c7933329ed74a442dd071fe2766ac774d4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Jul 2026 16:18:34 +0200 Subject: [PATCH 10/19] ColorPicker: added option to fix Saturation/Value triangle in wheel picker. Amends. (#9337) ConfigColorPickerRotateTriangle -> !ImGuiColorEditFlags_PickerNoRotate --- imgui.cpp | 1 - imgui.h | 8 ++++---- imgui_demo.cpp | 2 +- imgui_widgets.cpp | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index cf6ba2460..2e76a8e92 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1682,7 +1682,6 @@ ImGuiIO::ImGuiIO() ConfigInputTextEnterKeepActive = false; ConfigDragClickToInputText = false; ConfigColorEditFlags = ImGuiColorEditFlags_DefaultOptions_; // Current settings for ColorEdit/ColorPicker widgets. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. - ConfigColorPickerRotateTriangle = true; ConfigWindowsResizeFromEdges = true; ConfigWindowsMoveFromTitleBarOnly = false; ConfigWindowsCopyContentsWithCtrlC = false; diff --git a/imgui.h b/imgui.h index 5f797aba3..d63544c12 100644 --- a/imgui.h +++ b/imgui.h @@ -243,7 +243,7 @@ typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: f typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for InvisibleButton() typedef int ImGuiChildFlags; // -> enum ImGuiChildFlags_ // Flags: for BeginChild() -typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4(), style.ColorEditFlags etc. +typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4(), io.ConfigColorEditFlags etc. typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for BeginDragDropSource(), AcceptDragDropPayload() @@ -1915,8 +1915,9 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_Float = 1 << 24, // [DataType] // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats instead of 0..255 integers. No round-trip of value via integers. ImGuiColorEditFlags_PickerHueBar = 1 << 25, // [Picker] // ColorPicker: bar for Hue, rectangle for Sat/Value. ImGuiColorEditFlags_PickerHueWheel = 1 << 26, // [Picker] // ColorPicker: wheel for Hue, triangle for Sat/Value. - ImGuiColorEditFlags_InputRGB = 1 << 27, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. - ImGuiColorEditFlags_InputHSV = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. + ImGuiColorEditFlags_PickerNoRotate = 1 << 27, // [Picker] // ColorPicker: disable rotating Sat/Value triangle. Best set in io.ConfigColorEditFlags once. + ImGuiColorEditFlags_InputRGB = 1 << 28, // [Input] // ColorEdit, ColorPicker: input and output data in RGB format. + ImGuiColorEditFlags_InputHSV = 1 << 29, // [Input] // ColorEdit, ColorPicker: input and output data in HSV format. // Defaults Options copied to io.ConfigColorEditFlags during initialization. // The intent is that you probably don't want to override them in most of your calls. @@ -2443,7 +2444,6 @@ struct ImGuiIO bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will reactivate item and select all text (single-line only). ImGuiColorEditFlags ConfigColorEditFlags; // = // Current settings for ColorEdit/ColorPicker widgets. Must have one bit of ImGuiColorEditFlags_DisplayMask_, one bit of ImGuiColorEditFlags_DataTypeMask_, one bit of ImGuiColorEditFlags_PickerMask_, one bit of ImGuiColorEditFlags_InputMask_. Defaults to ImGuiColorEditFlags_DefaultOptions_. May be further edited by users, unless you also set ImGuiColorEditFlags_NoOptions. - bool ConfigColorPickerRotateTriangle;// = true // Rotate hue triangle in color picker. bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 25cf384e5..b1a5d7498 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1326,7 +1326,7 @@ static void DemoWindowWidgetsColorAndPickers() ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | base_flags); } } - ImGui::Checkbox("io.ConfigColorPickerRotate", &ImGui::GetIO().ConfigColorPickerRotateTriangle); + ImGui::CheckboxFlags("ImGuiColorEditFlags_PickerNoRotate", &color_picker_flags, ImGuiColorEditFlags_PickerNoRotate); ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0"); ImGui::SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode."); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index eedbb4400..c787a0bbd 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6126,7 +6126,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size * 0.5f); // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic. - const bool triangle_rotate = io.ConfigColorPickerRotateTriangle; + const bool triangle_rotate = (flags & ImGuiColorEditFlags_PickerNoRotate) == 0; float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f); ImVec2 triangle_pa = triangle_rotate ? ImVec2(triangle_r, 0.0f) : ImVec2(triangle_r * +0.866f, triangle_r * +0.5f); // Hue point. ImVec2 triangle_pb = triangle_rotate ? ImVec2(triangle_r * -0.5f, triangle_r * -0.866f) : ImVec2(0.0f, -triangle_r); // Black point. From cfdc953ba91fa6dc093dfd3223977fe9d8e00a9c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Jul 2026 16:21:36 +0200 Subject: [PATCH 11/19] ColorPicker: added option to fix Saturation/Value triangle in wheel picker. Amends. (#9337) The heat makes this week really not good with human mistakes I guess. --- docs/CHANGELOG.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4bceb3d99..445432bb1 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -115,7 +115,7 @@ Other Changes: Note that io.MouseSingleClickDelay is always > io.MouseDoubleClickTime. - ColorEdit: - Added `io.ConfigColorEditFlags` to read/modify current color edit/picker settings. - - ColorPicker: added `io.ConfigColorPickerRotateTriangle` to disable rotation of the + - ColorPicker: added `ImGuiColorEditFlags_PickerNoRotate` to disable rotation of the S/V triangle when in `ImGuiColorEditFlags_PickerHueWheel` mode. (#9337) [@SeanTheBuilder1] Likely best passed to `style.ColorEditFlags` to setup globally and once. - ColorButton: small rendering tweak/optimization for the alpha checkerboard. From 520a29dd518be4f3bdfc4a4740660b491ecfd3bb Mon Sep 17 00:00:00 2001 From: Kian <92978255+MERL10N@users.noreply.github.com> Date: Fri, 3 Jul 2026 15:34:32 -0700 Subject: [PATCH 12/19] Backends: Metal4: added metal-cpp support. (#9461) with amends. --- backends/imgui_impl_metal.mm | 1 - backends/imgui_impl_metal4.h | 33 +++++++++++++++++++++++++++++++- backends/imgui_impl_metal4.mm | 36 ++++++++++++++++++++++++++++++++++- docs/CHANGELOG.txt | 2 +- 4 files changed, 68 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 652668c78..445c4b36c 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -123,7 +123,6 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, ImGui_ImplMetal_RenderDrawData(draw_data, (__bridge id)(commandBuffer), (__bridge id)(commandEncoder)); - } bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device) diff --git a/backends/imgui_impl_metal4.h b/backends/imgui_impl_metal4.h index b5ec4ca56..b5b54cad0 100644 --- a/backends/imgui_impl_metal4.h +++ b/backends/imgui_impl_metal4.h @@ -7,7 +7,6 @@ // [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). // Missing features or Issues: -// [ ] Metal-cpp support. // [ ] Texture view pool support? Reevaluate which type to use for ImtextureID. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -53,6 +52,38 @@ IMGUI_IMPL_API void ImGui_ImplMetal4_UpdateTexture(ImTextureData* tex); #endif +//----------------------------------------------------------------------------- +// C++ API +//----------------------------------------------------------------------------- + +// Enable Metal C++ binding support with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file +// More info about using Metal from C++: https://developer.apple.com/metal/cpp/ + +#ifdef IMGUI_IMPL_METAL_CPP +#ifndef __OBJC__ + +// Forward declare relevant classes from the MTL and MTL4 namespace +namespace MTL { class Device; } +namespace MTL4 { class CommandQueue; class CommandBuffer; class RenderPassDescriptor; class RenderCommandEncoder; } + +// Follow "Getting Started" link and check examples/ folder to learn about using backends! +IMGUI_IMPL_API bool ImGui_ImplMetal4_Init(MTL::Device* device, MTL4::CommandQueue* commandQueue, int framesInFlight); +IMGUI_IMPL_API void ImGui_ImplMetal4_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplMetal4_NewFrame(MTL4::RenderPassDescriptor* renderPassDescriptor, int frameInFlightIndex); +IMGUI_IMPL_API void ImGui_ImplMetal4_RenderDrawData(ImDrawData* draw_data, + MTL4::CommandBuffer* commandBuffer, + MTL4::RenderCommandEncoder* commandEncoder); + +// Called by Init/NewFrame/Shutdown +IMGUI_IMPL_API bool ImGui_ImplMetal4_CreateDeviceObjects(MTL::Device* device); +IMGUI_IMPL_API void ImGui_ImplMetal4_DestroyDeviceObjects(); + +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = nullptr to handle this manually. +IMGUI_IMPL_API void ImGui_ImplMetal4_UpdateTexture(ImTextureData* tex); + +#endif +#endif + //----------------------------------------------------------------------------- #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_metal4.mm b/backends/imgui_impl_metal4.mm index f88d34b4e..d2d172a57 100644 --- a/backends/imgui_impl_metal4.mm +++ b/backends/imgui_impl_metal4.mm @@ -7,7 +7,6 @@ // [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). // Missing features or Issues: -// [ ] Metal-cpp support. // [ ] Texture view pool support? Reevaluate which type to use for ImtextureID. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -20,6 +19,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-07-07: Metal 4: Added metal-cpp support. (#9461) // 2026-07-02: Metal 4: Added new Metal 4 backend implementation. (#9458) #include "imgui.h" @@ -28,6 +28,10 @@ #import #import +#ifdef IMGUI_IMPL_METAL_CPP +#include +#endif + #pragma mark - Support classes and structs struct ImGui_Metal4_ConstantData @@ -95,6 +99,36 @@ static void ImGui_ImplMetal4_DestroyBackendData(){ IM_DELET static inline CFTimeInterval GetMachAbsoluteTimeInSeconds() { return (CFTimeInterval)(double)(clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1e9); } +#ifdef IMGUI_IMPL_METAL_CPP + +#pragma mark - Dear ImGui Metal C++ Backend API + +bool ImGui_ImplMetal4_Init(MTL::Device* device, MTL4::CommandQueue* commandQueue, int framesInFlight) +{ + return ImGui_ImplMetal4_Init((__bridge id)(device),(__bridge id)(commandQueue), framesInFlight); +} + +void ImGui_ImplMetal4_NewFrame(MTL4::RenderPassDescriptor* renderPassDescriptor, int frameInFlightIndex) +{ + ImGui_ImplMetal4_NewFrame((__bridge MTL4RenderPassDescriptor*)(renderPassDescriptor), frameInFlightIndex); +} + +void ImGui_ImplMetal4_RenderDrawData(ImDrawData* draw_data, + MTL4::CommandBuffer* commandBuffer, + MTL4::RenderCommandEncoder* commandEncoder) +{ + ImGui_ImplMetal4_RenderDrawData(draw_data, + (__bridge id)(commandBuffer), + (__bridge id)(commandEncoder)); +} + +bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device) +{ + return ImGui_ImplMetal4_CreateDeviceObjects((__bridge id)(device)); +} + +#endif // #ifdef IMGUI_IMPL_METAL_CPP + #pragma mark - Dear ImGui Metal Backend API void ImGui_ImplMetal4_NewFrame(MTL4RenderPassDescriptor* renderPassDescriptor, int frameInFlightIndex) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 445432bb1..b0afa23f8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -148,7 +148,7 @@ Other Changes: - Backends: - Metal4: - Added new Metal 4 backend (forked from Metal 3 backend). (#9458, #9451) [@AmelieHeinrich] - Note that Metal-cpp is not yet supported. + - Added Metal-cpp support enabled with `IMGUI_IMPL_METAL_CPP` define. (#9461) [@MERL10N] - OpenGL3: - GLSL version detection assume GLSL 410 when GL context is 4.1. Fixes an issue running on macOS with Wine. [#9427, #6577) [@perminovVS] From 481f2cea17e5862c2f27934c6cb8d4ef1c134191 Mon Sep 17 00:00:00 2001 From: Kian <92978255+MERL10N@users.noreply.github.com> Date: Mon, 6 Jul 2026 18:13:19 -0700 Subject: [PATCH 13/19] Backends: Metal4: added ImTextureID tex_id to residency set. (#9461, #9458, #9451) This will resolve runtime errors identified by XCode's Metal Shader Validator. --- backends/imgui_impl_metal4.mm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_metal4.mm b/backends/imgui_impl_metal4.mm index d2d172a57..2866ed1e2 100644 --- a/backends/imgui_impl_metal4.mm +++ b/backends/imgui_impl_metal4.mm @@ -239,9 +239,6 @@ void ImGui_ImplMetal4_RenderDrawData(ImDrawData* draw_data, idDisplayPos; // (0,0) unless using multi-viewports ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) - // Before rendering command lists, commit residency set - [bd->SharedMetalContext.residencySet commit]; - // Render command lists size_t vertexBufferOffset = 0; size_t indexBufferOffset = 0; @@ -292,6 +289,7 @@ void ImGui_ImplMetal4_RenderDrawData(ImDrawData* draw_data, id texture = (__bridge id)(void*)(intptr_t)tex_id; + [bd->SharedMetalContext.residencySet addAllocation:texture]; [bd->SharedMetalContext.argumentTable setTexture:texture.gpuResourceID atIndex:0]; } @@ -317,6 +315,9 @@ void ImGui_ImplMetal4_RenderDrawData(ImDrawData* draw_data, idSharedMetalContext.residencySet commit]; bd->RenderCommandEncoder = nil; } From d1eb8d031c69689371e72b027a472d12a0d9a14e Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Jul 2026 22:00:26 +0200 Subject: [PATCH 14/19] Settings: added explicit DiscardWhenMissingDate. (#9460, #9108) --- imgui_internal.h | 3 ++- imgui_tables.cpp | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 7f5e90dc0..c9ee4cbba 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2048,7 +2048,8 @@ struct ImGuiWindowSettings struct ImGuiSettingsCleanupArgs { - int DiscardOlderThanMonths = 0; // Enable to discard entries older than XX months. + int DiscardOlderThanMonths = 0; // Enable to discard entries older than XX months. + bool DiscardWhenMissingDate = false; // Enable to discard entries missing a date. bool SetCurrentSessionDateToAll = false; // Enable to write current SessionDate to all supporting entries. // Let us know in #9460 if you use this. bool SetCurrentSessionDateWhenMissingDate = false; // Enable to write current SessionDate to all supporting entries missing a date. // Let us know in #9460 if you use this. int _DiscardOlderThanDate = 0; // [Internal] diff --git a/imgui_tables.cpp b/imgui_tables.cpp index aa0b89efe..2fcce6cca 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -4134,9 +4134,12 @@ static void TableSettingsHandler_Cleanup(ImGuiContext* ctx, ImGuiSettingsHandler table->SettingsOffset = -1; for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) { + const bool is_valid = settings->LastUsedDate.IsValid(); if (args->_DiscardOlderThanDate != 0 && settings->LastUsedDate.Unpack() < args->_DiscardOlderThanDate) settings->ID = 0; - if (args->SetCurrentSessionDateToAll || (args->SetCurrentSessionDateWhenMissingDate && settings->LastUsedDate.IsValid() == false)) + else if (args->DiscardWhenMissingDate && !is_valid) + settings->ID = 0; + else if (args->SetCurrentSessionDateToAll || (args->SetCurrentSessionDateWhenMissingDate && !is_valid)) settings->LastUsedDate = g.SessionDate; } } From 85593d0869ecc9c49c9b8aa83c0433275e982e67 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Jul 2026 22:06:43 +0200 Subject: [PATCH 15/19] Tables, Settings: make TableSettingsCreate() recycle existing unbound entry (might happen after a GC or anything clearing table->SettingsOffset. (#9460, #9108) --- imgui_tables.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 2fcce6cca..e1328fe59 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -3875,8 +3875,15 @@ static size_t TableSettingsCalcChunkSize(int columns_count) ImGuiTableSettings* ImGui::TableSettingsCreate(ImGuiID id, int columns_count) { ImGuiContext& g = *GImGui; - //ImGuiTableSettings* old_settings = TableSettingsFindByID(id); // Comment out sanity check to avoid unnecessary lookups. - //IM_ASSERT(old_settings == NULL || old_settings->ColumnsCountMax < columns_count); + if (ImGuiTableSettings* settings = TableSettingsFindByID(id)) + { + if (settings->ColumnsCountMax >= columns_count) + { + TableSettingsInit(settings, id, columns_count, settings->ColumnsCountMax); // Recycle + return settings; + } + settings->ID = 0; // Invalidate storage, we won't fit because of a count change + } ImGuiTableSettings* settings = g.SettingsTables.alloc_chunk(TableSettingsCalcChunkSize(columns_count)); TableSettingsInit(settings, id, columns_count, columns_count); return settings; @@ -4162,16 +4169,6 @@ static void* TableSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, int columns_count = 0; if (sscanf(name, "0x%08X,%d", &id, &columns_count) < 2) return NULL; - - if (ImGuiTableSettings* settings = ImGui::TableSettingsFindByID(id)) - { - if (settings->ColumnsCountMax >= columns_count) - { - TableSettingsInit(settings, id, columns_count, settings->ColumnsCountMax); // Recycle - return settings; - } - settings->ID = 0; // Invalidate storage, we won't fit because of a count change - } return ImGui::TableSettingsCreate(id, columns_count); } From 2c49da44be5d878e69968bc4032f6c5e6c6dbade Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Jul 2026 22:17:55 +0200 Subject: [PATCH 16/19] Settings: added a type name filter to CleanupIniSettings() / ImGuiSettingsCleanupArgs. (#9460) --- imgui.cpp | 6 ++++-- imgui_internal.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2e76a8e92..3a43223e1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15713,12 +15713,14 @@ void ImGui::CleanupIniSettings(ImGuiSettingsCleanupArgs* args) ImGuiContext& g = *GImGui; if (g.PlatformIO.Platform_SessionDate == 0) return; + ImGuiID type_hash_filter = args->TypeName ? ImHashStr(args->TypeName) : 0; ImGuiPackedDate discard_older_than_date_p = g.PlatformIO.Platform_SessionDate; discard_older_than_date_p.SubtractMonths(args->DiscardOlderThanMonths); args->_DiscardOlderThanDate = discard_older_than_date_p.Unpack(); for (ImGuiSettingsHandler& handler : g.SettingsHandlers) - if (handler.CleanupFn != NULL) - handler.CleanupFn(&g, &handler, args); + if (type_hash_filter == 0 || handler.TypeHash == type_hash_filter) + if (handler.CleanupFn != NULL) + handler.CleanupFn(&g, &handler, args); } void ImGui::LoadIniSettingsFromDisk(const char* ini_filename) diff --git a/imgui_internal.h b/imgui_internal.h index c9ee4cbba..33f3ad756 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2048,6 +2048,7 @@ struct ImGuiWindowSettings struct ImGuiSettingsCleanupArgs { + const char* TypeName = NULL; // Set to restrict cleanup to a given .ini type, e.g. "Window", "Table". Otherwise every types supporting Cleanup are supported. int DiscardOlderThanMonths = 0; // Enable to discard entries older than XX months. bool DiscardWhenMissingDate = false; // Enable to discard entries missing a date. bool SetCurrentSessionDateToAll = false; // Enable to write current SessionDate to all supporting entries. // Let us know in #9460 if you use this. From 112d6d9eabe3995e0cfa0a093e287c68f865d3f1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Jul 2026 22:30:15 +0200 Subject: [PATCH 17/19] Settings: added a type name filter to CleanupIniSettings() / ImGuiSettingsCleanupArgs. Amends. (#9460) Request hash because storing const char* strings in struct is not entirely zen. Amend 2c49da4. --- imgui.cpp | 3 +-- imgui_internal.h | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3a43223e1..43409848e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15713,12 +15713,11 @@ void ImGui::CleanupIniSettings(ImGuiSettingsCleanupArgs* args) ImGuiContext& g = *GImGui; if (g.PlatformIO.Platform_SessionDate == 0) return; - ImGuiID type_hash_filter = args->TypeName ? ImHashStr(args->TypeName) : 0; ImGuiPackedDate discard_older_than_date_p = g.PlatformIO.Platform_SessionDate; discard_older_than_date_p.SubtractMonths(args->DiscardOlderThanMonths); args->_DiscardOlderThanDate = discard_older_than_date_p.Unpack(); for (ImGuiSettingsHandler& handler : g.SettingsHandlers) - if (type_hash_filter == 0 || handler.TypeHash == type_hash_filter) + if (args->TypeHashFilter == 0 || handler.TypeHash == args->TypeHashFilter) if (handler.CleanupFn != NULL) handler.CleanupFn(&g, &handler, args); } diff --git a/imgui_internal.h b/imgui_internal.h index 33f3ad756..a4be1621a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2048,7 +2048,7 @@ struct ImGuiWindowSettings struct ImGuiSettingsCleanupArgs { - const char* TypeName = NULL; // Set to restrict cleanup to a given .ini type, e.g. "Window", "Table". Otherwise every types supporting Cleanup are supported. + ImGuiID TypeHashFilter = 0; // Set to restrict cleanup to a given .ini type, e.g. == ImHashStr("Window"), ImHashStr("Table"). Otherwise every types supporting Cleanup will be affected. int DiscardOlderThanMonths = 0; // Enable to discard entries older than XX months. bool DiscardWhenMissingDate = false; // Enable to discard entries missing a date. bool SetCurrentSessionDateToAll = false; // Enable to write current SessionDate to all supporting entries. // Let us know in #9460 if you use this. From f903a7e8e23f2d80fbb5198e9e049632a28d798f Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Jul 2026 22:52:47 +0200 Subject: [PATCH 18/19] Settings: fixed Windows not honoring DiscardWhenMissingDate. (#9460) --- imgui.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 43409848e..5efb3a6e2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15904,9 +15904,10 @@ static void WindowSettingsHandler_Cleanup(ImGuiContext* ctx, ImGuiSettingsHandle ImGuiContext& g = *ctx; for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) { - if (args->_DiscardOlderThanDate != 0 && settings->LastUsedDate.Unpack() < args->_DiscardOlderThanDate) + const bool is_valid = settings->LastUsedDate.IsValid(); + if ((args->_DiscardOlderThanDate != 0 && settings->LastUsedDate.Unpack() < args->_DiscardOlderThanDate) || (args->DiscardWhenMissingDate && !is_valid)) settings->WantDelete = true; - if (args->SetCurrentSessionDateToAll || (args->SetCurrentSessionDateWhenMissingDate && settings->LastUsedDate.IsValid() == false)) + if (args->SetCurrentSessionDateToAll || (args->SetCurrentSessionDateWhenMissingDate && !is_valid)) settings->LastUsedDate = g.SessionDate; } } From 68fce9f3bddb6c3e015a33150796847190f50ac6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 8 Jul 2026 15:02:56 +0200 Subject: [PATCH 19/19] Settings: added DiscardAll option to CleanupIniSettings() / ImGuiSettingsCleanupArgs. (#9460) + Demo: tweak for scaling. --- imgui.cpp | 16 +++++++++++----- imgui_demo.cpp | 5 +++-- imgui_internal.h | 1 + 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5efb3a6e2..2954bd6eb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15711,11 +15711,17 @@ void ImGui::ClearIniSettings() void ImGui::CleanupIniSettings(ImGuiSettingsCleanupArgs* args) { ImGuiContext& g = *GImGui; - if (g.PlatformIO.Platform_SessionDate == 0) - return; - ImGuiPackedDate discard_older_than_date_p = g.PlatformIO.Platform_SessionDate; - discard_older_than_date_p.SubtractMonths(args->DiscardOlderThanMonths); - args->_DiscardOlderThanDate = discard_older_than_date_p.Unpack(); + if (args->DiscardAll) + for (ImGuiSettingsHandler& handler : g.SettingsHandlers) + if (args->TypeHashFilter == 0 || handler.TypeHash == args->TypeHashFilter) + if (handler.ClearAllFn != NULL) + handler.ClearAllFn(&g, &handler); + if (g.PlatformIO.Platform_SessionDate != 0 && args->DiscardOlderThanMonths != 0) + { + ImGuiPackedDate discard_older_than_date_p = g.PlatformIO.Platform_SessionDate; + discard_older_than_date_p.SubtractMonths(args->DiscardOlderThanMonths); + args->_DiscardOlderThanDate = discard_older_than_date_p.Unpack(); + } for (ImGuiSettingsHandler& handler : g.SettingsHandlers) if (args->TypeHashFilter == 0 || handler.TypeHash == args->TypeHashFilter) if (handler.CleanupFn != NULL) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b1a5d7498..b1a326570 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -5092,7 +5092,8 @@ static void DemoWindowLayout() // If you want to create your own time line for a real application you may be better off manipulating // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets // yourself. You may also want to use the lower-level ImDrawList API. - int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); + const int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3); + const float base_w = ImGui::GetFontSize() * 3; for (int n = 0; n < num_buttons; n++) { if (n > 0) ImGui::SameLine(); @@ -5104,7 +5105,7 @@ static void DemoWindowLayout() ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f)); - ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f)); + ImGui::Button(label, ImVec2(base_w + sinf((float)(line + n)) * base_w * 0.5f, 0.0f)); ImGui::PopStyleColor(3); ImGui::PopID(); } diff --git a/imgui_internal.h b/imgui_internal.h index a4be1621a..23b8ec0fd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2051,6 +2051,7 @@ struct ImGuiSettingsCleanupArgs ImGuiID TypeHashFilter = 0; // Set to restrict cleanup to a given .ini type, e.g. == ImHashStr("Window"), ImHashStr("Table"). Otherwise every types supporting Cleanup will be affected. int DiscardOlderThanMonths = 0; // Enable to discard entries older than XX months. bool DiscardWhenMissingDate = false; // Enable to discard entries missing a date. + bool DiscardAll = false; // Enable to discard all entries = same as calling ClearIniSettings() except it may be filtered. bool SetCurrentSessionDateToAll = false; // Enable to write current SessionDate to all supporting entries. // Let us know in #9460 if you use this. bool SetCurrentSessionDateWhenMissingDate = false; // Enable to write current SessionDate to all supporting entries missing a date. // Let us know in #9460 if you use this. int _DiscardOlderThanDate = 0; // [Internal]