From 734c6af187f80472100a940f59bf505ef588acb8 Mon Sep 17 00:00:00 2001 From: imkzh Date: Thu, 12 Jan 2023 18:42:38 +0800 Subject: [PATCH 1/8] Backends: SDL2: Implement SetPlatformImeDataFn. (#6071, #1953) --- backends/imgui_impl_sdl2.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index cff755bc..fe285ed6 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -84,6 +84,7 @@ #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0 #endif #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) +#define SDL_HAS_SET_TEXT_INPUT_RECT SDL_VERSION_ATLEAST(2,0,0) // SDL Data struct ImGui_ImplSDL2_Data @@ -336,6 +337,27 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) return false; } +#if SDL_HAS_SET_TEXT_INPUT_RECT +static void ImGui_ImplSDL2_SetPlatformImeData(ImGuiViewport* viewport, ImGuiPlatformImeData* data) +{ + (void)viewport; + if (data->WantVisible) + { + SDL_Rect r; + r.x = (int)data->InputPos.x; + r.y = (int)data->InputPos.y; + r.w = 1; + r.h = (int)data->InputLineHeight; + SDL_SetTextInputRect(&r); + SDL_StartTextInput(); + } + else + { + SDL_StopTextInput(); + } +} +#endif + static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer) { ImGuiIO& io = ImGui::GetIO(); @@ -367,6 +389,10 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer) io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText; io.ClipboardUserData = nullptr; +#if SDL_HAS_SET_TEXT_INPUT_RECT + io.SetPlatformImeDataFn = ImGui_ImplSDL2_SetPlatformImeData; +#endif + // Load mouse cursors bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); From fac19e18834fd993194ffeefbbb8a961a1bb18f9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Feb 2023 18:55:10 +0100 Subject: [PATCH 2/8] Backends: SDL2:+SDL3 Implement SetPlatformImeDataFn (amends). (#6071, #1953) + fix SDL3 setting PlatformHandleRaw. (#6146) --- backends/imgui_impl_sdl2.cpp | 55 +++++++++++----------- backends/imgui_impl_sdl2.h | 3 +- backends/imgui_impl_sdl3.cpp | 27 +++++++++-- backends/imgui_impl_sdl3.h | 2 + docs/CHANGELOG.txt | 3 ++ examples/example_sdl2_directx11/main.cpp | 5 ++ examples/example_sdl2_metal/main.mm | 3 ++ examples/example_sdl2_opengl2/main.cpp | 5 ++ examples/example_sdl2_opengl3/main.cpp | 5 ++ examples/example_sdl2_sdlrenderer/main.cpp | 5 ++ examples/example_sdl2_vulkan/main.cpp | 5 ++ examples/example_sdl3_opengl3/main.cpp | 3 ++ examples/imgui_examples.sln | 10 ---- imgui.cpp | 8 +++- 14 files changed, 95 insertions(+), 44 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index fe285ed6..35eaabeb 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -8,8 +8,7 @@ // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. -// Missing features: -// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME. +// [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -18,6 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2023-02-07: Implement IME handler (io.SetPlatformImeDataFn will call SDL_SetTextInputRect()/SDL_StartTextInput()). // 2023-02-07: *BREAKING CHANGE* Renamed this backend file from imgui_impl_sdl.cpp/.h to imgui_impl_sdl2.cpp/.h in prevision for the future release of SDL3. // 2023-02-02: Avoid calling SDL_SetCursor() when cursor has not changed, as the function is surprisingly costly on Mac with latest SDL (may be fixed in next SDL version). // 2023-02-02: Added support for SDL 2.0.18+ preciseX/preciseY mouse wheel data for smooth scrolling + Scaling X value on Emscripten (bug?). (#4019, #6096) @@ -84,7 +84,6 @@ #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0 #endif #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) -#define SDL_HAS_SET_TEXT_INPUT_RECT SDL_VERSION_ATLEAST(2,0,0) // SDL Data struct ImGui_ImplSDL2_Data @@ -127,6 +126,25 @@ static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text) SDL_SetClipboardText(text); } +// Note: native IME will only display if user calls SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1") _before_ SDL_CreateWindow(). +static void ImGui_ImplSDL2_SetPlatformImeData(ImGuiViewport*, ImGuiPlatformImeData* data) +{ + if (data->WantVisible) + { + SDL_Rect r; + r.x = (int)data->InputPos.x; + r.y = (int)data->InputPos.y; + r.w = 1; + r.h = (int)data->InputLineHeight; + SDL_SetTextInputRect(&r); + SDL_StartTextInput(); + } + else + { + SDL_StopTextInput(); + } +} + static ImGuiKey ImGui_ImplSDL2_KeycodeToImGuiKey(int keycode) { switch (keycode) @@ -337,27 +355,6 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) return false; } -#if SDL_HAS_SET_TEXT_INPUT_RECT -static void ImGui_ImplSDL2_SetPlatformImeData(ImGuiViewport* viewport, ImGuiPlatformImeData* data) -{ - (void)viewport; - if (data->WantVisible) - { - SDL_Rect r; - r.x = (int)data->InputPos.x; - r.y = (int)data->InputPos.y; - r.w = 1; - r.h = (int)data->InputLineHeight; - SDL_SetTextInputRect(&r); - SDL_StartTextInput(); - } - else - { - SDL_StopTextInput(); - } -} -#endif - static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer) { ImGuiIO& io = ImGui::GetIO(); @@ -388,10 +385,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer) io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText; io.ClipboardUserData = nullptr; - -#if SDL_HAS_SET_TEXT_INPUT_RECT io.SetPlatformImeDataFn = ImGui_ImplSDL2_SetPlatformImeData; -#endif // Load mouse cursors bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); @@ -428,6 +422,13 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer) SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); #endif + // From 2.0.18: Enable native IME. + // IMPORTANT: This is used at the time of SDL_CreateWindow() so this will only affects secondary windows, if any. + // For the main window to be affected, your application needs to call this manually before calling SDL_CreateWindow(). +#ifdef SDL_HINT_IME_SHOW_UI + SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); +#endif + // From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710) #ifdef SDL_HINT_MOUSE_AUTO_CAPTURE SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0"); diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index dc18c2cc..68da36a8 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -7,8 +7,7 @@ // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. -// Missing features: -// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME. +// [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 6e8abee8..42f67de3 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -8,6 +8,8 @@ // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// Missing features: +// [x] Platform: Basic IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -75,6 +77,24 @@ static void ImGui_ImplSDL3_SetClipboardText(void*, const char* text) SDL_SetClipboardText(text); } +static void ImGui_ImplSDL3_SetPlatformImeData(ImGuiViewport*, ImGuiPlatformImeData* data) +{ + if (data->WantVisible) + { + SDL_Rect r; + r.x = (int)data->InputPos.x; + r.y = (int)data->InputPos.y; + r.w = 1; + r.h = (int)data->InputLineHeight; + SDL_SetTextInputRect(&r); + SDL_StartTextInput(); + } + else + { + SDL_StopTextInput(); + } +} + static ImGuiKey ImGui_ImplSDL3_KeycodeToImGuiKey(int keycode) { switch (keycode) @@ -310,6 +330,7 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer) io.SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText; io.ClipboardUserData = nullptr; + io.SetPlatformImeDataFn = ImGui_ImplSDL3_SetPlatformImeData; // Load mouse cursors bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); @@ -327,11 +348,11 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer) ImGuiViewport* main_viewport = ImGui::GetMainViewport(); main_viewport->PlatformHandleRaw = nullptr; SDL_SysWMinfo info; - if (SDL_GetWindowWMInfo(window, &info, SDL_SYSWM_CURRENT_VERSION)) + if (SDL_GetWindowWMInfo(window, &info, SDL_SYSWM_CURRENT_VERSION) == 0) { -#if defined(SDL_VIDEO_DRIVER_WINDOWS) +#if defined(SDL_ENABLE_SYSWM_WINDOWS) main_viewport->PlatformHandleRaw = (void*)info.info.win.window; -#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA) +#elif defined(__APPLE__) && defined(SDL_ENABLE_SYSWM_COCOA) main_viewport->PlatformHandleRaw = (void*)info.info.cocoa.window; #endif } diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index f76ca948..fd7e49c2 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -8,6 +8,8 @@ // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// Missing features: +// [x] Platform: Basic IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 66324647..45286e54 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -98,6 +98,9 @@ All changes: for smooth scrolling as reported by SDL. (#4019, #6096) - Backends: SDL2: Avoid calling SDL_SetCursor() when cursor has not changed, as the function is surprisingly costly on Mac with latest SDL (may be fixed in next SDL version). (#6113) +- Backends: SDL2: Implement IME handler to call SDL_SetTextInputRect()/SDL_StartTextInput(). + It will only works with SDL 2.0.18+ if your code calls 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1")' + prior to calling SDL_CreateWindow(). Updated all examples accordingly. (#6071, #1953) - Backends: SDL3: Added experimental imgui_impl_sdl3.cpp backend. (#6146) [@dovker, @ocornut] SDL 3.0.0 has not yet been released, so it is possible that its specs/api will change before release. This backend is provided as a convenience for early adopters etc. We don't recommend diff --git a/examples/example_sdl2_directx11/main.cpp b/examples/example_sdl2_directx11/main.cpp index 58711e3e..1aedea96 100644 --- a/examples/example_sdl2_directx11/main.cpp +++ b/examples/example_sdl2_directx11/main.cpp @@ -35,6 +35,11 @@ int main(int, char**) return -1; } + // From 2.0.18: Enable native IME. +#ifdef SDL_HINT_IME_SHOW_UI + SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); +#endif + // Setup window SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+DirectX11 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); diff --git a/examples/example_sdl2_metal/main.mm b/examples/example_sdl2_metal/main.mm index 01cf5fb7..5b59d779 100644 --- a/examples/example_sdl2_metal/main.mm +++ b/examples/example_sdl2_metal/main.mm @@ -53,6 +53,9 @@ int main(int, char**) // Inform SDL that we will be using metal for rendering. Without this hint initialization of metal renderer may fail. SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal"); + // Enable native IME. + SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL+Metal example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); if (window == NULL) { diff --git a/examples/example_sdl2_opengl2/main.cpp b/examples/example_sdl2_opengl2/main.cpp index 2c3ad748..505b05fc 100644 --- a/examples/example_sdl2_opengl2/main.cpp +++ b/examples/example_sdl2_opengl2/main.cpp @@ -24,6 +24,11 @@ int main(int, char**) return -1; } + // From 2.0.18: Enable native IME. +#ifdef SDL_HINT_IME_SHOW_UI + SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); +#endif + // Setup window SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); diff --git a/examples/example_sdl2_opengl3/main.cpp b/examples/example_sdl2_opengl3/main.cpp index 3e63f7a2..95b720e1 100644 --- a/examples/example_sdl2_opengl3/main.cpp +++ b/examples/example_sdl2_opengl3/main.cpp @@ -53,6 +53,11 @@ int main(int, char**) SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #endif + // From 2.0.18: Enable native IME. +#ifdef SDL_HINT_IME_SHOW_UI + SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); +#endif + // Create window with graphics context SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); diff --git a/examples/example_sdl2_sdlrenderer/main.cpp b/examples/example_sdl2_sdlrenderer/main.cpp index 0812b76d..2468b829 100644 --- a/examples/example_sdl2_sdlrenderer/main.cpp +++ b/examples/example_sdl2_sdlrenderer/main.cpp @@ -27,6 +27,11 @@ int main(int, char**) return -1; } + // From 2.0.18: Enable native IME. +#ifdef SDL_HINT_IME_SHOW_UI + SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); +#endif + // Create window with SDL_Renderer graphics context SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+SDL_Renderer example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index c4130c15..31bf3f21 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -350,6 +350,11 @@ int main(int, char**) return -1; } + // From 2.0.18: Enable native IME. +#ifdef SDL_HINT_IME_SHOW_UI + SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); +#endif + // Create window with Vulkan graphics context SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+Vulkan example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); diff --git a/examples/example_sdl3_opengl3/main.cpp b/examples/example_sdl3_opengl3/main.cpp index 613228b0..b43f6b41 100644 --- a/examples/example_sdl3_opengl3/main.cpp +++ b/examples/example_sdl3_opengl3/main.cpp @@ -53,6 +53,9 @@ int main(int, char**) SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #endif + // Enable native IME. + SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); + // Create window with graphics context SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); diff --git a/examples/imgui_examples.sln b/examples/imgui_examples.sln index fdaf0692..9b442b27 100644 --- a/examples/imgui_examples.sln +++ b/examples/imgui_examples.sln @@ -27,8 +27,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl2_sdlrenderer", EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl2_vulkan", "example_sdl2_vulkan\example_sdl2_vulkan.vcxproj", "{BAE3D0B5-9695-4EB1-AD0F-75890EB4A3B3}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_opengl3", "example_sdl3_opengl3\example_sdl3_opengl3.vcxproj", "{84AAA301-84FE-428B-9E3E-817BC8123C0C}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -133,14 +131,6 @@ Global {BAE3D0B5-9695-4EB1-AD0F-75890EB4A3B3}.Release|Win32.Build.0 = Release|Win32 {BAE3D0B5-9695-4EB1-AD0F-75890EB4A3B3}.Release|x64.ActiveCfg = Release|x64 {BAE3D0B5-9695-4EB1-AD0F-75890EB4A3B3}.Release|x64.Build.0 = Release|x64 - {84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|Win32.ActiveCfg = Debug|Win32 - {84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|Win32.Build.0 = Debug|Win32 - {84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|x64.ActiveCfg = Debug|x64 - {84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|x64.Build.0 = Debug|x64 - {84AAA301-84FE-428B-9E3E-817BC8123C0C}.Release|Win32.ActiveCfg = Release|Win32 - {84AAA301-84FE-428B-9E3E-817BC8123C0C}.Release|Win32.Build.0 = Release|Win32 - {84AAA301-84FE-428B-9E3E-817BC8123C0C}.Release|x64.ActiveCfg = Release|x64 - {84AAA301-84FE-428B-9E3E-817BC8123C0C}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/imgui.cpp b/imgui.cpp index a4fe84a1..d635cf50 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4819,8 +4819,12 @@ void ImGui::EndFrame() ErrorCheckEndFrameSanityChecks(); // Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) - if (g.IO.SetPlatformImeDataFn && memcmp(&g.PlatformImeData, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0) - g.IO.SetPlatformImeDataFn(GetMainViewport(), &g.PlatformImeData); + ImGuiPlatformImeData* ime_data = &g.PlatformImeData; + if (g.IO.SetPlatformImeDataFn && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0) + { + IMGUI_DEBUG_LOG_IO("Calling io.SetPlatformImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y); + g.IO.SetPlatformImeDataFn(GetMainViewport(), ime_data); + } // Hide implicit/fallback "Debug" window if it hasn't been used g.WithinFrameScopeWithImplicitWindow = false; From 85395b76b08111961aa6e0ff026fd5152d48aa15 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 7 Feb 2023 20:17:18 +0100 Subject: [PATCH 3/8] CI: Update versions. Backends: GLFW: Warning fix under Linux. --- .github/workflows/build.yml | 18 +++++++++--------- .github/workflows/static-analysis.yml | 4 ++-- backends/imgui_impl_glfw.cpp | 2 ++ 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bd0c4a56..17aabecb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,7 @@ jobs: VS_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\ MSBUILD_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\ steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install Dependencies shell: powershell @@ -207,9 +207,9 @@ jobs: run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx12/example_win32_directx12.vcxproj /p:Platform=x64 /p:Configuration=Release' Linux: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install Dependencies run: | @@ -402,7 +402,7 @@ jobs: MacOS: runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install Dependencies run: | @@ -462,7 +462,7 @@ jobs: iOS: runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build example_apple_metal run: | @@ -470,9 +470,9 @@ jobs: xcodebuild -project examples/example_apple_metal/example_apple_metal.xcodeproj -target example_apple_metal_ios CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO Emscripten: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install Dependencies run: | @@ -497,9 +497,9 @@ jobs: make -C examples/example_emscripten_wgpu Android: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build example_android_opengl3 run: | diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 362cd9a2..caa9b3a4 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -10,9 +10,9 @@ on: jobs: PVS-Studio: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 with: fetch-depth: 1 diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 41d3a611..f0e70a6d 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -556,6 +556,8 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw main_viewport->PlatformHandleRaw = glfwGetWin32Window(bd->Window); #elif defined(__APPLE__) main_viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(bd->Window); +#else + IM_UNUSED(main_viewport); #endif bd->ClientApi = client_api; From 99c0bd65df8eb60758b9fe4ba9f32278a628ca12 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 10 Feb 2023 12:16:23 +0100 Subject: [PATCH 4/8] Added SeparatorText() widget. (#1643) --- docs/CHANGELOG.txt | 3 ++ imgui.cpp | 7 ++++ imgui.h | 9 ++++- imgui_demo.cpp | 74 ++++++++++++++++++++++++++-------------- imgui_internal.h | 1 + imgui_tables.cpp | 4 +-- imgui_widgets.cpp | 84 +++++++++++++++++++++++++++++++++++++++++----- 7 files changed, 145 insertions(+), 37 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 45286e54..0d10ea84 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -64,6 +64,9 @@ All changes: to find a way to detect this and set io.ConfigMacOSXBehaviors manually (if you know a way let us know!), or offer the "OSX-style behavior" option to their user. - Window: Avoid rendering shapes for hidden resize grips. +- SeparatorText(): Added SeparatorText() widget. (#1643) [@phed, @ocornut] + - Added to style: float SeparatorTextBorderSize. + - Added to style: ImVec2 SeparatorTextAlign, SeparatorTextPadding. - Tables: Raised max Columns count from 64 to 512. (#6094, #5305, #4876, #3572) The previous limit was due to using 64-bit integers but we moved to bits-array and tweaked the system enough to ensure no performance loss. diff --git a/imgui.cpp b/imgui.cpp index d635cf50..440ff199 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1119,6 +1119,9 @@ ImGuiStyle::ImGuiStyle() ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. 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. + SeparatorTextBorderSize = 3.0f; // Thickkness of border in SeparatorText() + SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). + SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows. MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. @@ -1156,6 +1159,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor); TabRounding = ImFloor(TabRounding * scale_factor); TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX; + SeparatorTextPadding = ImFloor(SeparatorTextPadding * scale_factor); DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); @@ -3024,6 +3028,9 @@ static const ImGuiStyleVarInfo GStyleVarInfo[] = { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign + { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextBorderSize) },// ImGuiStyleVar_SeparatorTextBorderSize + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign + { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding }; static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx) diff --git a/imgui.h b/imgui.h index 3736a461..b6b583de 100644 --- a/imgui.h +++ b/imgui.h @@ -23,7 +23,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345') #define IMGUI_VERSION "1.89.3 WIP" -#define IMGUI_VERSION_NUM 18927 +#define IMGUI_VERSION_NUM 18928 #define IMGUI_HAS_TABLE /* @@ -493,6 +493,7 @@ namespace ImGui IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2); IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text() IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); + IMGUI_API void SeparatorText(const char* label); // currently: formatted text with an horizontal line // Widgets: Main // - Most widgets return true when the value has been changed or when pressed/selected @@ -1608,6 +1609,9 @@ enum ImGuiStyleVar_ ImGuiStyleVar_TabRounding, // float TabRounding ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign + ImGuiStyleVar_SeparatorTextBorderSize,// float SeparatorTextBorderSize + ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign + ImGuiStyleVar_SeparatorTextPadding,// ImVec2 SeparatorTextPadding ImGuiStyleVar_COUNT }; @@ -1862,6 +1866,9 @@ struct ImGuiStyle ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. 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 SeparatorTextBorderSize; // Thickkness of border in SeparatorText() + ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). + ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly! float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 1c6de1ce..2859c947 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -426,6 +426,7 @@ void ImGui::ShowDemoWindow(bool* p_open) if (ImGui::TreeNode("Configuration##2")) { + ImGui::SeparatorText("General"); ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); ImGui::SameLine(); HelpMarker("Enable keyboard controls."); ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); @@ -448,6 +449,10 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility."); ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue); ImGui::SameLine(); HelpMarker("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."); + ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); + ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); + + ImGui::SeparatorText("Widgets"); ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive); @@ -458,11 +463,9 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback."); ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors); - ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); - ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); ImGui::Text("Also see Style->Rendering for rendering options."); ImGui::TreePop(); - ImGui::Separator(); + ImGui::Spacing(); } IMGUI_DEMO_MARKER("Configuration/Backend Flags"); @@ -480,7 +483,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &backend_flags, ImGuiBackendFlags_HasSetMousePos); ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &backend_flags, ImGuiBackendFlags_RendererHasVtxOffset); ImGui::TreePop(); - ImGui::Separator(); + ImGui::Spacing(); } IMGUI_DEMO_MARKER("Configuration/Style"); @@ -489,7 +492,7 @@ void ImGui::ShowDemoWindow(bool* p_open) HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); ImGui::ShowStyleEditor(); ImGui::TreePop(); - ImGui::Separator(); + ImGui::Spacing(); } IMGUI_DEMO_MARKER("Configuration/Capture, Logging"); @@ -557,6 +560,8 @@ static void ShowDemoWindowWidgets() IMGUI_DEMO_MARKER("Widgets/Basic"); if (ImGui::TreeNode("Basic")) { + ImGui::SeparatorText("General"); + IMGUI_DEMO_MARKER("Widgets/Basic/Button"); static int clicked = 0; if (ImGui::Button("Button")) @@ -646,6 +651,8 @@ static void ShowDemoWindowWidgets() ImGui::LabelText("label", "Value"); + ImGui::SeparatorText("Inputs"); + { // To wire InputText() with std::string or any other custom string type, // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. @@ -688,6 +695,8 @@ static void ShowDemoWindowWidgets() ImGui::InputFloat3("input float3", vec4a); } + ImGui::SeparatorText("Drags"); + { IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat"); static int i1 = 50, i2 = 42; @@ -704,6 +713,8 @@ static void ShowDemoWindowWidgets() ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); } + ImGui::SeparatorText("Sliders"); + { IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat"); static int i1 = 0; @@ -730,6 +741,8 @@ static void ShowDemoWindowWidgets() ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); } + ImGui::SeparatorText("Selectors/Pickers"); + { IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4"); static float col1[3] = { 1.0f, 0.0f, 0.2f }; @@ -1690,7 +1703,7 @@ static void ShowDemoWindowWidgets() } // Use functions to generate output - // FIXME: This is rather awkward because current plot API only pass in indices. + // FIXME: This is actually VERY awkward because current plot API only pass in indices. // We probably want an API passing floats and user provide sample rate/count. struct Funcs { @@ -1698,7 +1711,7 @@ static void ShowDemoWindowWidgets() static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } }; static int func_type = 0, display_count = 70; - ImGui::Separator(); + ImGui::SeparatorText("Functions"); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::SameLine(); @@ -1741,6 +1754,7 @@ static void ShowDemoWindowWidgets() static bool drag_and_drop = true; static bool options_menu = true; static bool hdr = false; + ImGui::SeparatorText("Options"); ImGui::Checkbox("With Alpha Preview", &alpha_preview); ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); ImGui::Checkbox("With Drag and Drop", &drag_and_drop); @@ -1749,6 +1763,7 @@ static void ShowDemoWindowWidgets() ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions); IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit"); + ImGui::SeparatorText("Inline color editor"); ImGui::Text("Color widget:"); ImGui::SameLine(); HelpMarker( "Click on the color square to open a color picker.\n" @@ -1846,7 +1861,7 @@ static void ShowDemoWindowWidgets() ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker"); - ImGui::Text("Color picker:"); + ImGui::SeparatorText("Color picker"); static bool alpha = true; static bool alpha_bar = true; static bool side_preview = true; @@ -2017,7 +2032,7 @@ static void ShowDemoWindowWidgets() const float drag_speed = 0.2f; static bool drag_clamp = false; IMGUI_DEMO_MARKER("Widgets/Data Types/Drags"); - ImGui::Text("Drags:"); + ImGui::SeparatorText("Drags"); ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); ImGui::SameLine(); HelpMarker( "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n" @@ -2037,7 +2052,7 @@ static void ShowDemoWindowWidgets() ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic); IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders"); - ImGui::Text("Sliders"); + ImGui::SeparatorText("Sliders"); ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); @@ -2062,7 +2077,7 @@ static void ShowDemoWindowWidgets() ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic); ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); - ImGui::Text("Sliders (reverse)"); + ImGui::SeparatorText("Sliders (reverse)"); ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d"); ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); @@ -2072,7 +2087,7 @@ static void ShowDemoWindowWidgets() IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs"); static bool inputs_step = true; - ImGui::Text("Inputs"); + ImGui::SeparatorText("Inputs"); ImGui::Checkbox("Show step buttons", &inputs_step); ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d"); ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u"); @@ -2096,22 +2111,23 @@ static void ShowDemoWindowWidgets() static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; static int vec4i[4] = { 1, 5, 100, 255 }; + ImGui::SeparatorText("2-wide"); ImGui::InputFloat2("input float2", vec4f); ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); ImGui::InputInt2("input int2", vec4i); ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); ImGui::SliderInt2("slider int2", vec4i, 0, 255); - ImGui::Spacing(); + ImGui::SeparatorText("3-wide"); ImGui::InputFloat3("input float3", vec4f); ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); ImGui::InputInt3("input int3", vec4i); ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); ImGui::SliderInt3("slider int3", vec4i, 0, 255); - ImGui::Spacing(); + ImGui::SeparatorText("4-wide"); ImGui::InputFloat4("input float4", vec4f); ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); @@ -2528,6 +2544,8 @@ static void ShowDemoWindowLayout() IMGUI_DEMO_MARKER("Layout/Child windows"); if (ImGui::TreeNode("Child windows")) { + ImGui::SeparatorText("Child windows"); + HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window."); static bool disable_mouse_wheel = false; static bool disable_menu = false; @@ -2580,7 +2598,7 @@ static void ShowDemoWindowLayout() ImGui::PopStyleVar(); } - ImGui::Separator(); + ImGui::SeparatorText("Misc/Advanced"); // Demonstrate a few extra things // - Changing ImGuiCol_ChildBg (which is transparent black in default styles) @@ -3344,8 +3362,7 @@ static void ShowDemoWindowPopups() ImGui::TextUnformatted(selected_fish == -1 ? "" : names[selected_fish]); if (ImGui::BeginPopup("my_select_popup")) { - ImGui::Text("Aquarium"); - ImGui::Separator(); + ImGui::SeparatorText("Aquarium"); for (int i = 0; i < IM_ARRAYSIZE(names); i++) if (ImGui::Selectable(names[i])) selected_fish = i; @@ -3522,7 +3539,7 @@ static void ShowDemoWindowPopups() if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n"); + ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!"); ImGui::Separator(); //static int unused_i = 0; @@ -6146,7 +6163,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { if (ImGui::BeginTabItem("Sizes")) { - ImGui::Text("Main"); + ImGui::SeparatorText("Main"); ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f"); @@ -6156,13 +6173,15 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); - ImGui::Text("Borders"); + + ImGui::SeparatorText("Borders"); ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); - ImGui::Text("Rounding"); + + ImGui::SeparatorText("Rounding"); ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); @@ -6170,7 +6189,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); - ImGui::Text("Alignment"); + + ImGui::SeparatorText("Widgets"); ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); int window_menu_button_position = style.WindowMenuButtonPosition + 1; if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) @@ -6180,10 +6200,13 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); - ImGui::Text("Safe Area Padding"); - ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); - ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); + ImGui::SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f"); + ImGui::SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%0.f"); ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); + + ImGui::SeparatorText("Misc"); + ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); ImGui::EndTabItem(); } @@ -6493,6 +6516,7 @@ static void ShowExampleMenuFile() IM_ASSERT(0); } if (ImGui::MenuItem("Checked", NULL, true)) {} + ImGui::Separator(); if (ImGui::MenuItem("Quit", "Alt+F4")) {} } diff --git a/imgui_internal.h b/imgui_internal.h index 9c8d02df..5c9fa77e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3078,6 +3078,7 @@ namespace ImGui IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0); IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags); + IMGUI_API void SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_width); IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value); IMGUI_API bool CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 06a21ed8..e2932474 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1144,12 +1144,12 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) EndPopup(); } - // [Part 13] Sanitize and build sort specs before we have a change to use them for display. + // [Part 12] Sanitize and build sort specs before we have a change to use them for display. // This path will only be exercised when sort specs are modified before header rows (e.g. init or visibility change) if (table->IsSortSpecsDirty && (table->Flags & ImGuiTableFlags_Sortable)) TableSortSpecsBuild(table); - // [Part 14] Setup inner window decoration size (for scrolling / nav tracking to properly take account of frozen rows/columns) + // [Part 13] Setup inner window decoration size (for scrolling / nav tracking to properly take account of frozen rows/columns) if (table->FreezeColumnsRequest > 0) table->InnerWindow->DecoInnerSizeX1 = table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsRequest - 1]].MaxX - table->OuterRect.Min.x; if (table->FreezeRowsRequest > 0) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f60845bf..a8db5c93 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1384,6 +1384,7 @@ void ImGui::AlignTextToFramePadding() } // Horizontal/vertical separating line +// FIXME: Surprisingly, this seemingly simple widget is adjacent to MANY different legacy/tricky layout issues. void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) { ImGuiWindow* window = GetCurrentWindow(); @@ -1393,20 +1394,19 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) ImGuiContext& g = *GImGui; IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected - float thickness_draw = 1.0f; - float thickness_layout = 0.0f; + const float thickness = 1.0f; // Cannot use g.Style.SeparatorTextSize yet for various reasons. if (flags & ImGuiSeparatorFlags_Vertical) { - // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout. + // Vertical separator, for menu bars (use current line height). float y1 = window->DC.CursorPos.y; float y2 = window->DC.CursorPos.y + window->DC.CurrLineSize.y; - const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness_draw, y2)); - ItemSize(ImVec2(thickness_layout, 0.0f)); + const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness, y2)); + ItemSize(ImVec2(thickness, 0.0f)); if (!ItemAdd(bb, 0)) return; // Draw - window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator)); + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator)); if (g.LogEnabled) LogText(" |"); } @@ -1434,13 +1434,14 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) // We don't provide our width to the layout so that it doesn't get feed back into AutoFit // FIXME: This prevents ->CursorMaxPos based bounding box evaluation from working (e.g. TableEndCell) - const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness_draw)); - ItemSize(ImVec2(0.0f, thickness_layout)); + const float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change. + const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness)); + ItemSize(ImVec2(0.0f, thickness_for_layout)); const bool item_visible = ItemAdd(bb, 0); if (item_visible) { // Draw - window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Separator)); + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator)); if (g.LogEnabled) LogRenderedText(&bb.Min, "--------------------------------\n"); @@ -1466,6 +1467,71 @@ void ImGui::Separator() SeparatorEx(flags); } +void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiStyle& style = g.Style; + + const ImVec2 label_size = CalcTextSize(label, label_end, false); + const ImVec2 pos = window->DC.CursorPos; + const ImVec2 padding = style.SeparatorTextPadding; + + const float separator_thickness = style.SeparatorTextBorderSize; + const ImVec2 min_size(label_size.x + extra_w + padding.x * 2.0f, ImMax(label_size.y + padding.y * 2.0f, separator_thickness)); + const ImRect bb(pos, ImVec2(window->WorkRect.Max.x, pos.y + min_size.y)); + const float text_baseline_y = ImFloor((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.99999f); //ImMax(padding.y, ImFloor((style.SeparatorTextSize - label_size.y) * 0.5f)); + ItemSize(min_size, text_baseline_y); + if (!ItemAdd(bb, id)) + return; + + const float sep1_x1 = pos.x; + const float sep2_x2 = bb.Max.x; + const float seps_y = ImFloor((bb.Min.y + bb.Max.y) * 0.5f + 0.99999f); + + const float label_avail_w = ImMax(0.0f, sep2_x2 - sep1_x1 - padding.x * 2.0f); + const ImVec2 label_pos(pos.x + padding.x + ImMax(0.0f, (label_avail_w - label_size.x - extra_w) * style.SeparatorTextAlign.x), pos.y + text_baseline_y); // FIXME-ALIGN + + // This allows using SameLine() to position something in the 'extra_w' + window->DC.CursorPosPrevLine.x = label_pos.x + label_size.x; + + const ImU32 separator_col = GetColorU32(ImGuiCol_Separator); + if (label_size.x > 0.0f) + { + const float sep1_x2 = label_pos.x - style.ItemSpacing.x; + const float sep2_x1 = label_pos.x + label_size.x + extra_w + style.ItemSpacing.x; + if (sep1_x2 > sep1_x1 && separator_thickness > 0.0f) + window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep1_x2, seps_y), separator_col, separator_thickness); + if (sep2_x2 > sep2_x1 && separator_thickness > 0.0f) + window->DrawList->AddLine(ImVec2(sep2_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness); + if (g.LogEnabled) + LogSetNextTextDecoration("---", NULL); + RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, bb.Max.x, label, label_end, &label_size); + } + else + { + if (g.LogEnabled) + LogText("---"); + if (separator_thickness > 0.0f) + window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness); + } +} + +void ImGui::SeparatorText(const char* label) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + // The SeparatorText() vs SeparatorTextEx() distinction is designed to be considerate that we may want: + // - allow headers to be draggable items (would require a stable ID + a noticeable highlight) + // - this high-level entry point to allow formatting? (may require ID separate from formatted string) + // - because of this we probably can't turn 'const char* label' into 'const char* fmt, ...' + // Otherwise, we can decide that users wanting to drag this would layout a dedicated drag-item, + // and then we can turn this into a format function. + SeparatorTextEx(0, label, FindRenderedTextEnd(label), 0.0f); +} + // Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise. bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend, float hover_visibility_delay, ImU32 bg_col) { From 0b865136e3835f06eb1642cbdac573466c01fe0e Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 10 Feb 2023 15:33:33 +0100 Subject: [PATCH 5/8] Internals: Settings: Added FindWindowSettingsByName() (replacing old version by ID) FindWindowSettingsByWindow() + remove unnecessary FindOrCreateWindowSettings(). In 1 code path we do a redundant hash but this happens only once per window per session so we are ok. --- imgui.cpp | 32 ++++++++++++++++++++------------ imgui_internal.h | 4 ++-- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 440ff199..3f1fcda5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5376,7 +5376,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) // User can disable loading and saving of settings. Tooltip and child windows also don't store settings. if (!(flags & ImGuiWindowFlags_NoSavedSettings)) - if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) + if (ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByWindow(window)) { // Retrieve settings from .ini file window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); @@ -12453,8 +12453,8 @@ void ImGui::LogButtons() // - UpdateSettings() [Internal] // - MarkIniSettingsDirty() [Internal] // - CreateNewWindowSettings() [Internal] -// - FindWindowSettings() [Internal] -// - FindOrCreateWindowSettings() [Internal] +// - FindWindowSettingsByName() [Internal] +// - FindWindowSettingsByWindow() [Internal] // - FindSettingsHandler() [Internal] // - ClearIniSettings() [Internal] // - LoadIniSettingsFromDisk() @@ -12529,20 +12529,24 @@ ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) return settings; } -ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id) +// This is called once per window .ini entry + once per newly instanciated window. +ImGuiWindowSettings* ImGui::FindWindowSettingsByName(const char* name) { ImGuiContext& g = *GImGui; + ImGuiID id = ImHashStr(name); for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) if (settings->ID == id) return settings; return NULL; } -ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name) +// This is faster if you are holding on a Window already as we don't need to perform a search. +ImGuiWindowSettings* ImGui::FindWindowSettingsByWindow(ImGuiWindow* window) { - if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name))) - return settings; - return CreateNewWindowSettings(name); + ImGuiContext& g = *GImGui; + if (window->SettingsOffset != -1) + return g.SettingsWindows.ptr_from_offset(window->SettingsOffset); + return FindWindowSettingsByName(window->Name); // Actual search executed once, so at this point we don't mind the redundant hashing. } void ImGui::AddSettingsHandler(const ImGuiSettingsHandler* handler) @@ -12569,6 +12573,7 @@ ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name) return NULL; } +// Clear all settings (windows, tables, docking etc.) void ImGui::ClearIniSettings() { ImGuiContext& g = *GImGui; @@ -12703,9 +12708,12 @@ static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandl static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) { - ImGuiWindowSettings* settings = ImGui::FindOrCreateWindowSettings(name); - ImGuiID id = settings->ID; - *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry + ImGuiID id = ImHashStr(name); + ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByName(name); + if (settings) + *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry + else + settings = ImGui::CreateNewWindowSettings(name); settings->ID = id; settings->WantApply = true; return (void*)settings; @@ -12745,7 +12753,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl if (window->Flags & ImGuiWindowFlags_NoSavedSettings) continue; - ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID); + ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByWindow(window); if (!settings) { settings = ImGui::CreateNewWindowSettings(window->Name); diff --git a/imgui_internal.h b/imgui_internal.h index 5c9fa77e..2c640db2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2764,8 +2764,8 @@ namespace ImGui IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window); IMGUI_API void ClearIniSettings(); IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); - IMGUI_API ImGuiWindowSettings* FindWindowSettings(ImGuiID id); - IMGUI_API ImGuiWindowSettings* FindOrCreateWindowSettings(const char* name); + IMGUI_API ImGuiWindowSettings* FindWindowSettingsByName(const char* name); + IMGUI_API ImGuiWindowSettings* FindWindowSettingsByWindow(ImGuiWindow* window); IMGUI_API void AddSettingsHandler(const ImGuiSettingsHandler* handler); IMGUI_API void RemoveSettingsHandler(const char* type_name); IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); From b2ebd03b16a277522bf30e44965bfea340dabf9b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 10 Feb 2023 15:51:26 +0100 Subject: [PATCH 6/8] Internals: Settings: moved Windows setting to their sub-section. --- imgui.cpp | 91 ++++++++++++++++++++++++------------------------ imgui_internal.h | 8 +++-- 2 files changed, 51 insertions(+), 48 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3f1fcda5..073f12f9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -12452,15 +12452,16 @@ void ImGui::LogButtons() //----------------------------------------------------------------------------- // - UpdateSettings() [Internal] // - MarkIniSettingsDirty() [Internal] -// - CreateNewWindowSettings() [Internal] -// - FindWindowSettingsByName() [Internal] -// - FindWindowSettingsByWindow() [Internal] // - FindSettingsHandler() [Internal] // - ClearIniSettings() [Internal] // - LoadIniSettingsFromDisk() // - LoadIniSettingsFromMemory() // - SaveIniSettingsToDisk() // - SaveIniSettingsToMemory() +//----------------------------------------------------------------------------- +// - CreateNewWindowSettings() [Internal] +// - FindWindowSettingsByName() [Internal] +// - FindWindowSettingsByWindow() [Internal] // - WindowSettingsHandler_***() [Internal] //----------------------------------------------------------------------------- @@ -12507,48 +12508,6 @@ void ImGui::MarkIniSettingsDirty(ImGuiWindow* window) g.SettingsDirtyTimer = g.IO.IniSavingRate; } -ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) -{ - ImGuiContext& g = *GImGui; - -#if !IMGUI_DEBUG_INI_SETTINGS - // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() - // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier. - if (const char* p = strstr(name, "###")) - name = p; -#endif - const size_t name_len = strlen(name); - - // Allocate chunk - const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1; - ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size); - IM_PLACEMENT_NEW(settings) ImGuiWindowSettings(); - settings->ID = ImHashStr(name, name_len); - memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator - - return settings; -} - -// This is called once per window .ini entry + once per newly instanciated window. -ImGuiWindowSettings* ImGui::FindWindowSettingsByName(const char* name) -{ - ImGuiContext& g = *GImGui; - ImGuiID id = ImHashStr(name); - for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) - if (settings->ID == id) - return settings; - return NULL; -} - -// This is faster if you are holding on a Window already as we don't need to perform a search. -ImGuiWindowSettings* ImGui::FindWindowSettingsByWindow(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - if (window->SettingsOffset != -1) - return g.SettingsWindows.ptr_from_offset(window->SettingsOffset); - return FindWindowSettingsByName(window->Name); // Actual search executed once, so at this point we don't mind the redundant hashing. -} - void ImGui::AddSettingsHandler(const ImGuiSettingsHandler* handler) { ImGuiContext& g = *GImGui; @@ -12698,6 +12657,48 @@ const char* ImGui::SaveIniSettingsToMemory(size_t* out_size) return g.SettingsIniData.c_str(); } +ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) +{ + ImGuiContext& g = *GImGui; + +#if !IMGUI_DEBUG_INI_SETTINGS + // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() + // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier. + if (const char* p = strstr(name, "###")) + name = p; +#endif + const size_t name_len = strlen(name); + + // Allocate chunk + const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1; + ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size); + IM_PLACEMENT_NEW(settings) ImGuiWindowSettings(); + settings->ID = ImHashStr(name, name_len); + memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator + + return settings; +} + +// This is called once per window .ini entry + once per newly instantiated window. +ImGuiWindowSettings* ImGui::FindWindowSettingsByName(const char* name) +{ + ImGuiContext& g = *GImGui; + ImGuiID id = ImHashStr(name); + for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) + if (settings->ID == id) + return settings; + return NULL; +} + +// This is faster if you are holding on a Window already as we don't need to perform a search. +ImGuiWindowSettings* ImGui::FindWindowSettingsByWindow(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (window->SettingsOffset != -1) + return g.SettingsWindows.ptr_from_offset(window->SettingsOffset); + return FindWindowSettingsByName(window->Name); // Actual search executed once, so at this point we don't mind the redundant hashing. +} + static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) { ImGuiContext& g = *ctx; diff --git a/imgui_internal.h b/imgui_internal.h index 2c640db2..42bb284e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2763,13 +2763,15 @@ namespace ImGui IMGUI_API void MarkIniSettingsDirty(); IMGUI_API void MarkIniSettingsDirty(ImGuiWindow* window); IMGUI_API void ClearIniSettings(); - IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); - IMGUI_API ImGuiWindowSettings* FindWindowSettingsByName(const char* name); - IMGUI_API ImGuiWindowSettings* FindWindowSettingsByWindow(ImGuiWindow* window); IMGUI_API void AddSettingsHandler(const ImGuiSettingsHandler* handler); IMGUI_API void RemoveSettingsHandler(const char* type_name); IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name); + // Settings - Windows + IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); + IMGUI_API ImGuiWindowSettings* FindWindowSettingsByName(const char* name); + IMGUI_API ImGuiWindowSettings* FindWindowSettingsByWindow(ImGuiWindow* window); + // Localization IMGUI_API void LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count); inline const char* LocalizeGetMsg(ImGuiLocKey key) { ImGuiContext& g = *GImGui; const char* msg = g.LocalizationTable[key]; return msg ? msg : "*Missing Text*"; } From 082b20e46b21308c7f00816f1d46065d315861ee Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 10 Feb 2023 15:59:01 +0100 Subject: [PATCH 7/8] Internals: Settings: added ClearWindowSettings(). Extract part of CreateNewWindow() into InitOrLoadWindowSettings(). Designed to that if the window reappear in the session it won't take an additional slot. --- imgui.cpp | 70 +++++++++++++++++++++++++++++++++--------------- imgui_internal.h | 2 ++ 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 073f12f9..fc7e963e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3631,7 +3631,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) : DrawListInst ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f); AutoFitFramesX = AutoFitFramesY = -1; AutoPosLastDirection = ImGuiDir_None; - SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; + SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = 0; SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); LastFrameActive = -1; LastTimeActive = -1.0f; @@ -5360,32 +5360,22 @@ static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, window->IsExplicitChild = new_is_explicit_child; } -static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) +static void InitOrLoadWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings) { - ImGuiContext& g = *GImGui; - //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags); - - // Create window the first time - ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); - window->Flags = flags; - g.WindowsById.SetVoidPtr(window->ID, window); - - // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. + // Initial window state with e.g. default/arbitrary window position + // Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window. const ImGuiViewport* main_viewport = ImGui::GetMainViewport(); window->Pos = main_viewport->Pos + ImVec2(60, 60); + window->SetWindowPosAllowFlags = window->SetWindowSizeAllowFlags = window->SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing; - // User can disable loading and saving of settings. Tooltip and child windows also don't store settings. - if (!(flags & ImGuiWindowFlags_NoSavedSettings)) - if (ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByWindow(window)) - { - // Retrieve settings from .ini file - window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); - SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); - ApplyWindowSettings(window, settings); - } + if (settings != NULL) + { + SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); + ApplyWindowSettings(window, settings); + } window->DC.CursorStartPos = window->DC.CursorMaxPos = window->DC.IdealMaxPos = window->Pos; // So first call to CalcWindowContentSizes() doesn't return crazy values - if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) + if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) { window->AutoFitFramesX = window->AutoFitFramesY = 2; window->AutoFitOnlyGrows = false; @@ -5398,6 +5388,23 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) window->AutoFitFramesY = 2; window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0); } +} + +static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags) +{ + // Create window the first time + //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name); + window->Flags = flags; + g.WindowsById.SetVoidPtr(window->ID, window); + + ImGuiWindowSettings* settings = NULL; + if (!(flags & ImGuiWindowFlags_NoSavedSettings)) + if ((settings = ImGui::FindWindowSettingsByWindow(window)) != 0) + window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings); + + InitOrLoadWindowSettings(window, settings); if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus) g.Windows.push_front(window); // Quite slow but rare and only once @@ -12699,6 +12706,20 @@ ImGuiWindowSettings* ImGui::FindWindowSettingsByWindow(ImGuiWindow* window) return FindWindowSettingsByName(window->Name); // Actual search executed once, so at this point we don't mind the redundant hashing. } +// This will revert window to its initial state, including enabling the ImGuiCond_FirstUseEver/ImGuiCond_Once conditions once more. +void ImGui::ClearWindowSettings(const char* name) +{ + //IMGUI_DEBUG_LOG("ClearWindowSettings('%s')\n", name); + ImGuiWindow* window = FindWindowByName(name); + if (window != NULL) + { + window->Flags |= ImGuiWindowFlags_NoSavedSettings; + InitOrLoadWindowSettings(window, NULL); + } + if (ImGuiWindowSettings* settings = window ? FindWindowSettingsByWindow(window) : FindWindowSettingsByName(name)) + settings->WantDelete = true; +} + static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) { ImGuiContext& g = *ctx; @@ -12765,12 +12786,15 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl settings->Size = ImVec2ih(window->SizeFull); settings->Collapsed = window->Collapsed; + settings->WantDelete = false; } // Write to text buffer buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) { + if (settings->WantDelete) + continue; const char* settings_name = settings->GetName(); buf->appendf("[%s][%s]\n", handler->TypeName, settings_name); buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y); @@ -14106,8 +14130,12 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings* settings) { + if (settings->WantDelete) + BeginDisabled(); Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d", settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed); + if (settings->WantDelete) + EndDisabled(); } void ImGui::DebugNodeWindowsList(ImVector* windows, const char* label) diff --git a/imgui_internal.h b/imgui_internal.h index 42bb284e..7ac81303 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1607,6 +1607,7 @@ struct ImGuiWindowSettings ImVec2ih Size; bool Collapsed; bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) + bool WantDelete; // Set to invalidate/delete the settings entry ImGuiWindowSettings() { memset(this, 0, sizeof(*this)); } char* GetName() { return (char*)(this + 1); } @@ -2771,6 +2772,7 @@ namespace ImGui IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); IMGUI_API ImGuiWindowSettings* FindWindowSettingsByName(const char* name); IMGUI_API ImGuiWindowSettings* FindWindowSettingsByWindow(ImGuiWindow* window); + IMGUI_API void ClearWindowSettings(const char* name); // Localization IMGUI_API void LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count); From f0ac68ad35d3ad99f12e583665374e9861a1cb7b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 10 Feb 2023 17:01:14 +0100 Subject: [PATCH 8/8] Internal: Settings: amend 0b86513 revert to use FindWindowSettingsByID(). Namely for docking system. --- imgui.cpp | 13 +++++++------ imgui_internal.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fc7e963e..96f79beb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -12467,8 +12467,9 @@ void ImGui::LogButtons() // - SaveIniSettingsToMemory() //----------------------------------------------------------------------------- // - CreateNewWindowSettings() [Internal] -// - FindWindowSettingsByName() [Internal] +// - FindWindowSettingsByID() [Internal] // - FindWindowSettingsByWindow() [Internal] +// - ClearWindowSettings() [Internal] // - WindowSettingsHandler_***() [Internal] //----------------------------------------------------------------------------- @@ -12686,11 +12687,11 @@ ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) return settings; } +// We don't provide a FindWindowSettingsByName() because Docking system doesn't always hold on names. // This is called once per window .ini entry + once per newly instantiated window. -ImGuiWindowSettings* ImGui::FindWindowSettingsByName(const char* name) +ImGuiWindowSettings* ImGui::FindWindowSettingsByID(ImGuiID id) { ImGuiContext& g = *GImGui; - ImGuiID id = ImHashStr(name); for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings)) if (settings->ID == id) return settings; @@ -12703,7 +12704,7 @@ ImGuiWindowSettings* ImGui::FindWindowSettingsByWindow(ImGuiWindow* window) ImGuiContext& g = *GImGui; if (window->SettingsOffset != -1) return g.SettingsWindows.ptr_from_offset(window->SettingsOffset); - return FindWindowSettingsByName(window->Name); // Actual search executed once, so at this point we don't mind the redundant hashing. + return FindWindowSettingsByID(window->ID); } // This will revert window to its initial state, including enabling the ImGuiCond_FirstUseEver/ImGuiCond_Once conditions once more. @@ -12716,7 +12717,7 @@ void ImGui::ClearWindowSettings(const char* name) window->Flags |= ImGuiWindowFlags_NoSavedSettings; InitOrLoadWindowSettings(window, NULL); } - if (ImGuiWindowSettings* settings = window ? FindWindowSettingsByWindow(window) : FindWindowSettingsByName(name)) + if (ImGuiWindowSettings* settings = window ? FindWindowSettingsByWindow(window) : FindWindowSettingsByID(ImHashStr(name))) settings->WantDelete = true; } @@ -12731,7 +12732,7 @@ static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandl static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) { ImGuiID id = ImHashStr(name); - ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByName(name); + ImGuiWindowSettings* settings = ImGui::FindWindowSettingsByID(id); if (settings) *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry else diff --git a/imgui_internal.h b/imgui_internal.h index 7ac81303..ecc84bb9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2770,7 +2770,7 @@ namespace ImGui // Settings - Windows IMGUI_API ImGuiWindowSettings* CreateNewWindowSettings(const char* name); - IMGUI_API ImGuiWindowSettings* FindWindowSettingsByName(const char* name); + IMGUI_API ImGuiWindowSettings* FindWindowSettingsByID(ImGuiID id); IMGUI_API ImGuiWindowSettings* FindWindowSettingsByWindow(ImGuiWindow* window); IMGUI_API void ClearWindowSettings(const char* name);