From a467715ce316af046fc7ae341dd39008d50e6a76 Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Sun, 16 Feb 2025 16:24:14 +0100 Subject: [PATCH] Switched to imgui fork https://github.com/thedmd/imgui/commits/feature/docking-layout-external/ commit 899d85eb9489796f73a4dc67ad86892729707ce9 --- 3rdparty/imgui/LICENSE.txt | 2 +- .../imgui/backends/imgui_impl_allegro5.cpp | 71 +- 3rdparty/imgui/backends/imgui_impl_allegro5.h | 11 +- .../imgui/backends/imgui_impl_android.cpp | 6 +- 3rdparty/imgui/backends/imgui_impl_android.h | 7 +- 3rdparty/imgui/backends/imgui_impl_dx10.cpp | 317 +- 3rdparty/imgui/backends/imgui_impl_dx10.h | 17 +- 3rdparty/imgui/backends/imgui_impl_dx11.cpp | 254 +- 3rdparty/imgui/backends/imgui_impl_dx11.h | 19 +- 3rdparty/imgui/backends/imgui_impl_dx12.cpp | 263 +- 3rdparty/imgui/backends/imgui_impl_dx12.h | 60 +- 3rdparty/imgui/backends/imgui_impl_dx9.cpp | 244 +- 3rdparty/imgui/backends/imgui_impl_dx9.h | 4 +- 3rdparty/imgui/backends/imgui_impl_glfw.cpp | 122 +- 3rdparty/imgui/backends/imgui_impl_glfw.h | 10 +- 3rdparty/imgui/backends/imgui_impl_glut.cpp | 5 +- 3rdparty/imgui/backends/imgui_impl_glut.h | 6 +- 3rdparty/imgui/backends/imgui_impl_metal.h | 4 +- 3rdparty/imgui/backends/imgui_impl_metal.mm | 61 +- .../imgui/backends/imgui_impl_opengl2.cpp | 44 +- 3rdparty/imgui/backends/imgui_impl_opengl2.h | 3 - .../imgui/backends/imgui_impl_opengl3.cpp | 55 +- 3rdparty/imgui/backends/imgui_impl_opengl3.h | 4 +- .../backends/imgui_impl_opengl3_loader.h | 6 - 3rdparty/imgui/backends/imgui_impl_osx.h | 8 +- 3rdparty/imgui/backends/imgui_impl_osx.mm | 43 +- 3rdparty/imgui/backends/imgui_impl_sdl2.cpp | 139 +- 3rdparty/imgui/backends/imgui_impl_sdl2.h | 11 +- 3rdparty/imgui/backends/imgui_impl_sdl3.cpp | 219 +- 3rdparty/imgui/backends/imgui_impl_sdl3.h | 19 +- .../backends/imgui_impl_sdlrenderer2.cpp | 44 +- .../imgui/backends/imgui_impl_sdlrenderer2.h | 24 +- .../backends/imgui_impl_sdlrenderer3.cpp | 50 +- .../imgui/backends/imgui_impl_sdlrenderer3.h | 26 +- 3rdparty/imgui/backends/imgui_impl_vulkan.cpp | 351 +- 3rdparty/imgui/backends/imgui_impl_vulkan.h | 80 +- 3rdparty/imgui/backends/imgui_impl_wgpu.cpp | 94 +- 3rdparty/imgui/backends/imgui_impl_wgpu.h | 22 +- 3rdparty/imgui/backends/imgui_impl_win32.cpp | 257 +- 3rdparty/imgui/backends/imgui_impl_win32.h | 5 +- 3rdparty/imgui/docs/BACKENDS.md | 40 +- 3rdparty/imgui/docs/CHANGELOG.txt | 1519 ++------- 3rdparty/imgui/docs/EXAMPLES.md | 91 +- 3rdparty/imgui/docs/FAQ.md | 56 +- 3rdparty/imgui/docs/FONTS.md | 8 +- 3rdparty/imgui/docs/README.md | 20 +- 3rdparty/imgui/docs/TODO.txt | 13 +- .../android/app/src/main/AndroidManifest.xml | 2 +- .../examples/example_android_opengl3/main.cpp | 2 +- .../examples/example_glfw_opengl2/main.cpp | 5 - .../example_glfw_opengl3/Makefile.emscripten | 3 - .../examples/example_glfw_opengl3/main.cpp | 13 +- .../example_glfw_vulkan/CMakeLists.txt | 2 +- .../example_glfw_vulkan/build_win32.bat | 4 +- .../example_glfw_vulkan/build_win64.bat | 7 +- .../example_glfw_vulkan.vcxproj | 8 +- .../examples/example_glfw_vulkan/main.cpp | 82 +- .../examples/example_glfw_wgpu/CMakeLists.txt | 6 +- .../example_glfw_wgpu/Makefile.emscripten | 3 - .../imgui/examples/example_glfw_wgpu/main.cpp | 5 - 3rdparty/imgui/examples/example_null/Makefile | 2 +- .../examples/example_sdl2_directx11/main.cpp | 5 - .../examples/example_sdl2_opengl2/main.cpp | 5 - .../example_sdl2_opengl3/Makefile.emscripten | 3 - .../examples/example_sdl2_opengl3/main.cpp | 20 +- .../example_sdl2_sdlrenderer2/main.cpp | 7 +- .../example_sdl2_vulkan/build_win32.bat | 6 +- .../example_sdl2_vulkan.vcxproj | 10 +- .../examples/example_sdl2_vulkan/main.cpp | 82 +- .../example_sdl3_opengl3/Makefile.emscripten | 3 - .../examples/example_sdl3_opengl3/README.md | 6 +- .../example_sdl3_opengl3/build_win32.bat | 8 +- .../examples/example_sdl3_opengl3/main.cpp | 23 +- .../example_sdl3_sdlrenderer3/main.cpp | 14 +- .../example_win32_directx12/build_win32.bat | 3 +- .../example_win32_directx12.vcxproj | 10 +- .../examples/example_win32_directx12/main.cpp | 109 +- .../examples/example_win32_opengl3/main.cpp | 5 - 3rdparty/imgui/examples/imgui_examples.sln | 30 - .../emscripten/emscripten_mainloop_stub.h | 7 +- 3rdparty/imgui/imconfig.h | 27 +- 3rdparty/imgui/imgui.cpp | 2995 +++++++---------- 3rdparty/imgui/imgui.h | 607 ++-- 3rdparty/imgui/imgui_demo.cpp | 1010 +++--- 3rdparty/imgui/imgui_draw.cpp | 654 ++-- 3rdparty/imgui/imgui_internal.h | 718 ++-- 3rdparty/imgui/imgui_stacklayout.cpp | 1206 +++++++ 3rdparty/imgui/imgui_stacklayout.h | 38 + 3rdparty/imgui/imgui_stacklayout_internal.h | 30 + 3rdparty/imgui/imgui_tables.cpp | 177 +- 3rdparty/imgui/imgui_widgets.cpp | 1596 ++++----- 3rdparty/imgui/imstb_textedit.h | 98 +- 3rdparty/imgui/misc/cpp/imgui_stdlib.cpp | 3 - 3rdparty/imgui/misc/cpp/imgui_stdlib.h | 4 - .../misc/fonts/binary_to_compressed_c.cpp | 66 +- 3rdparty/imgui/misc/freetype/README.md | 26 +- .../imgui/misc/freetype/imgui_freetype.cpp | 55 +- 3rdparty/imgui/misc/freetype/imgui_freetype.h | 7 - src/main.cc | 68 +- 99 files changed, 6274 insertions(+), 8345 deletions(-) create mode 100644 3rdparty/imgui/imgui_stacklayout.cpp create mode 100644 3rdparty/imgui/imgui_stacklayout.h create mode 100644 3rdparty/imgui/imgui_stacklayout_internal.h diff --git a/3rdparty/imgui/LICENSE.txt b/3rdparty/imgui/LICENSE.txt index 00ae473..3282f5b 100644 --- a/3rdparty/imgui/LICENSE.txt +++ b/3rdparty/imgui/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2025 Omar Cornut +Copyright (c) 2014-2024 Omar Cornut Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/3rdparty/imgui/backends/imgui_impl_allegro5.cpp b/3rdparty/imgui/backends/imgui_impl_allegro5.cpp index d0265b0..6a0153c 100644 --- a/3rdparty/imgui/backends/imgui_impl_allegro5.cpp +++ b/3rdparty/imgui/backends/imgui_impl_allegro5.cpp @@ -3,13 +3,13 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID! -// [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 ALLEGRO_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Clipboard support (from Allegro 5.1.12). -// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. -// Missing features or Issues: -// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually. +// [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 ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Clipboard support (from Allegro 5.1.12) +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// Missing features: +// [ ] Renderer: Multi-viewport support (multiple windows).. +// [ ] Renderer: The renderer is suboptimal as we need to convert vertices manually. // [ ] Platform: Missing gamepad support. -// [ ] Renderer: Multi-viewport support (multiple windows). // 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. @@ -21,10 +21,6 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-01-06: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). -// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: -// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn -// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn // 2022-11-30: Renderer: Restoring using al_draw_indexed_prim() when Allegro version is >= 5.2.5. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported). @@ -97,7 +93,6 @@ struct ImGui_ImplAllegro5_Data ALLEGRO_MOUSE_CURSOR* MouseCursorInvisible; ALLEGRO_VERTEX_DECL* VertexDecl; char* ClipboardTextData; - ImGuiMouseCursor LastCursor; ImVector BufVertices; ImVector BufIndices; @@ -152,14 +147,14 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) // Render command lists for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; + const ImDrawList* cmd_list = draw_data->CmdLists[n]; ImVector& vertices = bd->BufVertices; #if ALLEGRO_HAS_DRAW_INDEXED_PRIM - vertices.resize(draw_list->VtxBuffer.Size); - for (int i = 0; i < draw_list->VtxBuffer.Size; i++) + vertices.resize(cmd_list->VtxBuffer.Size); + for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) { - const ImDrawVert* src_v = &draw_list->VtxBuffer[i]; + const ImDrawVert* src_v = &cmd_list->VtxBuffer[i]; ImDrawVertAllegro* dst_v = &vertices[i]; DRAW_VERT_IMGUI_TO_ALLEGRO(dst_v, src_v); } @@ -169,21 +164,21 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) // FIXME-OPT: Allegro doesn't support 16-bit indices. // You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices. // Otherwise, we convert them from 16-bit to 32-bit at runtime here, which works perfectly but is a little wasteful. - bd->BufIndices.resize(draw_list->IdxBuffer.Size); - for (int i = 0; i < draw_list->IdxBuffer.Size; ++i) - bd->BufIndices[i] = (int)draw_list->IdxBuffer.Data[i]; + bd->BufIndices.resize(cmd_list->IdxBuffer.Size); + for (int i = 0; i < cmd_list->IdxBuffer.Size; ++i) + bd->BufIndices[i] = (int)cmd_list->IdxBuffer.Data[i]; indices = bd->BufIndices.Data; } else if (sizeof(ImDrawIdx) == 4) { - indices = (const int*)draw_list->IdxBuffer.Data; + indices = (const int*)cmd_list->IdxBuffer.Data; } #else // Allegro's implementation of al_draw_indexed_prim() for DX9 was broken until 5.2.5. Unindex buffers ourselves while converting vertex format. - vertices.resize(draw_list->IdxBuffer.Size); - for (int i = 0; i < draw_list->IdxBuffer.Size; i++) + vertices.resize(cmd_list->IdxBuffer.Size); + for (int i = 0; i < cmd_list->IdxBuffer.Size; i++) { - const ImDrawVert* src_v = &draw_list->VtxBuffer[draw_list->IdxBuffer[i]]; + const ImDrawVert* src_v = &cmd_list->VtxBuffer[cmd_list->IdxBuffer[i]]; ImDrawVertAllegro* dst_v = &vertices[i]; DRAW_VERT_IMGUI_TO_ALLEGRO(dst_v, src_v); } @@ -191,9 +186,9 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) // Render command lists ImVec2 clip_off = draw_data->DisplayPos; - for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { // User callback, registered via ImDrawList::AddCallback() @@ -201,7 +196,7 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) ImGui_ImplAllegro5_SetupRenderState(draw_data); else - pcmd->UserCallback(draw_list, pcmd); + pcmd->UserCallback(cmd_list, pcmd); } else { @@ -297,7 +292,7 @@ void ImGui_ImplAllegro5_InvalidateDeviceObjects() } #if ALLEGRO_HAS_CLIPBOARD -static const char* ImGui_ImplAllegro5_GetClipboardText(ImGuiContext*) +static const char* ImGui_ImplAllegro5_GetClipboardText(void*) { ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); if (bd->ClipboardTextData) @@ -306,16 +301,14 @@ static const char* ImGui_ImplAllegro5_GetClipboardText(ImGuiContext*) return bd->ClipboardTextData; } -static void ImGui_ImplAllegro5_SetClipboardText(ImGuiContext*, const char* text) +static void ImGui_ImplAllegro5_SetClipboardText(void*, const char* text) { ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); al_set_clipboard_text(bd->Display, text); } #endif -// Not static to allow third-party code to use that if they want to (but undocumented) -ImGuiKey ImGui_ImplAllegro5_KeyCodeToImGuiKey(int key_code); -ImGuiKey ImGui_ImplAllegro5_KeyCodeToImGuiKey(int key_code) +static ImGuiKey ImGui_ImplAllegro5_KeyCodeToImGuiKey(int key_code) { switch (key_code) { @@ -441,7 +434,6 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display) io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) bd->Display = display; - bd->LastCursor = ALLEGRO_SYSTEM_MOUSE_CURSOR_NONE; // Create custom vertex declaration. // Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 floats. @@ -456,9 +448,9 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display) bd->VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro)); #if ALLEGRO_HAS_CLIPBOARD - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - platform_io.Platform_SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText; - platform_io.Platform_GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText; + io.SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText; + io.GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText; + io.ClipboardUserData = nullptr; #endif return true; @@ -572,16 +564,9 @@ static void ImGui_ImplAllegro5_UpdateMouseCursor() ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); - - // Hide OS mouse cursor if imgui is drawing it - if (io.MouseDrawCursor) - imgui_cursor = ImGuiMouseCursor_None; - - if (bd->LastCursor == imgui_cursor) - return; - bd->LastCursor = imgui_cursor; - if (imgui_cursor == ImGuiMouseCursor_None) + if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None) { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor al_set_mouse_cursor(bd->Display, bd->MouseCursorInvisible); } else diff --git a/3rdparty/imgui/backends/imgui_impl_allegro5.h b/3rdparty/imgui/backends/imgui_impl_allegro5.h index e67ffe5..a7f7c0e 100644 --- a/3rdparty/imgui/backends/imgui_impl_allegro5.h +++ b/3rdparty/imgui/backends/imgui_impl_allegro5.h @@ -3,13 +3,13 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID! -// [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 ALLEGRO_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Clipboard support (from Allegro 5.1.12). -// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. -// Missing features or Issues: +// [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 ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Clipboard support (from Allegro 5.1.12) +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// Missing features: +// [ ] Renderer: Multi-viewport support (multiple windows).. // [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually. // [ ] Platform: Missing gamepad support. -// [ ] Renderer: Multi-viewport support (multiple windows). // 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. @@ -26,7 +26,6 @@ struct ALLEGRO_DISPLAY; union ALLEGRO_EVENT; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display); IMGUI_IMPL_API void ImGui_ImplAllegro5_Shutdown(); IMGUI_IMPL_API void ImGui_ImplAllegro5_NewFrame(); diff --git a/3rdparty/imgui/backends/imgui_impl_android.cpp b/3rdparty/imgui/backends/imgui_impl_android.cpp index 66eb88d..994b0c6 100644 --- a/3rdparty/imgui/backends/imgui_impl_android.cpp +++ b/3rdparty/imgui/backends/imgui_impl_android.cpp @@ -2,12 +2,12 @@ // This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3) // Implemented features: -// [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 AKEYCODE_* values are obsolete since 1.87 and not supported since 1.91.5] +// [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 AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. -// Missing features or Issues: +// Missing features: // [ ] Platform: Clipboard support. // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. +// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. // [ ] Platform: Multi-viewport support (multiple windows). Not meaningful on Android. // Important: // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. diff --git a/3rdparty/imgui/backends/imgui_impl_android.h b/3rdparty/imgui/backends/imgui_impl_android.h index da3e11a..7cd4ef1 100644 --- a/3rdparty/imgui/backends/imgui_impl_android.h +++ b/3rdparty/imgui/backends/imgui_impl_android.h @@ -2,12 +2,12 @@ // This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3) // Implemented features: -// [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 AKEYCODE_* values are obsolete since 1.87 and not supported since 1.91.5] +// [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 AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. -// Missing features or Issues: +// Missing features: // [ ] Platform: Clipboard support. // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. +// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. // [ ] Platform: Multi-viewport support (multiple windows). Not meaningful on Android. // Important: // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. @@ -29,7 +29,6 @@ struct ANativeWindow; struct AInputEvent; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplAndroid_Init(ANativeWindow* window); IMGUI_IMPL_API int32_t ImGui_ImplAndroid_HandleInputEvent(const AInputEvent* input_event); IMGUI_IMPL_API void ImGui_ImplAndroid_Shutdown(); diff --git a/3rdparty/imgui/backends/imgui_impl_dx10.cpp b/3rdparty/imgui/backends/imgui_impl_dx10.cpp index 5ac6514..0123aa6 100644 --- a/3rdparty/imgui/backends/imgui_impl_dx10.cpp +++ b/3rdparty/imgui/backends/imgui_impl_dx10.cpp @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -16,9 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2025-01-06: DirectX10: Expose selected render state in ImGui_ImplDX10_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. -// 2024-10-07: DirectX10: Changed default texture sampler to Clamp instead of Repeat/Wrap. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: DirectX10: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) @@ -49,7 +47,7 @@ #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. #endif -// DirectX10 data +// DirectX data struct ImGui_ImplDX10_Data { ID3D10Device* pd3dDevice; @@ -84,11 +82,11 @@ static ImGui_ImplDX10_Data* ImGui_ImplDX10_GetBackendData() } // Forward Declarations -static void ImGui_ImplDX10_InitMultiViewportSupport(); -static void ImGui_ImplDX10_ShutdownMultiViewportSupport(); +static void ImGui_ImplDX10_InitPlatformInterface(); +static void ImGui_ImplDX10_ShutdownPlatformInterface(); // Functions -static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* device) +static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* ctx) { ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); @@ -100,13 +98,90 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; - device->RSSetViewports(1, &vp); + ctx->RSSetViewports(1, &vp); + + // Bind shader and vertex buffers + unsigned int stride = sizeof(ImDrawVert); + unsigned int offset = 0; + ctx->IASetInputLayout(bd->pInputLayout); + ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset); + ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); + ctx->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ctx->VSSetShader(bd->pVertexShader); + ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer); + ctx->PSSetShader(bd->pPixelShader); + ctx->PSSetSamplers(0, 1, &bd->pFontSampler); + ctx->GSSetShader(nullptr); + + // Setup render state + const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; + ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff); + ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0); + ctx->RSSetState(bd->pRasterizerState); +} + +// Render function +void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) +{ + // Avoid rendering when minimized + if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) + return; + + ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); + ID3D10Device* ctx = bd->pd3dDevice; + + // Create and grow vertex/index buffers if needed + if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) + { + if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } + bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; + D3D10_BUFFER_DESC desc; + memset(&desc, 0, sizeof(D3D10_BUFFER_DESC)); + desc.Usage = D3D10_USAGE_DYNAMIC; + desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert); + desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; + desc.MiscFlags = 0; + if (ctx->CreateBuffer(&desc, nullptr, &bd->pVB) < 0) + return; + } + + if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount) + { + if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } + bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; + D3D10_BUFFER_DESC desc; + memset(&desc, 0, sizeof(D3D10_BUFFER_DESC)); + desc.Usage = D3D10_USAGE_DYNAMIC; + desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx); + desc.BindFlags = D3D10_BIND_INDEX_BUFFER; + desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; + if (ctx->CreateBuffer(&desc, nullptr, &bd->pIB) < 0) + return; + } + + // Copy and convert all vertices into a single contiguous buffer + ImDrawVert* vtx_dst = nullptr; + ImDrawIdx* idx_dst = nullptr; + bd->pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst); + bd->pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst); + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vtx_dst += cmd_list->VtxBuffer.Size; + idx_dst += cmd_list->IdxBuffer.Size; + } + bd->pVB->Unmap(); + bd->pIB->Unmap(); // Setup orthographic projection matrix into our constant buffer // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. - void* mapped_resource; - if (bd->pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) == S_OK) { + void* mapped_resource; + if (bd->pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) + return; VERTEX_CONSTANT_BUFFER_DX10* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX10*)mapped_resource; float L = draw_data->DisplayPos.x; float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; @@ -123,82 +198,6 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* bd->pVertexConstantBuffer->Unmap(); } - // Setup shader and vertex buffers - unsigned int stride = sizeof(ImDrawVert); - unsigned int offset = 0; - device->IASetInputLayout(bd->pInputLayout); - device->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset); - device->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); - device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - device->VSSetShader(bd->pVertexShader); - device->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer); - device->PSSetShader(bd->pPixelShader); - device->PSSetSamplers(0, 1, &bd->pFontSampler); - device->GSSetShader(nullptr); - - // Setup render state - const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; - device->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff); - device->OMSetDepthStencilState(bd->pDepthStencilState, 0); - device->RSSetState(bd->pRasterizerState); -} - -// Render function -void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) -{ - // Avoid rendering when minimized - if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) - return; - - ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); - ID3D10Device* device = bd->pd3dDevice; - - // Create and grow vertex/index buffers if needed - if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) - { - if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } - bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; - D3D10_BUFFER_DESC desc; - memset(&desc, 0, sizeof(D3D10_BUFFER_DESC)); - desc.Usage = D3D10_USAGE_DYNAMIC; - desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert); - desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; - desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; - desc.MiscFlags = 0; - if (device->CreateBuffer(&desc, nullptr, &bd->pVB) < 0) - return; - } - - if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount) - { - if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } - bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; - D3D10_BUFFER_DESC desc; - memset(&desc, 0, sizeof(D3D10_BUFFER_DESC)); - desc.Usage = D3D10_USAGE_DYNAMIC; - desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx); - desc.BindFlags = D3D10_BIND_INDEX_BUFFER; - desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; - if (device->CreateBuffer(&desc, nullptr, &bd->pIB) < 0) - return; - } - - // Copy and convert all vertices into a single contiguous buffer - ImDrawVert* vtx_dst = nullptr; - ImDrawIdx* idx_dst = nullptr; - bd->pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst); - bd->pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst); - for (int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - vtx_dst += draw_list->VtxBuffer.Size; - idx_dst += draw_list->IdxBuffer.Size; - } - bd->pVB->Unmap(); - bd->pIB->Unmap(); - // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!) struct BACKUP_DX10_STATE { @@ -224,31 +223,24 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) }; BACKUP_DX10_STATE old = {}; old.ScissorRectsCount = old.ViewportsCount = D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; - device->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects); - device->RSGetViewports(&old.ViewportsCount, old.Viewports); - device->RSGetState(&old.RS); - device->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask); - device->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef); - device->PSGetShaderResources(0, 1, &old.PSShaderResource); - device->PSGetSamplers(0, 1, &old.PSSampler); - device->PSGetShader(&old.PS); - device->VSGetShader(&old.VS); - device->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer); - device->GSGetShader(&old.GS); - device->IAGetPrimitiveTopology(&old.PrimitiveTopology); - device->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset); - device->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); - device->IAGetInputLayout(&old.InputLayout); + ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects); + ctx->RSGetViewports(&old.ViewportsCount, old.Viewports); + ctx->RSGetState(&old.RS); + ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask); + ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef); + ctx->PSGetShaderResources(0, 1, &old.PSShaderResource); + ctx->PSGetSamplers(0, 1, &old.PSSampler); + ctx->PSGetShader(&old.PS); + ctx->VSGetShader(&old.VS); + ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer); + ctx->GSGetShader(&old.GS); + ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology); + ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset); + ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); + ctx->IAGetInputLayout(&old.InputLayout); // Setup desired DX state - ImGui_ImplDX10_SetupRenderState(draw_data, device); - // Setup render state structure (for callbacks and custom texture bindings) - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - ImGui_ImplDX10_RenderState render_state; - render_state.Device = bd->pd3dDevice; - render_state.SamplerDefault = bd->pFontSampler; - render_state.VertexConstantBuffer = bd->pVertexConstantBuffer; - platform_io.Renderer_RenderState = &render_state; + ImGui_ImplDX10_SetupRenderState(draw_data, ctx); // Render command lists // (Because we merged all buffers into a single one, we maintain our own offset into them) @@ -257,18 +249,18 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) ImVec2 clip_off = draw_data->DisplayPos; for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback != nullptr) + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback) { // User callback, registered via ImDrawList::AddCallback() // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) - ImGui_ImplDX10_SetupRenderState(draw_data, device); + ImGui_ImplDX10_SetupRenderState(draw_data, ctx); else - pcmd->UserCallback(draw_list, pcmd); + pcmd->UserCallback(cmd_list, pcmd); } else { @@ -280,35 +272,34 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) // Apply scissor/clipping rectangle const D3D10_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y }; - device->RSSetScissorRects(1, &r); + ctx->RSSetScissorRects(1, &r); // Bind texture, Draw ID3D10ShaderResourceView* texture_srv = (ID3D10ShaderResourceView*)pcmd->GetTexID(); - device->PSSetShaderResources(0, 1, &texture_srv); - device->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset); + ctx->PSSetShaderResources(0, 1, &texture_srv); + ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset); } } - global_idx_offset += draw_list->IdxBuffer.Size; - global_vtx_offset += draw_list->VtxBuffer.Size; + global_idx_offset += cmd_list->IdxBuffer.Size; + global_vtx_offset += cmd_list->VtxBuffer.Size; } - platform_io.Renderer_RenderState = nullptr; // Restore modified DX state - device->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects); - device->RSSetViewports(old.ViewportsCount, old.Viewports); - device->RSSetState(old.RS); if (old.RS) old.RS->Release(); - device->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release(); - device->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release(); - device->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release(); - device->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release(); - device->PSSetShader(old.PS); if (old.PS) old.PS->Release(); - device->VSSetShader(old.VS); if (old.VS) old.VS->Release(); - device->GSSetShader(old.GS); if (old.GS) old.GS->Release(); - device->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release(); - device->IASetPrimitiveTopology(old.PrimitiveTopology); - device->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release(); - device->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release(); - device->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); + ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects); + ctx->RSSetViewports(old.ViewportsCount, old.Viewports); + ctx->RSSetState(old.RS); if (old.RS) old.RS->Release(); + ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release(); + ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release(); + ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release(); + ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release(); + ctx->PSSetShader(old.PS); if (old.PS) old.PS->Release(); + ctx->VSSetShader(old.VS); if (old.VS) old.VS->Release(); + ctx->GSSetShader(old.GS); if (old.GS) old.GS->Release(); + ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release(); + ctx->IASetPrimitiveTopology(old.PrimitiveTopology); + ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release(); + ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release(); + ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); } static void ImGui_ImplDX10_CreateFontsTexture() @@ -355,16 +346,21 @@ static void ImGui_ImplDX10_CreateFontsTexture() // Store our identifier io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView); -} -static void ImGui_ImplDX10_DestroyFontsTexture() -{ - ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); - if (bd->pFontTextureView) + // Create texture sampler + // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) { - bd->pFontTextureView->Release(); - bd->pFontTextureView = nullptr; - ImGui::GetIO().Fonts->SetTexID(0); // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well. + D3D10_SAMPLER_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR; + desc.AddressU = D3D10_TEXTURE_ADDRESS_WRAP; + desc.AddressV = D3D10_TEXTURE_ADDRESS_WRAP; + desc.AddressW = D3D10_TEXTURE_ADDRESS_WRAP; + desc.MipLODBias = 0.f; + desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS; + desc.MinLOD = 0.f; + desc.MaxLOD = 0.f; + bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler); } } @@ -517,22 +513,6 @@ bool ImGui_ImplDX10_CreateDeviceObjects() bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState); } - // Create texture sampler - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) - { - D3D10_SAMPLER_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR; - desc.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP; - desc.AddressV = D3D10_TEXTURE_ADDRESS_CLAMP; - desc.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP; - desc.MipLODBias = 0.f; - desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS; - desc.MinLOD = 0.f; - desc.MaxLOD = 0.f; - bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler); - } - ImGui_ImplDX10_CreateFontsTexture(); return true; @@ -544,9 +524,8 @@ void ImGui_ImplDX10_InvalidateDeviceObjects() if (!bd->pd3dDevice) return; - ImGui_ImplDX10_DestroyFontsTexture(); - if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = nullptr; } + if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well. if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; } @@ -586,8 +565,8 @@ bool ImGui_ImplDX10_Init(ID3D10Device* device) if (pDXGIAdapter) pDXGIAdapter->Release(); bd->pd3dDevice->AddRef(); - ImGui_ImplDX10_InitMultiViewportSupport(); - + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplDX10_InitPlatformInterface(); return true; } @@ -597,7 +576,7 @@ void ImGui_ImplDX10_Shutdown() IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplDX10_ShutdownMultiViewportSupport(); + ImGui_ImplDX10_ShutdownPlatformInterface(); ImGui_ImplDX10_InvalidateDeviceObjects(); if (bd->pFactory) { bd->pFactory->Release(); } if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } @@ -612,7 +591,7 @@ void ImGui_ImplDX10_NewFrame() ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX10_Init()?"); - if (!bd->pVertexShader) + if (!bd->pFontSampler) ImGui_ImplDX10_CreateDeviceObjects(); } @@ -724,7 +703,7 @@ static void ImGui_ImplDX10_SwapBuffers(ImGuiViewport* viewport, void*) vd->SwapChain->Present(0, 0); // Present without vsync } -void ImGui_ImplDX10_InitMultiViewportSupport() +void ImGui_ImplDX10_InitPlatformInterface() { ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Renderer_CreateWindow = ImGui_ImplDX10_CreateWindow; @@ -734,7 +713,7 @@ void ImGui_ImplDX10_InitMultiViewportSupport() platform_io.Renderer_SwapBuffers = ImGui_ImplDX10_SwapBuffers; } -void ImGui_ImplDX10_ShutdownMultiViewportSupport() +void ImGui_ImplDX10_ShutdownPlatformInterface() { ImGui::DestroyPlatformWindows(); } diff --git a/3rdparty/imgui/backends/imgui_impl_dx10.h b/3rdparty/imgui/backends/imgui_impl_dx10.h index 07bbd9f..39259bd 100644 --- a/3rdparty/imgui/backends/imgui_impl_dx10.h +++ b/3rdparty/imgui/backends/imgui_impl_dx10.h @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -19,27 +19,14 @@ #ifndef IMGUI_DISABLE struct ID3D10Device; -struct ID3D10SamplerState; -struct ID3D10Buffer; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device); IMGUI_IMPL_API void ImGui_ImplDX10_Shutdown(); IMGUI_IMPL_API void ImGui_ImplDX10_NewFrame(); IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data); // Use if you want to reset your rendering device without losing Dear ImGui state. -IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects(); - -// [BETA] Selected render state data shared with callbacks. -// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplDX10_RenderDrawData() call. -// (Please open an issue if you feel you need access to more data) -struct ImGui_ImplDX10_RenderState -{ - ID3D10Device* Device; - ID3D10SamplerState* SamplerDefault; - ID3D10Buffer* VertexConstantBuffer; -}; +IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects(); #endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/backends/imgui_impl_dx11.cpp b/3rdparty/imgui/backends/imgui_impl_dx11.cpp index 9c784b6..3d7ec7e 100644 --- a/3rdparty/imgui/backends/imgui_impl_dx11.cpp +++ b/3rdparty/imgui/backends/imgui_impl_dx11.cpp @@ -3,8 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -17,16 +16,13 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2025-01-06: DirectX11: Expose VertexConstantBuffer in ImGui_ImplDX11_RenderState. Reset projection matrix in ImDrawCallback_ResetRenderState handler. -// 2024-10-07: DirectX11: Changed default texture sampler to Clamp instead of Repeat/Wrap. -// 2024-10-07: DirectX11: Expose selected render state in ImGui_ImplDX11_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) // 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer. // 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled). -// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX11_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore. +// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore. // 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. // 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. // 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile(). @@ -87,11 +83,11 @@ static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData() } // Forward Declarations -static void ImGui_ImplDX11_InitMultiViewportSupport(); -static void ImGui_ImplDX11_ShutdownMultiViewportSupport(); +static void ImGui_ImplDX11_InitPlatformInterface(); +static void ImGui_ImplDX11_ShutdownPlatformInterface(); // Functions -static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* device_ctx) +static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx) { ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); @@ -103,50 +99,29 @@ static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceC vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; - device_ctx->RSSetViewports(1, &vp); - - // Setup orthographic projection matrix into our constant buffer - // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. - D3D11_MAPPED_SUBRESOURCE mapped_resource; - if (device_ctx->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) == S_OK) - { - VERTEX_CONSTANT_BUFFER_DX11* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX11*)mapped_resource.pData; - float L = draw_data->DisplayPos.x; - float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; - float T = draw_data->DisplayPos.y; - float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; - float mvp[4][4] = - { - { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, - { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.5f, 0.0f }, - { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, - }; - memcpy(&constant_buffer->mvp, mvp, sizeof(mvp)); - device_ctx->Unmap(bd->pVertexConstantBuffer, 0); - } + ctx->RSSetViewports(1, &vp); // Setup shader and vertex buffers unsigned int stride = sizeof(ImDrawVert); unsigned int offset = 0; - device_ctx->IASetInputLayout(bd->pInputLayout); - device_ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset); - device_ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); - device_ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - device_ctx->VSSetShader(bd->pVertexShader, nullptr, 0); - device_ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer); - device_ctx->PSSetShader(bd->pPixelShader, nullptr, 0); - device_ctx->PSSetSamplers(0, 1, &bd->pFontSampler); - device_ctx->GSSetShader(nullptr, nullptr, 0); - device_ctx->HSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used.. - device_ctx->DSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used.. - device_ctx->CSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used.. + ctx->IASetInputLayout(bd->pInputLayout); + ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset); + ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); + ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ctx->VSSetShader(bd->pVertexShader, nullptr, 0); + ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer); + ctx->PSSetShader(bd->pPixelShader, nullptr, 0); + ctx->PSSetSamplers(0, 1, &bd->pFontSampler); + ctx->GSSetShader(nullptr, nullptr, 0); + ctx->HSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used.. + ctx->DSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used.. + ctx->CSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used.. - // Setup render state + // Setup blend state const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; - device_ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff); - device_ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0); - device_ctx->RSSetState(bd->pRasterizerState); + ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff); + ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0); + ctx->RSSetState(bd->pRasterizerState); } // Render function @@ -157,7 +132,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) return; ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); - ID3D11DeviceContext* device = bd->pd3dDeviceContext; + ID3D11DeviceContext* ctx = bd->pd3dDeviceContext; // Create and grow vertex/index buffers if needed if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) @@ -190,22 +165,44 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) // Upload vertex/index data into a single contiguous GPU buffer D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource; - if (device->Map(bd->pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK) + if (ctx->Map(bd->pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK) return; - if (device->Map(bd->pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK) + if (ctx->Map(bd->pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK) return; ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData; ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData; for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - vtx_dst += draw_list->VtxBuffer.Size; - idx_dst += draw_list->IdxBuffer.Size; + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vtx_dst += cmd_list->VtxBuffer.Size; + idx_dst += cmd_list->IdxBuffer.Size; + } + ctx->Unmap(bd->pVB, 0); + ctx->Unmap(bd->pIB, 0); + + // Setup orthographic projection matrix into our constant buffer + // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. + { + D3D11_MAPPED_SUBRESOURCE mapped_resource; + if (ctx->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) + return; + VERTEX_CONSTANT_BUFFER_DX11* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX11*)mapped_resource.pData; + float L = draw_data->DisplayPos.x; + float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; + float T = draw_data->DisplayPos.y; + float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; + float mvp[4][4] = + { + { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, + { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.5f, 0.0f }, + { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, + }; + memcpy(&constant_buffer->mvp, mvp, sizeof(mvp)); + ctx->Unmap(bd->pVertexConstantBuffer, 0); } - device->Unmap(bd->pVB, 0); - device->Unmap(bd->pIB, 0); // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!) struct BACKUP_DX11_STATE @@ -234,35 +231,26 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) }; BACKUP_DX11_STATE old = {}; old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; - device->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects); - device->RSGetViewports(&old.ViewportsCount, old.Viewports); - device->RSGetState(&old.RS); - device->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask); - device->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef); - device->PSGetShaderResources(0, 1, &old.PSShaderResource); - device->PSGetSamplers(0, 1, &old.PSSampler); + ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects); + ctx->RSGetViewports(&old.ViewportsCount, old.Viewports); + ctx->RSGetState(&old.RS); + ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask); + ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef); + ctx->PSGetShaderResources(0, 1, &old.PSShaderResource); + ctx->PSGetSamplers(0, 1, &old.PSSampler); old.PSInstancesCount = old.VSInstancesCount = old.GSInstancesCount = 256; - device->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount); - device->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount); - device->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer); - device->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount); + ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount); + ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount); + ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer); + ctx->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount); - device->IAGetPrimitiveTopology(&old.PrimitiveTopology); - device->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset); - device->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); - device->IAGetInputLayout(&old.InputLayout); + ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology); + ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset); + ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); + ctx->IAGetInputLayout(&old.InputLayout); // Setup desired DX state - ImGui_ImplDX11_SetupRenderState(draw_data, device); - - // Setup render state structure (for callbacks and custom texture bindings) - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - ImGui_ImplDX11_RenderState render_state; - render_state.Device = bd->pd3dDevice; - render_state.DeviceContext = bd->pd3dDeviceContext; - render_state.SamplerDefault = bd->pFontSampler; - render_state.VertexConstantBuffer = bd->pVertexConstantBuffer; - platform_io.Renderer_RenderState = &render_state; + ImGui_ImplDX11_SetupRenderState(draw_data, ctx); // Render command lists // (Because we merged all buffers into a single one, we maintain our own offset into them) @@ -271,18 +259,18 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) ImVec2 clip_off = draw_data->DisplayPos; for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) - ImGui_ImplDX11_SetupRenderState(draw_data, device); + ImGui_ImplDX11_SetupRenderState(draw_data, ctx); else - pcmd->UserCallback(draw_list, pcmd); + pcmd->UserCallback(cmd_list, pcmd); } else { @@ -294,37 +282,36 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) // Apply scissor/clipping rectangle const D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y }; - device->RSSetScissorRects(1, &r); + ctx->RSSetScissorRects(1, &r); // Bind texture, Draw ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->GetTexID(); - device->PSSetShaderResources(0, 1, &texture_srv); - device->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset); + ctx->PSSetShaderResources(0, 1, &texture_srv); + ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset); } } - global_idx_offset += draw_list->IdxBuffer.Size; - global_vtx_offset += draw_list->VtxBuffer.Size; + global_idx_offset += cmd_list->IdxBuffer.Size; + global_vtx_offset += cmd_list->VtxBuffer.Size; } - platform_io.Renderer_RenderState = nullptr; // Restore modified DX state - device->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects); - device->RSSetViewports(old.ViewportsCount, old.Viewports); - device->RSSetState(old.RS); if (old.RS) old.RS->Release(); - device->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release(); - device->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release(); - device->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release(); - device->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release(); - device->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release(); + ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects); + ctx->RSSetViewports(old.ViewportsCount, old.Viewports); + ctx->RSSetState(old.RS); if (old.RS) old.RS->Release(); + ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release(); + ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release(); + ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release(); + ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release(); + ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release(); for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release(); - device->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release(); - device->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release(); - device->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release(); + ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release(); + ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release(); + ctx->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release(); for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release(); - device->IASetPrimitiveTopology(old.PrimitiveTopology); - device->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release(); - device->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release(); - device->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); + ctx->IASetPrimitiveTopology(old.PrimitiveTopology); + ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release(); + ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release(); + ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); } static void ImGui_ImplDX11_CreateFontsTexture() @@ -371,16 +358,21 @@ static void ImGui_ImplDX11_CreateFontsTexture() // Store our identifier io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView); -} -static void ImGui_ImplDX11_DestroyFontsTexture() -{ - ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); - if (bd->pFontTextureView) + // Create texture sampler + // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) { - bd->pFontTextureView->Release(); - bd->pFontTextureView = nullptr; - ImGui::GetIO().Fonts->SetTexID(0); // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well. + D3D11_SAMPLER_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + desc.MipLODBias = 0.f; + desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + desc.MinLOD = 0.f; + desc.MaxLOD = 0.f; + bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler); } } @@ -533,22 +525,6 @@ bool ImGui_ImplDX11_CreateDeviceObjects() bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState); } - // Create texture sampler - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) - { - D3D11_SAMPLER_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - desc.MipLODBias = 0.f; - desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - desc.MinLOD = 0.f; - desc.MaxLOD = 0.f; - bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler); - } - ImGui_ImplDX11_CreateFontsTexture(); return true; @@ -560,9 +536,8 @@ void ImGui_ImplDX11_InvalidateDeviceObjects() if (!bd->pd3dDevice) return; - ImGui_ImplDX11_DestroyFontsTexture(); - if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = nullptr; } + if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well. if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; } @@ -605,7 +580,8 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co bd->pd3dDevice->AddRef(); bd->pd3dDeviceContext->AddRef(); - ImGui_ImplDX11_InitMultiViewportSupport(); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplDX11_InitPlatformInterface(); return true; } @@ -616,7 +592,7 @@ void ImGui_ImplDX11_Shutdown() IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplDX11_ShutdownMultiViewportSupport(); + ImGui_ImplDX11_ShutdownPlatformInterface(); ImGui_ImplDX11_InvalidateDeviceObjects(); if (bd->pFactory) { bd->pFactory->Release(); } if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } @@ -744,7 +720,7 @@ static void ImGui_ImplDX11_SwapBuffers(ImGuiViewport* viewport, void*) vd->SwapChain->Present(0, 0); // Present without vsync } -static void ImGui_ImplDX11_InitMultiViewportSupport() +static void ImGui_ImplDX11_InitPlatformInterface() { ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Renderer_CreateWindow = ImGui_ImplDX11_CreateWindow; @@ -754,7 +730,7 @@ static void ImGui_ImplDX11_InitMultiViewportSupport() platform_io.Renderer_SwapBuffers = ImGui_ImplDX11_SwapBuffers; } -static void ImGui_ImplDX11_ShutdownMultiViewportSupport() +static void ImGui_ImplDX11_ShutdownPlatformInterface() { ImGui::DestroyPlatformWindows(); } diff --git a/3rdparty/imgui/backends/imgui_impl_dx11.h b/3rdparty/imgui/backends/imgui_impl_dx11.h index acdd62c..1713fbd 100644 --- a/3rdparty/imgui/backends/imgui_impl_dx11.h +++ b/3rdparty/imgui/backends/imgui_impl_dx11.h @@ -3,8 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -21,28 +20,14 @@ struct ID3D11Device; struct ID3D11DeviceContext; -struct ID3D11SamplerState; -struct ID3D11Buffer; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context); IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown(); IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame(); IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data); // Use if you want to reset your rendering device without losing Dear ImGui state. -IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); - -// [BETA] Selected render state data shared with callbacks. -// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplDX11_RenderDrawData() call. -// (Please open an issue if you feel you need access to more data) -struct ImGui_ImplDX11_RenderState -{ - ID3D11Device* Device; - ID3D11DeviceContext* DeviceContext; - ID3D11SamplerState* SamplerDefault; - ID3D11Buffer* VertexConstantBuffer; -}; +IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); #endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/backends/imgui_impl_dx12.cpp b/3rdparty/imgui/backends/imgui_impl_dx12.cpp index e53a0e7..cde8981 100644 --- a/3rdparty/imgui/backends/imgui_impl_dx12.cpp +++ b/3rdparty/imgui/backends/imgui_impl_dx12.cpp @@ -3,13 +3,17 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // FIXME: The transition from removing a viewport and moving the window in an existing hosted viewport tends to flicker. -// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification. -// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ +// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'. +// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*. +// To build this on 32-bit systems: +// - [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file) +// - [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like. +// - [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!) +// - [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file) // 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. @@ -21,15 +25,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2025-01-15: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own. -// 2024-12-09: DirectX12: Let user specifies the DepthStencilView format by setting ImGui_ImplDX12_InitInfo::DSVFormat. -// 2024-11-15: DirectX12: *BREAKING CHANGE* Changed ImGui_ImplDX12_Init() signature to take a ImGui_ImplDX12_InitInfo struct. Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete). -// 2024-11-15: DirectX12: *BREAKING CHANGE* User is now required to pass function pointers to allocate/free SRV Descriptors. We provide convenience legacy fields to pass a single descriptor, matching the old API, but upcoming features will want multiple. -// 2024-10-23: DirectX12: Unmap() call specify written range. The range is informational and may be used by debug tools. -// 2024-10-07: DirectX12: Changed default texture sampler to Clamp instead of Repeat/Wrap. -// 2024-10-07: DirectX12: Expose selected render state in ImGui_ImplDX12_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. -// 2024-10-07: DirectX12: Compiling with '#define ImTextureID=ImU64' is unnecessary now that dear imgui defaults ImTextureID to u64 instead of void*. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: DirectX12: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) @@ -60,30 +56,18 @@ #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. #endif -// DirectX12 data -struct ImGui_ImplDX12_RenderBuffers; - -struct ImGui_ImplDX12_Texture -{ - ID3D12Resource* pTextureResource; - D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle; - D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle; - - ImGui_ImplDX12_Texture() { memset((void*)this, 0, sizeof(*this)); } -}; - +// DirectX data struct ImGui_ImplDX12_Data { - ImGui_ImplDX12_InitInfo InitInfo; ID3D12Device* pd3dDevice; ID3D12RootSignature* pRootSignature; ID3D12PipelineState* pPipelineState; DXGI_FORMAT RTVFormat; - DXGI_FORMAT DSVFormat; + ID3D12Resource* pFontTextureResource; + D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle; + D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle; ID3D12DescriptorHeap* pd3dSrvDescHeap; UINT numFramesInFlight; - ImGui_ImplDX12_Texture FontTexture; - bool LegacySingleDescriptorUsed; ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -187,7 +171,7 @@ static void ImGui_ImplDX12_InitPlatformInterface(); static void ImGui_ImplDX12_ShutdownPlatformInterface(); // Functions -static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* command_list, ImGui_ImplDX12_RenderBuffers* fr) +static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx, ImGui_ImplDX12_RenderBuffers* fr) { ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); @@ -217,7 +201,7 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0.0f; - command_list->RSSetViewports(1, &vp); + ctx->RSSetViewports(1, &vp); // Bind shader and vertex buffers unsigned int stride = sizeof(ImDrawVert); @@ -227,21 +211,21 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic vbv.BufferLocation = fr->VertexBuffer->GetGPUVirtualAddress() + offset; vbv.SizeInBytes = fr->VertexBufferSize * stride; vbv.StrideInBytes = stride; - command_list->IASetVertexBuffers(0, 1, &vbv); + ctx->IASetVertexBuffers(0, 1, &vbv); D3D12_INDEX_BUFFER_VIEW ibv; memset(&ibv, 0, sizeof(D3D12_INDEX_BUFFER_VIEW)); ibv.BufferLocation = fr->IndexBuffer->GetGPUVirtualAddress(); ibv.SizeInBytes = fr->IndexBufferSize * sizeof(ImDrawIdx); ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; - command_list->IASetIndexBuffer(&ibv); - command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - command_list->SetPipelineState(bd->pPipelineState); - command_list->SetGraphicsRootSignature(bd->pRootSignature); - command_list->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0); + ctx->IASetIndexBuffer(&ibv); + ctx->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ctx->SetPipelineState(bd->pPipelineState); + ctx->SetGraphicsRootSignature(bd->pRootSignature); + ctx->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0); // Setup blend factor const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; - command_list->OMSetBlendFactor(blend_factor); + ctx->OMSetBlendFactor(blend_factor); } template @@ -253,13 +237,12 @@ static inline void SafeRelease(T*& res) } // Render function -void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* command_list) +void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx) { // Avoid rendering when minimized if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) return; - // FIXME: We are assuming that this only gets called once per frame! ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)draw_data->OwnerViewport->RendererUserData; vd->FrameIndex++; @@ -314,9 +297,9 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL } // Upload vertex/index data into a single contiguous GPU buffer - // During Map() we specify a null read range (as per DX12 API, this is informational and for tooling only) void* vtx_resource, *idx_resource; - D3D12_RANGE range = { 0, 0 }; + D3D12_RANGE range; + memset(&range, 0, sizeof(D3D12_RANGE)); if (fr->VertexBuffer->Map(0, &range, &vtx_resource) != S_OK) return; if (fr->IndexBuffer->Map(0, &range, &idx_resource) != S_OK) @@ -325,30 +308,17 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource; for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - vtx_dst += draw_list->VtxBuffer.Size; - idx_dst += draw_list->IdxBuffer.Size; + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vtx_dst += cmd_list->VtxBuffer.Size; + idx_dst += cmd_list->IdxBuffer.Size; } - - // During Unmap() we specify the written range (as per DX12 API, this is informational and for tooling only) - range.End = (SIZE_T)((intptr_t)vtx_dst - (intptr_t)vtx_resource); - IM_ASSERT(range.End == draw_data->TotalVtxCount * sizeof(ImDrawVert)); fr->VertexBuffer->Unmap(0, &range); - range.End = (SIZE_T)((intptr_t)idx_dst - (intptr_t)idx_resource); - IM_ASSERT(range.End == draw_data->TotalIdxCount * sizeof(ImDrawIdx)); fr->IndexBuffer->Unmap(0, &range); // Setup desired DX state - ImGui_ImplDX12_SetupRenderState(draw_data, command_list, fr); - - // Setup render state structure (for callbacks and custom texture bindings) - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - ImGui_ImplDX12_RenderState render_state; - render_state.Device = bd->pd3dDevice; - render_state.CommandList = command_list; - platform_io.Renderer_RenderState = &render_state; + ImGui_ImplDX12_SetupRenderState(draw_data, ctx, fr); // Render command lists // (Because we merged all buffers into a single one, we maintain our own offset into them) @@ -357,18 +327,18 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL ImVec2 clip_off = draw_data->DisplayPos; for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) - ImGui_ImplDX12_SetupRenderState(draw_data, command_list, fr); + ImGui_ImplDX12_SetupRenderState(draw_data, ctx, fr); else - pcmd->UserCallback(draw_list, pcmd); + pcmd->UserCallback(cmd_list, pcmd); } else { @@ -378,21 +348,18 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; - // Apply scissor/clipping rectangle + // Apply Scissor/clipping rectangle, Bind texture, Draw const D3D12_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y }; - command_list->RSSetScissorRects(1, &r); - - // Bind texture, Draw D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {}; texture_handle.ptr = (UINT64)pcmd->GetTexID(); - command_list->SetGraphicsRootDescriptorTable(1, texture_handle); - command_list->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); + ctx->SetGraphicsRootDescriptorTable(1, texture_handle); + ctx->RSSetScissorRects(1, &r); + ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); } } - global_idx_offset += draw_list->IdxBuffer.Size; - global_vtx_offset += draw_list->VtxBuffer.Size; + global_idx_offset += cmd_list->IdxBuffer.Size; + global_vtx_offset += cmd_list->VtxBuffer.Size; } - platform_io.Renderer_RenderState = nullptr; } static void ImGui_ImplDX12_CreateFontsTexture() @@ -405,7 +372,6 @@ static void ImGui_ImplDX12_CreateFontsTexture() io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Upload texture to graphics system - ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture; { D3D12_HEAP_PROPERTIES props; memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES)); @@ -431,11 +397,11 @@ static void ImGui_ImplDX12_CreateFontsTexture() bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pTexture)); - UINT upload_pitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u); - UINT upload_size = height * upload_pitch; + UINT uploadPitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u); + UINT uploadSize = height * uploadPitch; desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; desc.Alignment = 0; - desc.Width = upload_size; + desc.Width = uploadSize; desc.Height = 1; desc.DepthOrArraySize = 1; desc.MipLevels = 1; @@ -455,28 +421,26 @@ static void ImGui_ImplDX12_CreateFontsTexture() IM_ASSERT(SUCCEEDED(hr)); void* mapped = nullptr; - D3D12_RANGE range = { 0, upload_size }; + D3D12_RANGE range = { 0, uploadSize }; hr = uploadBuffer->Map(0, &range, &mapped); IM_ASSERT(SUCCEEDED(hr)); for (int y = 0; y < height; y++) - memcpy((void*) ((uintptr_t) mapped + y * upload_pitch), pixels + y * width * 4, width * 4); + memcpy((void*) ((uintptr_t) mapped + y * uploadPitch), pixels + y * width * 4, width * 4); uploadBuffer->Unmap(0, &range); D3D12_TEXTURE_COPY_LOCATION srcLocation = {}; - D3D12_TEXTURE_COPY_LOCATION dstLocation = {}; - { - srcLocation.pResource = uploadBuffer; - srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - srcLocation.PlacedFootprint.Footprint.Width = width; - srcLocation.PlacedFootprint.Footprint.Height = height; - srcLocation.PlacedFootprint.Footprint.Depth = 1; - srcLocation.PlacedFootprint.Footprint.RowPitch = upload_pitch; + srcLocation.pResource = uploadBuffer; + srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srcLocation.PlacedFootprint.Footprint.Width = width; + srcLocation.PlacedFootprint.Footprint.Height = height; + srcLocation.PlacedFootprint.Footprint.Depth = 1; + srcLocation.PlacedFootprint.Footprint.RowPitch = uploadPitch; - dstLocation.pResource = pTexture; - dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dstLocation.SubresourceIndex = 0; - } + D3D12_TEXTURE_COPY_LOCATION dstLocation = {}; + dstLocation.pResource = pTexture; + dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dstLocation.SubresourceIndex = 0; D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; @@ -490,9 +454,18 @@ static void ImGui_ImplDX12_CreateFontsTexture() hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)); IM_ASSERT(SUCCEEDED(hr)); - HANDLE event = ::CreateEvent(0, 0, 0, 0); + HANDLE event = CreateEvent(0, 0, 0, 0); IM_ASSERT(event != nullptr); + D3D12_COMMAND_QUEUE_DESC queueDesc = {}; + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + queueDesc.NodeMask = 1; + + ID3D12CommandQueue* cmdQueue = nullptr; + hr = bd->pd3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue)); + IM_ASSERT(SUCCEEDED(hr)); + ID3D12CommandAllocator* cmdAlloc = nullptr; hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc)); IM_ASSERT(SUCCEEDED(hr)); @@ -507,17 +480,17 @@ static void ImGui_ImplDX12_CreateFontsTexture() hr = cmdList->Close(); IM_ASSERT(SUCCEEDED(hr)); - ID3D12CommandQueue* cmdQueue = bd->InitInfo.CommandQueue; cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList); hr = cmdQueue->Signal(fence, 1); IM_ASSERT(SUCCEEDED(hr)); fence->SetEventOnCompletion(1, event); - ::WaitForSingleObject(event, INFINITE); + WaitForSingleObject(event, INFINITE); cmdList->Release(); cmdAlloc->Release(); - ::CloseHandle(event); + cmdQueue->Release(); + CloseHandle(event); fence->Release(); uploadBuffer->Release(); @@ -529,13 +502,21 @@ static void ImGui_ImplDX12_CreateFontsTexture() srvDesc.Texture2D.MipLevels = desc.MipLevels; srvDesc.Texture2D.MostDetailedMip = 0; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, font_tex->hFontSrvCpuDescHandle); - SafeRelease(font_tex->pTextureResource); - font_tex->pTextureResource = pTexture; + bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, bd->hFontSrvCpuDescHandle); + SafeRelease(bd->pFontTextureResource); + bd->pFontTextureResource = pTexture; } // Store our identifier - io.Fonts->SetTexID((ImTextureID)font_tex->hFontSrvGpuDescHandle.ptr); + // READ THIS IF THE STATIC_ASSERT() TRIGGERS: + // - Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'. + // - This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*. + // [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file) + // [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like. + // [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!) + // [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file) + static_assert(sizeof(ImTextureID) >= sizeof(bd->hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet."); + io.Fonts->SetTexID((ImTextureID)bd->hFontSrvGpuDescHandle.ptr); } bool ImGui_ImplDX12_CreateDeviceObjects() @@ -571,9 +552,9 @@ bool ImGui_ImplDX12_CreateDeviceObjects() // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. D3D12_STATIC_SAMPLER_DESC staticSampler = {}; staticSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; - staticSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; - staticSampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; - staticSampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + staticSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + staticSampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + staticSampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; staticSampler.MipLODBias = 0.f; staticSampler.MaxAnisotropy = 0; staticSampler.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; @@ -643,7 +624,6 @@ bool ImGui_ImplDX12_CreateDeviceObjects() psoDesc.SampleMask = UINT_MAX; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = bd->RTVFormat; - psoDesc.DSVFormat = bd->DSVFormat; psoDesc.SampleDesc.Count = 1; psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; @@ -786,18 +766,15 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() if (!bd || !bd->pd3dDevice) return; + ImGuiIO& io = ImGui::GetIO(); SafeRelease(bd->pRootSignature); SafeRelease(bd->pPipelineState); - - // Free SRV descriptor used by texture - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture; - bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, font_tex->hFontSrvCpuDescHandle, font_tex->hFontSrvGpuDescHandle); - SafeRelease(font_tex->pTextureResource); - io.Fonts->SetTexID(0); // We copied bd->hFontSrvGpuDescHandle to io.Fonts->TexID so let's clear that as well. + SafeRelease(bd->pFontTextureResource); + io.Fonts->SetTexID(0); // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well. } -bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) +bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap, + D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle) { ImGuiIO& io = ImGui::GetIO(); IMGUI_CHECKVERSION(); @@ -805,15 +782,6 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) // Setup backend capabilities flags ImGui_ImplDX12_Data* bd = IM_NEW(ImGui_ImplDX12_Data)(); - bd->InitInfo = *init_info; // Deep copy - init_info = &bd->InitInfo; - - bd->pd3dDevice = init_info->Device; - bd->RTVFormat = init_info->RTVFormat; - bd->DSVFormat = init_info->DSVFormat; - bd->numFramesInFlight = init_info->NumFramesInFlight; - bd->pd3dSrvDescHeap = init_info->SrvDescriptorHeap; - io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_dx12"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. @@ -821,56 +789,21 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui_ImplDX12_InitPlatformInterface(); + bd->pd3dDevice = device; + bd->RTVFormat = rtv_format; + bd->hFontSrvCpuDescHandle = font_srv_cpu_desc_handle; + bd->hFontSrvGpuDescHandle = font_srv_gpu_desc_handle; + bd->numFramesInFlight = num_frames_in_flight; + bd->pd3dSrvDescHeap = cbv_srv_heap; + // Create a dummy ImGui_ImplDX12_ViewportData holder for the main viewport, // Since this is created and managed by the application, we will only use the ->Resources[] fields. ImGuiViewport* main_viewport = ImGui::GetMainViewport(); main_viewport->RendererUserData = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight); -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - if (init_info->SrvDescriptorAllocFn == nullptr) - { - // Wrap legacy behavior of passing space for a single descriptor - IM_ASSERT(init_info->LegacySingleSrvCpuDescriptor.ptr != 0 && init_info->LegacySingleSrvGpuDescriptor.ptr != 0); - init_info->SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_handle) - { - ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); - IM_ASSERT(bd->LegacySingleDescriptorUsed == false); - *out_cpu_handle = bd->InitInfo.LegacySingleSrvCpuDescriptor; - *out_gpu_handle = bd->InitInfo.LegacySingleSrvGpuDescriptor; - bd->LegacySingleDescriptorUsed = true; - }; - init_info->SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_GPU_DESCRIPTOR_HANDLE) - { - ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); - IM_ASSERT(bd->LegacySingleDescriptorUsed == true); - bd->LegacySingleDescriptorUsed = false; - }; - } -#endif - - // Allocate 1 SRV descriptor for the font texture - IM_ASSERT(init_info->SrvDescriptorAllocFn != nullptr && init_info->SrvDescriptorFreeFn != nullptr); - init_info->SrvDescriptorAllocFn(&bd->InitInfo, &bd->FontTexture.hFontSrvCpuDescHandle, &bd->FontTexture.hFontSrvGpuDescHandle); - return true; } -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -// Legacy initialization API Obsoleted in 1.91.5 -// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap' -bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle) -{ - ImGui_ImplDX12_InitInfo init_info; - init_info.Device = device; - init_info.NumFramesInFlight = num_frames_in_flight; - init_info.RTVFormat = rtv_format; - init_info.SrvDescriptorHeap = srv_descriptor_heap; - init_info.LegacySingleSrvCpuDescriptor = font_srv_cpu_desc_handle; - init_info.LegacySingleSrvGpuDescriptor = font_srv_gpu_desc_handle;; - return ImGui_ImplDX12_Init(&init_info); -} -#endif - void ImGui_ImplDX12_Shutdown() { ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); diff --git a/3rdparty/imgui/backends/imgui_impl_dx12.h b/3rdparty/imgui/backends/imgui_impl_dx12.h index f90cb9b..f304cca 100644 --- a/3rdparty/imgui/backends/imgui_impl_dx12.h +++ b/3rdparty/imgui/backends/imgui_impl_dx12.h @@ -3,12 +3,11 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. -// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification. -// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ +// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'. +// See imgui_impl_dx12.cpp file for details. // 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. @@ -22,54 +21,25 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE #include // DXGI_FORMAT -#include // D3D12_CPU_DESCRIPTOR_HANDLE -// Initialization data, for ImGui_ImplDX12_Init() -struct ImGui_ImplDX12_InitInfo -{ - ID3D12Device* Device; - ID3D12CommandQueue* CommandQueue; - int NumFramesInFlight; - DXGI_FORMAT RTVFormat; // RenderTarget format. - DXGI_FORMAT DSVFormat; // DepthStencilView format. - void* UserData; +struct ID3D12Device; +struct ID3D12DescriptorHeap; +struct ID3D12GraphicsCommandList; +struct D3D12_CPU_DESCRIPTOR_HANDLE; +struct D3D12_GPU_DESCRIPTOR_HANDLE; - // Allocating SRV descriptors for textures is up to the application, so we provide callbacks. - // (current version of the backend will only allocate one descriptor, future versions will need to allocate more) - ID3D12DescriptorHeap* SrvDescriptorHeap; - void (*SrvDescriptorAllocFn)(ImGui_ImplDX12_InitInfo* info, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_desc_handle); - void (*SrvDescriptorFreeFn)(ImGui_ImplDX12_InitInfo* info, D3D12_CPU_DESCRIPTOR_HANDLE cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE gpu_desc_handle); -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - D3D12_CPU_DESCRIPTOR_HANDLE LegacySingleSrvCpuDescriptor; // To facilitate transition from single descriptor to allocator callback, you may use those. - D3D12_GPU_DESCRIPTOR_HANDLE LegacySingleSrvGpuDescriptor; -#endif - - ImGui_ImplDX12_InitInfo() { memset((void*)this, 0, sizeof(*this)); } -}; - -// Follow "Getting Started" link and check examples/ folder to learn about using backends! -IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* info); +// cmd_list is the command list that the implementation will use to render imgui draw lists. +// Before calling the render function, caller must prepare cmd_list by resetting it and setting the appropriate +// render target and descriptor heap that contains font_srv_cpu_desc_handle/font_srv_gpu_desc_handle. +// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture. +IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap, + D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle); IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown(); IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame(); IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list); -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -// Legacy initialization API Obsoleted in 1.91.5 -// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap' -IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle); -#endif - // Use if you want to reset your rendering device without losing Dear ImGui state. -IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects(); - -// [BETA] Selected render state data shared with callbacks. -// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplDX12_RenderDrawData() call. -// (Please open an issue if you feel you need access to more data) -struct ImGui_ImplDX12_RenderState -{ - ID3D12Device* Device; - ID3D12GraphicsCommandList* CommandList; -}; +IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects(); #endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/backends/imgui_impl_dx9.cpp b/3rdparty/imgui/backends/imgui_impl_dx9.cpp index d091d04..59475d2 100644 --- a/3rdparty/imgui/backends/imgui_impl_dx9.cpp +++ b/3rdparty/imgui/backends/imgui_impl_dx9.cpp @@ -3,8 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -17,8 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2024-10-07: DirectX9: Changed default texture sampler to Clamp instead of Repeat/Wrap. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2024-02-12: DirectX9: Using RGBA format when supported by the driver to avoid CPU side conversion. (#6575) // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). @@ -55,7 +53,6 @@ struct ImGui_ImplDX9_Data LPDIRECT3DTEXTURE9 FontTexture; int VertexBufferSize; int IndexBufferSize; - bool HasRgbaSupport; ImGui_ImplDX9_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; } }; @@ -82,8 +79,8 @@ static ImGui_ImplDX9_Data* ImGui_ImplDX9_GetBackendData() } // Forward Declarations -static void ImGui_ImplDX9_InitMultiViewportSupport(); -static void ImGui_ImplDX9_ShutdownMultiViewportSupport(); +static void ImGui_ImplDX9_InitPlatformInterface(); +static void ImGui_ImplDX9_ShutdownPlatformInterface(); static void ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows(); static void ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows(); @@ -99,45 +96,41 @@ static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data) vp.Height = (DWORD)draw_data->DisplaySize.y; vp.MinZ = 0.0f; vp.MaxZ = 1.0f; - - LPDIRECT3DDEVICE9 device = bd->pd3dDevice; - device->SetViewport(&vp); + bd->pd3dDevice->SetViewport(&vp); // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling. - device->SetPixelShader(nullptr); - device->SetVertexShader(nullptr); - device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); - device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); - device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); - device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); - device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - device->SetRenderState(D3DRS_ZENABLE, FALSE); - device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); - device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); - device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); - device->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); - device->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA); - device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); - device->SetRenderState(D3DRS_FOGENABLE, FALSE); - device->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE); - device->SetRenderState(D3DRS_SPECULARENABLE, FALSE); - device->SetRenderState(D3DRS_STENCILENABLE, FALSE); - device->SetRenderState(D3DRS_CLIPPING, TRUE); - device->SetRenderState(D3DRS_LIGHTING, FALSE); - device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); - device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); - device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); - device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); - device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); - device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); - device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + bd->pd3dDevice->SetPixelShader(nullptr); + bd->pd3dDevice->SetVertexShader(nullptr); + bd->pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + bd->pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + bd->pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + bd->pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + bd->pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + bd->pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + bd->pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + bd->pd3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + bd->pd3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE); + bd->pd3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA); + bd->pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + bd->pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE); + bd->pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE); + bd->pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + bd->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + bd->pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + bd->pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); // Setup orthographic projection matrix // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. @@ -155,9 +148,9 @@ static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data) 0.0f, 0.0f, 0.5f, 0.0f, (L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f } } }; - device->SetTransform(D3DTS_WORLD, &mat_identity); - device->SetTransform(D3DTS_VIEW, &mat_identity); - device->SetTransform(D3DTS_PROJECTION, &mat_projection); + bd->pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity); + bd->pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity); + bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection); } } @@ -168,53 +161,51 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) return; - ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); - LPDIRECT3DDEVICE9 device = bd->pd3dDevice; - // Create and grow buffers if needed + ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) { if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; - if (device->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, nullptr) < 0) + if (bd->pd3dDevice->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, nullptr) < 0) return; } if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount) { if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; - if (device->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0) + if (bd->pd3dDevice->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0) return; } // Backup the DX9 state - IDirect3DStateBlock9* state_block = nullptr; - if (device->CreateStateBlock(D3DSBT_ALL, &state_block) < 0) + IDirect3DStateBlock9* d3d9_state_block = nullptr; + if (bd->pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0) return; - if (state_block->Capture() < 0) + if (d3d9_state_block->Capture() < 0) { - state_block->Release(); + d3d9_state_block->Release(); return; } // Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to) D3DMATRIX last_world, last_view, last_projection; - device->GetTransform(D3DTS_WORLD, &last_world); - device->GetTransform(D3DTS_VIEW, &last_view); - device->GetTransform(D3DTS_PROJECTION, &last_projection); + bd->pd3dDevice->GetTransform(D3DTS_WORLD, &last_world); + bd->pd3dDevice->GetTransform(D3DTS_VIEW, &last_view); + bd->pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection); // Allocate buffers CUSTOMVERTEX* vtx_dst; ImDrawIdx* idx_dst; if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0) { - state_block->Release(); + d3d9_state_block->Release(); return; } if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0) { bd->pVB->Unlock(); - state_block->Release(); + d3d9_state_block->Release(); return; } @@ -224,9 +215,9 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) // 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; } for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - const ImDrawVert* vtx_src = draw_list->VtxBuffer.Data; - for (int i = 0; i < draw_list->VtxBuffer.Size; i++) + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data; + for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) { vtx_dst->pos[0] = vtx_src->pos.x; vtx_dst->pos[1] = vtx_src->pos.y; @@ -237,14 +228,14 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) vtx_dst++; vtx_src++; } - memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - idx_dst += draw_list->IdxBuffer.Size; + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + idx_dst += cmd_list->IdxBuffer.Size; } bd->pVB->Unlock(); bd->pIB->Unlock(); - device->SetStreamSource(0, bd->pVB, 0, sizeof(CUSTOMVERTEX)); - device->SetIndices(bd->pIB); - device->SetFVF(D3DFVF_CUSTOMVERTEX); + bd->pd3dDevice->SetStreamSource(0, bd->pVB, 0, sizeof(CUSTOMVERTEX)); + bd->pd3dDevice->SetIndices(bd->pIB); + bd->pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX); // Setup desired DX state ImGui_ImplDX9_SetupRenderState(draw_data); @@ -256,10 +247,10 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) ImVec2 clip_off = draw_data->DisplayPos; for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() @@ -267,7 +258,7 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) ImGui_ImplDX9_SetupRenderState(draw_data); else - pcmd->UserCallback(draw_list, pcmd); + pcmd->UserCallback(cmd_list, pcmd); } else { @@ -277,18 +268,16 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; - // Apply scissor/clipping rectangle + // Apply Scissor/clipping rectangle, Bind texture, Draw const RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y }; - device->SetScissorRect(&r); - - // Bind texture, Draw const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID(); - device->SetTexture(0, texture); - device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)draw_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3); + bd->pd3dDevice->SetTexture(0, texture); + bd->pd3dDevice->SetScissorRect(&r); + bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)cmd_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3); } } - global_idx_offset += draw_list->IdxBuffer.Size; - global_vtx_offset += draw_list->VtxBuffer.Size; + global_idx_offset += cmd_list->IdxBuffer.Size; + global_vtx_offset += cmd_list->VtxBuffer.Size; } // When using multi-viewports, it appears that there's an odd logic in DirectX9 which prevent subsequent windows @@ -297,31 +286,13 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 0, 0, 0); // Restore the DX9 transform - device->SetTransform(D3DTS_WORLD, &last_world); - device->SetTransform(D3DTS_VIEW, &last_view); - device->SetTransform(D3DTS_PROJECTION, &last_projection); + bd->pd3dDevice->SetTransform(D3DTS_WORLD, &last_world); + bd->pd3dDevice->SetTransform(D3DTS_VIEW, &last_view); + bd->pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection); // Restore the DX9 state - state_block->Apply(); - state_block->Release(); -} - -static bool ImGui_ImplDX9_CheckFormatSupport(LPDIRECT3DDEVICE9 pDevice, D3DFORMAT format) -{ - LPDIRECT3D9 pd3d = nullptr; - if (pDevice->GetDirect3D(&pd3d) != D3D_OK) - return false; - D3DDEVICE_CREATION_PARAMETERS param = {}; - D3DDISPLAYMODE mode = {}; - if (pDevice->GetCreationParameters(¶m) != D3D_OK || pDevice->GetDisplayMode(0, &mode) != D3D_OK) - { - pd3d->Release(); - return false; - } - // Font texture should support linear filter, color blend and write to render-target - bool support = (pd3d->CheckDeviceFormat(param.AdapterOrdinal, param.DeviceType, mode.Format, D3DUSAGE_DYNAMIC | D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, format)) == D3D_OK; - pd3d->Release(); - return support; + d3d9_state_block->Apply(); + d3d9_state_block->Release(); } bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) @@ -339,9 +310,9 @@ bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) bd->pd3dDevice = device; bd->pd3dDevice->AddRef(); - bd->HasRgbaSupport = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8); - ImGui_ImplDX9_InitMultiViewportSupport(); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplDX9_InitPlatformInterface(); return true; } @@ -352,7 +323,7 @@ void ImGui_ImplDX9_Shutdown() IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplDX9_ShutdownMultiViewportSupport(); + ImGui_ImplDX9_ShutdownPlatformInterface(); ImGui_ImplDX9_InvalidateDeviceObjects(); if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } io.BackendRendererName = nullptr; @@ -361,26 +332,22 @@ void ImGui_ImplDX9_Shutdown() IM_DELETE(bd); } -// Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices) -static void ImGui_ImplDX9_CopyTextureRegion(bool tex_use_colors, ImU32* src, int src_pitch, ImU32* dst, int dst_pitch, int w, int h) +static bool ImGui_ImplDX9_CheckFormatSupport(IDirect3DDevice9* pDevice, D3DFORMAT format) { -#ifndef IMGUI_USE_BGRA_PACKED_COLOR - ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); - const bool convert_rgba_to_bgra = (!bd->HasRgbaSupport && tex_use_colors); -#else - const bool convert_rgba_to_bgra = false; - IM_UNUSED(tex_use_colors); -#endif - for (int y = 0; y < h; y++) + IDirect3D9* pd3d = nullptr; + if (pDevice->GetDirect3D(&pd3d) != D3D_OK) + return false; + D3DDEVICE_CREATION_PARAMETERS param = {}; + D3DDISPLAYMODE mode = {}; + if (pDevice->GetCreationParameters(¶m) != D3D_OK || pDevice->GetDisplayMode(0, &mode) != D3D_OK) { - ImU32* src_p = (ImU32*)((unsigned char*)src + src_pitch * y); - ImU32* dst_p = (ImU32*)((unsigned char*)dst + dst_pitch * y); - if (convert_rgba_to_bgra) - for (int x = w; x > 0; x--, src_p++, dst_p++) // Convert copy - *dst_p = IMGUI_COL_TO_DX9_ARGB(*src_p); - else - memcpy(dst_p, src_p, w * 4); // Raw copy + pd3d->Release(); + return false; } + // Font texture should support linear filter, color blend and write to render-target + bool support = (pd3d->CheckDeviceFormat(param.AdapterOrdinal, param.DeviceType, mode.Format, D3DUSAGE_DYNAMIC | D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, format)) == D3D_OK; + pd3d->Release(); + return support; } static bool ImGui_ImplDX9_CreateFontsTexture() @@ -392,18 +359,39 @@ static bool ImGui_ImplDX9_CreateFontsTexture() int width, height, bytes_per_pixel; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel); + // Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices) +#ifndef IMGUI_USE_BGRA_PACKED_COLOR + const bool rgba_support = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8); + if (!rgba_support && io.Fonts->TexPixelsUseColors) + { + ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel); + for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++) + *dst = IMGUI_COL_TO_DX9_ARGB(*src); + pixels = (unsigned char*)dst_start; + } +#else + const bool rgba_support = false; +#endif + // Upload texture to graphics system bd->FontTexture = nullptr; - if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, bd->HasRgbaSupport ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0) + if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, rgba_support ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0) return false; D3DLOCKED_RECT tex_locked_rect; if (bd->FontTexture->LockRect(0, &tex_locked_rect, nullptr, 0) != D3D_OK) return false; - ImGui_ImplDX9_CopyTextureRegion(io.Fonts->TexPixelsUseColors, (ImU32*)pixels, width * bytes_per_pixel, (ImU32*)tex_locked_rect.pBits, (int)tex_locked_rect.Pitch, width, height); + for (int y = 0; y < height; y++) + memcpy((unsigned char*)tex_locked_rect.pBits + (size_t)tex_locked_rect.Pitch * y, pixels + (size_t)width * bytes_per_pixel * y, (size_t)width * bytes_per_pixel); bd->FontTexture->UnlockRect(0); // Store our identifier io.Fonts->SetTexID((ImTextureID)bd->FontTexture); + +#ifndef IMGUI_USE_BGRA_PACKED_COLOR + if (!rgba_support && io.Fonts->TexPixelsUseColors) + ImGui::MemFree(pixels); +#endif + return true; } @@ -549,7 +537,7 @@ static void ImGui_ImplDX9_SwapBuffers(ImGuiViewport* viewport, void*) IM_ASSERT(SUCCEEDED(hr) || hr == D3DERR_DEVICELOST); } -static void ImGui_ImplDX9_InitMultiViewportSupport() +static void ImGui_ImplDX9_InitPlatformInterface() { ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Renderer_CreateWindow = ImGui_ImplDX9_CreateWindow; @@ -559,7 +547,7 @@ static void ImGui_ImplDX9_InitMultiViewportSupport() platform_io.Renderer_SwapBuffers = ImGui_ImplDX9_SwapBuffers; } -static void ImGui_ImplDX9_ShutdownMultiViewportSupport() +static void ImGui_ImplDX9_ShutdownPlatformInterface() { ImGui::DestroyPlatformWindows(); } diff --git a/3rdparty/imgui/backends/imgui_impl_dx9.h b/3rdparty/imgui/backends/imgui_impl_dx9.h index 983d956..ecf7181 100644 --- a/3rdparty/imgui/backends/imgui_impl_dx9.h +++ b/3rdparty/imgui/backends/imgui_impl_dx9.h @@ -3,8 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -21,7 +20,6 @@ struct IDirect3DDevice9; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device); IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown(); IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame(); diff --git a/3rdparty/imgui/backends/imgui_impl_glfw.cpp b/3rdparty/imgui/backends/imgui_impl_glfw.cpp index 7a0b1f5..ce52939 100644 --- a/3rdparty/imgui/backends/imgui_impl_glfw.cpp +++ b/3rdparty/imgui/backends/imgui_impl_glfw.cpp @@ -6,11 +6,11 @@ // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only). -// [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 GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] +// [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 GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. -// Missing features or Issues: +// Issues: // [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -21,20 +21,9 @@ // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). // - Introduction, links and more at the top of imgui.cpp -// About Emscripten support: -// - Emscripten provides its own GLFW (3.2.1) implementation (syntax: "-sUSE_GLFW=3"), but Joystick is broken and several features are not supported (multiple windows, clipboard, timer, etc.) -// - A third-party Emscripten GLFW (3.4.0) implementation (syntax: "--use-port=contrib.glfw3") fixes the Joystick issue and implements all relevant features for the browser. -// See https://github.com/pongasoft/emscripten-glfw/blob/master/docs/Comparison.md for details. - // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2024-11-05: [Docking] Added Linux workaround for spurious mouse up events emitted while dragging and creating new viewport. (#3158, #7733, #7922) -// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: -// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn -// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn -// - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn -// 2024-07-31: Added ImGui_ImplGlfw_Sleep() helper function for usage by our examples app, since GLFW doesn't provide one. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2024-07-08: *BREAKING* Renamed ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback to ImGui_ImplGlfw_InstallEmscriptenCallbacks(), added GLFWWindow* parameter. // 2024-07-08: Emscripten: Added support for GLFW3 contrib port (GLFW 3.4.0 features + bug fixes): to enable, replace -sUSE_GLFW=3 with --use-port=contrib.glfw3 (requires emscripten 3.1.59+) (https://github.com/pongasoft/emscripten-glfw) // 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions. @@ -115,9 +104,6 @@ #endif #include // for glfwGetCocoaWindow() #endif -#ifndef _WIN32 -#include // for usleep() -#endif #ifdef __EMSCRIPTEN__ #include @@ -173,8 +159,6 @@ struct ImGui_ImplGlfw_Data double Time; GLFWwindow* MouseWindow; GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT]; - bool MouseIgnoreButtonUpWaitForFocusLoss; - bool MouseIgnoreButtonUp; ImVec2 LastValidMousePos; GLFWwindow* KeyOwnerWindows[GLFW_KEY_LAST]; bool InstalledCallbacks; @@ -214,17 +198,23 @@ static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() // Forward Declarations static void ImGui_ImplGlfw_UpdateMonitors(); -static void ImGui_ImplGlfw_InitMultiViewportSupport(); -static void ImGui_ImplGlfw_ShutdownMultiViewportSupport(); +static void ImGui_ImplGlfw_InitPlatformInterface(); +static void ImGui_ImplGlfw_ShutdownPlatformInterface(); // Functions - -// Not static to allow third-party code to use that if they want to (but undocumented) -ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode); -ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode) +static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) { - IM_UNUSED(scancode); - switch (keycode) + return glfwGetClipboardString((GLFWwindow*)user_data); +} + +static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text) +{ + glfwSetClipboardString((GLFWwindow*)user_data, text); +} + +static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key) +{ + switch (key) { case GLFW_KEY_TAB: return ImGuiKey_Tab; case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow; @@ -370,10 +360,6 @@ void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int acti if (bd->PrevUserCallbackMousebutton != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) bd->PrevUserCallbackMousebutton(window, button, action, mods); - // Workaround for Linux: ignore mouse up events which are following an focus loss following a viewport creation - if (bd->MouseIgnoreButtonUp && action == GLFW_RELEASE) - return; - ImGui_ImplGlfw_UpdateKeyModifiers(window); ImGuiIO& io = ImGui::GetIO(); @@ -396,7 +382,6 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yo io.AddMouseWheelEvent((float)xoffset, (float)yoffset); } -// FIXME: should this be baked into ImGui_ImplGlfw_KeyToImGuiKey()? then what about the values passed to io.SetKeyEventNativeData()? static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode) { #if GLFW_HAS_GETKEYNAME && !defined(EMSCRIPTEN_USE_EMBEDDED_GLFW3) @@ -447,7 +432,7 @@ void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, i keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode); ImGuiIO& io = ImGui::GetIO(); - ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode, scancode); + ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode); io.AddKeyEvent(imgui_key, (action == GLFW_PRESS)); io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code) } @@ -458,10 +443,6 @@ void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused) if (bd->PrevUserCallbackWindowFocus != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) bd->PrevUserCallbackWindowFocus(window, focused); - // Workaround for Linux: when losing focus with MouseIgnoreButtonUpWaitForFocusLoss set, we will temporarily ignore subsequent Mouse Up events - bd->MouseIgnoreButtonUp = (bd->MouseIgnoreButtonUpWaitForFocusLoss && focused == 0); - bd->MouseIgnoreButtonUpWaitForFocusLoss = false; - ImGuiIO& io = ImGui::GetIO(); io.AddFocusEvent(focused != 0); } @@ -597,11 +578,7 @@ void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows) } #ifdef __EMSCRIPTEN__ -#if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 34020240817 -void ImGui_ImplGlfw_EmscriptenOpenURL(const char* url) { if (url) emscripten::glfw3::OpenURL(url); } -#else -EM_JS(void, ImGui_ImplGlfw_EmscriptenOpenURL, (const char* url), { url = url ? UTF8ToString(url) : null; if (url) window.open(url, '_blank'); }); -#endif +EM_JS(void, ImGui_ImplGlfw_EmscriptenOpenURL, (char const* url), { url = url ? UTF8ToString(url) : null; if (url) window.open(url, '_blank'); }); #endif static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) @@ -628,11 +605,11 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw bd->Time = 0.0; bd->WantUpdateMonitors = true; - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* text) { glfwSetClipboardString(nullptr, text); }; - platform_io.Platform_GetClipboardTextFn = [](ImGuiContext*) { return glfwGetClipboardString(nullptr); }; + io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; + io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; + io.ClipboardUserData = bd->Window; #ifdef __EMSCRIPTEN__ - platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplGlfw_EmscriptenOpenURL(url); return true; }; + io.PlatformOpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplGlfw_EmscriptenOpenURL(url); return true; }; #endif // Create mouse cursors @@ -665,8 +642,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw if (install_callbacks) ImGui_ImplGlfw_InstallCallbacks(window); - // Update monitor a first time during init - // (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784) + // Update monitors the first time (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784) ImGui_ImplGlfw_UpdateMonitors(); glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback); @@ -680,7 +656,8 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw #else IM_UNUSED(main_viewport); #endif - ImGui_ImplGlfw_InitMultiViewportSupport(); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplGlfw_InitPlatformInterface(); // Windows: register a WndProc hook so we can intercept some messages. #ifdef _WIN32 @@ -689,23 +666,6 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc); #endif - // Emscripten: the same application can run on various platforms, so we detect the Apple platform at runtime - // to override io.ConfigMacOSXBehaviors from its default (which is always false in Emscripten). -#ifdef __EMSCRIPTEN__ -#if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 34020240817 - if (emscripten::glfw3::IsRuntimePlatformApple()) - { - ImGui::GetIO().ConfigMacOSXBehaviors = true; - - // Due to how the browser (poorly) handles the Meta Key, this line essentially disables repeats when used. - // This means that Meta + V only registers a single key-press, even if the keys are held. - // This is a compromise for dealing with this issue in ImGui since ImGui implements key repeat itself. - // See https://github.com/pongasoft/emscripten-glfw/blob/v3.4.0.20240817/docs/Usage.md#the-problem-of-the-super-key - emscripten::glfw3::SetSuperPlusKeyTimeouts(10, 10); - } -#endif -#endif - bd->ClientApi = client_api; return true; } @@ -731,7 +691,7 @@ void ImGui_ImplGlfw_Shutdown() IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplGlfw_ShutdownMultiViewportSupport(); + ImGui_ImplGlfw_ShutdownPlatformInterface(); if (bd->InstalledCallbacks) ImGui_ImplGlfw_RestoreCallbacks(bd->Window); @@ -776,7 +736,7 @@ static void ImGui_ImplGlfw_UpdateMouseData() #endif if (is_window_focused) { - // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user) + // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) // When multi-viewports are enabled, all Dear ImGui positions are same as OS positions. if (io.WantSetMousePos) glfwSetCursorPos(window, (double)(mouse_pos_prev.x - viewport->Pos.x), (double)(mouse_pos_prev.y - viewport->Pos.y)); @@ -942,8 +902,6 @@ static void ImGui_ImplGlfw_UpdateMonitors() // Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime. float x_scale, y_scale; glfwGetMonitorContentScale(glfw_monitors[n], &x_scale, &y_scale); - if (x_scale == 0.0f) - continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902. monitor.DpiScale = x_scale; #endif monitor.PlatformHandle = (void*)glfw_monitors[n]; // [...] GLFW doc states: "guaranteed to be valid only until the monitor configuration changes" @@ -976,7 +934,6 @@ void ImGui_ImplGlfw_NewFrame() io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f); bd->Time = current_time; - bd->MouseIgnoreButtonUp = false; ImGui_ImplGlfw_UpdateMouseData(); ImGui_ImplGlfw_UpdateMouseCursor(); @@ -984,16 +941,6 @@ void ImGui_ImplGlfw_NewFrame() ImGui_ImplGlfw_UpdateGamepads(); } -// GLFW doesn't provide a portable sleep function -void ImGui_ImplGlfw_Sleep(int milliseconds) -{ -#ifdef _WIN32 - ::Sleep(milliseconds); -#else - usleep(milliseconds * 1000); -#endif -} - #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 static EM_BOOL ImGui_ImplGlfw_OnCanvasSizeChange(int event_type, const EmscriptenUiEvent* event, void* user_data) { @@ -1064,7 +1011,7 @@ struct ImGui_ImplGlfw_ViewportData WNDPROC PrevWndProc; #endif - ImGui_ImplGlfw_ViewportData() { memset((void*)this, 0, sizeof(*this)); IgnoreWindowSizeEventFrame = IgnoreWindowPosEventFrame = -1; } + ImGui_ImplGlfw_ViewportData() { memset(this, 0, sizeof(*this)); IgnoreWindowSizeEventFrame = IgnoreWindowPosEventFrame = -1; } ~ImGui_ImplGlfw_ViewportData() { IM_ASSERT(Window == nullptr); } }; @@ -1116,11 +1063,6 @@ static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport) ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)(); viewport->PlatformUserData = vd; - // Workaround for Linux: ignore mouse up events corresponding to losing focus of the previously focused window (#7733, #3158, #7922) -#ifdef __linux__ - bd->MouseIgnoreButtonUpWaitForFocusLoss = true; -#endif - // GLFW 3.2 unfortunately always set focus on glfwCreateWindow() if GLFW_VISIBLE is set, regardless of GLFW_FOCUSED // With GLFW 3.3, the hint GLFW_FOCUS_ON_SHOW fixes this problem glfwWindowHint(GLFW_VISIBLE, false); @@ -1351,7 +1293,7 @@ static int ImGui_ImplGlfw_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_inst } #endif // GLFW_HAS_VULKAN -static void ImGui_ImplGlfw_InitMultiViewportSupport() +static void ImGui_ImplGlfw_InitPlatformInterface() { // Register platform interface (will be coupled with a renderer interface) ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); @@ -1386,7 +1328,7 @@ static void ImGui_ImplGlfw_InitMultiViewportSupport() main_viewport->PlatformHandle = (void*)bd->Window; } -static void ImGui_ImplGlfw_ShutdownMultiViewportSupport() +static void ImGui_ImplGlfw_ShutdownPlatformInterface() { ImGui::DestroyPlatformWindows(); } diff --git a/3rdparty/imgui/backends/imgui_impl_glfw.h b/3rdparty/imgui/backends/imgui_impl_glfw.h index 16930d1..91c4523 100644 --- a/3rdparty/imgui/backends/imgui_impl_glfw.h +++ b/3rdparty/imgui/backends/imgui_impl_glfw.h @@ -6,11 +6,11 @@ // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only). -// [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 GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] +// [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 GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. -// Missing features or Issues: +// Issues: // [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -28,7 +28,6 @@ struct GLFWwindow; struct GLFWmonitor; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks); IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks); IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks); @@ -61,7 +60,4 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event); -// GLFW helpers -IMGUI_IMPL_API void ImGui_ImplGlfw_Sleep(int milliseconds); - #endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/backends/imgui_impl_glut.cpp b/3rdparty/imgui/backends/imgui_impl_glut.cpp index 0459196..0678603 100644 --- a/3rdparty/imgui/backends/imgui_impl_glut.cpp +++ b/3rdparty/imgui/backends/imgui_impl_glut.cpp @@ -6,14 +6,13 @@ // !!! Nowadays, prefer using GLFW or SDL instead! // Implemented features: -// [X] Platform: Partial 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 GLUT values are obsolete since 1.87 and not supported since 1.91.5] -// Missing features or Issues: +// [X] Platform: Partial 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 GLUT values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// Missing features: // [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I // [ ] Platform: Missing horizontal mouse wheel support. // [ ] Platform: Missing mouse cursor shape/visibility support. // [ ] Platform: Missing clipboard support (not supported by Glut). // [ ] Platform: Missing gamepad support. -// [ ] Platform: Missing multi-viewport support (multiple windows). // 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/3rdparty/imgui/backends/imgui_impl_glut.h b/3rdparty/imgui/backends/imgui_impl_glut.h index d5d01a2..0067192 100644 --- a/3rdparty/imgui/backends/imgui_impl_glut.h +++ b/3rdparty/imgui/backends/imgui_impl_glut.h @@ -6,14 +6,13 @@ // !!! Nowadays, prefer using GLFW or SDL instead! // Implemented features: -// [X] Platform: Partial 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 GLUT values are obsolete since 1.87 and not supported since 1.91.5] -// Missing features or Issues: +// [X] Platform: Partial 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 GLUT values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// Missing features: // [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I // [ ] Platform: Missing horizontal mouse wheel support. // [ ] Platform: Missing mouse cursor shape/visibility support. // [ ] Platform: Missing clipboard support (not supported by Glut). // [ ] Platform: Missing gamepad support. -// [ ] Platform: Missing multi-viewport support (multiple windows). // 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. @@ -27,7 +26,6 @@ #ifndef IMGUI_DISABLE #include "imgui.h" // IMGUI_IMPL_API -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplGLUT_Init(); IMGUI_IMPL_API void ImGui_ImplGLUT_InstallFuncs(); IMGUI_IMPL_API void ImGui_ImplGLUT_Shutdown(); diff --git a/3rdparty/imgui/backends/imgui_impl_metal.h b/3rdparty/imgui/backends/imgui_impl_metal.h index dcf96ba..d9540fb 100644 --- a/3rdparty/imgui/backends/imgui_impl_metal.h +++ b/3rdparty/imgui/backends/imgui_impl_metal.h @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -26,7 +26,6 @@ @class MTLRenderPassDescriptor; @protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id device); IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown(); IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor); @@ -53,7 +52,6 @@ IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects(); #include #ifndef __OBJC__ -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplMetal_Init(MTL::Device* device); IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown(); IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor); diff --git a/3rdparty/imgui/backends/imgui_impl_metal.mm b/3rdparty/imgui/backends/imgui_impl_metal.mm index b90e506..22aa37e 100644 --- a/3rdparty/imgui/backends/imgui_impl_metal.mm +++ b/3rdparty/imgui/backends/imgui_impl_metal.mm @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -16,8 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-XX-XX: Metal: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2025-01-08: Metal: Fixed memory leaks when using metal-cpp (#8276, #8166) or when using multiple contexts (#7419). +// 2024-XX-XX: Metal: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-08-23: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'. // 2022-07-05: Metal: Add dispatch synchronization. // 2022-06-30: Metal: Use __bridge for ARC based systems. @@ -42,8 +41,8 @@ #import // Forward Declarations -static void ImGui_ImplMetal_InitMultiViewportSupport(); -static void ImGui_ImplMetal_ShutdownMultiViewportSupport(); +static void ImGui_ImplMetal_InitPlatformInterface(); +static void ImGui_ImplMetal_ShutdownPlatformInterface(); static void ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows(); static void ImGui_ImplMetal_InvalidateDeviceObjectsForPlatformWindows(); @@ -85,7 +84,7 @@ struct ImGui_ImplMetal_Data { MetalContext* SharedMetalContext; - ImGui_ImplMetal_Data() { memset((void*)this, 0, sizeof(*this)); } + ImGui_ImplMetal_Data() { memset(this, 0, sizeof(*this)); } }; static ImGui_ImplMetal_Data* ImGui_ImplMetal_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplMetal_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } @@ -146,7 +145,8 @@ bool ImGui_ImplMetal_Init(id device) bd->SharedMetalContext = [[MetalContext alloc] init]; bd->SharedMetalContext.device = device; - ImGui_ImplMetal_InitMultiViewportSupport(); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplMetal_InitPlatformInterface(); return true; } @@ -154,9 +154,8 @@ bool ImGui_ImplMetal_Init(id device) void ImGui_ImplMetal_Shutdown() { ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); - IM_UNUSED(bd); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); - ImGui_ImplMetal_ShutdownMultiViewportSupport(); + ImGui_ImplMetal_ShutdownPlatformInterface(); ImGui_ImplMetal_DestroyDeviceObjects(); ImGui_ImplMetal_DestroyBackendData(); @@ -170,11 +169,8 @@ void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor) { ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); IM_ASSERT(bd != nil && "Context or backend not initialized! Did you call ImGui_ImplMetal_Init()?"); -#ifdef IMGUI_IMPL_METAL_CPP - bd->SharedMetalContext.framebufferDescriptor = [[[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor]autorelease]; -#else bd->SharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor]; -#endif + if (bd->SharedMetalContext.depthStencilState == nil) ImGui_ImplMetal_CreateDeviceObjects(bd->SharedMetalContext.device); } @@ -263,14 +259,14 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, id c size_t indexBufferOffset = 0; for (int n = 0; n < drawData->CmdListsCount; n++) { - const ImDrawList* draw_list = drawData->CmdLists[n]; + const ImDrawList* cmd_list = drawData->CmdLists[n]; - memcpy((char*)vertexBuffer.buffer.contents + vertexBufferOffset, draw_list->VtxBuffer.Data, (size_t)draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy((char*)indexBuffer.buffer.contents + indexBufferOffset, draw_list->IdxBuffer.Data, (size_t)draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + memcpy((char*)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy((char*)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { // User callback, registered via ImDrawList::AddCallback() @@ -278,7 +274,7 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, id c if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) ImGui_ImplMetal_SetupRenderState(drawData, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, vertexBufferOffset); else - pcmd->UserCallback(draw_list, pcmd); + pcmd->UserCallback(cmd_list, pcmd); } else { @@ -308,7 +304,7 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, id c // Bind texture, Draw if (ImTextureID tex_id = pcmd->GetTexID()) - [commandEncoder setFragmentTexture:(__bridge id)(void*)(intptr_t)(tex_id) atIndex:0]; + [commandEncoder setFragmentTexture:(__bridge id)(tex_id) atIndex:0]; [commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0]; [commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle @@ -319,18 +315,21 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, id c } } - vertexBufferOffset += (size_t)draw_list->VtxBuffer.Size * sizeof(ImDrawVert); - indexBufferOffset += (size_t)draw_list->IdxBuffer.Size * sizeof(ImDrawIdx); + vertexBufferOffset += (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert); + indexBufferOffset += (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx); } - __block MetalContext* sharedMetalContext = bd->SharedMetalContext; [commandBuffer addCompletedHandler:^(id) { dispatch_async(dispatch_get_main_queue(), ^{ - @synchronized(bd->SharedMetalContext.bufferCache) + ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); + if (bd != nullptr) { - [sharedMetalContext.bufferCache addObject:vertexBuffer]; - [sharedMetalContext.bufferCache addObject:indexBuffer]; + @synchronized(bd->SharedMetalContext.bufferCache) + { + [bd->SharedMetalContext.bufferCache addObject:vertexBuffer]; + [bd->SharedMetalContext.bufferCache addObject:indexBuffer]; + } } }); }]; @@ -361,7 +360,7 @@ bool ImGui_ImplMetal_CreateFontsTexture(id device) id texture = [device newTextureWithDescriptor:textureDescriptor]; [texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)width, (NSUInteger)height) mipmapLevel:0 withBytes:pixels bytesPerRow:(NSUInteger)width * 4]; bd->SharedMetalContext.fontTexture = texture; - io.Fonts->SetTexID((ImTextureID)(intptr_t)(__bridge void*)bd->SharedMetalContext.fontTexture); // ImTextureID == ImU64 + io.Fonts->SetTexID((__bridge void*)bd->SharedMetalContext.fontTexture); // ImTextureID == void* return (bd->SharedMetalContext.fontTexture != nil); } @@ -382,10 +381,8 @@ bool ImGui_ImplMetal_CreateDeviceObjects(id device) depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways; bd->SharedMetalContext.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor]; ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows(); -#ifdef IMGUI_IMPL_METAL_CPP - [depthStencilDescriptor release]; -#endif ImGui_ImplMetal_CreateFontsTexture(device); + return true; } @@ -512,7 +509,7 @@ static void ImGui_ImplMetal_RenderWindow(ImGuiViewport* viewport, void*) [commandBuffer commit]; } -static void ImGui_ImplMetal_InitMultiViewportSupport() +static void ImGui_ImplMetal_InitPlatformInterface() { ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Renderer_CreateWindow = ImGui_ImplMetal_CreateWindow; @@ -521,7 +518,7 @@ static void ImGui_ImplMetal_InitMultiViewportSupport() platform_io.Renderer_RenderWindow = ImGui_ImplMetal_RenderWindow; } -static void ImGui_ImplMetal_ShutdownMultiViewportSupport() +static void ImGui_ImplMetal_ShutdownPlatformInterface() { ImGui::DestroyPlatformWindows(); } diff --git a/3rdparty/imgui/backends/imgui_impl_opengl2.cpp b/3rdparty/imgui/backends/imgui_impl_opengl2.cpp index 122d1ed..51ea82c 100644 --- a/3rdparty/imgui/backends/imgui_impl_opengl2.cpp +++ b/3rdparty/imgui/backends/imgui_impl_opengl2.cpp @@ -4,8 +4,6 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. -// Missing features or Issues: -// [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // 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. @@ -25,8 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2024-06-28: OpenGL: ImGui_ImplOpenGL2_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL2_DestroyFontsTexture(). (#7748) // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-12-08: OpenGL: Fixed mishandling of the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86. @@ -71,16 +68,6 @@ #include #endif -// [Debugging] -//#define IMGUI_IMPL_OPENGL_DEBUG -#ifdef IMGUI_IMPL_OPENGL_DEBUG -#include -#define GL_CALL(_CALL) do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0) // Call with error check -#else -#define GL_CALL(_CALL) _CALL // Call without error check -#endif - -// OpenGL data struct ImGui_ImplOpenGL2_Data { GLuint FontTexture; @@ -96,8 +83,8 @@ static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_GetBackendData() } // Forward Declarations -static void ImGui_ImplOpenGL2_InitMultiViewportSupport(); -static void ImGui_ImplOpenGL2_ShutdownMultiViewportSupport(); +static void ImGui_ImplOpenGL2_InitPlatformInterface(); +static void ImGui_ImplOpenGL2_ShutdownPlatformInterface(); // Functions bool ImGui_ImplOpenGL2_Init() @@ -112,7 +99,8 @@ bool ImGui_ImplOpenGL2_Init() io.BackendRendererName = "imgui_impl_opengl2"; io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) - ImGui_ImplOpenGL2_InitMultiViewportSupport(); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplOpenGL2_InitPlatformInterface(); return true; } @@ -123,7 +111,7 @@ void ImGui_ImplOpenGL2_Shutdown() IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplOpenGL2_ShutdownMultiViewportSupport(); + ImGui_ImplOpenGL2_ShutdownPlatformInterface(); ImGui_ImplOpenGL2_DestroyDeviceObjects(); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; @@ -176,7 +164,7 @@ static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_wid // Setup viewport, orthographic projection matrix // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. - GL_CALL(glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height)); + glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); @@ -216,16 +204,16 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) // Render command lists for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data; - const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; + const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + offsetof(ImDrawVert, pos))); glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + offsetof(ImDrawVert, uv))); glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + offsetof(ImDrawVert, col))); - for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { // User callback, registered via ImDrawList::AddCallback() @@ -233,7 +221,7 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height); else - pcmd->UserCallback(draw_list, pcmd); + pcmd->UserCallback(cmd_list, pcmd); } else { @@ -287,8 +275,6 @@ bool ImGui_ImplOpenGL2_CreateFontsTexture() glBindTexture(GL_TEXTURE_2D, bd->FontTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); @@ -341,13 +327,13 @@ static void ImGui_ImplOpenGL2_RenderWindow(ImGuiViewport* viewport, void*) ImGui_ImplOpenGL2_RenderDrawData(viewport->DrawData); } -static void ImGui_ImplOpenGL2_InitMultiViewportSupport() +static void ImGui_ImplOpenGL2_InitPlatformInterface() { ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL2_RenderWindow; } -static void ImGui_ImplOpenGL2_ShutdownMultiViewportSupport() +static void ImGui_ImplOpenGL2_ShutdownPlatformInterface() { ImGui::DestroyPlatformWindows(); } diff --git a/3rdparty/imgui/backends/imgui_impl_opengl2.h b/3rdparty/imgui/backends/imgui_impl_opengl2.h index c7b40e0..be8fb6c 100644 --- a/3rdparty/imgui/backends/imgui_impl_opengl2.h +++ b/3rdparty/imgui/backends/imgui_impl_opengl2.h @@ -4,8 +4,6 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. -// Missing features or Issues: -// [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // 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. @@ -27,7 +25,6 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplOpenGL2_Init(); IMGUI_IMPL_API void ImGui_ImplOpenGL2_Shutdown(); IMGUI_IMPL_API void ImGui_ImplOpenGL2_NewFrame(); diff --git a/3rdparty/imgui/backends/imgui_impl_opengl3.cpp b/3rdparty/imgui/backends/imgui_impl_opengl3.cpp index 0d683a4..259b3b6 100644 --- a/3rdparty/imgui/backends/imgui_impl_opengl3.cpp +++ b/3rdparty/imgui/backends/imgui_impl_opengl3.cpp @@ -5,7 +5,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! -// [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!] +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only). // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // About WebGL/ES: @@ -23,8 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2024-06-28: OpenGL: ImGui_ImplOpenGL3_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL3_DestroyFontsTexture(). (#7748) // 2024-05-07: OpenGL: Update loader for Linux to support EGL/GLVND. (#7562) // 2024-04-16: OpenGL: Detect ES3 contexts on desktop based on version string, to e.g. avoid calling glPolygonMode() on them. (#7447) @@ -127,7 +126,6 @@ // Clang/GCC warnings with -Weverything #if defined(__clang__) #pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: ignore unknown flags #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness #pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used @@ -139,7 +137,6 @@ #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' #pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader) -#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 #endif // GL includes @@ -167,7 +164,6 @@ // In the rest of your app/engine, you can use another loader of your choice (gl3w, glew, glad, glbinding, glext, glLoadGen, etc.). // If you happen to be developing a new feature for this backend (imgui_impl_opengl3.cpp): // - You may need to regenerate imgui_impl_opengl3_loader.h to add new symbols. See https://github.com/dearimgui/gl3w_stripped -// Typically you would run: python3 ./gl3w_gen.py --output ../imgui/backends/imgui_impl_opengl3_loader.h --ref ../imgui/backends/imgui_impl_opengl3.cpp ./extra_symbols.txt // - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases // Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version. #define IMGL3W_IMPL @@ -255,8 +251,8 @@ static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData() } // Forward Declarations -static void ImGui_ImplOpenGL3_InitMultiViewportSupport(); -static void ImGui_ImplOpenGL3_ShutdownMultiViewportSupport(); +static void ImGui_ImplOpenGL3_InitPlatformInterface(); +static void ImGui_ImplOpenGL3_ShutdownPlatformInterface(); // OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only) #ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY @@ -304,13 +300,13 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) io.BackendRendererName = "imgui_impl_opengl3"; // Query for GL version (e.g. 320 for GL 3.2) - const char* gl_version_str = (const char*)glGetString(GL_VERSION); #if defined(IMGUI_IMPL_OPENGL_ES2) // GLES 2 bd->GlVersion = 200; bd->GlProfileIsES2 = true; #else // Desktop or GLES 3 + const char* gl_version_str = (const char*)glGetString(GL_VERSION); GLint major = 0; GLint minor = 0; glGetIntegerv(GL_MAJOR_VERSION, &major); @@ -343,7 +339,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) #endif #ifdef IMGUI_IMPL_OPENGL_DEBUG - printf("GlVersion = %d, \"%s\"\nGlProfileIsCompat = %d\nGlProfileMask = 0x%X\nGlProfileIsES2/IsEs3 = %d/%d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", bd->GlVersion, gl_version_str, bd->GlProfileIsCompat, bd->GlProfileMask, bd->GlProfileIsES2, bd->GlProfileIsES3, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG] + printf("GlVersion = %d, \"%s\"\nGlProfileIsCompat = %d\nGlProfileMask = 0x%X\nGlProfileIsES2 = %d, GlProfileIsES3 = %d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", bd->GlVersion, gl_version_str, bd->GlProfileIsCompat, bd->GlProfileMask, bd->GlProfileIsES2, bd->GlProfileIsES3, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG] #endif #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET @@ -391,7 +387,8 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) } #endif - ImGui_ImplOpenGL3_InitMultiViewportSupport(); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplOpenGL3_InitPlatformInterface(); return true; } @@ -402,7 +399,7 @@ void ImGui_ImplOpenGL3_Shutdown() IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplOpenGL3_ShutdownMultiViewportSupport(); + ImGui_ImplOpenGL3_ShutdownPlatformInterface(); ImGui_ImplOpenGL3_DestroyDeviceObjects(); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; @@ -563,7 +560,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) // Render command lists for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; + const ImDrawList* cmd_list = draw_data->CmdLists[n]; // Upload vertex/index buffers // - OpenGL drivers are in a very sorry state nowadays.... @@ -573,8 +570,8 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) // - We are now back to using exclusively glBufferData(). So bd->UseBufferSubData IS ALWAYS FALSE in this code. // We are keeping the old code path for a while in case people finding new issues may want to test the bd->UseBufferSubData path. // - See https://github.com/ocornut/imgui/issues/4468 and please report any corruption issues. - const GLsizeiptr vtx_buffer_size = (GLsizeiptr)draw_list->VtxBuffer.Size * (int)sizeof(ImDrawVert); - const GLsizeiptr idx_buffer_size = (GLsizeiptr)draw_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx); + const GLsizeiptr vtx_buffer_size = (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert); + const GLsizeiptr idx_buffer_size = (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx); if (bd->UseBufferSubData) { if (bd->VertexBufferSize < vtx_buffer_size) @@ -587,18 +584,18 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) bd->IndexBufferSize = idx_buffer_size; GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, bd->IndexBufferSize, nullptr, GL_STREAM_DRAW)); } - GL_CALL(glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, (const GLvoid*)draw_list->VtxBuffer.Data)); - GL_CALL(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, (const GLvoid*)draw_list->IdxBuffer.Data)); + GL_CALL(glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data)); + GL_CALL(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data)); } else { - GL_CALL(glBufferData(GL_ARRAY_BUFFER, vtx_buffer_size, (const GLvoid*)draw_list->VtxBuffer.Data, GL_STREAM_DRAW)); - GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size, (const GLvoid*)draw_list->IdxBuffer.Data, GL_STREAM_DRAW)); + GL_CALL(glBufferData(GL_ARRAY_BUFFER, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW)); + GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW)); } - for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() @@ -606,7 +603,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); else - pcmd->UserCallback(draw_list, pcmd); + pcmd->UserCallback(cmd_list, pcmd); } else { @@ -694,14 +691,12 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture() GL_CALL(glBindTexture(GL_TEXTURE_2D, bd->FontTexture)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); #ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); #endif GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); - // Store identifier + // Store our identifier io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture); // Restore state @@ -907,15 +902,13 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() // Create shaders const GLchar* vertex_shader_with_version[2] = { bd->GlslVersionString, vertex_shader }; - GLuint vert_handle; - GL_CALL(vert_handle = glCreateShader(GL_VERTEX_SHADER)); + GLuint vert_handle = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vert_handle, 2, vertex_shader_with_version, nullptr); glCompileShader(vert_handle); CheckShader(vert_handle, "vertex shader"); const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader }; - GLuint frag_handle; - GL_CALL(frag_handle = glCreateShader(GL_FRAGMENT_SHADER)); + GLuint frag_handle = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(frag_handle, 2, fragment_shader_with_version, nullptr); glCompileShader(frag_handle); CheckShader(frag_handle, "fragment shader"); @@ -983,13 +976,13 @@ static void ImGui_ImplOpenGL3_RenderWindow(ImGuiViewport* viewport, void*) ImGui_ImplOpenGL3_RenderDrawData(viewport->DrawData); } -static void ImGui_ImplOpenGL3_InitMultiViewportSupport() +static void ImGui_ImplOpenGL3_InitPlatformInterface() { ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL3_RenderWindow; } -static void ImGui_ImplOpenGL3_ShutdownMultiViewportSupport() +static void ImGui_ImplOpenGL3_ShutdownPlatformInterface() { ImGui::DestroyPlatformWindows(); } diff --git a/3rdparty/imgui/backends/imgui_impl_opengl3.h b/3rdparty/imgui/backends/imgui_impl_opengl3.h index d562130..ae718d8 100644 --- a/3rdparty/imgui/backends/imgui_impl_opengl3.h +++ b/3rdparty/imgui/backends/imgui_impl_opengl3.h @@ -5,7 +5,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! -// [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!] +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only). // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // About WebGL/ES: @@ -30,7 +30,7 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE -// Follow "Getting Started" link and check examples/ folder to learn about using backends! +// Backend API IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr); IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); diff --git a/3rdparty/imgui/backends/imgui_impl_opengl3_loader.h b/3rdparty/imgui/backends/imgui_impl_opengl3_loader.h index d6ffa5a..3fbc348 100644 --- a/3rdparty/imgui/backends/imgui_impl_opengl3_loader.h +++ b/3rdparty/imgui/backends/imgui_impl_opengl3_loader.h @@ -181,9 +181,6 @@ typedef khronos_uint8_t GLubyte; #define GL_LINEAR 0x2601 #define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MIN_FILTER 0x2801 -#define GL_TEXTURE_WRAP_S 0x2802 -#define GL_TEXTURE_WRAP_T 0x2803 -#define GL_REPEAT 0x2901 typedef void (APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode); typedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); @@ -234,9 +231,6 @@ GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures); GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures); #endif #endif /* GL_VERSION_1_1 */ -#ifndef GL_VERSION_1_2 -#define GL_CLAMP_TO_EDGE 0x812F -#endif /* GL_VERSION_1_2 */ #ifndef GL_VERSION_1_3 #define GL_TEXTURE0 0x84C0 #define GL_ACTIVE_TEXTURE 0x84E0 diff --git a/3rdparty/imgui/backends/imgui_impl_osx.h b/3rdparty/imgui/backends/imgui_impl_osx.h index 08bfe76..1f2254b 100644 --- a/3rdparty/imgui/backends/imgui_impl_osx.h +++ b/3rdparty/imgui/backends/imgui_impl_osx.h @@ -4,11 +4,11 @@ // - Requires linking with the GameController framework ("-framework GameController"). // Implemented features: -// [X] Platform: Clipboard support is part of core Dear ImGui (no specific code in this backend). +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Mouse support. Can discriminate Mouse/Pen. -// [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 kVK_* values are obsolete since 1.87 and not supported since 1.91.5] +// [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 kVK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend). // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. // [x] Platform: Multi-viewport / platform windows. // Issues: @@ -31,7 +31,6 @@ @class NSEvent; @class NSView; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplOSX_Init(NSView* _Nonnull view); IMGUI_IMPL_API void ImGui_ImplOSX_Shutdown(); IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(NSView* _Nullable view); @@ -46,7 +45,6 @@ IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(NSView* _Nullable view); // #include #ifndef __OBJC__ -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplOSX_Init(void* _Nonnull view); IMGUI_IMPL_API void ImGui_ImplOSX_Shutdown(); IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(void* _Nullable view); diff --git a/3rdparty/imgui/backends/imgui_impl_osx.mm b/3rdparty/imgui/backends/imgui_impl_osx.mm index 5d067f5..fe7f534 100644 --- a/3rdparty/imgui/backends/imgui_impl_osx.mm +++ b/3rdparty/imgui/backends/imgui_impl_osx.mm @@ -4,11 +4,11 @@ // - Requires linking with the GameController framework ("-framework GameController"). // Implemented features: -// [X] Platform: Clipboard support is part of core Dear ImGui (no specific code in this backend). +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Mouse support. Can discriminate Mouse/Pen. -// [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 kVK_* values are obsolete since 1.87 and not supported since 1.91.5] +// [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 kVK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend). // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. // [x] Platform: Multi-viewport / platform windows. // Issues: @@ -33,12 +33,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-XX-XX: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2025-01-20: Removed notification observer when shutting down. (#8331) -// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: -// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn -// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn -// - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn +// 2024-XX-XX: Added support for multiple windows via the ImGuiPlatformIO interface. // 2024-07-02: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() renaming in main library. // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F20 function keys. Stopped mapping F13 into PrintScreen. // 2023-04-09: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_Pen. @@ -93,7 +88,7 @@ struct ImGui_ImplOSX_Data id Monitor; NSWindow* Window; - ImGui_ImplOSX_Data() { memset((void*)this, 0, sizeof(*this)); } + ImGui_ImplOSX_Data() { memset(this, 0, sizeof(*this)); } }; static ImGui_ImplOSX_Data* ImGui_ImplOSX_GetBackendData() { return (ImGui_ImplOSX_Data*)ImGui::GetIO().BackendPlatformUserData; } @@ -102,8 +97,8 @@ static void ImGui_ImplOSX_DestroyBackendData() { IM_DELETE( static inline CFTimeInterval GetMachAbsoluteTimeInSeconds() { return (CFTimeInterval)(double)(clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1e9); } // Forward Declarations -static void ImGui_ImplOSX_InitMultiViewportSupport(); -static void ImGui_ImplOSX_ShutdownMultiViewportSupport(); +static void ImGui_ImplOSX_InitPlatformInterface(); +static void ImGui_ImplOSX_ShutdownPlatformInterface(); static void ImGui_ImplOSX_UpdateMonitors(); static void ImGui_ImplOSX_AddTrackingArea(NSView* _Nonnull view); static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view); @@ -290,10 +285,7 @@ static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view); @end // Functions - -// Not static to allow third-party code to use that if they want to (but undocumented) -ImGuiKey ImGui_ImplOSX_KeyCodeToImGuiKey(int key_code); -ImGuiKey ImGui_ImplOSX_KeyCodeToImGuiKey(int key_code) +static ImGuiKey ImGui_ImplOSX_KeyCodeToImGuiKey(int key_code) { switch (key_code) { @@ -431,7 +423,6 @@ IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(void* _Nullable view) { bool ImGui_ImplOSX_Init(NSView* view) { ImGuiIO& io = ImGui::GetIO(); - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); @@ -449,7 +440,8 @@ bool ImGui_ImplOSX_Init(NSView* view) ImGuiViewport* main_viewport = ImGui::GetMainViewport(); main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (__bridge_retained void*)bd->Window; ImGui_ImplOSX_UpdateMonitors(); - ImGui_ImplOSX_InitMultiViewportSupport(); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplOSX_InitPlatformInterface(); // Load cursors. Some of them are undocumented. bd->MouseCursorHidden = false; @@ -466,14 +458,14 @@ bool ImGui_ImplOSX_Init(NSView* view) // Note that imgui.cpp also include default OSX clipboard handlers which can be enabled // by adding '#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS' in imconfig.h and adding '-framework ApplicationServices' to your linker command-line. // Since we are already in ObjC land here, it is easy for us to add a clipboard handler using the NSPasteboard api. - platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* str) -> void + io.SetClipboardTextFn = [](void*, const char* str) -> void { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; [pasteboard declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil]; [pasteboard setString:[NSString stringWithUTF8String:str] forType:NSPasteboardTypeString]; }; - platform_io.Platform_GetClipboardTextFn = [](ImGuiContext*) -> const char* + io.GetClipboardTextFn = [](void*) -> const char* { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; NSString* available = [pasteboard availableTypeFromArray: [NSArray arrayWithObject:NSPasteboardTypeString]]; @@ -508,7 +500,7 @@ bool ImGui_ImplOSX_Init(NSView* view) [view addSubview:bd->KeyEventResponder]; ImGui_ImplOSX_AddTrackingArea(view); - platform_io.Platform_SetImeDataFn = [](ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) -> void + io.PlatformSetImeDataFn = [](ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) -> void { ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); if (data->WantVisible) @@ -532,7 +524,6 @@ void ImGui_ImplOSX_Shutdown() ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); - [[NSNotificationCenter defaultCenter] removeObserver:bd->Observer]; bd->Observer = nullptr; if (bd->Monitor != nullptr) { @@ -540,7 +531,7 @@ void ImGui_ImplOSX_Shutdown() bd->Monitor = nullptr; } - ImGui_ImplOSX_ShutdownMultiViewportSupport(); + ImGui_ImplOSX_ShutdownPlatformInterface(); ImGui_ImplOSX_DestroyBackendData(); ImGuiIO& io = ImGui::GetIO(); io.BackendPlatformName = nullptr; @@ -928,7 +919,7 @@ static void ImGui_ImplOSX_CreateWindow(ImGuiViewport* viewport) window.opaque = YES; KeyEventResponder* view = [[KeyEventResponder alloc] initWithFrame:rect]; - if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6 && ceil(NSAppKitVersionNumber) < NSAppKitVersionNumber10_15) + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) [view setWantsBestResolutionOpenGLSurface:YES]; window.contentView = view; @@ -1099,7 +1090,7 @@ static void ImGui_ImplOSX_UpdateMonitors() } } -static void ImGui_ImplOSX_InitMultiViewportSupport() +static void ImGui_ImplOSX_InitPlatformInterface() { ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); @@ -1133,7 +1124,7 @@ static void ImGui_ImplOSX_InitMultiViewportSupport() object:nil]; } -static void ImGui_ImplOSX_ShutdownMultiViewportSupport() +static void ImGui_ImplOSX_ShutdownPlatformInterface() { ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); [NSNotificationCenter.defaultCenter removeObserver:bd->Observer diff --git a/3rdparty/imgui/backends/imgui_impl_sdl2.cpp b/3rdparty/imgui/backends/imgui_impl_sdl2.cpp index 5270126..d038cb8 100644 --- a/3rdparty/imgui/backends/imgui_impl_sdl2.cpp +++ b/3rdparty/imgui/backends/imgui_impl_sdl2.cpp @@ -6,14 +6,14 @@ // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. -// [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 are obsolete since 1.87 and not supported since 1.91.5] +// [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 (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. -// [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. -// Missing features or Issues: +// Issues: // [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows). // [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). +// [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. @@ -25,17 +25,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2025-01-20: Made ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode_Manual) accept an empty array. -// 2024-10-24: Emscripten: from SDL 2.30.9, SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f. -// 2024-09-09: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190) -// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: -// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn -// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn -// - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn -// - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn -// 2024-08-19: Storing SDL's Uint32 WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. -// 2024-08-19: ImGui_ImplSDL2_ProcessEvent() now ignores events intended for other SDL windows. (#7853) +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions. // 2024-07-02: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() renaming in main library. // 2024-02-14: Inputs: Handle gamepad disconnection. Added ImGui_ImplSDL2_SetGamepadMode(). @@ -126,10 +116,7 @@ #define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4) #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) #define SDL_HAS_DISPLAY_EVENT SDL_VERSION_ATLEAST(2,0,9) -#define SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT SDL_VERSION_ATLEAST(2,0,18) -#if SDL_HAS_VULKAN -#include -#else +#if !SDL_HAS_VULKAN static const Uint32 SDL_WINDOW_VULKAN = 0x10000000; #endif @@ -137,7 +124,6 @@ static const Uint32 SDL_WINDOW_VULKAN = 0x10000000; struct ImGui_ImplSDL2_Data { SDL_Window* Window; - Uint32 WindowID; SDL_Renderer* Renderer; Uint64 Time; char* ClipboardTextData; @@ -172,11 +158,11 @@ static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_GetBackendData() // Forward Declarations static void ImGui_ImplSDL2_UpdateMonitors(); -static void ImGui_ImplSDL2_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context); -static void ImGui_ImplSDL2_ShutdownMultiViewportSupport(); +static void ImGui_ImplSDL2_InitPlatformInterface(SDL_Window* window, void* sdl_gl_context); +static void ImGui_ImplSDL2_ShutdownPlatformInterface(); // Functions -static const char* ImGui_ImplSDL2_GetClipboardText(ImGuiContext*) +static const char* ImGui_ImplSDL2_GetClipboardText(void*) { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); if (bd->ClipboardTextData) @@ -185,7 +171,7 @@ static const char* ImGui_ImplSDL2_GetClipboardText(ImGuiContext*) return bd->ClipboardTextData; } -static void ImGui_ImplSDL2_SetClipboardText(ImGuiContext*, const char* text) +static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text) { SDL_SetClipboardText(text); } @@ -204,9 +190,7 @@ static void ImGui_ImplSDL2_PlatformSetImeData(ImGuiContext*, ImGuiViewport* view } } -// Not static to allow third-party code to use that if they want to (but undocumented) -ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode); -ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode) +static ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode) { IM_UNUSED(scancode); switch (keycode) @@ -344,15 +328,11 @@ static void ImGui_ImplSDL2_UpdateKeyModifiers(SDL_Keymod sdl_key_mods) io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & KMOD_GUI) != 0); } -static ImGuiViewport* ImGui_ImplSDL2_GetViewportForWindowID(Uint32 window_id) -{ - return ImGui::FindViewportByPlatformHandle((void*)(intptr_t)window_id); -} - // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. +// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field. bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); @@ -363,8 +343,6 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) { case SDL_MOUSEMOTION: { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->motion.windowID) == nullptr) - return false; ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { @@ -379,8 +357,6 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_MOUSEWHEEL: { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->wheel.windowID) == nullptr) - return false; //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY); #if SDL_VERSION_ATLEAST(2,0,18) // If this fails to compile on Emscripten: update to latest Emscripten! float wheel_x = -event->wheel.preciseX; @@ -389,7 +365,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) float wheel_x = -(float)event->wheel.x; float wheel_y = (float)event->wheel.y; #endif -#if defined(__EMSCRIPTEN__) && !SDL_VERSION_ATLEAST(2,31,0) +#ifdef __EMSCRIPTEN__ wheel_x /= 100.0f; #endif io.AddMouseSourceEvent(event->wheel.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); @@ -399,8 +375,6 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->button.windowID) == nullptr) - return false; int mouse_button = -1; if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; } @@ -416,19 +390,13 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_TEXTINPUT: { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->text.windowID) == nullptr) - return false; io.AddInputCharactersUTF8(event->text.text); return true; } case SDL_KEYDOWN: case SDL_KEYUP: { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID) == nullptr) - return false; ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod); - //IMGUI_DEBUG_LOG("SDL_KEY_%s : key=%d ('%s'), scancode=%d ('%s'), mod=%X\n", - // (event->type == SDL_KEYDOWN) ? "DOWN" : "UP ", event->key.keysym.sym, SDL_GetKeyName(event->key.keysym.sym), event->key.keysym.scancode, SDL_GetScancodeName(event->key.keysym.scancode), event->key.keysym.mod); ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode); io.AddKeyEvent(key, (event->type == SDL_KEYDOWN)); io.SetKeyEventNativeData(key, event->key.keysym.sym, event->key.keysym.scancode, event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. @@ -445,10 +413,6 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) #endif case SDL_WINDOWEVENT: { - ImGuiViewport* viewport = ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID); - if (viewport == NULL) - return false; - // - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right. // - However we won't get a correct LEAVE event for a captured window. // - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late, @@ -466,12 +430,17 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) io.AddFocusEvent(true); else if (window_event == SDL_WINDOWEVENT_FOCUS_LOST) io.AddFocusEvent(false); - else if (window_event == SDL_WINDOWEVENT_CLOSE) - viewport->PlatformRequestClose = true; - else if (window_event == SDL_WINDOWEVENT_MOVED) - viewport->PlatformRequestMove = true; - else if (window_event == SDL_WINDOWEVENT_RESIZED) - viewport->PlatformRequestResize = true; + if (window_event == SDL_WINDOWEVENT_CLOSE || window_event == SDL_WINDOWEVENT_MOVED || window_event == SDL_WINDOWEVENT_RESIZED) + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(event->window.windowID))) + { + if (window_event == SDL_WINDOWEVENT_CLOSE) + viewport->PlatformRequestClose = true; + if (window_event == SDL_WINDOWEVENT_MOVED) + viewport->PlatformRequestMove = true; + if (window_event == SDL_WINDOWEVENT_RESIZED) + viewport->PlatformRequestResize = true; + return true; + } return true; } case SDL_CONTROLLERDEVICEADDED: @@ -515,7 +484,6 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) bd->Window = window; - bd->WindowID = SDL_GetWindowID(window); bd->Renderer = renderer; // SDL on Linux/OSX doesn't report events for unfocused windows (see https://github.com/ocornut/imgui/issues/4960) @@ -526,19 +494,16 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void #else bd->MouseCanReportHoveredViewport = false; #endif + bd->WantUpdateMonitors = true; - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; - platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText; - platform_io.Platform_ClipboardUserData = nullptr; - platform_io.Platform_SetImeDataFn = ImGui_ImplSDL2_PlatformSetImeData; + io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; + io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText; + io.ClipboardUserData = nullptr; + io.PlatformSetImeDataFn = ImGui_ImplSDL2_PlatformSetImeData; #ifdef __EMSCRIPTEN__ - platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplSDL2_EmscriptenOpenURL(url); return true; }; + io.PlatformOpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplSDL2_EmscriptenOpenURL(url); return true; }; #endif - // Update monitor a first time during init - ImGui_ImplSDL2_UpdateMonitors(); - // Gamepad handling bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst; bd->WantUpdateGamepadsList = true; @@ -557,7 +522,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void // Set platform dependent data in viewport // Our mouse update function expect PlatformHandle to be filled for the main viewport ImGuiViewport* main_viewport = ImGui::GetMainViewport(); - main_viewport->PlatformHandle = (void*)(intptr_t)bd->WindowID; + main_viewport->PlatformHandle = (void*)window; main_viewport->PlatformHandleRaw = nullptr; SDL_SysWMinfo info; SDL_VERSION(&info.version); @@ -592,9 +557,9 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void #endif // We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports. - // We left the call to ImGui_ImplSDL2_InitMultiViewportSupport() outside of #ifdef to avoid unused-function warnings. - if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) - ImGui_ImplSDL2_InitMultiViewportSupport(window, sdl_gl_context); + // We left the call to ImGui_ImplSDL2_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings. + if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) && (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports)) + ImGui_ImplSDL2_InitPlatformInterface(window, sdl_gl_context); return true; } @@ -647,7 +612,7 @@ void ImGui_ImplSDL2_Shutdown() IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplSDL2_ShutdownMultiViewportSupport(); + ImGui_ImplSDL2_ShutdownPlatformInterface(); if (bd->ClipboardTextData) SDL_free(bd->ClipboardTextData); @@ -672,7 +637,7 @@ static void ImGui_ImplSDL2_UpdateMouseData() // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside SDL_CaptureMouse((bd->MouseButtonsDown != 0) ? SDL_TRUE : SDL_FALSE); SDL_Window* focused_window = SDL_GetKeyboardFocus(); - const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui_ImplSDL2_GetViewportForWindowID(SDL_GetWindowID(focused_window)) != NULL)); + const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui::FindViewportByPlatformHandle((void*)focused_window))); #else SDL_Window* focused_window = bd->Window; const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only @@ -680,7 +645,7 @@ static void ImGui_ImplSDL2_UpdateMouseData() if (is_app_focused) { - // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user) + // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) if (io.WantSetMousePos) { #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE @@ -718,8 +683,9 @@ static void ImGui_ImplSDL2_UpdateMouseData() if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport) { ImGuiID mouse_viewport_id = 0; - if (ImGuiViewport* mouse_viewport = ImGui_ImplSDL2_GetViewportForWindowID(bd->MouseWindowID)) - mouse_viewport_id = mouse_viewport->ID; + if (SDL_Window* sdl_mouse_window = SDL_GetWindowFromID(bd->MouseWindowID)) + if (ImGuiViewport* mouse_viewport = ImGui::FindViewportByPlatformHandle((void*)sdl_mouse_window)) + mouse_viewport_id = mouse_viewport->ID; io.AddMouseViewportEvent(mouse_viewport_id); } } @@ -765,7 +731,7 @@ void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_ ImGui_ImplSDL2_CloseGamepads(); if (mode == ImGui_ImplSDL2_GamepadMode_Manual) { - IM_ASSERT(manual_gamepads_array != nullptr || manual_gamepads_count <= 0); + IM_ASSERT(manual_gamepads_array != nullptr && manual_gamepads_count > 0); for (int n = 0; n < manual_gamepads_count; n++) bd->Gamepads.push_back(manual_gamepads_array[n]); } @@ -881,11 +847,7 @@ static void ImGui_ImplSDL2_UpdateMonitors() // DpiScale to cocoa_window.backingScaleFactor here. float dpi = 0.0f; if (!SDL_GetDisplayDPI(n, &dpi, nullptr, nullptr)) - { - if (dpi <= 0.0f) - continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902. monitor.DpiScale = dpi / 96.0f; - } #endif monitor.PlatformHandle = (void*)(intptr_t)n; platform_io.Monitors.push_back(monitor); @@ -906,10 +868,6 @@ void ImGui_ImplSDL2_NewFrame() w = h = 0; if (bd->Renderer != nullptr) SDL_GetRendererOutputSize(bd->Renderer, &display_w, &display_h); -#if SDL_HAS_VULKAN - else if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_VULKAN) - SDL_Vulkan_GetDrawableSize(bd->Window, &display_w, &display_h); -#endif else SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h); io.DisplaySize = ImVec2((float)w, (float)h); @@ -1010,7 +968,7 @@ static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport) if (use_opengl && backup_context) SDL_GL_MakeCurrent(vd->Window, backup_context); - viewport->PlatformHandle = (void*)(intptr_t)SDL_GetWindowID(vd->Window); + viewport->PlatformHandle = (void*)vd->Window; viewport->PlatformHandleRaw = nullptr; SDL_SysWMinfo info; SDL_VERSION(&info.version); @@ -1042,7 +1000,7 @@ static void ImGui_ImplSDL2_DestroyWindow(ImGuiViewport* viewport) static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport) { ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; -#if defined(_WIN32) && !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP || WINAPI_FAMILY == WINAPI_FAMILY_GAMES)) +#if defined(_WIN32) HWND hwnd = (HWND)viewport->PlatformHandleRaw; // SDL hack: Hide icon from task bar @@ -1054,11 +1012,7 @@ static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport) ex_style |= WS_EX_TOOLWINDOW; ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style); } -#endif -#if SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT - SDL_SetHint(SDL_HINT_WINDOW_NO_ACTIVATION_WHEN_SHOWN, (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) ? "1" : "0"); -#elif defined(_WIN32) // SDL hack: SDL always activate/focus windows :/ if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) { @@ -1066,6 +1020,7 @@ static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport) return; } #endif + SDL_ShowWindow(vd->Window); } @@ -1159,7 +1114,7 @@ static int ImGui_ImplSDL2_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_inst } #endif // SDL_HAS_VULKAN -static void ImGui_ImplSDL2_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context) +static void ImGui_ImplSDL2_InitPlatformInterface(SDL_Window* window, void* sdl_gl_context) { // Register platform interface (will be coupled with a renderer interface) ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); @@ -1192,10 +1147,10 @@ static void ImGui_ImplSDL2_InitMultiViewportSupport(SDL_Window* window, void* sd vd->WindowOwned = false; vd->GLContext = sdl_gl_context; main_viewport->PlatformUserData = vd; - main_viewport->PlatformHandle = (void*)(intptr_t)vd->WindowID; + main_viewport->PlatformHandle = vd->Window; } -static void ImGui_ImplSDL2_ShutdownMultiViewportSupport() +static void ImGui_ImplSDL2_ShutdownPlatformInterface() { ImGui::DestroyPlatformWindows(); } diff --git a/3rdparty/imgui/backends/imgui_impl_sdl2.h b/3rdparty/imgui/backends/imgui_impl_sdl2.h index 008794c..1fba66c 100644 --- a/3rdparty/imgui/backends/imgui_impl_sdl2.h +++ b/3rdparty/imgui/backends/imgui_impl_sdl2.h @@ -5,14 +5,14 @@ // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. -// [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 are obsolete since 1.87 and not supported since 1.91.5] +// [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 (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. -// [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. -// Missing features or Issues: +// Issues: // [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows). // [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). +// [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. @@ -31,7 +31,6 @@ struct SDL_Renderer; struct _SDL_GameController; typedef union SDL_Event SDL_Event; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window); @@ -45,6 +44,6 @@ IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); // Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this. // When using manual mode, caller is responsible for opening/closing gamepad. enum ImGui_ImplSDL2_GamepadMode { ImGui_ImplSDL2_GamepadMode_AutoFirst, ImGui_ImplSDL2_GamepadMode_AutoAll, ImGui_ImplSDL2_GamepadMode_Manual }; -IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array = nullptr, int manual_gamepads_count = -1); +IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array = NULL, int manual_gamepads_count = -1); #endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/backends/imgui_impl_sdl3.cpp b/3rdparty/imgui/backends/imgui_impl_sdl3.cpp index 3e4d5bc..dd633da 100644 --- a/3rdparty/imgui/backends/imgui_impl_sdl3.cpp +++ b/3rdparty/imgui/backends/imgui_impl_sdl3.cpp @@ -1,17 +1,19 @@ -// dear imgui: Platform Backend for SDL3 -// This needs to be used along with a Renderer (e.g. SDL_GPU, DirectX11, OpenGL3, Vulkan..) +// dear imgui: Platform Backend for SDL3 (*EXPERIMENTAL*) +// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) // (Info: SDL3 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) +// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN**) + // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. -// [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 are obsolete since 1.87 and not supported since 1.91.5] +// [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 (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue. -// Missing features or Issues: +// Issues: // [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows). -// [x] Platform: IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. +// [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). // 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. @@ -23,19 +25,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2025-01-20: Made ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode_Manual) accept an empty array. -// 2024-10-24: Emscripten: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f on Emscripten. -// 2024-09-11: (Docking) Added support for viewport->ParentViewportId field to support parenting at OS level. (#7973) -// 2024-09-03: Update for SDL3 api changes: SDL_GetGamepads() memory ownership revert. (#7918, #7898, #7807) -// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: -// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn -// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn -// - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn -// 2024-08-19: Storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. -// 2024-08-19: ImGui_ImplSDL3_ProcessEvent() now ignores events intended for other SDL windows. (#7853) -// 2024-07-22: Update for SDL3 api changes: SDL_GetGamepads() memory ownership change. (#7807) -// 2024-07-18: Update for SDL3 api changes: SDL_GetClipboardText() memory ownership change. (#7801) +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-07-18: Update for SDL3 api changes: SDL_GetClipboardText() string ownership change. (#7801) // 2024-07-15: Update for SDL3 api changes: SDL_GetProperty() change to SDL_GetPointerProperty(). (#7794) // 2024-07-02: Update for SDL3 api changes: SDLK_x renames and SDLK_KP_x removals (#7761, #7762). // 2024-07-01: Update for SDL3 api changes: SDL_SetTextInputRect() changed to SDL_SetTextInputArea(). @@ -93,7 +84,6 @@ struct ImGui_ImplSDL3_Data { SDL_Window* Window; - SDL_WindowID WindowID; SDL_Renderer* Renderer; Uint64 Time; char* ClipboardTextData; @@ -131,21 +121,21 @@ static ImGui_ImplSDL3_Data* ImGui_ImplSDL3_GetBackendData() // Forward Declarations static void ImGui_ImplSDL3_UpdateMonitors(); -static void ImGui_ImplSDL3_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context); -static void ImGui_ImplSDL3_ShutdownMultiViewportSupport(); +static void ImGui_ImplSDL3_InitPlatformInterface(SDL_Window* window, void* sdl_gl_context); +static void ImGui_ImplSDL3_ShutdownPlatformInterface(); // Functions -static const char* ImGui_ImplSDL3_GetClipboardText(ImGuiContext*) +static const char* ImGui_ImplSDL3_GetClipboardText(void*) { ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); if (bd->ClipboardTextData) SDL_free(bd->ClipboardTextData); const char* sdl_clipboard_text = SDL_GetClipboardText(); - bd->ClipboardTextData = sdl_clipboard_text ? SDL_strdup(sdl_clipboard_text) : nullptr; + bd->ClipboardTextData = sdl_clipboard_text ? SDL_strdup(sdl_clipboard_text) : NULL; return bd->ClipboardTextData; } -static void ImGui_ImplSDL3_SetClipboardText(ImGuiContext*, const char* text) +static void ImGui_ImplSDL3_SetClipboardText(void*, const char* text) { SDL_SetClipboardText(text); } @@ -153,9 +143,8 @@ static void ImGui_ImplSDL3_SetClipboardText(ImGuiContext*, const char* text) static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) { ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); - SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle; - SDL_Window* window = SDL_GetWindowFromID(window_id); - if ((data->WantVisible == false || bd->ImeWindow != window) && bd->ImeWindow != nullptr) + SDL_Window* window = (SDL_Window*)viewport->PlatformHandle; + if ((data->WantVisible == false || bd->ImeWindow != window) && bd->ImeWindow != NULL) { SDL_StopTextInput(bd->ImeWindow); bd->ImeWindow = nullptr; @@ -173,9 +162,7 @@ static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* view } } -// Not static to allow third-party code to use that if they want to (but undocumented) -ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode); -ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode) +static ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode) { // Keypad doesn't have individual key values in SDL3 switch (scancode) @@ -317,15 +304,11 @@ static void ImGui_ImplSDL3_UpdateKeyModifiers(SDL_Keymod sdl_key_mods) io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & SDL_KMOD_GUI) != 0); } -static ImGuiViewport* ImGui_ImplSDL3_GetViewportForWindowID(SDL_WindowID window_id) -{ - return ImGui::FindViewportByPlatformHandle((void*)(intptr_t)window_id); -} - // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. +// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field. bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) { ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); @@ -336,8 +319,6 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) { case SDL_EVENT_MOUSE_MOTION: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->motion.windowID) == nullptr) - return false; ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { @@ -352,11 +333,12 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_MOUSE_WHEEL: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->wheel.windowID) == nullptr) - return false; //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY); float wheel_x = -event->wheel.x; float wheel_y = event->wheel.y; + #ifdef __EMSCRIPTEN__ + wheel_x /= 100.0f; + #endif io.AddMouseSourceEvent(event->wheel.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); io.AddMouseWheelEvent(wheel_x, wheel_y); return true; @@ -364,8 +346,6 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->button.windowID) == nullptr) - return false; int mouse_button = -1; if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; } @@ -381,19 +361,14 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_TEXT_INPUT: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->text.windowID) == nullptr) - return false; io.AddInputCharactersUTF8(event->text.text); return true; } case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->key.windowID) == nullptr) - return false; + //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%d: key=%d, scancode=%d, mod=%X\n", (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP", event->key.key, event->key.scancode, event->key.mod); ImGui_ImplSDL3_UpdateKeyModifiers((SDL_Keymod)event->key.mod); - //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%s : key=%d ('%s'), scancode=%d ('%s'), mod=%X\n", - // (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP ", event->key.key, SDL_GetKeyName(event->key.key), event->key.scancode, SDL_GetScancodeName(event->key.scancode), event->key.mod); ImGuiKey key = ImGui_ImplSDL3_KeyEventToImGuiKey(event->key.key, event->key.scancode); io.AddKeyEvent(key, (event->type == SDL_EVENT_KEY_DOWN)); io.SetKeyEventNativeData(key, event->key.key, event->key.scancode, event->key.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. @@ -410,8 +385,6 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_WINDOW_MOUSE_ENTER: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == nullptr) - return false; bd->MouseWindowID = event->window.windowID; bd->MousePendingLeaveFrame = 0; return true; @@ -422,34 +395,29 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) // FIXME: Unconfirmed whether this is still needed with SDL3. case SDL_EVENT_WINDOW_MOUSE_LEAVE: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == nullptr) - return false; bd->MousePendingLeaveFrame = ImGui::GetFrameCount() + 1; return true; } case SDL_EVENT_WINDOW_FOCUS_GAINED: - case SDL_EVENT_WINDOW_FOCUS_LOST: - { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == nullptr) - return false; - io.AddFocusEvent(event->type == SDL_EVENT_WINDOW_FOCUS_GAINED); + io.AddFocusEvent(true); + return true; + case SDL_EVENT_WINDOW_FOCUS_LOST: + io.AddFocusEvent(false); return true; - } case SDL_EVENT_WINDOW_CLOSE_REQUESTED: case SDL_EVENT_WINDOW_MOVED: case SDL_EVENT_WINDOW_RESIZED: - { - ImGuiViewport* viewport = ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID); - if (viewport == NULL) - return false; - if (event->type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) - viewport->PlatformRequestClose = true; - if (event->type == SDL_EVENT_WINDOW_MOVED) - viewport->PlatformRequestMove = true; - if (event->type == SDL_EVENT_WINDOW_RESIZED) - viewport->PlatformRequestResize = true; + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(event->window.windowID))) + { + if (event->type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) + viewport->PlatformRequestClose = true; + if (event->type == SDL_EVENT_WINDOW_MOVED) + viewport->PlatformRequestMove = true; + if (event->type == SDL_EVENT_WINDOW_RESIZED) + viewport->PlatformRequestResize = true; + return true; + } return true; - } case SDL_EVENT_GAMEPAD_ADDED: case SDL_EVENT_GAMEPAD_REMOVED: { @@ -462,7 +430,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) static void ImGui_ImplSDL3_SetupPlatformHandles(ImGuiViewport* viewport, SDL_Window* window) { - viewport->PlatformHandle = (void*)(intptr_t)SDL_GetWindowID(window); + viewport->PlatformHandle = window; viewport->PlatformHandleRaw = nullptr; #if defined(_WIN32) && !defined(__WINRT__) viewport->PlatformHandleRaw = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr); @@ -499,7 +467,6 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) bd->Window = window; - bd->WindowID = SDL_GetWindowID(window); bd->Renderer = renderer; // SDL on Linux/OSX doesn't report events for unfocused windows (see https://github.com/ocornut/imgui/issues/4960) @@ -510,14 +477,12 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void #else bd->MouseCanReportHoveredViewport = false; #endif + bd->WantUpdateMonitors = true; - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText; - platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText; - platform_io.Platform_SetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData; - - // Update monitor a first time during init - ImGui_ImplSDL3_UpdateMonitors(); + io.SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText; + io.GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText; + io.ClipboardUserData = nullptr; + io.PlatformSetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData; // Gamepad handling bd->GamepadMode = ImGui_ImplSDL3_GamepadMode_AutoFirst; @@ -554,8 +519,8 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void // We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports. // We left the call to ImGui_ImplSDL3_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings. - if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) - ImGui_ImplSDL3_InitMultiViewportSupport(window, sdl_gl_context); + if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) && (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports)) + ImGui_ImplSDL3_InitPlatformInterface(window, sdl_gl_context); return true; } @@ -593,11 +558,6 @@ bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* rendere return ImGui_ImplSDL3_Init(window, renderer, nullptr); } -bool ImGui_ImplSDL3_InitForSDLGPU(SDL_Window* window) -{ - return ImGui_ImplSDL3_Init(window, nullptr, nullptr); -} - bool ImGui_ImplSDL3_InitForOther(SDL_Window* window) { return ImGui_ImplSDL3_Init(window, nullptr, nullptr); @@ -611,7 +571,7 @@ void ImGui_ImplSDL3_Shutdown() IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplSDL3_ShutdownMultiViewportSupport(); + ImGui_ImplSDL3_ShutdownPlatformInterface(); if (bd->ClipboardTextData) SDL_free(bd->ClipboardTextData); @@ -634,16 +594,16 @@ static void ImGui_ImplSDL3_UpdateMouseData() // We forward mouse input when hovered or captured (via SDL_EVENT_MOUSE_MOTION) or when focused (below) #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside - SDL_CaptureMouse(bd->MouseButtonsDown != 0); + SDL_CaptureMouse((bd->MouseButtonsDown != 0) ? SDL_TRUE : SDL_FALSE); SDL_Window* focused_window = SDL_GetKeyboardFocus(); - const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui_ImplSDL3_GetViewportForWindowID(SDL_GetWindowID(focused_window)) != NULL)); + const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui::FindViewportByPlatformHandle((void*)focused_window))); #else SDL_Window* focused_window = bd->Window; const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only #endif if (is_app_focused) { - // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user) + // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) if (io.WantSetMousePos) { #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE @@ -682,8 +642,9 @@ static void ImGui_ImplSDL3_UpdateMouseData() if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport) { ImGuiID mouse_viewport_id = 0; - if (ImGuiViewport* mouse_viewport = ImGui_ImplSDL3_GetViewportForWindowID(bd->MouseWindowID)) - mouse_viewport_id = mouse_viewport->ID; + if (SDL_Window* sdl_mouse_window = SDL_GetWindowFromID(bd->MouseWindowID)) + if (ImGuiViewport* mouse_viewport = ImGui::FindViewportByPlatformHandle((void*)sdl_mouse_window)) + mouse_viewport_id = mouse_viewport->ID; io.AddMouseViewportEvent(mouse_viewport_id); } } @@ -729,7 +690,7 @@ void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode, SDL_Gamepad* ImGui_ImplSDL3_CloseGamepads(); if (mode == ImGui_ImplSDL3_GamepadMode_Manual) { - IM_ASSERT(manual_gamepads_array != nullptr || manual_gamepads_count <= 0); + IM_ASSERT(manual_gamepads_array != nullptr && manual_gamepads_count > 0); for (int n = 0; n < manual_gamepads_count; n++) bd->Gamepads.push_back(manual_gamepads_array[n]); } @@ -780,8 +741,8 @@ static void ImGui_ImplSDL3_UpdateGamepads() if (bd->GamepadMode == ImGui_ImplSDL3_GamepadMode_AutoFirst) break; } - bd->WantUpdateGamepadsList = false; SDL_free(sdl_gamepads); + bd->WantUpdateGamepadsList = false; } // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. @@ -845,11 +806,8 @@ static void ImGui_ImplSDL3_UpdateMonitors() // DpiScale to cocoa_window.backingScaleFactor here. monitor.DpiScale = SDL_GetDisplayContentScale(display_id); monitor.PlatformHandle = (void*)(intptr_t)n; - if (monitor.DpiScale <= 0.0f) - continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902. platform_io.Monitors.push_back(monitor); } - SDL_free(displays); } void ImGui_ImplSDL3_NewFrame() @@ -913,34 +871,20 @@ void ImGui_ImplSDL3_NewFrame() struct ImGui_ImplSDL3_ViewportData { SDL_Window* Window; - SDL_Window* ParentWindow; Uint32 WindowID; bool WindowOwned; SDL_GLContext GLContext; - ImGui_ImplSDL3_ViewportData() { Window = ParentWindow = nullptr; WindowID = 0; WindowOwned = false; GLContext = nullptr; } + ImGui_ImplSDL3_ViewportData() { Window = nullptr; WindowID = 0; WindowOwned = false; GLContext = nullptr; } ~ImGui_ImplSDL3_ViewportData() { IM_ASSERT(Window == nullptr && GLContext == nullptr); } }; -static SDL_Window* ImGui_ImplSDL3_GetSDLWindowFromViewportID(ImGuiID viewport_id) -{ - if (viewport_id != 0) - if (ImGuiViewport* viewport = ImGui::FindViewportByID(viewport_id)) - { - SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle; - return SDL_GetWindowFromID(window_id); - } - return nullptr; -} - static void ImGui_ImplSDL3_CreateWindow(ImGuiViewport* viewport) { ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); ImGui_ImplSDL3_ViewportData* vd = IM_NEW(ImGui_ImplSDL3_ViewportData)(); viewport->PlatformUserData = vd; - vd->ParentWindow = ImGui_ImplSDL3_GetSDLWindowFromViewportID(viewport->ParentViewportId); - ImGuiViewport* main_viewport = ImGui::GetMainViewport(); ImGui_ImplSDL3_ViewportData* main_viewport_data = (ImGui_ImplSDL3_ViewportData*)main_viewport->PlatformUserData; @@ -954,16 +898,17 @@ static void ImGui_ImplSDL3_CreateWindow(ImGuiViewport* viewport) SDL_GL_MakeCurrent(main_viewport_data->Window, main_viewport_data->GLContext); } - SDL_WindowFlags sdl_flags = 0; - sdl_flags |= SDL_WINDOW_HIDDEN; + Uint32 sdl_flags = 0; sdl_flags |= use_opengl ? SDL_WINDOW_OPENGL : (bd->UseVulkan ? SDL_WINDOW_VULKAN : 0); - sdl_flags |= SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_HIGH_PIXEL_DENSITY; + sdl_flags |= SDL_GetWindowFlags(bd->Window); sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0; sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE; +#if !defined(_WIN32) + // See SDL hack in ImGui_ImplSDL3_ShowWindow(). sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) ? SDL_WINDOW_UTILITY : 0; +#endif sdl_flags |= (viewport->Flags & ImGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0; vd->Window = SDL_CreateWindow("No Title Yet", (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags); - SDL_SetWindowParent(vd->Window, vd->ParentWindow); SDL_SetWindowPosition(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y); vd->WindowOwned = true; if (use_opengl) @@ -995,39 +940,30 @@ static void ImGui_ImplSDL3_DestroyWindow(ImGuiViewport* viewport) static void ImGui_ImplSDL3_ShowWindow(ImGuiViewport* viewport) { ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; -#if defined(_WIN32) && !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP || WINAPI_FAMILY == WINAPI_FAMILY_GAMES)) +#if defined(_WIN32) HWND hwnd = (HWND)viewport->PlatformHandleRaw; - // SDL hack: Show icon in task bar (#7989) - // Note: SDL_WINDOW_UTILITY can be used to control task bar visibility, but on Windows, it does not affect child windows. - if (!(viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon)) + // SDL hack: Hide icon from task bar + // Note: SDL 3.0.0+ has a SDL_WINDOW_UTILITY flag which is supported under Windows but the way it create the window breaks our seamless transition. + if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) { LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE); - ex_style |= WS_EX_APPWINDOW; - ex_style &= ~WS_EX_TOOLWINDOW; - ::ShowWindow(hwnd, SW_HIDE); + ex_style &= ~WS_EX_APPWINDOW; + ex_style |= WS_EX_TOOLWINDOW; ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style); } + + // SDL hack: SDL always activate/focus windows :/ + if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) + { + ::ShowWindow(hwnd, SW_SHOWNA); + return; + } #endif - SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN, (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) ? "0" : "1"); SDL_ShowWindow(vd->Window); } -static void ImGui_ImplSDL3_UpdateWindow(ImGuiViewport* viewport) -{ - ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; - - // Update SDL3 parent if it changed _after_ creation. - // This is for advanced apps that are manipulating ParentViewportID manually. - SDL_Window* new_parent = ImGui_ImplSDL3_GetSDLWindowFromViewportID(viewport->ParentViewportId); - if (new_parent != vd->ParentWindow) - { - vd->ParentWindow = new_parent; - SDL_SetWindowParent(vd->Window, vd->ParentWindow); - } -} - static ImVec2 ImGui_ImplSDL3_GetWindowPos(ImGuiViewport* viewport) { ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; @@ -1110,18 +1046,17 @@ static int ImGui_ImplSDL3_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_inst { ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; (void)vk_allocator; - bool ret = SDL_Vulkan_CreateSurface(vd->Window, (VkInstance)vk_instance, (VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface); + SDL_bool ret = SDL_Vulkan_CreateSurface(vd->Window, (VkInstance)vk_instance, (VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface); return ret ? 0 : 1; // ret ? VK_SUCCESS : VK_NOT_READY } -static void ImGui_ImplSDL3_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context) +static void ImGui_ImplSDL3_InitPlatformInterface(SDL_Window* window, void* sdl_gl_context) { // Register platform interface (will be coupled with a renderer interface) ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Platform_CreateWindow = ImGui_ImplSDL3_CreateWindow; platform_io.Platform_DestroyWindow = ImGui_ImplSDL3_DestroyWindow; platform_io.Platform_ShowWindow = ImGui_ImplSDL3_ShowWindow; - platform_io.Platform_UpdateWindow = ImGui_ImplSDL3_UpdateWindow; platform_io.Platform_SetWindowPos = ImGui_ImplSDL3_SetWindowPos; platform_io.Platform_GetWindowPos = ImGui_ImplSDL3_GetWindowPos; platform_io.Platform_SetWindowSize = ImGui_ImplSDL3_SetWindowSize; @@ -1144,10 +1079,10 @@ static void ImGui_ImplSDL3_InitMultiViewportSupport(SDL_Window* window, void* sd vd->WindowOwned = false; vd->GLContext = (SDL_GLContext)sdl_gl_context; main_viewport->PlatformUserData = vd; - main_viewport->PlatformHandle = (void*)(intptr_t)vd->WindowID; + main_viewport->PlatformHandle = vd->Window; } -static void ImGui_ImplSDL3_ShutdownMultiViewportSupport() +static void ImGui_ImplSDL3_ShutdownPlatformInterface() { ImGui::DestroyPlatformWindows(); } diff --git a/3rdparty/imgui/backends/imgui_impl_sdl3.h b/3rdparty/imgui/backends/imgui_impl_sdl3.h index 064e1f0..f1af723 100644 --- a/3rdparty/imgui/backends/imgui_impl_sdl3.h +++ b/3rdparty/imgui/backends/imgui_impl_sdl3.h @@ -1,17 +1,20 @@ -// dear imgui: Platform Backend for SDL3 -// This needs to be used along with a Renderer (e.g. SDL_GPU, DirectX11, OpenGL3, Vulkan..) +// dear imgui: Platform Backend for SDL3 (*EXPERIMENTAL*) +// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) // (Info: SDL3 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) +// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN**) + // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. -// [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 are obsolete since 1.87 and not supported since 1.91.5] +// [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 (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue. -// Missing features or Issues: +// Issues: // [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows). -// [x] Platform: IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. +// [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). +// [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. @@ -30,13 +33,11 @@ struct SDL_Renderer; struct SDL_Gamepad; typedef union SDL_Event SDL_Event; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForMetal(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer); -IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLGPU(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOther(SDL_Window* window); IMGUI_IMPL_API void ImGui_ImplSDL3_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDL3_NewFrame(); @@ -45,6 +46,6 @@ IMGUI_IMPL_API bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event); // Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this. // When using manual mode, caller is responsible for opening/closing gamepad. enum ImGui_ImplSDL3_GamepadMode { ImGui_ImplSDL3_GamepadMode_AutoFirst, ImGui_ImplSDL3_GamepadMode_AutoAll, ImGui_ImplSDL3_GamepadMode_Manual }; -IMGUI_IMPL_API void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode, SDL_Gamepad** manual_gamepads_array = nullptr, int manual_gamepads_count = -1); +IMGUI_IMPL_API void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode, SDL_Gamepad** manual_gamepads_array = NULL, int manual_gamepads_count = -1); #endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/backends/imgui_impl_sdlrenderer2.cpp b/3rdparty/imgui/backends/imgui_impl_sdlrenderer2.cpp index ef5f858..a046ed9 100644 --- a/3rdparty/imgui/backends/imgui_impl_sdlrenderer2.cpp +++ b/3rdparty/imgui/backends/imgui_impl_sdlrenderer2.cpp @@ -1,18 +1,15 @@ // dear imgui: Renderer Backend for SDL_Renderer for SDL2 // (Requires: SDL 2.0.17+) -// Note that SDL_Renderer is an _optional_ component of SDL2, which IMHO is now largely obsolete. -// For a multi-platform app consider using other technologies: -// - SDL3+SDL_GPU: SDL_GPU is SDL3 new graphics abstraction API. You will need to update to SDL3. -// - SDL2+DirectX, SDL2+OpenGL, SDL2+Vulkan: combine SDL with dedicated renderers. -// If your application wants to render any non trivial amount of graphics other than UI, -// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user -// and it might be difficult to step out of those boundaries. +// Note how SDL_Renderer is an _optional_ component of SDL2. +// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. +// If your application will want to render any non trivial amount of graphics other than UI, +// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and +// it might be difficult to step out of those boundaries. // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // Missing features: // [ ] Renderer: Multi-viewport support (multiple windows). @@ -25,8 +22,6 @@ // - Introduction, links and more at the top of imgui.cpp // CHANGELOG -// 2025-01-18: Use endian-dependent RGBA32 texture format, to match SDL_Color. -// 2024-10-09: Expose selected render state in ImGui_ImplSDLRenderer2_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. // 2024-05-14: *BREAKING CHANGE* ImGui_ImplSDLRenderer3_RenderDrawData() requires SDL_Renderer* passed as parameter. // 2023-05-30: Renamed imgui_impl_sdlrenderer.h/.cpp to imgui_impl_sdlrenderer2.h/.cpp to accommodate for upcoming SDL3. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. @@ -147,29 +142,21 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* SDL_RenderGetViewport(renderer, &old.Viewport); SDL_RenderGetClipRect(renderer, &old.ClipRect); - // Setup desired state - ImGui_ImplSDLRenderer2_SetupRenderState(renderer); - - // Setup render state structure (for callbacks and custom texture bindings) - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - ImGui_ImplSDLRenderer2_RenderState render_state; - render_state.Renderer = renderer; - platform_io.Renderer_RenderState = &render_state; - // Will project scissor/clipping rectangles into framebuffer space ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports ImVec2 clip_scale = render_scale; // Render command lists + ImGui_ImplSDLRenderer2_SetupRenderState(renderer); for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data; - const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; + const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; - for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { // User callback, registered via ImDrawList::AddCallback() @@ -177,7 +164,7 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) ImGui_ImplSDLRenderer2_SetupRenderState(renderer); else - pcmd->UserCallback(draw_list, pcmd); + pcmd->UserCallback(cmd_list, pcmd); } else { @@ -208,12 +195,11 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* xy, (int)sizeof(ImDrawVert), color, (int)sizeof(ImDrawVert), uv, (int)sizeof(ImDrawVert), - draw_list->VtxBuffer.Size - pcmd->VtxOffset, + cmd_list->VtxBuffer.Size - pcmd->VtxOffset, idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx)); } } } - platform_io.Renderer_RenderState = nullptr; // Restore modified SDL_Renderer state SDL_RenderSetViewport(renderer, &old.Viewport); @@ -233,7 +219,7 @@ bool ImGui_ImplSDLRenderer2_CreateFontsTexture() // Upload texture to graphics system // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) - bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height); + bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height); if (bd->FontTexture == nullptr) { SDL_Log("error creating texture"); diff --git a/3rdparty/imgui/backends/imgui_impl_sdlrenderer2.h b/3rdparty/imgui/backends/imgui_impl_sdlrenderer2.h index f5b8172..7c662ca 100644 --- a/3rdparty/imgui/backends/imgui_impl_sdlrenderer2.h +++ b/3rdparty/imgui/backends/imgui_impl_sdlrenderer2.h @@ -1,18 +1,15 @@ // dear imgui: Renderer Backend for SDL_Renderer for SDL2 // (Requires: SDL 2.0.17+) -// Note that SDL_Renderer is an _optional_ component of SDL2, which IMHO is now largely obsolete. -// For a multi-platform app consider using other technologies: -// - SDL3+SDL_GPU: SDL_GPU is SDL3 new graphics abstraction API. You will need to update to SDL3. -// - SDL2+DirectX, SDL2+OpenGL, SDL2+Vulkan: combine SDL with dedicated renderers. -// If your application wants to render any non trivial amount of graphics other than UI, -// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user -// and it might be difficult to step out of those boundaries. +// Note how SDL_Renderer is an _optional_ component of SDL2. +// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. +// If your application will want to render any non trivial amount of graphics other than UI, +// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and +// it might be difficult to step out of those boundaries. // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // Missing features: // [ ] Renderer: Multi-viewport support (multiple windows). @@ -30,7 +27,6 @@ struct SDL_Renderer; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer); IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_NewFrame(); @@ -42,12 +38,4 @@ IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyFontsTexture(); IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyDeviceObjects(); -// [BETA] Selected render state data shared with callbacks. -// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplSDLRenderer2_RenderDrawData() call. -// (Please open an issue if you feel you need access to more data) -struct ImGui_ImplSDLRenderer2_RenderState -{ - SDL_Renderer* Renderer; -}; - #endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/backends/imgui_impl_sdlrenderer3.cpp b/3rdparty/imgui/backends/imgui_impl_sdlrenderer3.cpp index d76eebe..56d6113 100644 --- a/3rdparty/imgui/backends/imgui_impl_sdlrenderer3.cpp +++ b/3rdparty/imgui/backends/imgui_impl_sdlrenderer3.cpp @@ -1,18 +1,15 @@ // dear imgui: Renderer Backend for SDL_Renderer for SDL3 -// (Requires: SDL 3.1.8+) +// (Requires: SDL 3.0.0+) -// Note that SDL_Renderer is an _optional_ component of SDL3, which IMHO is now largely obsolete. -// For a multi-platform app consider using other technologies: -// - SDL3+SDL_GPU: SDL_GPU is SDL3 new graphics abstraction API. -// - SDL3+DirectX, SDL3+OpenGL, SDL3+Vulkan: combine SDL with dedicated renderers. -// If your application wants to render any non trivial amount of graphics other than UI, -// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user -// and it might be difficult to step out of those boundaries. +// Note how SDL_Renderer is an _optional_ component of SDL3. +// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. +// If your application will want to render any non trivial amount of graphics other than UI, +// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and +// it might be difficult to step out of those boundaries. // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // Missing features: // [ ] Renderer: Multi-viewport support (multiple windows). @@ -25,8 +22,6 @@ // - Introduction, links and more at the top of imgui.cpp // CHANGELOG -// 2025-01-18: Use endian-dependent RGBA32 texture format, to match SDL_Color. -// 2024-10-09: Expose selected render state in ImGui_ImplSDLRenderer3_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. // 2024-07-01: Update for SDL3 api changes: SDL_RenderGeometryRaw() uint32 version was removed (SDL#9009). // 2024-05-14: *BREAKING CHANGE* ImGui_ImplSDLRenderer3_RenderDrawData() requires SDL_Renderer* passed as parameter. // 2024-02-12: Amend to query SDL_RenderViewportSet() and restore viewport accordingly. @@ -163,34 +158,26 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* SDL_Rect ClipRect; }; BackupSDLRendererState old = {}; - old.ViewportEnabled = SDL_RenderViewportSet(renderer); - old.ClipEnabled = SDL_RenderClipEnabled(renderer); + old.ViewportEnabled = SDL_RenderViewportSet(renderer) == SDL_TRUE; + old.ClipEnabled = SDL_RenderClipEnabled(renderer) == SDL_TRUE; SDL_GetRenderViewport(renderer, &old.Viewport); SDL_GetRenderClipRect(renderer, &old.ClipRect); - // Setup desired state - ImGui_ImplSDLRenderer3_SetupRenderState(renderer); - - // Setup render state structure (for callbacks and custom texture bindings) - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - ImGui_ImplSDLRenderer3_RenderState render_state; - render_state.Renderer = renderer; - platform_io.Renderer_RenderState = &render_state; - // Will project scissor/clipping rectangles into framebuffer space ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports ImVec2 clip_scale = render_scale; // Render command lists + ImGui_ImplSDLRenderer3_SetupRenderState(renderer); for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data; - const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; + const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; - for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { // User callback, registered via ImDrawList::AddCallback() @@ -198,7 +185,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) ImGui_ImplSDLRenderer3_SetupRenderState(renderer); else - pcmd->UserCallback(draw_list, pcmd); + pcmd->UserCallback(cmd_list, pcmd); } else { @@ -225,12 +212,11 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* xy, (int)sizeof(ImDrawVert), color, (int)sizeof(ImDrawVert), uv, (int)sizeof(ImDrawVert), - draw_list->VtxBuffer.Size - pcmd->VtxOffset, + cmd_list->VtxBuffer.Size - pcmd->VtxOffset, idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx)); } } } - platform_io.Renderer_RenderState = nullptr; // Restore modified SDL_Renderer state SDL_SetRenderViewport(renderer, old.ViewportEnabled ? &old.Viewport : nullptr); @@ -250,7 +236,7 @@ bool ImGui_ImplSDLRenderer3_CreateFontsTexture() // Upload texture to graphics system // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) - bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height); + bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height); if (bd->FontTexture == nullptr) { SDL_Log("error creating texture"); diff --git a/3rdparty/imgui/backends/imgui_impl_sdlrenderer3.h b/3rdparty/imgui/backends/imgui_impl_sdlrenderer3.h index f79aa1b..a284743 100644 --- a/3rdparty/imgui/backends/imgui_impl_sdlrenderer3.h +++ b/3rdparty/imgui/backends/imgui_impl_sdlrenderer3.h @@ -1,18 +1,15 @@ // dear imgui: Renderer Backend for SDL_Renderer for SDL3 -// (Requires: SDL 3.1.8+) +// (Requires: SDL 3.0.0+) -// Note that SDL_Renderer is an _optional_ component of SDL3, which IMHO is now largely obsolete. -// For a multi-platform app consider using other technologies: -// - SDL3+SDL_GPU: SDL_GPU is SDL3 new graphics abstraction API. -// - SDL3+DirectX, SDL3+OpenGL, SDL3+Vulkan: combine SDL with dedicated renderers. -// If your application wants to render any non trivial amount of graphics other than UI, -// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user -// and it might be difficult to step out of those boundaries. +// Note how SDL_Renderer is an _optional_ component of SDL3. +// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. +// If your application will want to render any non trivial amount of graphics other than UI, +// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and +// it might be difficult to step out of those boundaries. // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // Missing features: // [ ] Renderer: Multi-viewport support (multiple windows). @@ -30,7 +27,6 @@ struct SDL_Renderer; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer); IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_NewFrame(); @@ -42,12 +38,4 @@ IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_DestroyFontsTexture(); IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_DestroyDeviceObjects(); -// [BETA] Selected render state data shared with callbacks. -// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplSDLRenderer3_RenderDrawData() call. -// (Please open an issue if you feel you need access to more data) -struct ImGui_ImplSDLRenderer3_RenderState -{ - SDL_Renderer* Renderer; -}; - #endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/backends/imgui_impl_vulkan.cpp b/3rdparty/imgui/backends/imgui_impl_vulkan.cpp index 03e1f8d..036307a 100644 --- a/3rdparty/imgui/backends/imgui_impl_vulkan.cpp +++ b/3rdparty/imgui/backends/imgui_impl_vulkan.cpp @@ -2,11 +2,18 @@ // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions. -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [x] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport). +// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'. +// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*. +// To build this on 32-bit systems and support texture changes: +// - [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in our .vcxproj files) +// - [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like. +// - [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!) +// - [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in our batch files) + // The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ @@ -27,14 +34,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2025-01-09: Vulkan: Added IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE to clarify how many image sampler descriptors are expected to be available in descriptor pool. (#6642) -// 2025-01-06: Vulkan: Added more ImGui_ImplVulkanH_XXXX helper functions to simplify our examples. -// 2024-12-11: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) -// 2024-11-27: Vulkan: Make user-provided descriptor pool optional. As a convenience, when setting init_info->DescriptorPoolSize the backend will create one itself. (#8172, #4867) -// 2024-10-07: Vulkan: Changed default texture sampler to Clamp instead of Repeat/Wrap. -// 2024-10-07: Vulkan: Expose selected render state in ImGui_ImplVulkan_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. -// 2024-10-07: Vulkan: Compiling with '#define ImTextureID=ImU64' is unnecessary now that dear imgui defaults ImTextureID to u64 instead of void*. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2024-04-19: Vulkan: Added convenience support for Volk via IMGUI_IMPL_VULKAN_USE_VOLK define (you can also use IMGUI_IMPL_VULKAN_NO_PROTOTYPES + wrap Volk via ImGui_ImplVulkan_LoadFunctions().) // 2024-02-14: *BREAKING CHANGE*: Moved RenderPass parameter from ImGui_ImplVulkan_Init() function to ImGui_ImplVulkan_InitInfo structure. Not required when using dynamic rendering. // 2024-02-12: *BREAKING CHANGE*: Dynamic rendering now require filling PipelineRenderingCreateInfo structure. @@ -141,7 +141,6 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetViewport) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateBuffer) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateCommandPool) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateDescriptorPool) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateDescriptorSetLayout) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateFence) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateFramebuffer) \ @@ -156,7 +155,6 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSwapchainKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyBuffer) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyCommandPool) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyDescriptorPool) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyDescriptorSetLayout) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyFence) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyFramebuffer) \ @@ -171,7 +169,6 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySurfaceKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySwapchainKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDeviceWaitIdle) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkEnumeratePhysicalDevices) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkEndCommandBuffer) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFlushMappedMemoryRanges) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeCommandBuffers) \ @@ -179,9 +176,7 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeMemory) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetBufferMemoryRequirements) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetImageMemoryRequirements) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceProperties) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceMemoryProperties) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceQueueFamilyProperties) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceFormatsKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfacePresentModesKHR) \ @@ -226,17 +221,7 @@ struct ImGui_ImplVulkan_WindowRenderBuffers { uint32_t Index; uint32_t Count; - ImVector FrameRenderBuffers; -}; - -struct ImGui_ImplVulkan_Texture -{ - VkDeviceMemory Memory; - VkImage Image; - VkImageView ImageView; - VkDescriptorSet DescriptorSet; - - ImGui_ImplVulkan_Texture() { memset((void*)this, 0, sizeof(*this)); } + ImGui_ImplVulkan_FrameRenderBuffers* FrameRenderBuffers; }; // For multi-viewport support: @@ -247,10 +232,9 @@ struct ImGui_ImplVulkan_ViewportData ImGui_ImplVulkan_WindowRenderBuffers RenderBuffers; // Used by all viewports bool WindowOwned; bool SwapChainNeedRebuild; // Flag when viewport swapchain resized in the middle of processing a frame - bool SwapChainSuboptimal; // Flag when VK_SUBOPTIMAL_KHR was returned. - ImGui_ImplVulkan_ViewportData() { WindowOwned = SwapChainNeedRebuild = SwapChainSuboptimal = false; memset(&RenderBuffers, 0, sizeof(RenderBuffers)); } - ~ImGui_ImplVulkan_ViewportData() { } + ImGui_ImplVulkan_ViewportData() { WindowOwned = SwapChainNeedRebuild = false; memset(&RenderBuffers, 0, sizeof(RenderBuffers)); } + ~ImGui_ImplVulkan_ViewportData() { } }; // Vulkan data @@ -265,13 +249,15 @@ struct ImGui_ImplVulkan_Data VkPipeline PipelineForViewports; // pipeline for secondary viewports (created by backend) VkShaderModule ShaderModuleVert; VkShaderModule ShaderModuleFrag; - VkDescriptorPool DescriptorPool; - // Texture management - ImGui_ImplVulkan_Texture FontTexture; - VkSampler TexSampler; - VkCommandPool TexCommandPool; - VkCommandBuffer TexCommandBuffer; + // Font data + VkSampler FontSampler; + VkDeviceMemory FontMemory; + VkImage FontImage; + VkImageView FontView; + VkDescriptorSet FontDescriptorSet; + VkCommandPool FontCommandPool; + VkCommandBuffer FontCommandBuffer; // Render buffers for main window ImGui_ImplVulkan_WindowRenderBuffers MainWindowRenderBuffers; @@ -288,8 +274,8 @@ struct ImGui_ImplVulkan_Data //----------------------------------------------------------------------------- // Forward Declarations -static void ImGui_ImplVulkan_InitMultiViewportSupport(); -static void ImGui_ImplVulkan_ShutdownMultiViewportSupport(); +static void ImGui_ImplVulkan_InitPlatformInterface(); +static void ImGui_ImplVulkan_ShutdownPlatformInterface(); // backends/vulkan/glsl_shader.vert, compiled with: // # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert @@ -436,7 +422,7 @@ static inline VkDeviceSize AlignBufferSize(VkDeviceSize size, VkDeviceSize align return (size + alignment - 1) & ~(alignment - 1); } -static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& buffer_size, VkDeviceSize new_size, VkBufferUsageFlagBits usage) +static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& buffer_size, size_t new_size, VkBufferUsageFlagBits usage) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; @@ -532,12 +518,12 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm ImGui_ImplVulkan_ViewportData* viewport_renderer_data = (ImGui_ImplVulkan_ViewportData*)draw_data->OwnerViewport->RendererUserData; IM_ASSERT(viewport_renderer_data != nullptr); ImGui_ImplVulkan_WindowRenderBuffers* wrb = &viewport_renderer_data->RenderBuffers; - if (wrb->FrameRenderBuffers.Size == 0) + if (wrb->FrameRenderBuffers == nullptr) { wrb->Index = 0; wrb->Count = v->ImageCount; - wrb->FrameRenderBuffers.resize(wrb->Count); - memset((void*)wrb->FrameRenderBuffers.Data, 0, wrb->FrameRenderBuffers.size_in_bytes()); + wrb->FrameRenderBuffers = (ImGui_ImplVulkan_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkan_FrameRenderBuffers) * wrb->Count); + memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkan_FrameRenderBuffers) * wrb->Count); } IM_ASSERT(wrb->Count == v->ImageCount); wrb->Index = (wrb->Index + 1) % wrb->Count; @@ -546,8 +532,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm if (draw_data->TotalVtxCount > 0) { // Create or resize the vertex/index buffers - VkDeviceSize vertex_size = AlignBufferSize(draw_data->TotalVtxCount * sizeof(ImDrawVert), bd->BufferMemoryAlignment); - VkDeviceSize index_size = AlignBufferSize(draw_data->TotalIdxCount * sizeof(ImDrawIdx), bd->BufferMemoryAlignment); + size_t vertex_size = AlignBufferSize(draw_data->TotalVtxCount * sizeof(ImDrawVert), bd->BufferMemoryAlignment); + size_t index_size = AlignBufferSize(draw_data->TotalIdxCount * sizeof(ImDrawIdx), bd->BufferMemoryAlignment); if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size) CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size) @@ -562,11 +548,11 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm check_vk_result(err); for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - vtx_dst += draw_list->VtxBuffer.Size; - idx_dst += draw_list->IdxBuffer.Size; + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vtx_dst += cmd_list->VtxBuffer.Size; + idx_dst += cmd_list->IdxBuffer.Size; } VkMappedMemoryRange range[2] = {}; range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; @@ -584,14 +570,6 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // Setup desired Vulkan state ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); - // Setup render state structure (for callbacks and custom texture bindings) - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - ImGui_ImplVulkan_RenderState render_state; - render_state.CommandBuffer = command_buffer; - render_state.Pipeline = pipeline; - render_state.PipelineLayout = bd->PipelineLayout; - platform_io.Renderer_RenderState = &render_state; - // Will project scissor/clipping rectangles into framebuffer space ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) @@ -602,10 +580,10 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm int global_idx_offset = 0; for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() @@ -613,7 +591,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height); else - pcmd->UserCallback(draw_list, pcmd); + pcmd->UserCallback(cmd_list, pcmd); } else { @@ -638,17 +616,22 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm vkCmdSetScissor(command_buffer, 0, 1, &scissor); // Bind DescriptorSet with font or user texture - VkDescriptorSet desc_set = (VkDescriptorSet)pcmd->GetTexID(); - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &desc_set, 0, nullptr); + VkDescriptorSet desc_set[1] = { (VkDescriptorSet)pcmd->TextureId }; + if (sizeof(ImTextureID) < sizeof(ImU64)) + { + // We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures haven't been used. + IM_ASSERT(pcmd->TextureId == (ImTextureID)bd->FontDescriptorSet); + desc_set[0] = bd->FontDescriptorSet; + } + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, desc_set, 0, nullptr); // Draw vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); } } - global_idx_offset += draw_list->IdxBuffer.Size; - global_vtx_offset += draw_list->VtxBuffer.Size; + global_idx_offset += cmd_list->IdxBuffer.Size; + global_vtx_offset += cmd_list->VtxBuffer.Size; } - platform_io.Renderer_RenderState = nullptr; // Note: at this point both vkCmdSetViewport() and vkCmdSetScissor() have been called. // Our last values will leak into user/application rendering IF: @@ -669,39 +652,39 @@ bool ImGui_ImplVulkan_CreateFontsTexture() VkResult err; // Destroy existing texture (if any) - if (bd->FontTexture.DescriptorSet) + if (bd->FontView || bd->FontImage || bd->FontMemory || bd->FontDescriptorSet) { vkQueueWaitIdle(v->Queue); ImGui_ImplVulkan_DestroyFontsTexture(); } // Create command pool/buffer - if (bd->TexCommandPool == VK_NULL_HANDLE) + if (bd->FontCommandPool == VK_NULL_HANDLE) { VkCommandPoolCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; info.flags = 0; info.queueFamilyIndex = v->QueueFamily; - vkCreateCommandPool(v->Device, &info, v->Allocator, &bd->TexCommandPool); + vkCreateCommandPool(v->Device, &info, v->Allocator, &bd->FontCommandPool); } - if (bd->TexCommandBuffer == VK_NULL_HANDLE) + if (bd->FontCommandBuffer == VK_NULL_HANDLE) { VkCommandBufferAllocateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - info.commandPool = bd->TexCommandPool; + info.commandPool = bd->FontCommandPool; info.commandBufferCount = 1; - err = vkAllocateCommandBuffers(v->Device, &info, &bd->TexCommandBuffer); + err = vkAllocateCommandBuffers(v->Device, &info, &bd->FontCommandBuffer); check_vk_result(err); } // Start command buffer { - err = vkResetCommandPool(v->Device, bd->TexCommandPool, 0); + err = vkResetCommandPool(v->Device, bd->FontCommandPool, 0); check_vk_result(err); VkCommandBufferBeginInfo begin_info = {}; begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - err = vkBeginCommandBuffer(bd->TexCommandBuffer, &begin_info); + err = vkBeginCommandBuffer(bd->FontCommandBuffer, &begin_info); check_vk_result(err); } @@ -711,7 +694,6 @@ bool ImGui_ImplVulkan_CreateFontsTexture() size_t upload_size = width * height * 4 * sizeof(char); // Create the Image: - ImGui_ImplVulkan_Texture* backend_tex = &bd->FontTexture; { VkImageCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -727,17 +709,17 @@ bool ImGui_ImplVulkan_CreateFontsTexture() info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - err = vkCreateImage(v->Device, &info, v->Allocator, &backend_tex->Image); + err = vkCreateImage(v->Device, &info, v->Allocator, &bd->FontImage); check_vk_result(err); VkMemoryRequirements req; - vkGetImageMemoryRequirements(v->Device, backend_tex->Image, &req); + vkGetImageMemoryRequirements(v->Device, bd->FontImage, &req); VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = IM_MAX(v->MinAllocationSize, req.size); alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits); - err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &backend_tex->Memory); + err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &bd->FontMemory); check_vk_result(err); - err = vkBindImageMemory(v->Device, backend_tex->Image, backend_tex->Memory, 0); + err = vkBindImageMemory(v->Device, bd->FontImage, bd->FontMemory, 0); check_vk_result(err); } @@ -745,18 +727,18 @@ bool ImGui_ImplVulkan_CreateFontsTexture() { VkImageViewCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - info.image = backend_tex->Image; + info.image = bd->FontImage; info.viewType = VK_IMAGE_VIEW_TYPE_2D; info.format = VK_FORMAT_R8G8B8A8_UNORM; info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; info.subresourceRange.levelCount = 1; info.subresourceRange.layerCount = 1; - err = vkCreateImageView(v->Device, &info, v->Allocator, &backend_tex->ImageView); + err = vkCreateImageView(v->Device, &info, v->Allocator, &bd->FontView); check_vk_result(err); } // Create the Descriptor Set: - backend_tex->DescriptorSet = ImGui_ImplVulkan_AddTexture(bd->TexSampler, backend_tex->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + bd->FontDescriptorSet = (VkDescriptorSet)ImGui_ImplVulkan_AddTexture(bd->FontSampler, bd->FontView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); // Create the Upload Buffer: VkDeviceMemory upload_buffer_memory; @@ -806,11 +788,11 @@ bool ImGui_ImplVulkan_CreateFontsTexture() copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; copy_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; copy_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - copy_barrier[0].image = backend_tex->Image; + copy_barrier[0].image = bd->FontImage; copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy_barrier[0].subresourceRange.levelCount = 1; copy_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, copy_barrier); + vkCmdPipelineBarrier(bd->FontCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, copy_barrier); VkBufferImageCopy region = {}; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -818,7 +800,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture() region.imageExtent.width = width; region.imageExtent.height = height; region.imageExtent.depth = 1; - vkCmdCopyBufferToImage(bd->TexCommandBuffer, upload_buffer, backend_tex->Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + vkCmdCopyBufferToImage(bd->FontCommandBuffer, upload_buffer, bd->FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); VkImageMemoryBarrier use_barrier[1] = {}; use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -828,22 +810,22 @@ bool ImGui_ImplVulkan_CreateFontsTexture() use_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; use_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; use_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - use_barrier[0].image = backend_tex->Image; + use_barrier[0].image = bd->FontImage; use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; use_barrier[0].subresourceRange.levelCount = 1; use_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, use_barrier); + vkCmdPipelineBarrier(bd->FontCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, use_barrier); } // Store our identifier - io.Fonts->SetTexID((ImTextureID)backend_tex->DescriptorSet); + io.Fonts->SetTexID((ImTextureID)bd->FontDescriptorSet); // End command buffer VkSubmitInfo end_info = {}; end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; end_info.commandBufferCount = 1; - end_info.pCommandBuffers = &bd->TexCommandBuffer; - err = vkEndCommandBuffer(bd->TexCommandBuffer); + end_info.pCommandBuffers = &bd->FontCommandBuffer; + err = vkEndCommandBuffer(bd->FontCommandBuffer); check_vk_result(err); err = vkQueueSubmit(v->Queue, 1, &end_info, VK_NULL_HANDLE); check_vk_result(err); @@ -864,17 +846,16 @@ void ImGui_ImplVulkan_DestroyFontsTexture() ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - ImGui_ImplVulkan_Texture* backend_tex = &bd->FontTexture; - - if (backend_tex->DescriptorSet) + if (bd->FontDescriptorSet) { - ImGui_ImplVulkan_RemoveTexture(backend_tex->DescriptorSet); - backend_tex->DescriptorSet = VK_NULL_HANDLE; + ImGui_ImplVulkan_RemoveTexture(bd->FontDescriptorSet); + bd->FontDescriptorSet = VK_NULL_HANDLE; io.Fonts->SetTexID(0); } - if (backend_tex->ImageView) { vkDestroyImageView(v->Device, backend_tex->ImageView, v->Allocator); backend_tex->ImageView = VK_NULL_HANDLE; } - if (backend_tex->Image) { vkDestroyImage(v->Device, backend_tex->Image, v->Allocator); backend_tex->Image = VK_NULL_HANDLE; } - if (backend_tex->Memory) { vkFreeMemory(v->Device, backend_tex->Memory, v->Allocator); backend_tex->Memory = VK_NULL_HANDLE; } + + if (bd->FontView) { vkDestroyImageView(v->Device, bd->FontView, v->Allocator); bd->FontView = VK_NULL_HANDLE; } + if (bd->FontImage) { vkDestroyImage(v->Device, bd->FontImage, v->Allocator); bd->FontImage = VK_NULL_HANDLE; } + if (bd->FontMemory) { vkFreeMemory(v->Device, bd->FontMemory, v->Allocator); bd->FontMemory = VK_NULL_HANDLE; } } static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAllocationCallbacks* allocator) @@ -1006,7 +987,7 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC if (bd->VulkanInitInfo.UseDynamicRendering) { IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR && "PipelineRenderingCreateInfo sType must be VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR"); - IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pNext == nullptr && "PipelineRenderingCreateInfo pNext must be nullptr"); + IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pNext == nullptr && "PipelineRenderingCreateInfo pNext must be NULL"); info.pNext = &bd->VulkanInitInfo.PipelineRenderingCreateInfo; info.renderPass = VK_NULL_HANDLE; // Just make sure it's actually nullptr. } @@ -1022,7 +1003,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; VkResult err; - if (!bd->TexSampler) + if (!bd->FontSampler) { // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. VkSamplerCreateInfo info = {}; @@ -1030,13 +1011,13 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() info.magFilter = VK_FILTER_LINEAR; info.minFilter = VK_FILTER_LINEAR; info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; info.minLod = -1000; info.maxLod = 1000; info.maxAnisotropy = 1.0f; - err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->TexSampler); + err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->FontSampler); check_vk_result(err); } @@ -1054,21 +1035,6 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } - if (v->DescriptorPoolSize != 0) - { - IM_ASSERT(v->DescriptorPoolSize > IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE); - VkDescriptorPoolSize pool_size = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, v->DescriptorPoolSize }; - VkDescriptorPoolCreateInfo pool_info = {}; - pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = v->DescriptorPoolSize; - pool_info.poolSizeCount = 1; - pool_info.pPoolSizes = &pool_size; - - err = vkCreateDescriptorPool(v->Device, &pool_info, v->Allocator, &bd->DescriptorPool); - check_vk_result(err); - } - if (!bd->PipelineLayout) { // Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix @@ -1099,27 +1065,17 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(v->Device, v->Allocator); ImGui_ImplVulkan_DestroyFontsTexture(); - if (bd->TexCommandBuffer) { vkFreeCommandBuffers(v->Device, bd->TexCommandPool, 1, &bd->TexCommandBuffer); bd->TexCommandBuffer = VK_NULL_HANDLE; } - if (bd->TexCommandPool) { vkDestroyCommandPool(v->Device, bd->TexCommandPool, v->Allocator); bd->TexCommandPool = VK_NULL_HANDLE; } - if (bd->TexSampler) { vkDestroySampler(v->Device, bd->TexSampler, v->Allocator); bd->TexSampler = VK_NULL_HANDLE; } + if (bd->FontCommandBuffer) { vkFreeCommandBuffers(v->Device, bd->FontCommandPool, 1, &bd->FontCommandBuffer); bd->FontCommandBuffer = VK_NULL_HANDLE; } + if (bd->FontCommandPool) { vkDestroyCommandPool(v->Device, bd->FontCommandPool, v->Allocator); bd->FontCommandPool = VK_NULL_HANDLE; } if (bd->ShaderModuleVert) { vkDestroyShaderModule(v->Device, bd->ShaderModuleVert, v->Allocator); bd->ShaderModuleVert = VK_NULL_HANDLE; } if (bd->ShaderModuleFrag) { vkDestroyShaderModule(v->Device, bd->ShaderModuleFrag, v->Allocator); bd->ShaderModuleFrag = VK_NULL_HANDLE; } + if (bd->FontSampler) { vkDestroySampler(v->Device, bd->FontSampler, v->Allocator); bd->FontSampler = VK_NULL_HANDLE; } if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; } if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; } if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; } if (bd->PipelineForViewports) { vkDestroyPipeline(v->Device, bd->PipelineForViewports, v->Allocator); bd->PipelineForViewports = VK_NULL_HANDLE; } - if (bd->DescriptorPool) { vkDestroyDescriptorPool(v->Device, bd->DescriptorPool, v->Allocator); bd->DescriptorPool = VK_NULL_HANDLE; } } -#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING -static void ImGui_ImplVulkan_LoadDynamicRenderingFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) -{ - // Manually load those two (see #5446) - ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func("vkCmdBeginRenderingKHR", user_data)); - ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(loader_func("vkCmdEndRenderingKHR", user_data)); -} -#endif - bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) { // Load function pointers @@ -1135,7 +1091,9 @@ bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const ch #undef IMGUI_VULKAN_FUNC_LOAD #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - ImGui_ImplVulkan_LoadDynamicRenderingFunctions(loader_func, user_data); + // Manually load those two (see #5446) + ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func("vkCmdBeginRenderingKHR", user_data)); + ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(loader_func("vkCmdEndRenderingKHR", user_data)); #endif #else IM_UNUSED(loader_func); @@ -1154,7 +1112,8 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) { #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING #ifndef IMGUI_IMPL_VULKAN_USE_LOADER - ImGui_ImplVulkan_LoadDynamicRenderingFunctions([](const char* function_name, void* user_data) { return vkGetInstanceProcAddr((VkInstance)user_data, function_name); }, (void*)info->Instance); + ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(vkGetInstanceProcAddr(info->Instance, "vkCmdBeginRenderingKHR")); + ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(vkGetInstanceProcAddr(info->Instance, "vkCmdEndRenderingKHR")); #endif IM_ASSERT(ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR != nullptr); IM_ASSERT(ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR != nullptr); @@ -1178,10 +1137,7 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) IM_ASSERT(info->PhysicalDevice != VK_NULL_HANDLE); IM_ASSERT(info->Device != VK_NULL_HANDLE); IM_ASSERT(info->Queue != VK_NULL_HANDLE); - if (info->DescriptorPool != VK_NULL_HANDLE) // Either DescriptorPool or DescriptorPoolSize must be set, not both! - IM_ASSERT(info->DescriptorPoolSize == 0); - else - IM_ASSERT(info->DescriptorPoolSize > 0); + IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE); IM_ASSERT(info->MinImageCount >= 2); IM_ASSERT(info->ImageCount >= info->MinImageCount); if (info->UseDynamicRendering == false) @@ -1195,7 +1151,8 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) ImGuiViewport* main_viewport = ImGui::GetMainViewport(); main_viewport->RendererUserData = IM_NEW(ImGui_ImplVulkan_ViewportData)(); - ImGui_ImplVulkan_InitMultiViewportSupport(); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplVulkan_InitPlatformInterface(); return true; } @@ -1216,7 +1173,7 @@ void ImGui_ImplVulkan_Shutdown() main_viewport->RendererUserData = nullptr; // Clean up windows - ImGui_ImplVulkan_ShutdownMultiViewportSupport(); + ImGui_ImplVulkan_ShutdownPlatformInterface(); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; @@ -1229,7 +1186,7 @@ void ImGui_ImplVulkan_NewFrame() ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplVulkan_Init()?"); - if (!bd->FontTexture.DescriptorSet) + if (!bd->FontDescriptorSet) ImGui_ImplVulkan_CreateFontsTexture(); } @@ -1249,20 +1206,19 @@ void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count) bd->VulkanInitInfo.MinImageCount = min_image_count; } -// Register a texture by creating a descriptor +// Register a texture // FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem, please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions. VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - VkDescriptorPool pool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool; // Create Descriptor Set: VkDescriptorSet descriptor_set; { VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = pool; + alloc_info.descriptorPool = v->DescriptorPool; alloc_info.descriptorSetCount = 1; alloc_info.pSetLayouts = &bd->DescriptorSetLayout; VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set); @@ -1290,8 +1246,7 @@ void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - VkDescriptorPool pool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool; - vkFreeDescriptorSets(v->Device, pool, 1, &descriptor_set); + vkFreeDescriptorSets(v->Device, v->DescriptorPool, 1, &descriptor_set); } void ImGui_ImplVulkan_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkan_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator) @@ -1308,7 +1263,8 @@ void ImGui_ImplVulkan_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulk { for (uint32_t n = 0; n < buffers->Count; n++) ImGui_ImplVulkan_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator); - buffers->FrameRenderBuffers.clear(); + IM_FREE(buffers->FrameRenderBuffers); + buffers->FrameRenderBuffers = nullptr; buffers->Index = 0; buffers->Count = 0; } @@ -1397,49 +1353,6 @@ VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_d return VK_PRESENT_MODE_FIFO_KHR; // Always available } -VkPhysicalDevice ImGui_ImplVulkanH_SelectPhysicalDevice(VkInstance instance) -{ - uint32_t gpu_count; - VkResult err = vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr); - check_vk_result(err); - IM_ASSERT(gpu_count > 0); - - ImVector gpus; - gpus.resize(gpu_count); - err = vkEnumeratePhysicalDevices(instance, &gpu_count, gpus.Data); - check_vk_result(err); - - // If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers - // most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple - // dedicated GPUs) is out of scope of this sample. - for (VkPhysicalDevice& device : gpus) - { - VkPhysicalDeviceProperties properties; - vkGetPhysicalDeviceProperties(device, &properties); - if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) - return device; - } - - // Use first GPU (Integrated) is a Discrete one is not available. - if (gpu_count > 0) - return gpus[0]; - return VK_NULL_HANDLE; -} - - -uint32_t ImGui_ImplVulkanH_SelectQueueFamilyIndex(VkPhysicalDevice physical_device) -{ - uint32_t count; - vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count, nullptr); - ImVector queues_properties; - queues_properties.resize((int)count); - vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count, queues_properties.Data); - for (uint32_t i = 0; i < count; i++) - if (queues_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) - return i; - return (uint32_t)-1; -} - void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator) { IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE); @@ -1517,8 +1430,10 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator); for (uint32_t i = 0; i < wd->SemaphoreCount; i++) ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator); - wd->Frames.clear(); - wd->FrameSemaphores.clear(); + IM_FREE(wd->Frames); + IM_FREE(wd->FrameSemaphores); + wd->Frames = nullptr; + wd->FrameSemaphores = nullptr; wd->ImageCount = 0; if (wd->RenderPass) vkDestroyRenderPass(device, wd->RenderPass, allocator); @@ -1529,10 +1444,6 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V // Create Swapchain { - VkSurfaceCapabilitiesKHR cap; - err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, wd->Surface, &cap); - check_vk_result(err); - VkSwapchainCreateInfoKHR info = {}; info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; info.surface = wd->Surface; @@ -1542,15 +1453,19 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V info.imageArrayLayers = 1; info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; // Assume that graphics family == present family - info.preTransform = (cap.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : cap.currentTransform; + info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; info.presentMode = wd->PresentMode; info.clipped = VK_TRUE; info.oldSwapchain = old_swapchain; + VkSurfaceCapabilitiesKHR cap; + err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, wd->Surface, &cap); + check_vk_result(err); if (info.minImageCount < cap.minImageCount) info.minImageCount = cap.minImageCount; else if (cap.maxImageCount != 0 && info.minImageCount > cap.maxImageCount) info.minImageCount = cap.maxImageCount; + if (cap.currentExtent.width == 0xffffffff) { info.imageExtent.width = wd->Width = w; @@ -1571,11 +1486,12 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers); check_vk_result(err); + IM_ASSERT(wd->Frames == nullptr && wd->FrameSemaphores == nullptr); wd->SemaphoreCount = wd->ImageCount + 1; - wd->Frames.resize(wd->ImageCount); - wd->FrameSemaphores.resize(wd->SemaphoreCount); - memset(wd->Frames.Data, 0, wd->Frames.size_in_bytes()); - memset(wd->FrameSemaphores.Data, 0, wd->FrameSemaphores.size_in_bytes()); + wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount); + wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->SemaphoreCount); + memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount); + memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->SemaphoreCount); for (uint32_t i = 0; i < wd->ImageCount; i++) wd->Frames[i].Backbuffer = backbuffers[i]; } @@ -1686,8 +1602,10 @@ void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator); for (uint32_t i = 0; i < wd->SemaphoreCount; i++) ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator); - wd->Frames.clear(); - wd->FrameSemaphores.clear(); + IM_FREE(wd->Frames); + IM_FREE(wd->FrameSemaphores); + wd->Frames = nullptr; + wd->FrameSemaphores = nullptr; vkDestroyRenderPass(device, wd->RenderPass, allocator); vkDestroySwapchainKHR(device, wd->Swapchain, allocator); vkDestroySurfaceKHR(instance, wd->Surface, allocator); @@ -1815,26 +1733,24 @@ static void ImGui_ImplVulkan_RenderWindow(ImGuiViewport* viewport, void*) ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; VkResult err; - if (vd->SwapChainNeedRebuild || vd->SwapChainSuboptimal) + if (vd->SwapChainNeedRebuild) { ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount); - vd->SwapChainNeedRebuild = vd->SwapChainSuboptimal = false; + vd->SwapChainNeedRebuild = false; } - ImGui_ImplVulkanH_Frame* fd = nullptr; + ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex]; { { err = vkAcquireNextImageKHR(v->Device, wd->Swapchain, UINT64_MAX, fsd->ImageAcquiredSemaphore, VK_NULL_HANDLE, &wd->FrameIndex); if (err == VK_ERROR_OUT_OF_DATE_KHR) { - vd->SwapChainNeedRebuild = true; // Since we are not going to swap this frame anyway, it's ok that recreation happens on next frame. + // Since we are not going to swap this frame anyway, it's ok that recreation happens on next frame. + vd->SwapChainNeedRebuild = true; return; } - if (err == VK_SUBOPTIMAL_KHR) - vd->SwapChainSuboptimal = true; - else - check_vk_result(err); + check_vk_result(err); fd = &wd->Frames[wd->FrameIndex]; } for (;;) @@ -1976,19 +1892,18 @@ static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*) info.pSwapchains = &wd->Swapchain; info.pImageIndices = &present_index; err = vkQueuePresentKHR(v->Queue, &info); - if (err == VK_ERROR_OUT_OF_DATE_KHR) + if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) { vd->SwapChainNeedRebuild = true; return; } - if (err == VK_SUBOPTIMAL_KHR) - vd->SwapChainSuboptimal = true; - else - check_vk_result(err); + check_vk_result(err); + + wd->FrameIndex = (wd->FrameIndex + 1) % wd->ImageCount; // This is for the next vkWaitForFences() wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores } -void ImGui_ImplVulkan_InitMultiViewportSupport() +void ImGui_ImplVulkan_InitPlatformInterface() { ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) @@ -2000,7 +1915,7 @@ void ImGui_ImplVulkan_InitMultiViewportSupport() platform_io.Renderer_SwapBuffers = ImGui_ImplVulkan_SwapBuffers; } -void ImGui_ImplVulkan_ShutdownMultiViewportSupport() +void ImGui_ImplVulkan_ShutdownPlatformInterface() { ImGui::DestroyPlatformWindows(); } diff --git a/3rdparty/imgui/backends/imgui_impl_vulkan.h b/3rdparty/imgui/backends/imgui_impl_vulkan.h index d90f003..2358d66 100644 --- a/3rdparty/imgui/backends/imgui_impl_vulkan.h +++ b/3rdparty/imgui/backends/imgui_impl_vulkan.h @@ -2,11 +2,13 @@ // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions. -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [x] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport). +// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'. +// See imgui_impl_vulkan.cpp file for details. + // The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ @@ -62,18 +64,11 @@ #define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING #endif -// Current version of the backend use 1 descriptor for the font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture(). -// It is expected that as early as Q1 2025 the backend will use a few more descriptors. Use this value + number of desired calls to ImGui_ImplVulkan_AddTexture(). -#define IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE (1) // Minimum per atlas - // Initialization data, for ImGui_ImplVulkan_Init() +// - VkDescriptorPool should be created with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, +// and must contain a pool size large enough to hold an ImGui VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor. +// - When using dynamic rendering, set UseDynamicRendering=true and fill PipelineRenderingCreateInfo structure. // [Please zero-clear before use!] -// - About descriptor pool: -// - A VkDescriptorPool should be created with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, -// and must contain a pool size large enough to hold a small number of VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptors. -// - As an convenience, by setting DescriptorPoolSize > 0 the backend will create one for you. -// - About dynamic rendering: -// - When using dynamic rendering, set UseDynamicRendering=true and fill PipelineRenderingCreateInfo structure. struct ImGui_ImplVulkan_InitInfo { VkInstance Instance; @@ -81,7 +76,7 @@ struct ImGui_ImplVulkan_InitInfo VkDevice Device; uint32_t QueueFamily; VkQueue Queue; - VkDescriptorPool DescriptorPool; // See requirements in note above; ignored if using DescriptorPoolSize > 0 + VkDescriptorPool DescriptorPool; // See requirements in note above VkRenderPass RenderPass; // Ignored if using dynamic rendering uint32_t MinImageCount; // >= 2 uint32_t ImageCount; // >= MinImageCount @@ -91,9 +86,6 @@ struct ImGui_ImplVulkan_InitInfo VkPipelineCache PipelineCache; uint32_t Subpass; - // (Optional) Set to create internal descriptor pool instead of using DescriptorPool - uint32_t DescriptorPoolSize; - // (Optional) Dynamic Rendering // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3. bool UseDynamicRendering; @@ -107,55 +99,39 @@ struct ImGui_ImplVulkan_InitInfo VkDeviceSize MinAllocationSize; // Minimum allocation size. Set to 1024*1024 to satisfy zealous best practices validation layer and waste a little memory. }; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! -IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info); -IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); -IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); -IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE); -IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated) +// Called by user code +IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info); +IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); +IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE); +IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(); +IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture(); +IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated) // Register a texture (VkDescriptorSet == ImTextureID) // FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem // Please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions. -IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout); -IMGUI_IMPL_API void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set); +IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout); +IMGUI_IMPL_API void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set); // Optional: load Vulkan functions with a custom function loader // This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES -IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = nullptr); - -// [BETA] Selected render state data shared with callbacks. -// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplVulkan_RenderDrawData() call. -// (Please open an issue if you feel you need access to more data) -struct ImGui_ImplVulkan_RenderState -{ - VkCommandBuffer CommandBuffer; - VkPipeline Pipeline; - VkPipelineLayout PipelineLayout; -}; +IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = nullptr); //------------------------------------------------------------------------- // Internal / Miscellaneous Vulkan Helpers +// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.) //------------------------------------------------------------------------- -// Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app. -// // You probably do NOT need to use or care about those functions. // Those functions only exist because: // 1) they facilitate the readability and maintenance of the multiple main.cpp examples files. // 2) the multi-viewport / platform window implementation needs them internally. -// Generally we avoid exposing any kind of superfluous high-level helpers in the backends, +// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings, // but it is too much code to duplicate everywhere so we exceptionally expose them. // -// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, -// render pass, frame buffers, etc.). You may read this code if you are curious, but -// it is recommended you use you own custom tailored code to do equivalent work. -// -// We don't provide a strong guarantee that we won't change those functions API. -// -// The ImGui_ImplVulkanH_XXX functions should NOT interact with any of the state used -// by the regular ImGui_ImplVulkan_XXX functions). +// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.). +// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work. +// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions) //------------------------------------------------------------------------- struct ImGui_ImplVulkanH_Frame; @@ -166,8 +142,6 @@ IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateOrResizeWindow(VkIns IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator); IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space); IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count); -IMGUI_IMPL_API VkPhysicalDevice ImGui_ImplVulkanH_SelectPhysicalDevice(VkInstance instance); -IMGUI_IMPL_API uint32_t ImGui_ImplVulkanH_SelectQueueFamilyIndex(VkPhysicalDevice physical_device); IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode); // Helper structure to hold the data needed by one rendering frame @@ -207,8 +181,8 @@ struct ImGui_ImplVulkanH_Window uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count) uint32_t SemaphoreCount; // Number of simultaneous in-flight frames + 1, to be able to use it in vkAcquireNextImageKHR uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data) - ImVector Frames; - ImVector FrameSemaphores; + ImGui_ImplVulkanH_Frame* Frames; + ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores; ImGui_ImplVulkanH_Window() { diff --git a/3rdparty/imgui/backends/imgui_impl_wgpu.cpp b/3rdparty/imgui/backends/imgui_impl_wgpu.cpp index e414a12..ceee552 100644 --- a/3rdparty/imgui/backends/imgui_impl_wgpu.cpp +++ b/3rdparty/imgui/backends/imgui_impl_wgpu.cpp @@ -4,8 +4,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // Missing features: // [ ] Renderer: Multi-viewport support (multiple windows). Not meaningful on the web. @@ -19,10 +18,6 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2024-10-14: Update Dawn support for change of string usages. (#8082, #8083) -// 2024-10-07: Expose selected render state in ImGui_ImplWGPU_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. -// 2024-10-07: Changed default texture sampler to Clamp instead of Repeat/Wrap. -// 2024-09-16: Added support for optional IMGUI_IMPL_WEBGPU_BACKEND_DAWN / IMGUI_IMPL_WEBGPU_BACKEND_WGPU define to handle ever-changing native implementations. (#7977) // 2024-01-22: Added configurable PipelineMultisampleState struct. (#7240) // 2024-01-22: (Breaking) ImGui_ImplWGPU_Init() now takes a ImGui_ImplWGPU_InitInfo structure instead of variety of parameters, allowing for easier further changes. // 2024-01-22: Fixed pipeline layout leak. (#7245) @@ -42,18 +37,6 @@ // 2021-02-18: Change blending equation to preserve alpha in output buffer. // 2021-01-28: Initial version. -// When targeting native platforms (i.e. NOT emscripten), one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN -// or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be provided. See imgui_impl_wgpu.h for more details. -#ifndef __EMSCRIPTEN__ - #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) == defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) - #error exactly one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be defined! - #endif -#else - #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) - #error neither IMGUI_IMPL_WEBGPU_BACKEND_DAWN nor IMGUI_IMPL_WEBGPU_BACKEND_WGPU may be defined if targeting emscripten! - #endif -#endif - #include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_wgpu.h" @@ -263,26 +246,16 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const c { ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN - WGPUShaderSourceWGSL wgsl_desc = {}; - wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL; - wgsl_desc.code = { wgsl_source, WGPU_STRLEN }; -#else - WGPUShaderModuleWGSLDescriptor wgsl_desc = {}; + WGPUShaderModuleWGSLDescriptor wgsl_desc = {}; wgsl_desc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor; - wgsl_desc.code = wgsl_source; -#endif + wgsl_desc.code = wgsl_source; WGPUShaderModuleDescriptor desc = {}; desc.nextInChain = reinterpret_cast(&wgsl_desc); WGPUProgrammableStageDescriptor stage_desc = {}; stage_desc.module = wgpuDeviceCreateShaderModule(bd->wgpuDevice, &desc); -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN - stage_desc.entryPoint = { "main", WGPU_STRLEN }; -#else stage_desc.entryPoint = "main"; -#endif return stage_desc; } @@ -395,9 +368,6 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder { nullptr, "Dear ImGui Vertex buffer", -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN - WGPU_STRLEN, -#endif WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex, MEMALIGN(fr->VertexBufferSize * sizeof(ImDrawVert), 4), false @@ -422,9 +392,6 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder { nullptr, "Dear ImGui Index buffer", -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN - WGPU_STRLEN, -#endif WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index, MEMALIGN(fr->IndexBufferSize * sizeof(ImDrawIdx), 4), false @@ -441,11 +408,11 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder ImDrawIdx* idx_dst = (ImDrawIdx*)fr->IndexBufferHost; for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); - memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); - vtx_dst += draw_list->VtxBuffer.Size; - idx_dst += draw_list->IdxBuffer.Size; + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vtx_dst += cmd_list->VtxBuffer.Size; + idx_dst += cmd_list->IdxBuffer.Size; } int64_t vb_write_size = MEMALIGN((char*)vtx_dst - (char*)fr->VertexBufferHost, 4); int64_t ib_write_size = MEMALIGN((char*)idx_dst - (char*)fr->IndexBufferHost, 4); @@ -455,13 +422,6 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder // Setup desired render state ImGui_ImplWGPU_SetupRenderState(draw_data, pass_encoder, fr); - // Setup render state structure (for callbacks and custom texture bindings) - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - ImGui_ImplWGPU_RenderState render_state; - render_state.Device = bd->wgpuDevice; - render_state.RenderPassEncoder = pass_encoder; - platform_io.Renderer_RenderState = &render_state; - // Render command lists // (Because we merged all buffers into a single one, we maintain our own offset into them) int global_vtx_offset = 0; @@ -470,10 +430,10 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder ImVec2 clip_off = draw_data->DisplayPos; for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() @@ -481,7 +441,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) ImGui_ImplWGPU_SetupRenderState(draw_data, pass_encoder, fr); else - pcmd->UserCallback(draw_list, pcmd); + pcmd->UserCallback(cmd_list, pcmd); } else { @@ -517,10 +477,9 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder wgpuRenderPassEncoderDrawIndexed(pass_encoder, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); } } - global_idx_offset += draw_list->IdxBuffer.Size; - global_vtx_offset += draw_list->VtxBuffer.Size; + global_idx_offset += cmd_list->IdxBuffer.Size; + global_vtx_offset += cmd_list->VtxBuffer.Size; } - platform_io.Renderer_RenderState = nullptr; } static void ImGui_ImplWGPU_CreateFontsTexture() @@ -535,11 +494,7 @@ static void ImGui_ImplWGPU_CreateFontsTexture() // Upload texture to graphics system { WGPUTextureDescriptor tex_desc = {}; -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN - tex_desc.label = { "Dear ImGui Font Texture", WGPU_STRLEN }; -#else tex_desc.label = "Dear ImGui Font Texture"; -#endif tex_desc.dimension = WGPUTextureDimension_2D; tex_desc.size.width = width; tex_desc.size.height = height; @@ -583,9 +538,9 @@ static void ImGui_ImplWGPU_CreateFontsTexture() sampler_desc.minFilter = WGPUFilterMode_Linear; sampler_desc.magFilter = WGPUFilterMode_Linear; sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Linear; - sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeW = WGPUAddressMode_ClampToEdge; + sampler_desc.addressModeU = WGPUAddressMode_Repeat; + sampler_desc.addressModeV = WGPUAddressMode_Repeat; + sampler_desc.addressModeW = WGPUAddressMode_Repeat; sampler_desc.maxAnisotropy = 1; bd->renderResources.Sampler = wgpuDeviceCreateSampler(bd->wgpuDevice, &sampler_desc); } @@ -602,9 +557,6 @@ static void ImGui_ImplWGPU_CreateUniformBuffer() { nullptr, "Dear ImGui Uniform buffer", -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN - WGPU_STRLEN, -#endif WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform, MEMALIGN(sizeof(Uniforms), 16), false @@ -710,11 +662,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() // Create depth-stencil State WGPUDepthStencilState depth_stencil_state = {}; depth_stencil_state.format = bd->depthStencilFormat; -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN - depth_stencil_state.depthWriteEnabled = WGPUOptionalBool_False; -#else depth_stencil_state.depthWriteEnabled = false; -#endif depth_stencil_state.depthCompare = WGPUCompareFunction_Always; depth_stencil_state.stencilFront.compare = WGPUCompareFunction_Always; depth_stencil_state.stencilFront.failOp = WGPUStencilOperation_Keep; @@ -784,15 +732,7 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info) // Setup backend capabilities flags ImGui_ImplWGPU_Data* bd = IM_NEW(ImGui_ImplWGPU_Data)(); io.BackendRendererUserData = (void*)bd; -#if defined(__EMSCRIPTEN__) - io.BackendRendererName = "imgui_impl_webgpu_emscripten"; -#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) - io.BackendRendererName = "imgui_impl_webgpu_dawn"; -#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) - io.BackendRendererName = "imgui_impl_webgpu_wgpu"; -#else io.BackendRendererName = "imgui_impl_webgpu"; -#endif io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. bd->initInfo = *init_info; diff --git a/3rdparty/imgui/backends/imgui_impl_wgpu.h b/3rdparty/imgui/backends/imgui_impl_wgpu.h index 3262ac5..a43f34c 100644 --- a/3rdparty/imgui/backends/imgui_impl_wgpu.h +++ b/3rdparty/imgui/backends/imgui_impl_wgpu.h @@ -2,17 +2,9 @@ // This needs to be used along with a Platform Binding (e.g. GLFW) // (Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break.) -// Important note to dawn and/or wgpu users: when targeting native platforms (i.e. NOT emscripten), -// one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be provided. -// Add #define to your imconfig.h file, or as a compilation flag in your build system. -// This requirement will be removed once WebGPU stabilizes and backends converge on a unified interface. -//#define IMGUI_IMPL_WEBGPU_BACKEND_DAWN -//#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU - // Implemented features: // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // Missing features: // [ ] Renderer: Multi-viewport support (multiple windows). Not meaningful on the web. @@ -47,23 +39,13 @@ struct ImGui_ImplWGPU_InitInfo } }; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info); IMGUI_IMPL_API void ImGui_ImplWGPU_Shutdown(); IMGUI_IMPL_API void ImGui_ImplWGPU_NewFrame(); IMGUI_IMPL_API void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder pass_encoder); // Use if you want to reset your rendering device without losing Dear ImGui state. -IMGUI_IMPL_API bool ImGui_ImplWGPU_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplWGPU_InvalidateDeviceObjects(); - -// [BETA] Selected render state data shared with callbacks. -// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplWGPU_RenderDrawData() call. -// (Please open an issue if you feel you need access to more data) -struct ImGui_ImplWGPU_RenderState -{ - WGPUDevice Device; - WGPURenderPassEncoder RenderPassEncoder; -}; +IMGUI_IMPL_API bool ImGui_ImplWGPU_CreateDeviceObjects(); #endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/backends/imgui_impl_win32.cpp b/3rdparty/imgui/backends/imgui_impl_win32.cpp index 3c7f7b3..7470e5e 100644 --- a/3rdparty/imgui/backends/imgui_impl_win32.cpp +++ b/3rdparty/imgui/backends/imgui_impl_win32.cpp @@ -4,9 +4,9 @@ // Implemented features: // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. -// [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 VK_* values are obsolete since 1.87 and not supported since 1.91.5] +// [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 VK_* 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 (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -22,10 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2024-11-21: [Docking] Fixed a crash when multiple processes are running with multi-viewports, caused by misusage of GetProp(). (#8162, #8069) -// 2024-10-28: [Docking] Rely on property stored inside HWND to retrieve context/viewport, should facilitate attempt to use this for parallel contexts. (#8069) -// 2024-09-16: [Docking] Inputs: fixed an issue where a viewport destroyed while clicking would hog mouse tracking and temporary lead to incorrect update of HoveredWindow. (#7971) +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2024-07-08: Inputs: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. (#7768) // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys. // 2023-09-25: Inputs: Synthesize key-down event on key-up for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit it (same behavior as GLFW/SDL). @@ -109,15 +106,15 @@ typedef DWORD(WINAPI* PFN_XInputGetState)(DWORD, XINPUT_STATE*); #endif // Forward Declarations -static void ImGui_ImplWin32_InitMultiViewportSupport(bool platform_has_own_dc); -static void ImGui_ImplWin32_ShutdownMultiViewportSupport(); +static void ImGui_ImplWin32_InitPlatformInterface(bool platform_has_own_dc); +static void ImGui_ImplWin32_ShutdownPlatformInterface(); static void ImGui_ImplWin32_UpdateMonitors(); struct ImGui_ImplWin32_Data { HWND hWnd; HWND MouseHwnd; - int MouseTrackedArea; // 0: not tracked, 1: client area, 2: non-client area + int MouseTrackedArea; // 0: not tracked, 1: client are, 2: non-client area int MouseButtonsDown; INT64 Time; INT64 TicksPerSecond; @@ -144,16 +141,12 @@ static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplWin32_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; } -static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData(ImGuiIO& io) -{ - return (ImGui_ImplWin32_Data*)io.BackendPlatformUserData; -} // Functions -static void ImGui_ImplWin32_UpdateKeyboardCodePage(ImGuiIO& io) +static void ImGui_ImplWin32_UpdateKeyboardCodePage() { // Retrieve keyboard code page, required for handling of non-Unicode Windows. - ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); HKL keyboard_layout = ::GetKeyboardLayout(0); LCID keyboard_lcid = MAKELCID(HIWORD(keyboard_layout), SORT_DEFAULT); if (::GetLocaleInfoA(keyboard_lcid, (LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE), (LPSTR)&bd->KeyboardCodePage, sizeof(bd->KeyboardCodePage)) == 0) @@ -182,22 +175,17 @@ static bool ImGui_ImplWin32_InitEx(void* hwnd, bool platform_has_own_dc) io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional) bd->hWnd = (HWND)hwnd; + bd->WantUpdateMonitors = true; bd->TicksPerSecond = perf_frequency; bd->Time = perf_counter; bd->LastMouseCursor = ImGuiMouseCursor_COUNT; - ImGui_ImplWin32_UpdateKeyboardCodePage(io); - - // Update monitor a first time during init - ImGui_ImplWin32_UpdateMonitors(); + ImGui_ImplWin32_UpdateKeyboardCodePage(); // Our mouse update function expect PlatformHandle to be filled for the main viewport ImGuiViewport* main_viewport = ImGui::GetMainViewport(); main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (void*)bd->hWnd; - - // Be aware that GetPropA()/SetPropA() may be accessed from other processes. - // So as we store a pointer in IMGUI_CONTEXT we need to make sure we only call GetPropA() on windows owned by our process. - ::SetPropA(bd->hWnd, "IMGUI_CONTEXT", ImGui::GetCurrentContext()); - ImGui_ImplWin32_InitMultiViewportSupport(platform_has_own_dc); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplWin32_InitPlatformInterface(platform_has_own_dc); // Dynamically load XInput library #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD @@ -240,8 +228,7 @@ void ImGui_ImplWin32_Shutdown() IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); - ::SetPropA(bd->hWnd, "IMGUI_CONTEXT", nullptr); - ImGui_ImplWin32_ShutdownMultiViewportSupport(); + ImGui_ImplWin32_ShutdownPlatformInterface(); // Unload XInput library #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD @@ -255,11 +242,13 @@ void ImGui_ImplWin32_Shutdown() IM_DELETE(bd); } -static bool ImGui_ImplWin32_UpdateMouseCursor(ImGuiIO& io, ImGuiMouseCursor imgui_cursor) +static bool ImGui_ImplWin32_UpdateMouseCursor() { + ImGuiIO& io = ImGui::GetIO(); if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) return false; + ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) { // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor @@ -291,62 +280,54 @@ static bool IsVkDown(int vk) return (::GetKeyState(vk) & 0x8000) != 0; } -static void ImGui_ImplWin32_AddKeyEvent(ImGuiIO& io, ImGuiKey key, bool down, int native_keycode, int native_scancode = -1) +static void ImGui_ImplWin32_AddKeyEvent(ImGuiKey key, bool down, int native_keycode, int native_scancode = -1) { + ImGuiIO& io = ImGui::GetIO(); io.AddKeyEvent(key, down); io.SetKeyEventNativeData(key, native_keycode, native_scancode); // To support legacy indexing (<1.87 user code) IM_UNUSED(native_scancode); } -static void ImGui_ImplWin32_ProcessKeyEventsWorkarounds(ImGuiIO& io) +static void ImGui_ImplWin32_ProcessKeyEventsWorkarounds() { // Left & right Shift keys: when both are pressed together, Windows tend to not generate the WM_KEYUP event for the first released one. if (ImGui::IsKeyDown(ImGuiKey_LeftShift) && !IsVkDown(VK_LSHIFT)) - ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftShift, false, VK_LSHIFT); + ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, false, VK_LSHIFT); if (ImGui::IsKeyDown(ImGuiKey_RightShift) && !IsVkDown(VK_RSHIFT)) - ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightShift, false, VK_RSHIFT); + ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, false, VK_RSHIFT); // Sometimes WM_KEYUP for Win key is not passed down to the app (e.g. for Win+V on some setups, according to GLFW). if (ImGui::IsKeyDown(ImGuiKey_LeftSuper) && !IsVkDown(VK_LWIN)) - ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftSuper, false, VK_LWIN); + ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftSuper, false, VK_LWIN); if (ImGui::IsKeyDown(ImGuiKey_RightSuper) && !IsVkDown(VK_RWIN)) - ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightSuper, false, VK_RWIN); + ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightSuper, false, VK_RWIN); } -static void ImGui_ImplWin32_UpdateKeyModifiers(ImGuiIO& io) +static void ImGui_ImplWin32_UpdateKeyModifiers() { + ImGuiIO& io = ImGui::GetIO(); io.AddKeyEvent(ImGuiMod_Ctrl, IsVkDown(VK_CONTROL)); io.AddKeyEvent(ImGuiMod_Shift, IsVkDown(VK_SHIFT)); io.AddKeyEvent(ImGuiMod_Alt, IsVkDown(VK_MENU)); io.AddKeyEvent(ImGuiMod_Super, IsVkDown(VK_LWIN) || IsVkDown(VK_RWIN)); } -static ImGuiViewport* ImGui_ImplWin32_FindViewportByPlatformHandle(ImGuiPlatformIO& platform_io, HWND hwnd) -{ - // We cannot use ImGui::FindViewportByPlatformHandle() because it doesn't take a context. - // When called from ImGui_ImplWin32_WndProcHandler_PlatformWindow() we don't assume that context is bound. - //return ImGui::FindViewportByPlatformHandle((void*)hwnd); - for (ImGuiViewport* viewport : platform_io.Viewports) - if (viewport->PlatformHandle == hwnd) - return viewport; - return nullptr; -} - // This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports) // Because of that, it is a little more complicated than your typical single-viewport binding code! -static void ImGui_ImplWin32_UpdateMouseData(ImGuiIO& io, ImGuiPlatformIO& platform_io) +static void ImGui_ImplWin32_UpdateMouseData() { - ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); + ImGuiIO& io = ImGui::GetIO(); IM_ASSERT(bd->hWnd != 0); POINT mouse_screen_pos; bool has_mouse_screen_pos = ::GetCursorPos(&mouse_screen_pos) != 0; HWND focused_window = ::GetForegroundWindow(); - const bool is_app_focused = (focused_window && (focused_window == bd->hWnd || ::IsChild(focused_window, bd->hWnd) || ImGui_ImplWin32_FindViewportByPlatformHandle(platform_io, focused_window))); + const bool is_app_focused = (focused_window && (focused_window == bd->hWnd || ::IsChild(focused_window, bd->hWnd) || ImGui::FindViewportByPlatformHandle((void*)focused_window))); if (is_app_focused) { - // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user) + // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) // When multi-viewports are enabled, all Dear ImGui positions are same as OS positions. if (io.WantSetMousePos) { @@ -381,16 +362,17 @@ static void ImGui_ImplWin32_UpdateMouseData(ImGuiIO& io, ImGuiPlatformIO& platfo ImGuiID mouse_viewport_id = 0; if (has_mouse_screen_pos) if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos)) - if (ImGuiViewport* viewport = ImGui_ImplWin32_FindViewportByPlatformHandle(platform_io, hovered_hwnd)) + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hovered_hwnd)) mouse_viewport_id = viewport->ID; io.AddMouseViewportEvent(mouse_viewport_id); } // Gamepad navigation mapping -static void ImGui_ImplWin32_UpdateGamepads(ImGuiIO& io) +static void ImGui_ImplWin32_UpdateGamepads() { #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD - ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); //if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. // return; @@ -439,9 +421,7 @@ static void ImGui_ImplWin32_UpdateGamepads(ImGuiIO& io) MAP_ANALOG(ImGuiKey_GamepadRStickDown, gamepad.sThumbRY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); #undef MAP_BUTTON #undef MAP_ANALOG -#else // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD - IM_UNUSED(io); -#endif +#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD } static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc(HMONITOR monitor, HDC, LPRECT, LPARAM) @@ -457,8 +437,6 @@ static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc(HMONITOR monitor, H imgui_monitor.WorkSize = ImVec2((float)(info.rcWork.right - info.rcWork.left), (float)(info.rcWork.bottom - info.rcWork.top)); imgui_monitor.DpiScale = ImGui_ImplWin32_GetDpiScaleForMonitor(monitor); imgui_monitor.PlatformHandle = (void*)monitor; - if (imgui_monitor.DpiScale <= 0.0f) - return TRUE; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902. ImGuiPlatformIO& io = ImGui::GetPlatformIO(); if (info.dwFlags & MONITORINFOF_PRIMARY) io.Monitors.push_front(imgui_monitor); @@ -480,7 +458,6 @@ void ImGui_ImplWin32_NewFrame() ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized? Did you call ImGui_ImplWin32_Init()?"); ImGuiIO& io = ImGui::GetIO(); - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); // Setup display size (every frame to accommodate for window resizing) RECT rect = { 0, 0, 0, 0 }; @@ -496,32 +473,29 @@ void ImGui_ImplWin32_NewFrame() bd->Time = current_time; // Update OS mouse position - ImGui_ImplWin32_UpdateMouseData(io, platform_io); + ImGui_ImplWin32_UpdateMouseData(); // Process workarounds for known Windows key handling issues - ImGui_ImplWin32_ProcessKeyEventsWorkarounds(io); + ImGui_ImplWin32_ProcessKeyEventsWorkarounds(); // Update OS mouse cursor with the cursor requested by imgui ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); if (bd->LastMouseCursor != mouse_cursor) { bd->LastMouseCursor = mouse_cursor; - ImGui_ImplWin32_UpdateMouseCursor(io, mouse_cursor); + ImGui_ImplWin32_UpdateMouseCursor(); } // Update game controllers (if enabled and available) - ImGui_ImplWin32_UpdateGamepads(io); + ImGui_ImplWin32_UpdateGamepads(); } -// Map VK_xxx to ImGuiKey_xxx. -// Not static to allow third-party code to use that if they want to (but undocumented) -ImGuiKey ImGui_ImplWin32_KeyEventToImGuiKey(WPARAM wParam, LPARAM lParam); -ImGuiKey ImGui_ImplWin32_KeyEventToImGuiKey(WPARAM wParam, LPARAM lParam) -{ - // There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED. - if ((wParam == VK_RETURN) && (HIWORD(lParam) & KF_EXTENDED)) - return ImGuiKey_KeypadEnter; +// There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED, we assign it an arbitrary value to make code more readable (VK_ codes go up to 255) +#define IM_VK_KEYPAD_ENTER (VK_RETURN + 256) +// Map VK_xxx to ImGuiKey_xxx. +static ImGuiKey ImGui_ImplWin32_VirtualKeyToImGuiKey(WPARAM wParam) +{ switch (wParam) { case VK_TAB: return ImGuiKey_Tab; @@ -570,6 +544,7 @@ ImGuiKey ImGui_ImplWin32_KeyEventToImGuiKey(WPARAM wParam, LPARAM lParam) case VK_MULTIPLY: return ImGuiKey_KeypadMultiply; case VK_SUBTRACT: return ImGuiKey_KeypadSubtract; case VK_ADD: return ImGuiKey_KeypadAdd; + case IM_VK_KEYPAD_ENTER: return ImGuiKey_KeypadEnter; case VK_LSHIFT: return ImGuiKey_LeftShift; case VK_LCONTROL: return ImGuiKey_LeftCtrl; case VK_LMENU: return ImGuiKey_LeftAlt; @@ -653,10 +628,22 @@ ImGuiKey ImGui_ImplWin32_KeyEventToImGuiKey(WPARAM wParam, LPARAM lParam) #define DBT_DEVNODES_CHANGED 0x0007 #endif -// Helper to obtain the source of mouse messages. +// Win32 message handler (process Win32 mouse/keyboard inputs, etc.) +// Call from your application's message handler. Keep calling your message handler unless this function returns TRUE. +// When implementing your own backend, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs. +// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. +// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. +// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags. +// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds. +// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag. +#if 0 +// Copy this line into your .cpp file to forward declare the function. +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif + // See https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages // Prefer to call this at the top of the message handler to avoid the possibility of other Win32 calls interfering with this. -static ImGuiMouseSource ImGui_ImplWin32_GetMouseSourceFromMessageExtraInfo() +static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() { LPARAM extra_info = ::GetMessageExtraInfo(); if ((extra_info & 0xFFFFFF80) == 0xFF515700) @@ -666,40 +653,22 @@ static ImGuiMouseSource ImGui_ImplWin32_GetMouseSourceFromMessageExtraInfo() return ImGuiMouseSource_Mouse; } -// Win32 message handler (process Win32 mouse/keyboard inputs, etc.) -// Call from your application's message handler. Keep calling your message handler unless this function returns TRUE. -// When implementing your own backend, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs. -// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. -// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. -// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags. -// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag. - -// Copy either line into your .cpp file to forward declare the function: -extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Use ImGui::GetCurrentContext() -extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, ImGuiIO& io); // Doesn't use ImGui::GetCurrentContext() - IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // Most backends don't have silent checks like this one, but we need it because WndProc are called early in CreateWindow(). // We silently allow both context or just only backend data to be nullptr. - if (ImGui::GetCurrentContext() == nullptr) - return 0; - return ImGui_ImplWin32_WndProcHandlerEx(hwnd, msg, wParam, lParam, ImGui::GetIO()); -} - -// This version is in theory thread-safe in the sense that no path should access ImGui::GetCurrentContext(). -IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, ImGuiIO& io) -{ - ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); if (bd == nullptr) return 0; + ImGuiIO& io = ImGui::GetIO(); + switch (msg) { case WM_MOUSEMOVE: case WM_NCMOUSEMOVE: { // We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events - ImGuiMouseSource mouse_source = ImGui_ImplWin32_GetMouseSourceFromMessageExtraInfo(); + ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo(); const int area = (msg == WM_MOUSEMOVE) ? 1 : 2; bd->MouseHwnd = hwnd; if (bd->MouseTrackedArea != area) @@ -734,29 +703,19 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA } return 0; } - case WM_DESTROY: - if (bd->MouseHwnd == hwnd && bd->MouseTrackedArea != 0) - { - TRACKMOUSEEVENT tme_cancel = { sizeof(tme_cancel), TME_CANCEL, hwnd, 0 }; - ::TrackMouseEvent(&tme_cancel); - bd->MouseHwnd = nullptr; - bd->MouseTrackedArea = 0; - io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); - } - return 0; case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: { - ImGuiMouseSource mouse_source = ImGui_ImplWin32_GetMouseSourceFromMessageExtraInfo(); + ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo(); int button = 0; if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; } if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; } if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; } if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } if (bd->MouseButtonsDown == 0 && ::GetCapture() == nullptr) - ::SetCapture(hwnd); // Allow us to read mouse coordinates when dragging mouse outside of our window bounds. + ::SetCapture(hwnd); bd->MouseButtonsDown |= 1 << button; io.AddMouseSourceEvent(mouse_source); io.AddMouseButtonEvent(button, true); @@ -767,7 +726,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA case WM_MBUTTONUP: case WM_XBUTTONUP: { - ImGuiMouseSource mouse_source = ImGui_ImplWin32_GetMouseSourceFromMessageExtraInfo(); + ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo(); int button = 0; if (msg == WM_LBUTTONUP) { button = 0; } if (msg == WM_RBUTTONUP) { button = 1; } @@ -795,37 +754,40 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA if (wParam < 256) { // Submit modifiers - ImGui_ImplWin32_UpdateKeyModifiers(io); + ImGui_ImplWin32_UpdateKeyModifiers(); - // Obtain virtual key code and convert to ImGuiKey - const ImGuiKey key = ImGui_ImplWin32_KeyEventToImGuiKey(wParam, lParam); - const int vk = (int)wParam; + // Obtain virtual key code + // (keypad enter doesn't have its own... VK_RETURN with KF_EXTENDED flag means keypad enter, see IM_VK_KEYPAD_ENTER definition for details, it is mapped to ImGuiKey_KeyPadEnter.) + int vk = (int)wParam; + if ((wParam == VK_RETURN) && (HIWORD(lParam) & KF_EXTENDED)) + vk = IM_VK_KEYPAD_ENTER; + const ImGuiKey key = ImGui_ImplWin32_VirtualKeyToImGuiKey(vk); const int scancode = (int)LOBYTE(HIWORD(lParam)); // Special behavior for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit the key down event. if (key == ImGuiKey_PrintScreen && !is_key_down) - ImGui_ImplWin32_AddKeyEvent(io, key, true, vk, scancode); + ImGui_ImplWin32_AddKeyEvent(key, true, vk, scancode); // Submit key event if (key != ImGuiKey_None) - ImGui_ImplWin32_AddKeyEvent(io, key, is_key_down, vk, scancode); + ImGui_ImplWin32_AddKeyEvent(key, is_key_down, vk, scancode); // Submit individual left/right modifier events if (vk == VK_SHIFT) { // Important: Shift keys tend to get stuck when pressed together, missing key-up events are corrected in ImGui_ImplWin32_ProcessKeyEventsWorkarounds() - if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); } - if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); } + if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); } + if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); } } else if (vk == VK_CONTROL) { - if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); } - if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); } + if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); } + if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); } } else if (vk == VK_MENU) { - if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); } - if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); } + if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); } + if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); } } } return 0; @@ -835,7 +797,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA io.AddFocusEvent(msg == WM_SETFOCUS); return 0; case WM_INPUTLANGCHANGE: - ImGui_ImplWin32_UpdateKeyboardCodePage(io); + ImGui_ImplWin32_UpdateKeyboardCodePage(); return 0; case WM_CHAR: if (::IsWindowUnicode(hwnd)) @@ -853,7 +815,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA return 0; case WM_SETCURSOR: // This is required to restore cursor when transitioning from e.g resize borders to client area. - if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor(io, bd->LastMouseCursor)) + if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) return 1; return 0; case WM_DEVICECHANGE: @@ -1087,8 +1049,8 @@ static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport) // Create window RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) }; ::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle); - vd->Hwnd = ::CreateWindowExW( - vd->DwExStyle, L"ImGui Platform", L"Untitled", vd->DwStyle, // Style, class name, window name + vd->Hwnd = ::CreateWindowEx( + vd->DwExStyle, _T("ImGui Platform"), _T("Untitled"), vd->DwStyle, // Style, class name, window name rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area vd->HwndParent, nullptr, ::GetModuleHandle(nullptr), nullptr); // Owner window, Menu, Instance, Param vd->HwndOwned = true; @@ -1194,20 +1156,11 @@ static ImVec2 ImGui_ImplWin32_GetWindowPos(ImGuiViewport* viewport) return ImVec2((float)pos.x, (float)pos.y); } -static void ImGui_ImplWin32_UpdateWin32StyleFromWindow(ImGuiViewport* viewport) -{ - ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; - vd->DwStyle = ::GetWindowLongW(vd->Hwnd, GWL_STYLE); - vd->DwExStyle = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE); -} - static void ImGui_ImplWin32_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos) { ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; IM_ASSERT(vd->Hwnd != 0); RECT rect = { (LONG)pos.x, (LONG)pos.y, (LONG)pos.x, (LONG)pos.y }; - if (viewport->Flags & ImGuiViewportFlags_OwnedByApp) - ImGui_ImplWin32_UpdateWin32StyleFromWindow(viewport); // Not our window, poll style before using ::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle); ::SetWindowPos(vd->Hwnd, nullptr, rect.left, rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); } @@ -1226,8 +1179,6 @@ static void ImGui_ImplWin32_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; IM_ASSERT(vd->Hwnd != 0); RECT rect = { 0, 0, (LONG)size.x, (LONG)size.y }; - if (viewport->Flags & ImGuiViewportFlags_OwnedByApp) - ImGui_ImplWin32_UpdateWin32StyleFromWindow(viewport); // Not our window, poll style before using ::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle); // Client to Screen ::SetWindowPos(vd->Hwnd, nullptr, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); } @@ -1274,14 +1225,14 @@ static void ImGui_ImplWin32_SetWindowAlpha(ImGuiViewport* viewport, float alpha) IM_ASSERT(alpha >= 0.0f && alpha <= 1.0f); if (alpha < 1.0f) { - DWORD ex_style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) | WS_EX_LAYERED; - ::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, ex_style); + DWORD style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) | WS_EX_LAYERED; + ::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, style); ::SetLayeredWindowAttributes(vd->Hwnd, 0, (BYTE)(255 * alpha), LWA_ALPHA); } else { - DWORD ex_style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED; - ::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, ex_style); + DWORD style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED; + ::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, style); } } @@ -1308,21 +1259,18 @@ static void ImGui_ImplWin32_OnChangedViewport(ImGuiViewport* viewport) #endif } -namespace ImGui { extern ImGuiIO& GetIOEx(ImGuiContext*); extern ImGuiPlatformIO& GetPlatformIOEx(ImGuiContext*); } - static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { // Allow secondary viewport WndProc to be called regardless of current context - ImGuiContext* ctx = (ImGuiContext*)::GetPropA(hWnd, "IMGUI_CONTEXT"); - if (ctx == NULL) - return DefWindowProc(hWnd, msg, wParam, lParam); // unlike ImGui_ImplWin32_WndProcHandler() we are called directly by Windows, we can't just return 0. + ImGuiContext* hwnd_ctx = (ImGuiContext*)::GetPropA(hWnd, "IMGUI_CONTEXT"); + ImGuiContext* prev_ctx = ImGui::GetCurrentContext(); + if (hwnd_ctx != prev_ctx && hwnd_ctx != NULL) + ImGui::SetCurrentContext(hwnd_ctx); - ImGuiIO& io = ImGui::GetIOEx(ctx); - ImGuiPlatformIO& platform_io = ImGui::GetPlatformIOEx(ctx); LRESULT result = 0; - if (ImGui_ImplWin32_WndProcHandlerEx(hWnd, msg, wParam, lParam, io)) + if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) result = true; - else if (ImGuiViewport* viewport = ImGui_ImplWin32_FindViewportByPlatformHandle(platform_io, hWnd)) + else if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hWnd)) { switch (msg) { @@ -1351,13 +1299,15 @@ static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, } if (result == 0) result = DefWindowProc(hWnd, msg, wParam, lParam); + if (hwnd_ctx != prev_ctx && hwnd_ctx != NULL) + ImGui::SetCurrentContext(prev_ctx); return result; } -static void ImGui_ImplWin32_InitMultiViewportSupport(bool platform_has_own_dc) +static void ImGui_ImplWin32_InitPlatformInterface(bool platform_has_own_dc) { - WNDCLASSEXW wcex; - wcex.cbSize = sizeof(WNDCLASSEXW); + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW | (platform_has_own_dc ? CS_OWNDC : 0); wcex.lpfnWndProc = ImGui_ImplWin32_WndProcHandler_PlatformWindow; wcex.cbClsExtra = 0; @@ -1367,9 +1317,9 @@ static void ImGui_ImplWin32_InitMultiViewportSupport(bool platform_has_own_dc) wcex.hCursor = nullptr; wcex.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1); wcex.lpszMenuName = nullptr; - wcex.lpszClassName = L"ImGui Platform"; + wcex.lpszClassName = _T("ImGui Platform"); wcex.hIconSm = nullptr; - ::RegisterClassExW(&wcex); + ::RegisterClassEx(&wcex); ImGui_ImplWin32_UpdateMonitors(); @@ -1399,9 +1349,10 @@ static void ImGui_ImplWin32_InitMultiViewportSupport(bool platform_has_own_dc) vd->Hwnd = bd->hWnd; vd->HwndOwned = false; main_viewport->PlatformUserData = vd; + main_viewport->PlatformHandle = (void*)bd->hWnd; } -static void ImGui_ImplWin32_ShutdownMultiViewportSupport() +static void ImGui_ImplWin32_ShutdownPlatformInterface() { ::UnregisterClass(_T("ImGui Platform"), ::GetModuleHandle(nullptr)); ImGui::DestroyPlatformWindows(); diff --git a/3rdparty/imgui/backends/imgui_impl_win32.h b/3rdparty/imgui/backends/imgui_impl_win32.h index 6584ff8..cebe661 100644 --- a/3rdparty/imgui/backends/imgui_impl_win32.h +++ b/3rdparty/imgui/backends/imgui_impl_win32.h @@ -4,9 +4,9 @@ // Implemented features: // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. -// [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 VK_* values are obsolete since 1.87 and not supported since 1.91.5] +// [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 VK_* 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 (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -21,7 +21,6 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE -// Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd); IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd); IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); diff --git a/3rdparty/imgui/docs/BACKENDS.md b/3rdparty/imgui/docs/BACKENDS.md index de5cd66..88a96a6 100644 --- a/3rdparty/imgui/docs/BACKENDS.md +++ b/3rdparty/imgui/docs/BACKENDS.md @@ -2,10 +2,23 @@ _(You may browse this at https://github.com/ocornut/imgui/blob/master/docs/BACKE ## Dear ImGui: Backends -### Integrating backends +**The backends/ folder contains backends for popular platforms/graphics API, which you can use in +your application or engine to easily integrate Dear ImGui.** Each backend is typically self-contained in a pair of files: imgui_impl_XXXX.cpp + imgui_impl_XXXX.h. + +- The 'Platform' backends are in charge of: mouse/keyboard/gamepad inputs, cursor shape, timing, and windowing.
+ e.g. Windows ([imgui_impl_win32.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_win32.cpp)), GLFW ([imgui_impl_glfw.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_glfw.cpp)), SDL2 ([imgui_impl_sdl2.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_sdl2.cpp)), etc. + +- The 'Renderer' backends are in charge of: creating atlas texture, and rendering imgui draw data.
+ e.g. DirectX11 ([imgui_impl_dx11.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_dx11.cpp)), OpenGL/WebGL ([imgui_impl_opengl3.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_opengl3.cpp)), Vulkan ([imgui_impl_vulkan.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_vulkan.cpp)), etc. + +- For some high-level frameworks, a single backend usually handles both 'Platform' and 'Renderer' parts.
+ e.g. Allegro 5 ([imgui_impl_allegro5.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_allegro5.cpp)). If you end up creating a custom backend for your engine, you may want to do the same. + +An application usually combines one Platform backend + one Renderer backend + main Dear ImGui sources. +For example, the [example_win32_directx11](https://github.com/ocornut/imgui/tree/master/examples/example_win32_directx11) application combines imgui_impl_win32.cpp + imgui_impl_dx11.cpp. There are 20+ examples in the [examples/](https://github.com/ocornut/imgui/blob/master/examples/) folder. See [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) for details. + +**Once Dear ImGui is setup and running, run and refer to `ImGui::ShowDemoWindow()` in imgui_demo.cpp for usage of the end-user API.** -💡 The **[Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) wiki guide** has examples of how to integrate Dear ImGui into an existing application. -
The [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) documentation may also be worth a read. ### What are backends? @@ -25,7 +38,7 @@ Dear ImGui is highly portable and only requires a few things to run and render, - Optional: multi-viewports support. etc. -This is essentially what each backend is doing + obligatory portability cruft. Using standard backends ensure you can get all those features including the ones that would be harder to implement on your side (e.g. multi-viewports support). +This is essentially what each backend is doing + obligatory portability cruft. Using default backends ensure you can get all those features including the ones that would be harder to implement on your side (e.g. multi-viewports support). It is important to understand the difference between the core Dear ImGui library (files in the root folder) and the backends which we are describing here (backends/ folder). @@ -34,24 +47,11 @@ and the backends which we are describing here (backends/ folder). - You should be able to write backends for pretty much any platform and any 3D graphics API. e.g. you can get creative and use software rendering or render remotely on a different machine. -### Standard backends -**The [backends/](https://github.com/ocornut/imgui/blob/master/backends) folder contains backends for popular platforms/graphics API, which you can use in -your application or engine to easily integrate Dear ImGui.** Each backend is typically self-contained in a pair of files: imgui_impl_XXXX.cpp + imgui_impl_XXXX.h. +### Integrating a backend -- The 'Platform' backends are in charge of: mouse/keyboard/gamepad inputs, cursor shape, timing, and windowing.
- e.g. Windows ([imgui_impl_win32.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_win32.cpp)), GLFW ([imgui_impl_glfw.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_glfw.cpp)), SDL2 ([imgui_impl_sdl2.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_sdl2.cpp)), etc. +See "Getting Started" section of [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) for more details. -- The 'Renderer' backends are in charge of: creating atlas texture, and rendering imgui draw data.
- e.g. DirectX11 ([imgui_impl_dx11.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_dx11.cpp)), OpenGL/WebGL ([imgui_impl_opengl3.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_opengl3.cpp)), Vulkan ([imgui_impl_vulkan.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_vulkan.cpp)), etc. - -- For some high-level frameworks, a single backend usually handles both 'Platform' and 'Renderer' parts.
- e.g. Allegro 5 ([imgui_impl_allegro5.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_allegro5.cpp)). If you end up creating a custom backend for your engine, you may want to do the same. - -An application usually combines one Platform backend + one Renderer backend + main Dear ImGui sources. -For example, the [example_win32_directx11](https://github.com/ocornut/imgui/tree/master/examples/example_win32_directx11) application combines imgui_impl_win32.cpp + imgui_impl_dx11.cpp. There are 20+ examples in the [examples/](https://github.com/ocornut/imgui/blob/master/examples/) folder. See [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) for details. - -**Once Dear ImGui is setup and running, run and refer to `ImGui::ShowDemoWindow()` in imgui_demo.cpp for usage of the end-user API.** ### List of backends @@ -135,7 +135,7 @@ Generally: It is unlikely you will add value to your project by creating your own backend. Also: -The [multi-viewports feature](https://github.com/ocornut/imgui/wiki/Multi-Viewports) of the 'docking' branch allows +The [multi-viewports feature](https://github.com/ocornut/imgui/issues/1542) of the 'docking' branch allows Dear ImGui windows to be seamlessly detached from the main application window. This is achieved using an extra layer to the Platform and Renderer backends, which allows Dear ImGui to communicate platform-specific requests such as: "create an additional OS window", "create a render context", "get the OS position of this diff --git a/3rdparty/imgui/docs/CHANGELOG.txt b/3rdparty/imgui/docs/CHANGELOG.txt index 98ac669..0550550 100644 --- a/3rdparty/imgui/docs/CHANGELOG.txt +++ b/3rdparty/imgui/docs/CHANGELOG.txt @@ -36,633 +36,9 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.91.8 (Released 2025-01-31) + VERSION 1.91.0 WIP (In Progress) ----------------------------------------------------------------------- -Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.8 - -Breaking changes: - -- ColorEdit, ColorPicker: redesigned how alpha is displayed in the preview - square. (#8335, #1578, #346) - - Removed ImGuiColorEditFlags_AlphaPreview (made value 0): it is now the default behavior. - - Prior to 1.91.8: alpha was made opaque in the preview by default _unless_ using ImGuiColorEditFlags_AlphaPreview. - - We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior. - - The new flags may be combined better and allow finer controls: - - ImGuiColorEditFlags_AlphaOpaque: disable alpha in the preview, but alpha value still editable. - - ImGuiColorEditFlags_AlphaNoBg: disable rendering a checkerboard background behind transparent color. - - ImGuiColorEditFlags_AlphaPreviewHalf: display half opaque / half transparent preview. -- Backends: SDLGPU3: Renamed ImGui_ImplSDLGPU3_InitInfo::GpuDevice to Device - for consistency. (#8163, #7998, #7988) - -Other changes: - -- imgui_freetype: fixed issue where glyph advances would incorrectly be - snapped to pixels. Effectively it would only be noticeable when hinting - is disabled with ImGuiFreeTypeBuilderFlags_NoHinting, as hinting itself - snaps glyph advances. -- Inputs: added IsMouseReleasedWithDelay() helper. (#8337, #8320) - Use if you absolutely need to distinguish single-click from double-clicks - by introducing a delay. This is a very rarely used UI idiom, but some apps - use this: e.g. MS Explorer single-click on an icon triggers a rename. - Generally use with 'delay >= io.MouseDoubleClickTime' + combine with a - 'GetMouseClickedCount() == 1' check. -- Windows: legacy SetWindowFontScale() is properly inherited by nested child - windows. Note that an upcoming major release should make this obsolete, - but in the meanwhile it works better now. (#2701, #8138, #1018) -- Windows, Style: Fixed small rendering issues with menu bar, resize grip and - scrollbar when using thick border sizes. (#8267, #7887) -- Windows: Fixed IsItemXXXX() functions not working on append-version of EndChild(). (#8350) - Also made some of the fields accessible after BeginChild() to match Begin() logic. -- Error Handling: Recovery from missing EndMenuBar() call. (#1651) -- Tables, Menus: Fixed using BeginTable() in menu layer (any menu bar). (#8355) - It previously overrode the current layer back to main layer, which caused an issue - with MainMenuBar attempted to release focus when leaving the menu layer. -- Tables, Menus: Fixed tables or child windows submitted inside BeginMainMenuBar() - being unable to save their settings, as the main menu bar uses _NoSavedSettings. (#8356) -- ColorEdit, ColorPicker: Fixed alpha preview broken in 1.91.7. (#8336, #8241). [@PathogenDavid] -- Tabs, Style: reworked selected overline rendering to better accommodate - for rounded tabs. Reduced default thickness (style.TabBarOverlineSize), - increased default rounding (style.TabRounding). (#8334) [@Kian738, @ocornut] -- Debug Tools: Tweaked font preview. -- ImDrawList: texture baked storage for thick line reduced from ~64x64 to ~32x32. (#3245) -- Fonts: IndexLookup[] table hold 16-bit values even in ImWchar32 mode, - as it accounts for number of glyphs in same font. This is favorable to - CalcTextSize() calls touching less memory. -- Fonts: OversampleH/OversampleV defaults to 0 for automatic selection. - - OversampleH == 0 --> use 1 or 2 depending on font size and use of PixelSnapH. - - OversampleV == 0 --> always use 1. -- ImFontAtlas: made calling ClearFonts() call ClearInputData(), as calling - one without the other is never correct. (#8174, #6556, #6336, #4723) -- Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in - provided example, to reduce latency. -- Backends+Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by - vkAcquireNextImageKHR() or vkQueuePresentKHR(). (#7825, #7831) [@NostraMagister] -- Backends: SDL2: removed assert preventing using ImGui_ImplSDL2_SetGamepadMode() - with ImGui_ImplSDL2_GamepadMode_Manual and an empty array. (#8329) -- Backends: SDL3: removed assert preventing using ImGui_ImplSDL3_SetGamepadMode() - with ImGui_ImplSDL3_GamepadMode_Manual and an empty array. (#8329) -- Backends: SDLGPU3: Exposed ImGui_ImplSDLGPU3_CreateDeviceObjects()/_DestroyDeviceObjects(). - Removed return value from ImGui_ImplSDLGPU3_CreateFontsTexture(). (#8163, #7998, #7988) -- Backends: SDL_Renderer2/3: Use endian-dependent RGBA32 texture format, to match - SDL_Color. (#8327) [@dkosmari] -- Backends: DirectX12: Texture upload use the command queue provided in - ImGui_ImplDX12_InitInfo instead of creating its own. -- Backends: OSX: Removed notification observer when shutting down. (#8331) [@jrachele] - -Docking+Viewports Branch: - -- Docking: Fixed an issue in 1.91.7 where using legacy ImGuiWindowFlags_NavFlattened - flag (instead of ImGuiChildFlags_NavFlattened) in docking branch would conflict - with internal docking flags. (#8357) [@DanielGibson] -- Backends: SDL3: new viewport windows are created with the SDL_WINDOW_HIDDEN flag - before calling SDL_ShowWindow(). (#8328) [@PathogenDavid] - - ------------------------------------------------------------------------ - VERSION 1.91.7 (Released 2025-01-14) ------------------------------------------------------------------------ - -Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.7 - -Breaking changes: - -- TreeNode: renamed ImGuiTreeNodeFlags_SpanTextWidth to ImGuiTreeNodeFlags_SpanLabelWidth - for consistency with other names. Kept redirection enum (will obsolete). (#6937) - -Other changes: - -- Fixed issues with IsItemDeactivated() and IsItemDeactivatedAfterEdit() not - emitting a reliable signal when an item is deactivated externally: e.g. - via an explicit clear of focus, clear of active id, opening of modal etc. - (#5184, #5904, #6766, #8303, #8004) - - It used to work when the interruption happened in the frame before the - active item as submitted, but not after. It should work in both cases now. - - While this is not specific to a certain widgets, typically it would - mostly be noticeable on InputText() because it keeps ActiveId for a - longer time while allowing other interaction to happen. -- Error Handling: Fixed bugs recovering from within a table that created - a child window, and from nested child windows. (#1651) -- Error Handling: Turned common EndTable() and other TableXXX functions - fail cases into a recoverable error. (#1651, #8314) -- Error Handling: Basic error handling options in Demo->Tools->Debug Options. (#1651) -- InputText: Fixed a bug where character replacements performed from a callback - were not applied when pasting from clipboard. (#8229) -- InputText: Fixed issue when activating a ReadOnly field when the underlying - value is being modified. (#8242) -- InputText: Added sanity check to detect some cases of passing a non - zero-terminated input buffer. -- InputText: Fixed not calling CallbackEdit on revert/clear with Escape key, - although IsItemEdited() was behaving correctly. (#8273) -- Tables: Fixed TableAngledHeadersRow() creating an infinite horizontal - scrolling region when the table is hosted in a viewport with negative - coordinates (left of primary monitor, with multi-viewports enabled). -- Tables, MultiSelect: Fixed an issue where column width may be mismeasured - when calling BeginMultiSelect() while inside a table. (#8250) -- TreeNode, Tables: Added ImGuiTreeNodeFlags_LabelSpanAllColumns to make - the label (not only the highlight/frame) also spans all columns. This is - useful for table rows where you know nothing else is submitted. (#8318, #3565) - Obviously best used with ImGuiTableFlags_NoBordersInBodyUntilResize. -- Selectable: Fixed horizontal label alignment when combined with using - ImGuiSelectableFlags_SpanAllColumns. (#8338) -- Drags: Added ImGuiSliderFlags_NoSpeedTweaks flag to disable keyboard - modifiers altering the tweak speed. Useful if you want to alter tweak speed - yourself based on your own logic. (#8223) -- Nav: Fixed an issue where Alt key would clear current active item on - windows with the ImGuiWindowFlags_NoNavInputs flag. (#8231) -- Debug Tools: Debug Log: hovering 0xXXXXXXXX values in log is allowed even - if a popup is blocking mouse access to the debug log window. (#5855) -- Debug Tools: Item Picker: Always available in Tools menu regardless of value - of io.ConfigDebugIsDebuggerPresent. (#2673) -- Fonts: Fixed miscalculation of Ellipsis ("...") character width when automatically - created from a single comma character, affecting some fonts/settings (not all). -- Demo: Added label edition to Property Editor demo + fix an ID issue. (#8266) [@moritz-h] -- Misc: Fixed misc/cpp/imgui_stdlib.h/.cpp not supporting IMGUI_DISABLE. (#8294) [@juur] -- Misc: Fixed MinGW builds not using UTF-8 friendly _wfopen(). (#8300) -- Backends: SDLGPU3 for SDL3: Added backend for SDL_GPU! (#8163, #7998, #7988) [@DeltaW0x]. -- Backends: SDL3: Added ImGui_ImplSDL3_InitForSDLGPU() for consistency, even - though it is currently not doing anything particular. (#8163, #7998, #7988) -- Backends: Allegro5: Avoid calling al_set_mouse_cursor() repeatedly since it appears - to leak on on X11 (#8256). [@Helodity] -- Backends: Metal: Fixed leaks when using metal-cpp. (#8276, #8166) [@selimsandal] -- Backends: Metal: Fixed resource leak when using multiple contexts. (#7419) [@anszom] -- Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for - platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) [@Zer0xFF] -- Backends: Vulkan: Added a few more ImGui_ImplVulkanH_XXX helper functions - primarily for the purpose of making our examples simpler. -- Backends: Vulkan: Added IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE to clarify - how many image sampler descriptors are expected to be available in the provided - descriptor pool. Current backend needs 1 but it is expected that by end of Q1 2025 - this number will grow (will stay a small number). (#6642) -- Backends: DX11: Expose vertex constant buffer in ImGui_ImplDX11_RenderState. - Reset projection matrix in ImDrawCallback_ResetRenderState handlers. (#6969, #5834, #7468, #3590) -- Backends: DX10: Expose ImGui_ImplDX10_RenderState for completeness. (#6969, #5834, #7468, #3590) -- Examples: Added Win32+Vulkan example for completeness. (#8180) [@jristic] - - ------------------------------------------------------------------------ - VERSION 1.91.6 (Released 2024-12-11) ------------------------------------------------------------------------ - -Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.6 - -Breaking changes: - -- Backends: DX12: Changed ImGui_ImplDX12_Init() signature to take a - ImGui_ImplDX12_InitInfo struct. - - Using the new API, application is now required to pass function pointers - to allocate/free SRV Descriptors. - - We provide convenience legacy fields to pass a single descriptor, - matching the old API, but upcoming features will want multiple. - - Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete). -- Misc: changed CRC32 table from CRC32-adler to CRC32c polynomial in order to - be compatible with the result of SSE 4.2 instructions. (#8169, #4933) [@Teselka] - - As a result, some .ini data may be partially lost when storing checksums - (docking and tables information particularly). - - Because some users have crafted and storing .ini data as a way to workaround - limitations of the docking API, we are providing a '#define IMGUI_USE_LEGACY_CRC32_ADLER' - compile-time option to keep using old CRC32 tables if you cannot afford invalidating - old .ini data. - -Other changes: - -- Error Handling: fixed cases where recoverable error handling would crash when - processing errors outside of the NewFrame()..EndFrame() scope. (#1651) -- Tables: fixed SetNextWindowScroll() value being ignored by BeginTable() during - the first frame or when scrolling flags have changed. (#8196) -- InputText: added ImGuiInputTextFlags_ElideLeft to elide left side and ensure right side - of contents is visible when whole text is not fitting (useful for paths/filenames). - (#1442, #1440, #4391, #7208, #8216) [@kucoman, @ocornut] -- InputText: reactivating last activated InputText() doesn't restore horizontal scrolling - (which was disabled during deactivation anyway). -- Misc: changed embedded ProggyClean encoding to save a bit of binary space (~12kb to 9.5kb). -- Misc: added IMGUI_DISABLE_DEFAULT_FONT to strip embedded font from binary. (#8161) - [@demonese] -- Demo: example tree used by Property Editor & Selection demos properly freed - on application closure. (#8158) [@Legulysse] -- Fonts: fixed AddCustomRect() not being packed with TexGlyphPadding + not accounted - for surface area used to determine best-guess texture size. (#8107) [@YarikTH, @ocornut] -- Misc: use SSE 4.2 crc32 instructions when available. (#8169, #4933) [@Teselka] -- Tools: binary_to_compressed_c: added -u8/-u32/-base85 export options. -- Backends: DirectX12: Let user specifies the DepthStencilView format by setting - ImGui_ImplDX12_InitInfo::DSVFormat. (#8217) [@bmarques1995] -- Backends: Vulkan: Make user-provided descriptor pool optional. As a convenience, - when setting init_info->DescriptorPoolSize then the backend will create and manage - one itself. (#8172, #4867) [@zeux] -- Examples: Win32+DX12: Using a basic free-list allocator to manage multiple - SRV descriptors. - -Docking+Viewports Branch: - -- Docking: Added an assert to clarify that ImGuiDockNodeFlags_CentralNode flag - (from internals) does not need to be passed to DockSpace(), as it causes general - havoc. (#8145) -- Backends: Win32: Fixed a crash/regression in 1.91.5 when running two processes - with multi-viewports (was using GetProp() to query property which could have - belonged to another process). (#8162, #8069) [@sammyfreg, @ocornut] - - ------------------------------------------------------------------------ - VERSION 1.91.5 (Released 2024-11-07) ------------------------------------------------------------------------ - -Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.5 - -Breaking changes: - -- Commented out pre-1.87 IO system (equivalent to using IMGUI_DISABLE_OBSOLETE_KEYIO or IMGUI_DISABLE_OBSOLETE_FUNCTIONS before). - - io.KeyMap[] and io.KeysDown[] are removed (obsoleted February 2022). Use IsKeyDown() instead. - - io.NavInputs[] and ImGuiNavInput are removed (obsoleted July 2022). - - Pre-1.87 backends are not supported: - - backends need to call io.AddKeyEvent(), io.AddMouseEvent() instead of writing to io.KeysDown[], io.MouseDown[] fields. - - backends need to call io.AddKeyAnalogEvent() for gamepad values instead of writing to io.NavInputs[] fields. - - you can use IsKeyDown() instead of reading from io.KeysDown[]. - - For more references: - - read 1.87 and 1.88 part of API BREAKING CHANGES in imgui.cpp or read Changelog for 1.87 and 1.88. - - read https://github.com/ocornut/imgui/issues/4921 - - If you have trouble updating a very old codebase using legacy backend-specific key codes: - consider updating to 1.91.4 first, then #define IMGUI_DISABLE_OBSOLETE_KEYIO, then update to latest. - - Obsoleted ImGuiKey_COUNT (it is unusually error-prone/misleading since valid keys don't start at 0). - Probably use ImGuiKey_NamedKey_BEGIN/ImGuiKey_NamedKey_END? -- Fonts: removed const qualifiers from most font functions in prevision for upcoming fonts improvements. - -Other changes: - -- Selectable: selected Selectables use ImGuiCol_Header instead of an arbitrary lerp - between _Header and _HeaderHovered which was introduced v1.91 (#8106, #1861) -- Buttons: using ImGuiItemFlags_ButtonRepeat makes default button behavior use - PressedOnClick instead of PressedOnClickRelease when unspecified. - - This is intended to make the +/- buttons of InputInt/InputFloat react on the - initial mouse down event. - - Note that it may reveal incorrect usage if you were using InputInt/InputFloat - without persistent storage by relying solely on e.g. IsItemDeactivatedAfterEdit(): - this was never supported and didn't work consistantly (see #8149). -- InputText: fixed a bug (regression in 1.91.2) where modifying text buffer within - a callback would sometimes prevents further appending to the buffer. -- Tabs, Style: made ImGuiCol_TabDimmedSelectedOverline alpha 0 (not visible) in default - styles as the current look is not right (but ImGuiCol_TabSelectedOverline stays the same). -- Log/Capture: added experimental io.ConfigWindowsCopyContentsWithCtrlC option to - automatically copy window contents into clipboard using CTRL+C. This is experimental - because (1) it currently breaks on nested Begin/End, (2) text output quality varies, - and (3) text output comes in submission order rather than spatial order. -- Log/Capture: better decorating of BeginMenu() and TabItem() output. -- Log/Capture: a non terminated log ends automatically in the window which called it. -- imgui_freetype: Fixed a crash in build font atlas when using merged fonts and the - first font in a merged set has no loaded glyph. (#8081) -- Backends: DX12: Unmap() call specify written range. The range is informational and - may be used by debug tools. -- Backends: SDL2: Replace SDL_Vulkan_GetDrawableSize() forward declaration with the - actual include. (#8095, #7967, #3190) [@sev-] -- Backends: SDL2, SDL3: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing - by 100.0f on Emscripten target. (#4019, #6096, #1463) -- Examples: SDL3+Vulkan: Added example. (#8084, #8085) -- Examples: Android+OpenGL: Using ALooper_pollOnce() instead of ALooper_pollAll() - which has been deprecated. (#8013) [@feather179] - -Docking+Viewports Branch: - -- Backends: GLFW: added Linux workaround for spurious mouse up events emitted while dragging - and creating new viewports. Generally they would be interrupting a dragging operations. - (#3158, #7733, #7922) [@rokups, @ocornut] -- Docking: fixed using ImGuiDockNodeFlags_KeepAliveOnly with DockSpaceOverViewport(): - the normally invisible space did erroneously claim mouse hover and could be potentially - focused. (#8125) [@kcbanner] - - ------------------------------------------------------------------------ - VERSION 1.91.4 (Released 2024-10-18) ------------------------------------------------------------------------ - -Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.4 - -Breaking changes: - -- Style: renamed ImGuiCol_NavHighlight to ImGuiCol_NavCursor, for consistency with - newly exposed and reworked features. Kept inline redirection enum (will obsolete). -- The typedef for ImTextureID now defaults to ImU64 instead of void*. (#1641) - - This removes the requirement to redefine it for backends which are e.g. storing - descriptor sets or other 64-bits structures when building on 32-bits archs - (namely our DX12 and Vulkan backends). It therefore simplify various building scripts/helpers. - - You may have compile-time warnings if you were casting to 'void*' instead of 'ImTextureID' - when passing your types to functions taking ImTextureID values, e.g. ImGui::Image(). - In doubt it is almost always better to do an intermediate intptr_t cast, since it - allows casting any pointer/integer type without warning: - - May warn: ImGui::Image((void*)MyTextureData, ...); - - May warn: ImGui::Image((void*)(intptr_t)MyTextureData, ...); - - Won't warn: ImGui::Image((ImTextureID)(intptr_t)MyTextureData), ...); - - Note that you can always define ImTextureID to be your own high-level structures - (with dedicated constructors and extra render parameters) if you like. -- IO: moved ImGuiConfigFlags_NavEnableSetMousePos to standalone io.ConfigNavMoveSetMousePos bool. -- IO: moved ImGuiConfigFlags_NavNoCaptureKeyboard to standalone io.ConfigNavCaptureKeyboard bool - (note the inverted value!). (#2517, #2009) - Kept legacy names (will obsolete) + code that copies settings once the first time. - Dynamically changing the old value won't work. Switch to using the new value! - -Other changes: - -- IO: added 'void* platform_io.Renderer_RenderState' which is set during the - ImGui_ImplXXXX_RenderDrawData() of standard backends to expose selected render - states to your draw callbacks. (#6969, #5834, #7468, #3590) -- IO: io.WantCaptureKeyboard is never set when ImGuiConfigFlags_NoKeyboard is enabled. (#4921) -- Error Handling: turned a few more functions into recoverable errors. (#1651) -- Nav (Keyboard/Gamepad navigation): - - Nav: added io.ConfigNavCursorVisibleAuto and io.ConfigNavCursorVisibleAlways to configure - visibility of navigation cursor. (#1074, #2048, #7237, #8059, #3200, #787) - - Set io.ConfigNavCursorVisibleAuto = true (default) to enable automatic toggling - of cursor visibility (mouse click hide the cursor, arrow keys makes it visible). - - Set io.ConfigNavCursorVisibleAlways to keep cursor always visible. - - Nav: added NavSetCursorVisible(bool visible) function to manipulate visibility of - navigation cursor (e.g. set default state, or after some actions). (#1074, #2048, #7237, #8059) - - Nav: added io.ConfigNavEscapeClearFocusItem and io.ConfigNavEscapeClearFocusWindow to change - how pressing Escape affects navigation. (#8059, #2048, #1074, #3200) - - Set io.ConfigNavEscapeClearFocusItem = true (default) to clear focused item and highlight. - - Set io.ConfigNavEscapeClearFocusItem = false for Escape to not have an effect. - - Set io.ConfigNavEscapeClearFocusWindow = true to completely unfocus the dear imgui window, - is for some reason your app relies on imgui focus to take other decisions. - - Nav: pressing escape to hide the navigation cursor doesn't clear location, so it may be - restored when Ctrl+Tabbing back into the same window later. - - Nav: fixed Ctrl+Tab initiated with no focused window from skipping the top-most window. (#3200) - - Nav: navigation cursor is not rendered for items with `ImGuiItemFlags_NoNav`. Can be relevant - when e.g activating a _NoNav item with mouse, then Ctrl+Tabbing back and forth. -- Disabled: clicking a disabled item focuses parent window. (#8064) -- InvisibleButton, Nav: fixed an issue when InvisibleButton() would be navigable into but - not display navigation highlight. Properly navigation on it by default. (#8057) -- InvisibleButton: added ImGuiButtonFlags_EnableNav to enable navigation. (#8057) -- Tooltips: fixed incorrect tooltip positioning when using keyboard/gamepad navigation - (1.91.3 regression). (#8036) -- DrawList: AddCallback() added an optional size parameter allowing to copy and - store any amount of user data for usage by callbacks: (#6969, #4770, #7665) - - If userdata_size == 0: we copy/store the 'userdata' argument as-is (existing behavior). - It will be available unmodified in ImDrawCmd::UserCallbackData during render. - - If userdata_size > 0, we copy/store 'userdata_size' bytes pointed to by 'userdata' (new behavior). - We store them in a buffer stored inside the drawlist. ImDrawCmd::UserCallbackData - will point inside that buffer so you have to retrieve data from there. Your callback - may need to use ImDrawCmd::UserCallbackDataSize if you expect dynamically-sized data. - - Note that we use a raw type-less copy. -- Tables: fixed initial auto-sizing issue with synced-instances. (#8045, #7218) -- InputText: fixed an issue with not declaring ownership of Delete/Backspace/Arrow keys, - preventing use of external shortcuts that are not guarded by an ActiveId check. (#8048) - [@geertbleyen] -- InputText: ensure mouse cursor shape is set regardless of whether keyboard mode is - enabled or not. (#6417) -- InputScalar: added an assert to clarify that ImGuiInputTextFlags_EnterReturnsTrue is not - supported by InputFloat, InputInt, InputScalar etc. widgets. It actually never was. (#8065, #3946) -- imgui_freetype: Added support for plutosvg (as an alternative to lunasvg) to render - OpenType SVG fonts. Requires defining IMGUI_ENABLE_FREETYPE_PLUTOSVG along with IMGUI_ENABLE_FREETYPE. - Providing headers/librairies for plutosvg + plutovg is up to you (see #7927 for help). - (#7927, #7187, #6591, #6607) [@pthom] -- Backends: DX11, DX12, SDLRenderer2/3. Vulkan, WGPU: expose selected state in - ImGui_ImplXXXX_RenderState structures during render loop user draw callbacks. - (#6969, #5834, #7468, #3590) -- Backends: DX9, DX10, DX11, DX12, OpenGL, Vulkan, WGPU: Changed default texture sampler - to Clamp instead of Repeat/Wrap. (#7468, #7511, #5999, #5502, #7230) - -Docking+Viewports Branch: - -- Backends: changed all backends to allow enabling ImGuiConfigFlags_ViewportsEnable - after initialization. (#5371) - - ------------------------------------------------------------------------ - VERSION 1.91.3 (Released 2024-10-04) ------------------------------------------------------------------------ - -Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.3 - -Breaking changes: - -- Drags: treat v_min==v_max as a valid clamping range when != 0.0f. Zero is still a special - value due to legacy reasons, unless using ImGuiSliderFlags_ClampZeroRange. (#7968, #3361, #76) -- Drags: extended behavior of ImGuiSliderFlags_AlwaysClamp to include _ClampZeroRange. - It considers v_min==v_max==0.0f as a valid clamping range (aka edits not allowed). - Although unlikely, it you wish to only clamp on text input but want v_min==v_max==0.0f - to mean unclamped drags, you can use _ClampOnInput instead of _AlwaysClamp. (#7968, #3361, #76) - -Other changes: - -- Error Handling: Enabled/improved error recovery systems. (#1651, #5654) - - Error recovery is provided as a way to facilitate: - - Recovery after a programming error. Native code or scripting language (the later - tends to facilitate iterating on code while running). - - Recovery after running an exception handler or any error processing which may skip code - after an error has been detected. - - Error recovery is not perfect nor guaranteed! It is a feature to ease development. - You not are not supposed to rely on it in the course of a normal application run. - - Functions that support error recovery are using IM_ASSERT_USER_ERROR() instead of IM_ASSERT(). - - By design, we do not allow error recovery to be 100% silent. One of the options needs to be enabled! - - Possible usage: facilitate recovery from errors triggered from a scripting language or - after specific exceptions handlers. Surface errors to programmers in less aggressive ways. - - Always ensure that on programmers seats you have at minimum Asserts or Tooltips enabled - when making direct imgui API calls! Otherwise it would severely hinder your ability to - catch and correct mistakes! - - Added io.ConfigErrorRecovery to enable error recovery support. - - Added io.ConfigErrorRecoveryEnableAssert to assert on recoverable errors. - - Added io.ConfigErrorRecoveryEnableDebugLog to output to debug log on recoverable errors. - - Added io.ConfigErrorRecoveryEnableTooltip to enable displaying an error tooltip on recoverable errors. - The tooltip include a way to enable asserts if they were disabled. - - All options are enabled by default. - - Read https://github.com/ocornut/imgui/wiki/Error-Handling for a bit more details. -- Windows: BeginChild(): made it possible to call SetNextWindowSize() on a child window - using ImGuiChildFlags_ResizeX,ImGuiChildFlags_ResizeY in order to override its current - size. (#1710, #8020) -- Scrollbar: Shift+Click scroll to clicked location (pre-1.90.8 default). (#8002, #7328) -- Scrollbar: added io.ConfigScrollbarScrollByPage setting (default to true). (#8002, #7328) - Set io.ConfigScrollbarScrollByPage=false to enforce always scrolling to clicked location. -- Drags: split ImGuiSliderFlags_AlwaysClamp into two distinct flags: (#7968, #3361, #76) - - ImGuiSliderFlags_AlwaysClamp = ImGuiSliderFlags_ClampOnInput + ImGuiSliderFlags_ClampZeroRange. - - Previously _AlwaysClamp only did the equivalent of _ClampOnInput. - - Added ImGuiSliderFlags_ClampOnInput which is now a subset of AlwaysClamp. - (note that it was the old name of AlwaysClamp, but we are reintroducing that name). - - Added ImGuiSliderFlags_ClampZeroRange to enforce clamping even when v_min==v_max==0.0f - in drag functions. Sliders are not affected. -- Tooltips, Drag and Drop: Fixed an issue where the fallback drag and drop payload tooltip - appeared during drag and drop release. -- Tooltips, Drag and Drop: Stabilized name of drag and drop tooltip window so that - transitioning from an item tooltip to a drag tooltip doesn't leak window auto-sizing - info from one to the other. (#8036) -- Tooltips: Tooltips triggered from touch inputs are positioned above the item. (#8036) -- Backends: SDL3: Update for API changes: SDL_bool removal. SDL_INIT_TIMER removal. -- Backends: WebGPU: Fixed DAWN api change using WGPUStringView in WGPUShaderSourceWGSL. - (#8009, #8010) [@blitz-research] - -Docking+Viewports Branch: - -- Backends: SDL2, SDL3: Fixed building for UWP platforms. (#8008) -- Backends: Win32: Use ResisterClassW()/CreateWindowExW() for secondary viewports, to - ensure correct IME input even if the backend was compiled in MBCS mode. (#7979, #5725) - - ------------------------------------------------------------------------ - VERSION 1.91.2 (Released 2024-09-19) ------------------------------------------------------------------------ - -Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.2 - -Breaking changes: - - - Internals: using multiple overlayed ButtonBehavior() with same ID will now have the - io.ConfigDebugHighlightIdConflicts=true feature emit a warning. (#8030) - It was one of the rare case where using same ID is legal. Workarounds: - - use single ButtonBehavior() call with multiple _MouseButton flags - - or surround the calls with PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); ... PopItemFlag() - -Other changes: - -- Added io.ConfigDebugHighlightIdConflicts debug feature! (#7961, #7669) - THIS DETECTS THE MOST COMMON USER ERROR BY FIRST-TIME DEAR IMGUI PROGRAMMERS! - - The tool detects when multiple items are sharing the same identifier, due to not - using PushID/PopID in loops, or not using ID stack facilities such as "##" suffixes. - Very frequently it happens when using empty "" labels. - - When hovering an item with a conflicting ID, all visible items with the same ID will - be highlighted and an explanatory tooltip is made visible. - - The feature may be disabled and is exposed in Demo->Tools menu. - - I've been wanting to add this tool for a long time, but was stalled by finding a way to - not make it spammy + make it practically zero cost. After @pthom made various proposals to - solve the same problem (thanks for pushing me!), I decided it was time to finish it. - - Added ImGuiItemFlags_AllowDuplicateId to use with PushItemFlag()/PopItemFlag() if for some - reason you intend to have duplicate identifiers. - - (#74, #96, #480, #501, #647, #654, #719, #843, #894, #1057, #1173, #1390, #1414, #1556, #1768, - #2041, #2116, #2330, #2475, #2562, #2667, #2807, #2885, #3102, #3375, #3526, #3964, #4008, - #4070, #4158, #4172, #4199, #4375, #4395, #4471, #4548, #4612, #4631, #4657, #4796, #5210, - #5303, #5360, #5393, #5533, #5692, #5707, #5729, #5773, #5787, #5884, #6046, #6093, #6186, - #6223, #6364, #6387, #6567, #6692, #6724, #6939, #6984, #7246, #7270, #7375, #7421, #7434, - #7472, #7581, #7724, #7926, #7937 and probably more..) -- Nav: pressing any keyboard key while holding Alt disable toggling nav layer on Alt release. (#4439) -- MultiSelect+Tables: fixed an issue where box-select would skip items while drag-scrolling - in a table with outer borders. (#7970, #7821). -- Inputs: SetNextItemShortcut() with ImGuiInputFlags_Tooltip doesn't show tooltip when item is active. -- InputText: internal refactoring to simplify and optimize the code. The ImWchar buffer has been - removed. Simplifications allowed to implement new optimizations for handling very large text buffers - (e.g. in our testing, handling of a 1 MB text buffer is now 3 times faster in VS2022 Debug build). - This is the first step toward more refactoring. (#7925) [@alektron, @ocornut] -- InputText: added CJK double-width punctuation to list of separators considered for CTRL+Arrow. -- Tables: fixed auto-width columns when using synced-instances of same table. The previous fix - done in v1.90.5 was incomplete. (#7218) -- Tables: fixed assertion related to inconsistent outer clipping when sizes are not rounded. (#7957) [@eclbtownsend] -- Tables: fixed assertion with tables with borders when clipped by parent. (#6765, #3752, #7428) -- Windows: fixed an issue where double-click to collapse could be triggered even while another - item is active, if the item didn't use the left mouse button. (#7841) -- Misc: Made it accepted to call SetMouseCursor() with any out-of-bound value, as a way to allow - hacking in custom cursors if desirable. -- Fonts: fixed ellipsis "..." rendering width miscalculation bug introduced in 1.91.0. (#7976) [@DDeimos] -- TextLinkOpenURL(): modified tooltip to display a verb "Open 'xxxx'". (#7885, #7660) -- Backends: SDL2: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190) [@scribam] -- Backends: GLFW+Emscripten: use OSX behaviors automatically when using contrib glfw port. (#7965, #7915) - [@ypujante] -- Backends: WebGPU: Added support for optional IMGUI_IMPL_WEBGPU_BACKEND_DAWN / IMGUI_IMPL_WEBGPU_BACKEND_WGPU - defines to handle ever-changing native implementations. (#7977, #7969, #6602, #6188, #7523) [@acgaudette] - -Docking+Viewports Branch: - -- Viewports: fixed an issue where a window manually constrained to the main viewport while crossing - over main viewport bounds isn't translated properly. (#7985) -- Backends: SDL2, SDL3, Win32: ensure that ImGuiPlatformMonitor list is available after backend Init call. (#7995) -- Backends: Win32: fixed direct calls to platform_io.Platform_SetWindowPos()/Platform_SetWindowSize() - on windows created by application (typically main viewport). -- Backends: Win32: fixed an issue where a viewport destroyed while clicking would hog - mouse tracking and temporary lead to incorrect update of HoveredWindow. (#7971) -- Backends: SDL3: added support for viewport->ParentViewportId field to support parenting - windows at OS level. (#7973, #7989) [@RT2code] - ------------------------------------------------------------------------ - VERSION 1.91.1 (Released 2024-09-04) ------------------------------------------------------------------------ - -Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.1 - -Breaking changes: - -- BeginChild(): renamed ImGuiChildFlags_Border to ImGuiChildFlags_Borders for consistency. [@cfillion] - Kept inline redirection flag (will obsolete). -- IO: moved clipboard functions from ImGuiIO to ImGuiPlatformIO: - - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn - - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn - - in function signatures, changed 'void* user_data' to 'ImGuiContext* ctx' for consistency - with other functions. Pull your user data from platform_io.ClipboardUserData if used. - - as this is will affect all users of custom engines/backends, we are providing proper - legacy redirection (will obsolete). -- IO: moved other functions from ImGuiIO to ImGuiPlatformIO: - - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn (#7660) - - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn - - io.PlatformLocaleDecimalPoint -> platform_io.Platform_LocaleDecimalPoint (#7389, #6719, #2278) - - access those via GetPlatformIO() instead of GetIO(). - (Because PlatformOpenInShellFn and PlatformSetImeDataFn were introduced very recently and - often automatically set by core library and backends, we are exceptionally not maintaining - a legacy redirection symbol for those two.) -- Commented the old ImageButton() signature obsoleted in 1.89 (~August 2022). (#5533, #4471, #2464, #1390) - - old ImageButton() used ImTextureId as item id (created issue with e.g. multiple buttons in same scope, transient texture id values, opaque computation of ID) - - new ImageButton() requires an explicit 'const char* str_id' - - old ImageButton() had frame_padding' override argument. - - new ImageButton() always use style.FramePadding, which you can modify using PushStyleVar()/PopStyleVar(). - -Other changes: - -- IO: Added GetPlatformIO() and ImGuiPlatformIO, pulled from 'docking' branch, which - is a centralized spot to connect os/platform/renderer related functions. - Clipboard, IME and OpenInShell hooks are moved here. (#7660) -- IO, InputText: fixed an issue where typing text in an InputText() would defer character - processing by one frame, because of the trickling input queue. Reworked interleaved - keys<>char trickling to take account for keys known to input characters. (#7889, #4921, #4858) -- Windows: adjust default ClipRect to better match rendering of thick borders (which are in - theory not supported). Compensate for the fact that borders are centered around the windows - edge rather than inner. (#7887, #7888 + #3312, #7540, #3756, #6170, #6365) -- Made BeginItemTooltip() and IsItemHovered() with delay flag infer an implicit ID (for - ID-less items such as Text element) in a way that works when item resizes. (#7945, #1485) -- MultiSelect+TreeNode+Drag and Drop: fixed an issue where carrying a drag and drop payload - over an already open tree node using multi-select would incorrectly select it. (#7850) -- MultiSelect+TreeNode: default open behavior is _OpenOnDoubleClick + _OpenOnArrow when - used in a multi-select context without any ImGuiTreeNode_OpenOnXXX flags set. (#7850) -- Tables: fixes/revert a 1.90 change were outer border would be moved bottom and right - by an extra pixel + rework the change so that contents doesn't overlap the bottom and - right border in a scrolling table. (#6765, #3752, #7428) -- Tables: fixed an issue resizing columns or querying hovered column/row when using multiple - synched instances that are layed out at different X positions. (#7933) -- Tabs: avoid queuing a refocus when tab is already focused, which would have the - side-effect of e.g. closing popup on a mouse release. (#7914) -- InputText: allow callback to update buffer while in read-only mode. (imgui_club/#46) -- InputText: fixed an issue programmatically refocusing a multi-line input which was just active. (#4761, #7870) -- TextLink(), TextLinkOpenURL(): change mouse cursor to Hand shape when hovered. (#7885, #7660) -- Tooltips, Drag and Drop: made it possible to override BeginTooltip() position while inside - a drag and drop source or target: a SetNextWindowPos() call won't be overridden. (#6973) -- PlotHistogram, PlotLines: register item ID and use button behavior in a more idiomatic manner, - fixes preventing e.g. GetItemID() and other ID-based helper to work. (#7935, #3072) -- Style: added PushStyleVarX(), PushStyleVarY() helpers to conveniently modify only - one component of a ImVec2 var. -- Fonts: made it possible to use PushFont()/PopFont() calls across Begin() calls. (#3224, #3875, #6398, #7903) -- Backends: - - Backends: GLFW: added ImGui_ImplGlfw_Sleep() helper function because GLFW does not - provide a way to do a portable sleep. (#7844) - - Backends: GLFW+Emscripten: Use OpenURL() from GLFW3 contrib port when available and using - the contrib port instead of Emscripten own GLFW3 implementation. (#7647, #7915, #7660) [@ypujante] - - Backends: SDL2, SDL3: ignore events of other SDL windows. (#7853) [@madebr, @ocornut] - - Backends: SDL2, SDL3: storing SDL_WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*. - - Backends: SDL3: Update for API changes: SDL_GetGamepads() memory ownership logic was reverted back - by SDL3 on July 27. (#7918, #7898, #7807) [@cheyao, @MattGuerrette] - - Backends: GLFW: passing null window to glfwGetClipboardString()/glfwSetClipboardString() - since GLFW own tests are doing that and it seems unnecessary. - - Backends: SDL2, SDL3, GLFW, OSX, Allegro: update to set function handlers in ImGuiPlatformIO - instead of ImGuiIO. -- Examples: - - Examples: GLFW (all), SDL2 (all), SDL3 (all), Win32+OpenGL3: rework examples main loop - to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) - - Examples: SDL3: Update for API changes: SDL_Init() returns 0 on failure. - -Docking+Viewports Branch: - -- Viewports: added optional platform_io.Platform_GetWindowWorkAreaInsets() hook - to allow backends to alter the default per-viewport work-area. (#7823) -- Backends: don't report monitors with DpiScale of 0, which seemed to be reported for - virtual monitors instead by accessibility drivers. (#7902) [@nicolasnoble, @ocornut] -- Backends: SDL2, SDL3: using SDL_HINT_WINDOW_NO_ACTIVATION_WHEN_SHOWN to support the - ImGuiViewportFlags_NoFocusOnAppearing flag, instead of using a Win32-specific hack. - (#7896) [@RT2Code] - ------------------------------------------------------------------------ - VERSION 1.91.0 (Released 2024-07-30) ------------------------------------------------------------------------ - -Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.0 - Breaking changes: - IO, IME: renamed platform IME hook and added explicit context for consistency and future-proofness. @@ -670,15 +46,6 @@ Breaking changes: - new: io.PlatformSetImeDataFn(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); It is expected that for a vast majority of users this is automatically set by core library and/or platform backend so it won't have any effect. -- Obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). (#7838) - You should never need those functions! You can do everything in less a confusing manner by only - using GetCursorScreenPos() and GetContentRegionAvail(). Also always consider that if you are using - GetWindowPos() and GetCursorPos() you may also be making things unnecessarily complicated. - I repeat: You can do everything with GetCursorScreenPos() and GetContentRegionAvail()! - - GetWindowContentRegionMax().x - GetCursorPos().x --> GetContentRegionAvail().x - - GetWindowContentRegionMax().x + GetWindowPos().x --> GetCursorScreenPos().x + GetContentRegionAvail().x // when called from left edge of window - - GetContentRegionMax() --> GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos() // right edge in local coordinates - - GetWindowContentRegionMax().x - GetWindowContentRegionMin().x --> GetContentRegionAvail() // when called from left edge of window - Item flag changes: - Obsoleted PushButtonRepeat()/PopButtonRepeat() in favor of using new PushItemFlag()/PopItemFlag() with ImGuiItemFlags_ButtonRepeat. Kept inline redirecting functions (will obsolete). @@ -693,25 +60,30 @@ Breaking changes: - Commented out obsolete ImGuiModFlags_XXX values (renamed to ImGuiMod_XXX in 1.89). (#4921, #456) - ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl, ImGuiModFlags_Shift -> ImGuiMod_Shift etc. - Backends: GLFW+Emscripten: Renamed ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback() to - ImGui_ImplGlfw_InstallEmscriptenCallbacks(), with an additional GLFWWindow* parameter. (#7647) [@ypujante] + ImGui_ImplGlfw_InstallEmscriptenCallbacks(), with additional GLFWWindow* parameter. (#7647) [@ypujante] Other changes: - Added TextLink(), TextLinkOpenURL() hyperlink widgets. (#7660) - IO: added io.PlatformOpenInShellFn handler to open a link/folder/file in OS shell. (#7660) - (*EDIT* From next version 1.91.1 we moved this to platform_io.Platform_OpenInShellFn *EDIT**) - Added IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS to disable default Windows/Linux/Mac implementations. -- IO: added io.ConfigNavSwapGamepadButtons to swap Activate/Cancel (A<>B) buttons, to match the - typical "Nintendo/Japanese consoles" button layout when using Gamepad navigation. (#787, #5723) + Default to use ShellExecute() under Windows, and system("") under Mac/Linux/etc. + Added IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS to disable default implementation. - Added PushItemFlag()/PopItemFlags(), ImGuiItemFlags to modify shared item flags: - - Added ImGuiItemFlags_NoTabStop to disable tabbing through items. - - Added ImGuiItemFlags_NoNav to disable any navigation and focus of items. (#787) - - Added ImGuiItemFlags_NoNavDefaultFocus to disable item being default focus. (#787) - - Added ImGuiItemFlags_ButtonRepeat to enable repeat on any button-like behavior. - - Added ImGuiItemFlags_AutoClosePopups to disable menu items/selection auto closing parent popups. - Disabling this was previously possible for Selectable() via a direct flag but not for MenuItem(). - (#1379, #1468, #2200, #4936, #5216, #7302, #7573) - - This was mostly all previously in imgui_internal.h. + - Added ImGuiItemFlags_NoTabStop to disable tabbing through items. + - Added ImGuiItemFlags_NoNav to disable any navigation and focus of items. (#787) + - Added ImGuiItemFlags_NoNavDefaultFocus to disable item being default focus. (#787) + - Added ImGuiItemFlags_ButtonRepeat to enable repeat on any button-like behavior. + - Added ImGuiItemFlags_AutoClosePopups to disable menu items/selection auto closing parent popups. + Disabling this was previously possible for Selectable() via a direct flag but not for MenuItem(). + (#1379, #1468, #2200, #4936, #5216, #7302, #7573) + - This was mostly all previously in imgui_internal.h. +- Inputs: added SetItemKeyOwner(ImGuiKey key) in public API. This is a simplified version of a more + complete set of function available in imgui_internal.h. One common use-case for this is to allow + your items to disable standard inputs behaviors such as Tab or Alt handling, Mouse Wheel scrolling, + etc. (#456, #2637, #2620, #2891, #3370, #3724, #4828, #5108, #5242, #5641) + // Hovering or activating the button will disable mouse wheel default behavior to scroll + InvisibleButton(...); + SetItemKeyOwner(ImGuiKey_MouseWheelY); - Multi-Select: added multi-select API and demos. (#1861, #6518) - This system implements standard multi-selection idioms (CTRL+mouse click, CTRL+keyboard moves, SHIFT+mouse click, SHIFT+keyboard moves, etc.) with support for clipper (not submitting non-visible @@ -720,16 +92,16 @@ Other changes: This is designed to allow all kinds of selection storage you may use in your application (e.g. set/map/hash, intrusive selection, interval trees, up to you). - The supported widgets are Selectable(), Checkbox(). TreeNode() is also technically supported but... - using this correctly is more complicated. You need some sort of linear/random access to your tree, + using this correctly is more complicated (you need some sort of linear/random access to your tree, which is suited to advanced trees setups already implementing filters and clipper. - We will work toward simplifying our existing demo for trees. - - A helper ImGuiSelectionBasicStorage is provided to facilitate getting started in a typical app - (likely to suit a majority of users). + We will work toward simplifying and demoing this later. + - A helper ImGuiSelectionBasicStorage is provided to facilitate getting started in a typical app. - Documentation: - Wiki page https://github.com/ocornut/imgui/wiki/Multi-Select for API overview. - - Demo code + headers are well commented. + - Demo code. + - Headers are well commented. - Added BeginMultiSelect(), EndMultiSelect(), SetNextItemSelectionUserData(). - - Added IsItemToggledSelection() for use if you need latest selection update during current iteration. + - Added IsItemToggledSelection() for use if you need latest selection update during currnet iteration. - Added ImGuiMultiSelectIO and ImGuiSelectionRequest structures: - BeginMultiSelect() and EndMultiSelect() return a ImGuiMultiSelectIO structure, which is mostly an array of ImGuiSelectionRequest actions (clear, select all, set range, etc.) @@ -760,71 +132,39 @@ Other changes: - Multi-Select (with clipper) - Multi-Select (with deletion) - Multi-Select (dual list box) (#6648) - - Multi-Select (in a table) - Multi-Select (checkboxes) - Multi-Select (multiple scopes) - - Multi-Select (tiled assert browser) - - Multi-Select (trees) (#1861) - Multi-Select (advanced) -- Inputs: added SetItemKeyOwner(ImGuiKey key) in public API. - This is a simplified version of a more complete set of function available in imgui_internal.h. - One common use-case for this is to allow your widgets to disable standard inputs behaviors such - as Tab or Alt handling, Mouse Wheel scrolling, etc. - (#456, #2637, #2620, #2891, #3370, #3724, #4828, #5108, #5242, #5641) - // Hovering or activating the button will disable mouse wheel default behavior to scroll - InvisibleButton(...); - SetItemKeyOwner(ImGuiKey_MouseWheelY); -- Nav: fixed clicking window decorations (e.g. resize borders) from losing focused item when - within a child window using ImGuiChildFlags_NavFlattened. -- InputText: added '\' and '/' as word separator. (#7824, #7704) [@reduf] -- TreeNode: added SetNextItemStorageID() to specify/override the identifier used for persisting - open/close storage. Useful if needing to often read/write from storage without manipulating - the ID stack. (#7553, #6990, #3823, #1131) -- Selectable: added ImGuiSelectableFlags_Highlight flag to highlight items independently from - the hovered state. (#7820) [@rerilier] - Clipper: added SeekCursorForItem() function. When using ImGuiListClipper::Begin(INT_MAX) you can can use the clipper without knowing the amount of items beforehand. (#1311) - In this situation, call ImGuiListClipper::SeekCursorForItem(items_count) at the end of your iteration + In this situation, call ImGuiListClipper::SeekCursorForItem(items_count) as the end of your iteration loop to position the layout cursor correctly. This is done automatically if provided a count to Begin(). -- Groups, Tables: fixed EndGroup() failing to correctly capture current table occupied size. (#7543) -- Style, TabBar: added style.TabBarOverlineSize / ImGuiStyleVar_TabBarOverlineSize to manipulate - thickness of the horizontal line over selected tabs. [@DctrNoob] - Style: close button and collapse/window-menu button hover highlight made rectangular instead of round. -- Misc: added GetID(int) variant for consistency. (#7111) -- Debug Tools: - - Debug Log: Added IMGUI_DEBUG_LOG(), ImGui::DebugLog() in public API. (#5855) - Printed entries include imgui frame counter prefix + are redirected to ShowDebugLogWindow() and - other configurable locations. Always call IMGUI_DEBUG_LOG() for maximum stripping in caller code. - - Debug Log: Added "Configure Outputs.." button. (#5855) - - Debug Log: Fixed incorrect checkbox layout when partially clipped. -- Demo: Reworked "Property Editor" demo in a manner that more resemble the tree data and +- Debug Tools: Added IMGUI_DEBUG_LOG(), ImGui::DebugLog() in public API. (#5855) + Debug log entries add a imgui frame counter prefix + are redirected to ShowDebugLogWindow() and + other configurable locations. Always call IMGUI_DEBUG_LOG() for maximum stripping in caller code. +- Debug Tools: Debug Log: Added "Configure Outputs.." button. (#5855) +- Demo: Reworked "Property Editor" demo in a manner that more ressemble the tree data and struct description data that a real application would want to use. -- Backends: - - Backends: Win32: Fixed ImGuiMod_Super being mapped to VK_APPS instead of (VK_LWIN || VK_RWIN). - (#7768, #4858, #2622) [@Aemony] - - Backends: SDL3: Update for API changes: SDL_GetGamepads() memory ownership change. (#7807) - - Backends: SDL3: Update for API changes: SDL_GetClipboardText() memory ownership change. (#7801) - - Backends: SDL3: Update for API changes: SDLK_x renames and SDLK_KP_x removals (#7761, #7762) - - Backends: SDL3: Update for API changes: SDL_GetProperty() change to SDL_GetPointerProperty(). (#7794) [@wermipls] - - Backends: SDL2,SDL3,OSX: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() rename. - - Backends: GLFW,SDL2: Added io.PlatformOpenInShellFn handler for web/Emscripten versions. (#7660) - [@ypujante, @ocornut] - - Backends: GLFW+Emscripten: Added support for GLFW3 contrib port which fixes many of the things - not supported by the embedded GLFW: gamepad support, mouse cursor shapes, copy to clipboard, - workaround for Super/Meta key, different ways of resizing, multi-window (glfw/canvas) support. - (#7647) [@ypujante] - - Backends: GLFW+Emscripten: Fixed Emscripten warning when using mouse wheel on some setups - "Unable to preventDefault inside passive event listener". (#7647, #7600) [@ypujante] +- Backends: Win32: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. + (#7768, #4858, #2622) [@Aemony] +- Backends: SDL3: Update for API changes: SDL_GetClipboardText() string ownership change. (#7801) +- Backends: SDL3: Update for API changes: SDLK_x renames and SDLK_KP_x removals (#7761, #7762) +- Backends: SDL3: Update for API changes: SDL_GetProperty() change to SDL_GetPointerProperty(). (#7794) [@wermipls] +- Backends: SDL2,SDL3,OSX: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() rename. +- Backends: GLFW,SDL2: Added io.PlatformOpenInShellFn handler for web/Emscripten versions. (#7660) + [@ypujante, @ocornut] +- Backends; GLFW+Emscripten: Added support for GLFW3 contrib port which fixes many of the things + not supported by the embedded GLFW: gamepad support, mouse cursor shapes, copy to clipboard, + workaround for Super/Meta key, different ways of resizing, multi-window (glfw/canvas) support. + (#7647) [@ypujante] +- Backends: GLFW+Emscripten: Fixed Emscripten warning when using mouse wheel on some setups + "Unable to preventDefault inside passive event listener". (#7647, #7600) [@ypujante] Docking+Viewports Branch: -- Viewports: Always update fallback monitor to primary monitor if there's one. -- Backends: OSX: Fixed NSAppKitVersion version limit for setWantsBestResolutionOpenGLSurface - usage. (#7814) [@YGXXD] - Backends: SDL3: Fixed a bug preventing ImGuiViewportFlags_NoFocusOnAppearing support from working (Windows only). -- Backends: Vulkan: ImGui_ImplVulkan_SwapBuffers() used by secondary viewports still proceeds - increasing frame counters on VK_SUBOPTIMAL_KHR. (#7825, #3881) [@NostraMagister] ----------------------------------------------------------------------- @@ -865,7 +205,6 @@ Other changes: which was pressed over void/underlying app, which is consistent/needed to allow the mouse up event of a drag over void/underlying app to catch release. (#1392) [@Moka42] - IO: Added io.ClearInputMouse() to clear mouse state. (#4921) -- IO: Added ImGuiConfigFlags_NoKeyboard for consistency and convenience. (#4921) - Windows: BeginChild(): fixed a glitch when during a resize of a child window which is tightly close to the boundaries of its parent (e.g. with zero WindowPadding), the child position could have temporarily be moved around by erroneous padding application. (#7706) @@ -1482,7 +821,6 @@ Breaking changes: Before: BeginChild("Name", size, false) After: BeginChild("Name", size) or BeginChild("Name", 0) or BeginChild("Name", size, ImGuiChildFlags_None) Existing code will still work as 'ImGuiChildFlags_Border == true', but you are encouraged to update call sites. - **AMEND FROM THE FUTURE: from 1.91.1, 'ImGuiChildFlags_Border' is called 'ImGuiChildFlags_Borders'** - BeginChild(): Added child-flag ImGuiChildFlags_AlwaysUseWindowPadding as a replacement for the window-flag ImGuiWindowFlags_AlwaysUseWindowPadding: the feature only ever made sense for use with BeginChild() anyhow, passing it to Begin() had no effect. Now that we accept @@ -1532,7 +870,6 @@ Other changes: child windows from the bottom/right border (toward layout direction). Resized child windows settings are saved and persistent in .ini file. (#1710) - BeginChild(): Added ImGuiChildFlags_Border as a replacement for 'bool border = true' parameter. - **AMEND FROM THE FUTURE: from 1.91.1, 'ImGuiChildFlags_Border' is called 'ImGuiChildFlags_Borders'** - BeginChild(): Added ImGuiChildFlags_AutoResizeX and ImGuiChildFlags_AutoResizeY to auto-resize on one axis, while generally providing a size on the other axis. (#1666, #1395, #1496, #1710) e.g. BeginChild("name", {-FLT_MIN, 0.0f}, ImGuiChildFlags_AutoResizeY); @@ -2772,7 +2109,6 @@ Breaking Changes: - For all calls to IO new functions, the Dear ImGui context should be bound/current. - Reworked IO keyboard input API: (#4921, #2625, #3724) [@thedmd, @ocornut] - Added io.AddKeyEvent() function, obsoleting writing directly to io.KeyMap[], io.KeysDown[] arrays. - - You can use IsKeyDown() instead of reading from io.KeysDown[]. - For keyboard modifiers, you can call io.AddKeyEvent() with ImGuiKey_ModXXX values, obsoleting writing directly to io.KeyCtrl, io.KeyShift etc. - Added io.SetKeyEventNativeData() function (optional) to pass native and old legacy indices. @@ -5368,27 +4704,20 @@ Other Changes: - See https://github.com/ocornut/imgui/issues/1599 for recommended gamepad mapping or download PNG/PSD at http://goo.gl/9LgVZW - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. Read imgui.cpp for more details. - To use Keyboard Navigation: - - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically - fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. - - Basic controls: arrows to navigate, Alt to enter menus, Space to activate item, Enter to edit text, - Escape to cancel/close, Ctrl-Tab to focus windows, etc. - - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), - the io.WantCaptureKeyboard flag will be set. - - For more advanced uses, you may want to read from io.NavActive or io.NavVisible. Read imgui.cpp for more details. + - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. + - Basic controls: arrows to navigate, Alt to enter menus, Space to activate item, Enter to edit text, Escape to cancel/close, Ctrl-Tab to focus windows, etc. + - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag will be set. + For more advanced uses, you may want to read from io.NavActive or io.NavVisible. Read imgui.cpp for more details. - Navigation: SetItemDefaultFocus() sets the navigation position in addition to scrolling. (#787) - Navigation: Added IsItemFocused(), added IsAnyItemFocused(). (#787) - Navigation: Added window flags: ImGuiWindowFlags_NoNav (== ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus). - Navigation: Style: Added ImGuiCol_NavHighlight, ImGuiCol_NavWindowingHighlight colors. (#787) - Navigation: TreeNode: Added ImGuiTreeNodeFlags_NavLeftJumpsBackHere flag to allow Nav Left direction to jump back to parent tree node from any of its child. (#1079) - Navigation: IO: Added io.ConfigFlags (input), io.NavActive (output), io.NavVisible (output). (#787) -- Context: Removed the default global context and font atlas instances, which caused various - problems to users of multiple contexts and DLL users. (#1565, #1599) YOU NOW NEED TO CALL - ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. - Existing apps will assert/crash without it. -- Context: Added SetAllocatorFunctions() to rewire memory allocators (as a replacement to previous - parameters to CreateContext()). Allocators are shared by all contexts and imgui helpers. (#1565, #586, #992, #1007, #1558) -- Context: You may pass a ImFontAtlas to CreateContext() to specify a font atlas to share. - Shared font atlas are not owned by the context and not destroyed along with it. (#1599) +- Context: Removed the default global context and font atlas instances, which caused various problems to users of multiple contexts and DLL users. (#1565, #1599) + YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. Existing apps will assert/crash without it. +- Context: Added SetAllocatorFunctions() to rewire memory allocators (as a replacement to previous parameters to CreateContext()). Allocators are shared by all contexts and imgui helpers. (#1565, #586, #992, #1007, #1558) +- Context: You may pass a ImFontAtlas to CreateContext() to specify a font atlas to share. Shared font atlas are not owned by the context and not destroyed along with it. (#1599) - Context: Added IMGUI_DISABLE_DEFAULT_ALLOCATORS to disable linking with malloc/free. (#1565, #586, #992, #1007, #1558) - IO: Added io.ConfigFlags for user application to store settings for imgui and for the backend: - ImGuiConfigFlags_NavEnableKeyboard: Enable keyboard navigation. @@ -5397,85 +4726,61 @@ Other Changes: - ImGuiConfigFlags_NoMouseCursorChange: Instruct backend to not alter mouse cursor shape and visibility (by default the example backend use mouse cursor API of the platform when available) - ImGuiConfigFlags_NoMouse: Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information passed by the backend. - ImGuiConfigFlags_IsSRGB, ImGuiConfigFlags_IsTouchScreen: Flags for general application use. -- IO: Added io.BackendFlags for backend to store its capabilities (currently: _HasGamepad, - _HasMouseCursors, _HasSetMousePos). This will be used more in the next version. +- IO: Added io.BackendFlags for backend to store its capabilities (currently: _HasGamepad, _HasMouseCursors, _HasSetMousePos). This will be used more in the next version. - IO: Added ImGuiKey_Insert, ImGuiKey_Space keys. Setup in all example backends. (#1541) - IO: Added Horizontal Mouse Wheel support for horizontal scrolling. (#1463) [@tseeker] - IO: Added IsAnyMouseDown() helper which is helpful for backends to handle mouse capturing. -- Window: Clicking on a window with the ImGuiWIndowFlags_NoMove flags takes an ActiveId so - we can't hover something else when dragging afterwards. (#1381, #1337) -- Window: IsWindowHovered(): Added ImGuiHoveredFlags_AnyWindow, ImGuiFocusedFlags_AnyWindow flags - (See Breaking Changes). Added to demo. (#1382) -- Window: Added SetNextWindowBgAlpha() helper. Particularly helpful since the legacy 5-parameters - version of Begin() has been marked as obsolete in 1.53. (#1567) -- Window: Fixed SetNextWindowContentSize() with 0.0f on Y axis (or SetNextWindowContentWidth()) - overwriting the contents size. Got broken on Dec 10 (1.53). (#1363) +- Window: Clicking on a window with the ImGuiWIndowFlags_NoMove flags takes an ActiveId so we can't hover something else when dragging afterwards. (#1381, #1337) +- Window: IsWindowHovered(): Added ImGuiHoveredFlags_AnyWindow, ImGuiFocusedFlags_AnyWindow flags (See Breaking Changes). Added to demo. (#1382) +- Window: Added SetNextWindowBgAlpha() helper. Particularly helpful since the legacy 5-parameters version of Begin() has been marked as obsolete in 1.53. (#1567) +- Window: Fixed SetNextWindowContentSize() with 0.0f on Y axis (or SetNextWindowContentWidth()) overwriting the contents size. Got broken on Dec 10 (1.53). (#1363) - ArrowButton: Added ArrowButton() given a cardinal direction (e.g. ImGuiDir_Left). - InputText: Added alternative clipboard shortcuts: Shift+Delete (cut), CTRL+Insert (copy), Shift+Insert (paste). (#1541) -- InputText: Fixed losing Cursor X position when clicking outside on an item that's submitted - after the InputText(). It was only noticeable when restoring focus programmatically. (#1418, #1554) -- InputText: Added ImGuiInputTextFlags_CharsScientific flag to also allow 'e'/'E' for input of values - using scientific notation. Automatically used by InputFloat. +- InputText: Fixed losing Cursor X position when clicking outside on an item that's submitted after the InputText(). It was only noticeable when restoring focus programmatically. (#1418, #1554) +- InputText: Added ImGuiInputTextFlags_CharsScientific flag to also allow 'e'/'E' for input of values using scientific notation. Automatically used by InputFloat. - Style: Default style is now StyleColorsDark(), instead of the old StyleColorsClassic(). (#707) - Style: Enable window border by default. (#707) -- Style: Exposed ImGuiStyleVar_WindowTitleAlign, ImGuiStyleVar_ScrollbarSize, ImGuiStyleVar_ScrollbarRounding, - ImGuiStyleVar_GrabRounding + added an assert to reduce accidental breakage. (#1181) +- Style: Exposed ImGuiStyleVar_WindowTitleAlign, ImGuiStyleVar_ScrollbarSize, ImGuiStyleVar_ScrollbarRounding, ImGuiStyleVar_GrabRounding + added an assert to reduce accidental breakage. (#1181) - Style: Added style.MouseCursorScale help when using the software mouse cursor facility. (#939). - Style: Close button nows display a cross before hovering. Fixed cross positioning being a little off. Uses button colors for highlight when hovering. (#707) - Popup: OpenPopup() Always reopen existing pop-ups. (Removed imgui_internal.h's OpenPopupEx() which was used for this.) (#1497, #1533). - Popup: BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid(), OpenPopupOnItemClick() all react on mouse release instead of mouse press. (~#439) -- Popup: Better handling of user mistakenly calling OpenPopup() every frame (with the 'reopen_existing' option). - The error will now be more visible and easier to understand. (#1497) +- Popup: Better handling of user mistakenly calling OpenPopup() every frame (with reopen_existing option). The error will now be more visible and easier to understand. (#1497) - Popup: BeginPopup(): Exposed extra_flags parameter that are passed through to Begin(). (#1533) -- Popup: BeginPopupModal: fixed the conditional test for SetNextWindowPos() which was polling - the wrong window, which in practice made the test succeed all the time. +- Popup: BeginPopupModal: fixed the conditional test for SetNextWindowPos() which was polling the wrong window, which in practice made the test succeed all the time. - Tooltip: BeginTooltip() sets ImGuiWindowFlags_NoInputs flag. -- Scrollbar: Fixed ScrollbarY enable test after ScrollbarX has been enabled being a little - off (small regression from Nov 2017). (#1574) -- Scrollbar: Fixed ScrollbarX enable test subtracting WindowPadding.x (this has been there - since the addition of horizontal scroll bar!). +- Scrollbar: Fixed ScrollbarY enable test after ScrollbarX has been enabled being a little off (small regression from Nov 2017). (#1574) +- Scrollbar: Fixed ScrollbarX enable test subtracting WindowPadding.x (this has been there since the addition of horizontal scroll bar!). - Columns: Clear offsets data when columns count changed. (#1525) - Columns: Fixed a memory leak of ImGuiColumnsSet's Columns vector. (#1529) [@unprompted] - Columns: Fixed resizing a window very small breaking some columns positioning (broken in 1.53). -- Columns: The available column extent takes consideration of the right-most clipped pixel, - so the right-most column may look a little wider but will contain the same amount of visible contents. +- Columns: The available column extent takes consideration of the right-most clipped pixel, so the right-most column may look a little wider but will contain the same amount of visible contents. - MenuBar: Fixed menu bar pushing a clipping rect outside of its allocated bound (usually unnoticeable). - TreeNode: nodes with the ImGuiTreeNodeFlags_Leaf flag correctly disable highlight when DragDrop is active. (#143, #581) - Drag and Drop: Increased payload type string to 32 characters instead of 8. (#143) - Drag and Drop: TreeNode as drop target displays rectangle over full frame. (#1597, #143) - DragFloat: Fix/workaround for backends which do not preserve a valid mouse position when dragged out of bounds. (#1559) - InputFloat: Allow inputing value using scientific notation e.g. "1e+10". -- InputDouble: Added InputDouble() function. We use a format string instead of a 'decimal_precision' - parameter to also for "%e" and variants. (#1011) +- InputDouble: Added InputDouble() function. We use a format string instead of a decimal_precision parameter to also for "%e" and variants. (#1011) - Slider, Combo: Use ImGuiCol_FrameBgHovered color when hovered. (#1456) [@stfx] -- Combo: BeginCombo(): Added ImGuiComboFlags_NoArrowButton to disable the arrow button and - only display the wide value preview box. -- Combo: BeginCombo(): Added ImGuiComboFlags_NoPreview to disable the preview and only - display a square arrow button. +- Combo: BeginCombo(): Added ImGuiComboFlags_NoArrowButton to disable the arrow button and only display the wide value preview box. +- Combo: BeginCombo(): Added ImGuiComboFlags_NoPreview to disable the preview and only display a square arrow button. - Combo: Arrow button isn't displayed over frame background so its blended color matches other buttons. Left side of the button isn't rounded. - PlotLines: plot a flat line if scale_min==scale_max. (#1621) -- Fonts: Changed DisplayOffset.y to defaults to 0 instead of +1. Fixed rounding of Ascent/Descent - to match TrueType renderer. If you were adding or subtracting (not assigning) to ImFont::DisplayOffset - check if your fonts are correctly aligned vertically. (#1619) +- Fonts: Changed DisplayOffset.y to defaults to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. + If you were adding or subtracting (not assigning) to ImFont::DisplayOffset check if your fonts are correctly aligned vertically. (#1619) - Fonts: Updated stb_truetype from 1.14 to stb_truetype 1.19. (w/ include fix from some platforms #1622) - Fonts: Added optional FreeType rasterizer in misc/freetype. Moved from imgui_club repo. (#618) [@Vuhdo, @mikesart, @ocornut] - Fonts: Moved extra_fonts/ to misc/fonts/. - ImFontAtlas: Fixed cfg.MergeMode not reusing existing glyphs if available (always overwrote). -- ImFontAtlas: Handle stb_truetype stbtt_InitFont() and stbtt_PackBegin() possible failures - more gracefully, GetTexDataAsRGBA32() won't crash during conversion. (#1527) -- ImFontAtlas: Moved mouse cursor data out of ImGuiContext, fix drawing them with multiple contexts. - Also remove the last remaining undesirable dependency on ImGui in imgui_draw.cpp. (#939) -- ImFontAtlas: Added ImFontAtlasFlags_NoPowerOfTwoHeight flag to disable padding font height - to nearest power of two. (#1613) -- ImFontAtlas: Added ImFontAtlasFlags_NoMouseCursors flag to disable baking software mouse cursors, - mostly to save texture memory on very low end hardware. (#1613) -- ImDrawList: Fixed AddRect() with anti-aliasing disabled (lower-right corner pixel was often - missing, rounding looks a little better.) (#1646) +- ImFontAtlas: Handle stb_truetype stbtt_InitFont() and stbtt_PackBegin() possible failures more gracefully, GetTexDataAsRGBA32() won't crash during conversion. (#1527) +- ImFontAtlas: Moved mouse cursor data out of ImGuiContext, fix drawing them with multiple contexts. Also remove the last remaining undesirable dependency on ImGui in imgui_draw.cpp. (#939) +- ImFontAtlas: Added ImFontAtlasFlags_NoPowerOfTwoHeight flag to disable padding font height to nearest power of two. (#1613) +- ImFontAtlas: Added ImFontAtlasFlags_NoMouseCursors flag to disable baking software mouse cursors, mostly to save texture memory on very low end hardware. (#1613) +- ImDrawList: Fixed AddRect() with anti-aliasing disabled (lower-right corner pixel was often missing, rounding looks a little better.) (#1646) - ImDrawList: Added CloneOutput() helper to facilitate the cloning of ImDrawData or ImDrawList for multi-threaded rendering. -- Misc: Functions passed to libc qsort are explicitly marked cdecl to support compiling with - vectorcall as the default calling convention. (#1230, #1611) [@RandyGaul] -- Misc: ImVec2: added [] operator. This is becoming desirable for some code working of either - axes independently. Better adding it sooner than later. +- Misc: Functions passed to libc qsort are explicitly marked cdecl to support compiling with vectorcall as the default calling convention. (#1230, #1611) [@RandyGaul] +- Misc: ImVec2: added [] operator. This is becoming desirable for some code working of either axes independently. Better adding it sooner than later. - Misc: NewFrame(): Added an assert to detect incorrect filling of the io.KeyMap[] array earlier. (#1555) - Misc: Added IM_OFFSETOF() helper in imgui.h (previously was in imgui_internal.h) - Misc: Added IM_NEW(), IM_DELETE() helpers in imgui.h (previously were in imgui_internal.h) @@ -5494,8 +4799,7 @@ Other Changes: - Examples: Using Dark theme by default. (#707). Tweaked demo code. - Examples: Added support for horizontal mouse wheel for API that allows it. (#1463) [@tseeker] - Examples: All examples now setup the io.BackendFlags to signify they can honor mouse cursors, gamepad, etc. -- Examples: DirectX10: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that - was left in DX10 example but removed in 1.47 (Nov 2015) in every other backends. (#1733) +- Examples: DirectX10: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that was left in DX10 example but removed in 1.47 (Nov 2015) in every other backends. (#1733) - Examples: DirectX12: Added DirectX 12 example. (#301) [@jdm3] - Examples: OpenGL3+GLFW,SDL: Changed GLSL shader version from 330 to 150. (#1466, #1504) - Examples: OpenGL3+GLFW,SDL: Added a way to override the GLSL version string in the Init function. (#1466, #1504). @@ -5509,13 +4813,11 @@ Other Changes: - Examples: GLFW: Added support for mouse cursor shapes (the diagonal resize cursors are unfortunately not supported by GLFW at the moment. (#1495) - Examples: GLFW: Don't attempt to change the mouse cursor input mode if it is set to GLFW_CURSOR_DISABLED by the application. (#1202) [@PhilCK] - Examples: SDL: Added support for mouse cursor shapes. (#1626) [@olls] -- Examples: SDL: Using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging - (SDL 2.0.4+ only, otherwise using SDL_WINDOW_INPUT_FOCUS instead of previously SDL_WINDOW_MOUSE_FOCUS). (#1559) +- Examples: SDL: Using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging (SDL 2.0.4+ only, otherwise using SDL_WINDOW_INPUT_FOCUS instead of previously SDL_WINDOW_MOUSE_FOCUS). (#1559) - Examples: SDL: Enabled vsync by default so people don't come at us when the examples are running at 2000 FPS and burning a CPU core. - Examples: SDL: Using SDL_GetPerformanceCounter() / SDL_GetPerformanceFrequency() to handle frame-rate over 1000 FPS properly. (#996) - Examples: SDL: Using scan-code exclusively instead of a confusing mixture of scan-codes and key-codes. -- Examples: SDL: Visual Studio: Added .vcxproj file. Using %SDL2_DIR% in the default .vcxproj - and build files instead of %SDL_DIR%, the earlier being more standard. +- Examples: SDL: Visual Studio: Added .vcxproj file. Using %SDL2_DIR% in the default .vcxproj and build files instead of %SDL_DIR%, the earlier being more standard. - Examples: Vulkan: Visual Studio: Added .vcxproj file. - Examples: Apple: Fixed filenames in OSX xcode project. Various other Mac friendly fixes. [@gerryhernandez etc.] - Examples: Visual Studio: Disabled extraneous function-level check in Release build. @@ -5561,63 +4863,41 @@ Other Changes: - See ImGuiDragDropFlags for various options. - The ColorEdit4() and ColorButton() widgets now support Drag and Drop. - The API is tagged as Beta as it still may be subject to small changes. -- Drag and Drop: When drag and drop is active, tree nodes and collapsing header can be opened - by hovering on them for 0.7 seconds. -- Renamed io.OSXBehaviors to io.OptMacOSXBehaviors. Should not affect users as the compile-time - default is usually enough. (#473, #650) +- Drag and Drop: When drag and drop is active, tree nodes and collapsing header can be opened by hovering on them for 0.7 seconds. +- Renamed io.OSXBehaviors to io.OptMacOSXBehaviors. Should not affect users as the compile-time default is usually enough. (#473, #650) - Style: Added StyleColorsDark() style. (#707) [@dougbinks] - Style: Added StyleColorsLight() style. Best used with frame borders + thicker font than the default font. (#707) - Style: Added style.PopupRounding setting. (#1112) -- Style: Added style.FrameBorderSize, style.WindowBorderSize, style.PopupBorderSize. - Removed ImGuiWindowFlags_ShowBorders window flag! +- Style: Added style.FrameBorderSize, style.WindowBorderSize, style.PopupBorderSize. Removed ImGuiWindowFlags_ShowBorders window flag! Borders are now fully set up in the ImGuiStyle structure. Use ImGui::ShowStyleEditor() to look them up. (#707, fix #819, #1031) - Style: Various small changes to the classic style (most noticeably, buttons are now using blue shades). (#707) - Style: Renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg. - Style: Renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding. - Style: Removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency. (#707) - Style: Made the ScaleAllSizes() helper rounds down every values so they are aligned on integers. -- Focus: Added SetItemDefaultFocus(), which in the current (master) branch behave the same - as doing `if (IsWindowAppearing()) SetScrollHere()`. In the navigation branch this will also - set the default focus. Prefer using this when creating combo boxes with `BeginCombo()` so your - code will be forward-compatible with gamepad/keyboard navigation features. (#787) -- Combo: Pop-up grows horizontally to accommodate for contents that is larger then the parent - combo button. -- Combo: Added BeginCombo()/EndCombo() API which allows use to submit content of any form and - manage your selection state without relying on indices. -- Combo: Added ImGuiComboFlags_PopupAlignLeft flag to BeginCombo() to prioritize keeping the - pop-up on the left side (for small-button-looking combos). -- Combo: Added ImGuiComboFlags_HeightSmall, ImGuiComboFlags_HeightLarge, ImGuiComboFlags_HeightLargest - to easily provide desired pop-up height. -- Combo: You can use SetNextWindowSizeConstraints() before BeginCombo() to specify specific - pop-up width/height constraints. +- Focus: Added SetItemDefaultFocus(), which in the current (master) branch behave the same as doing `if (IsWindowAppearing()) SetScrollHere()`. + In the navigation branch this will also set the default focus. Prefer using this when creating combo boxes with `BeginCombo()` so your code will be forward-compatible with gamepad/keyboard navigation features. (#787) +- Combo: Pop-up grows horizontally to accommodate for contents that is larger then the parent combo button. +- Combo: Added BeginCombo()/EndCombo() API which allows use to submit content of any form and manage your selection state without relying on indices. +- Combo: Added ImGuiComboFlags_PopupAlignLeft flag to BeginCombo() to prioritize keeping the pop-up on the left side (for small-button-looking combos). +- Combo: Added ImGuiComboFlags_HeightSmall, ImGuiComboFlags_HeightLarge, ImGuiComboFlags_HeightLargest to easily provide desired pop-up height. +- Combo: You can use SetNextWindowSizeConstraints() before BeginCombo() to specify specific pop-up width/height constraints. - Combo: Offset popup position by border size so that a double border isn't so visible. (#707) - Combo: Recycling windows by using a stack number instead of a unique id, wasting less memory (like menus do). - InputText: Added ImGuiInputTextFlags_NoUndoRedo flag. (#1506, #1508) [@ibachar] -- Window: Fixed auto-resize allocating too much space for scrollbar when SizeContents is - bigger than maximum window size (fixes c0547d3). (#1417) -- Window: Child windows with MenuBar use regular WindowPadding.y so layout look consistent as - child or as a regular window. -- Window: Begin(): Fixed appending into a child window with a second Begin() from a different - window stack querying the wrong window for the window->Collapsed test. -- Window: Calling IsItemActive(), IsItemHovered() etc. after a call to Begin() provides item - data for the title bar, so you can easily test if the title bar is being hovered, etc. (#823) +- Window: Fixed auto-resize allocating too much space for scrollbar when SizeContents is bigger than maximum window size (fixes c0547d3). (#1417) +- Window: Child windows with MenuBar use regular WindowPadding.y so layout look consistent as child or as a regular window. +- Window: Begin(): Fixed appending into a child window with a second Begin() from a different window stack querying the wrong window for the window->Collapsed test. +- Window: Calling IsItemActive(), IsItemHovered() etc. after a call to Begin() provides item data for the title bar, so you can easily test if the title bar is being hovered, etc. (#823) - Window: Made it possible to use SetNextWindowPos() on a child window. -- Window: Fixed a one frame glitch. When an appearing window claimed the focus themselves, the - title bar wouldn't use the focused color for one frame. -- Window: Added ImGuiWindowFlags_ResizeFromAnySide flag to resize from any borders or from the - lower-left corner of a window. This requires your backend to honor GetMouseCursor() requests - for full usability. (#822) +- Window: Fixed a one frame glitch. When an appearing window claimed the focus themselves, the title bar wouldn't use the focused color for one frame. +- Window: Added ImGuiWindowFlags_ResizeFromAnySide flag to resize from any borders or from the lower-left corner of a window. This requires your backend to honor GetMouseCursor() requests for full usability. (#822) - Window: Sizing fixes when using SetNextWindowSize() on individual axises. -- Window: Hide new window for one frame until they calculate their size. - Also fixes SetNextWindowPos() given a non-zero pivot. (#1694) +- Window: Hide new window for one frame until they calculate their size. Also fixes SetNextWindowPos() given a non-zero pivot. (#1694) - Window: Made mouse wheel scrolling accommodate better to windows that are smaller than the scroll step. -- Window: SetNextWindowContentSize() adjust for the size of decorations (title bar/menu bar), - but _not_ for borders are we consistently make borders not affect layout. - If you need a non-child window of an exact size with border enabled but zero window padding, - you'll need to accommodate for the border size yourself. -- Window: Using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel - event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar - are also set. (#1380, #1502) +- Window: SetNextWindowContentSize() adjust for the size of decorations (title bar/menu bar), but _not_ for borders are we consistently make borders not affect layout. + If you need a non-child window of an exact size with border enabled but zero window padding, you'll need to accommodate for the border size yourself. +- Window: Using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set. (#1380, #1502) - Window: Active Modal window always set the WantCaptureKeyboard flag. (#744) - Window: Moving window doesn't use accumulating MouseDelta so straying out of imgui boundaries keeps moved imgui window at the same cursor-relative position. - IsWindowFocused(): Added ImGuiFocusedFlags_ChildWindows flag to include child windows in the focused test. (#1382). @@ -5626,52 +4906,39 @@ Other Changes: - IsWindowHovered(): Added ImGuiHoveredFlags_RootWindow flag to start hovered test from the root (top-most) window. The combination of both flags obsoletes IsRootWindowOrAnyChildHovered(). (#1382) - IsWindowHovered(): Fixed return value when an item is active to use the same logic as IsItemHovered(). (#1382, #1404) - IsWindowHovered(): Always return true when current window is being moved. (#1382) -- Scrollbar: Fixed issues with vertical scrollbar flickering/appearing, typically when manually - resizing and using a pattern of filling available height (e.g. full sized BeginChild). +- Scrollbar: Fixed issues with vertical scrollbar flickering/appearing, typically when manually resizing and using a pattern of filling available height (e.g. full sized BeginChild). - Scrollbar: Minor graphical fix for when scrollbar don't have enough visible space to display the full grab. -- Scrolling: Fixed padding and scrolling asymmetry where lower/right sides of a window wouldn't - use WindowPadding properly + causing minor scrolling glitches. +- Scrolling: Fixed padding and scrolling asymmetry where lower/right sides of a window wouldn't use WindowPadding properly + causing minor scrolling glitches. - Tree: TreePush with zero arguments was ambiguous. Resolved by making it call TreePush(const void*). [@JasonWilkins] - Tree: Renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. (#600, #1330) - MenuBar: Fixed minor rendering issues on the right size when resizing a window very small and using rounded window corners. -- MenuBar: better software clipping to handle small windows, in particular child window don't have - minimum constraints so we need to render clipped menus better. +- MenuBar: better software clipping to handle small windows, in particular child window don't have minimum constraints so we need to render clipped menus better. - BeginMenu(): Tweaked the Arrow/Triangle displayed on child menu items. -- Columns: Clipping columns borders on Y axis on CPU because some Linux GPU drivers appears to - be unhappy with triangle spanning large regions. (#125) -- Columns: Added ImGuiColumnsFlags_GrowParentContentsSize to internal API to restore old content - sizes behavior (may be obsolete). (#1444, #125) -- Columns: Columns width is no longer lost when dragging a column to the right side of the window, - until releasing the mouse button you have a chance to save them. (#1499, #125). [@ggtucker] +- Columns: Clipping columns borders on Y axis on CPU because some Linux GPU drivers appears to be unhappy with triangle spanning large regions. (#125) +- Columns: Added ImGuiColumnsFlags_GrowParentContentsSize to internal API to restore old content sizes behavior (may be obsolete). (#1444, #125) +- Columns: Columns width is no longer lost when dragging a column to the right side of the window, until releasing the mouse button you have a chance to save them. (#1499, #125). [@ggtucker] - Columns: Fixed dragging when using a same of columns multiple times in the frame. (#125) - Indent(), Unindent(): Allow passing negative values. - ColorEdit4(): Made IsItemActive() return true when picker pop-up is active. (#1489) - ColorEdit4(): Tweaked tooltip so that the color button aligns more correctly with text. -- ColorEdit4(): Support drag and drop. Color buttons can be used as drag sources, and ColorEdit - widgets as drag targets. (#143) -- ColorPicker4(): Fixed continuously returning true when holding mouse button on the sat/value/alpha - locations. We only return true on value change. (#1489) -- NewFrame(): using literal strings in the most-frequently firing IM_ASSERT expressions to - increase the odd of programmers seeing them (especially those who don't use a debugger). -- NewFrame() now asserts if neither Render or EndFrame have been called. Exposed EndFrame(). - Made it legal to call EndFrame() more than one. (#1423) +- ColorEdit4(): Support drag and drop. Color buttons can be used as drag sources, and ColorEdit widgets as drag targets. (#143) +- ColorPicker4(): Fixed continuously returning true when holding mouse button on the sat/value/alpha locations. We only return true on value change. (#1489) +- NewFrame(): using literal strings in the most-frequently firing IM_ASSERT expressions to increase the odd of programmers seeing them (especially those who don't use a debugger). +- NewFrame() now asserts if neither Render or EndFrame have been called. Exposed EndFrame(). Made it legal to call EndFrame() more than one. (#1423) - ImGuiStorage: Added BuildSortByKey() helper to rebuild storage from scratch. - ImFont: Added GetDebugName() helper. - ImFontAtlas: Added missing Thai punctuation in the GetGlyphRangesThai() ranges. (#1396) [@nProtect] - ImDrawList: Removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Anti-aliasing is controlled via the regular style.AntiAliased flags. - ImDrawList: Added ImDrawList::AddImageRounded() helper. (#845) [@thedmd] - ImDrawList: Refactored to make ImDrawList independent of ImGui. Removed static variable in PathArcToFast() which caused linking issues to some. -- ImDrawList: Exposed ImDrawCornerFlags, replaced occurrences of ~0 with an explicit ImDrawCornerFlags_All. - NB: Inversed BotLeft (prev 1<<3, now 1<<2) and BotRight (prev 1<<2, now 1<<3). +- ImDrawList: Exposed ImDrawCornerFlags, replaced occurrences of ~0 with an explicit ImDrawCornerFlags_All. NB: Inversed BotLeft (prev 1<<3, now 1<<2) and BotRight (prev 1<<2, now 1<<3). - ImVector: Added ImVector::push_front() helper. - ImVector: Added ImVector::contains() helper. - ImVector: insert() uses grow_capacity() instead of using grow policy inconsistent with push_back(). - Internals: Remove requirement to define IMGUI_DEFINE_PLACEMENT_NEW to use the IM_PLACEMENT_NEW macro. (#1103) -- Internals: ButtonBehavior: Fixed ImGuiButtonFlags_NoHoldingActiveID flag from incorrectly - setting the ActiveIdClickOffset field. This had no known effect within imgui code but could have - affected custom drag and drop patterns. And it is more correct this way! (#1418) -- Internals: ButtonBehavior: Fixed ImGuiButtonFlags_AllowOverlapMode to avoid temporarily activating -widgets on click before they have been correctly double-hovered. (#319, #600) +- Internals: ButtonBehavior: Fixed ImGuiButtonFlags_NoHoldingActiveID flag from incorrectly setting the ActiveIdClickOffset field. + This had no known effect within imgui code but could have affected custom drag and drop patterns. And it is more correct this way! (#1418) +- Internals: ButtonBehavior: Fixed ImGuiButtonFlags_AllowOverlapMode to avoid temporarily activating widgets on click before they have been correctly double-hovered. (#319, #600) - Internals: Added SplitterBehavior() helper. (#319) - Internals: Added IM_NEW(), IM_DELETE() helpers. (#484, #504, #1517) - Internals: Basic refactor of the settings API which now allows external elements to be loaded/saved. @@ -5680,11 +4947,9 @@ widgets on click before they have been correctly double-hovered. (#319, #600) - Demo: Renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). - Demo: Style Editor: Added a "Simplified settings" sections with check-boxes for border size and frame rounding. (#707, #1019) - Demo: Style Editor: Added combo box to select stock styles and select current font when multiple are loaded. (#707) -- Demo: Style Editor: Using local storage so Save/Revert button makes more sense without code passing - its storage. Added horizontal scroll bar. Fixed Save/Revert button to be always accessible. (#1211) +- Demo: Style Editor: Using local storage so Save/Revert button makes more sense without code passing its storage. Added horizontal scroll bar. Fixed Save/Revert button to be always accessible. (#1211) - Demo: Console: Fixed context menu issue. (#1404) -- Demo: Console: Fixed incorrect positioning which was hidden by a minor scroll issue (this would - affect people who copied the Console code as is). +- Demo: Console: Fixed incorrect positioning which was hidden by a minor scroll issue (this would affect people who copied the Console code as is). - Demo: Constrained Resize: Added more test cases. (#1417) - Demo: Custom Rendering: Fixed clipping rectangle extruding out of parent window. - Demo: Layout: Removed unnecessary and misleading BeginChild/EndChild calls. @@ -5706,41 +4971,24 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: -- IO: `io.MousePos` needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing, - instead of ImVec2(-1,-1) as previously) This is needed so we can clear `io.MouseDelta` field when - the mouse is made available again. -- Renamed `AlignFirstTextHeightToWidgets()` to `AlignTextToFramePadding()`. - Kept inline redirection function (will obsolete). -- Obsoleted the legacy 5 parameters version of Begin(). Please avoid using it. If you need a - transparent window background, uses `PushStyleColor()`. The old size parameter there was also - misleading and equivalent to calling `SetNextWindowSize(size, ImGuiCond_FirstTimeEver)`. - Kept inline redirection function (will obsolete). -- Obsoleted `IsItemHoveredRect()`, `IsMouseHoveringWindow()` in favor of using the newly introduced - flags of `IsItemHovered()` and `IsWindowHovered()`. Kept inline redirection function (will obsolete). (#1382) -- Obsoleted 'SetNextWindowPosCenter()' in favor of using 1SetNextWindowPos()` with a pivot value which - allows to do the same and more. Keep inline redirection function. -- Removed `IsItemRectHovered()`, `IsWindowRectHovered()` recently introduced in 1.51 which were merely - the more consistent/correct names for the above functions which are now obsolete anyway. (#1382) -- Changed `IsWindowHovered()` default parameters behavior to return false if an item is active in - another window (e.g. click-dragging item from another window to this window). You can use the newly - introduced IsWindowHovered() flags to requests this specific behavior if you need it. (#1382) -- Renamed imconfig.h's `IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS`/`IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS` - to `IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS`/`IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS` for consistency. +- IO: `io.MousePos` needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing, instead of ImVec2(-1,-1) as previously) This is needed so we can clear `io.MouseDelta` field when the mouse is made available again. +- Renamed `AlignFirstTextHeightToWidgets()` to `AlignTextToFramePadding()`. Kept inline redirection function (will obsolete). +- Obsoleted the legacy 5 parameters version of Begin(). Please avoid using it. If you need a transparent window background, uses `PushStyleColor()`. The old size parameter there was also misleading and equivalent to calling `SetNextWindowSize(size, ImGuiCond_FirstTimeEver)`. Kept inline redirection function (will obsolete). +- Obsoleted `IsItemHoveredRect()`, `IsMouseHoveringWindow()` in favor of using the newly introduced flags of `IsItemHovered()` and `IsWindowHovered()`. Kept inline redirection function (will obsolete). (#1382) +- Obsoleted 'SetNextWindowPosCenter()' in favor of using 1SetNextWindowPos()` with a pivot value which allows to do the same and more. Keep inline redirection function. +- Removed `IsItemRectHovered()`, `IsWindowRectHovered()` recently introduced in 1.51 which were merely the more consistent/correct names for the above functions which are now obsolete anyway. (#1382) +- Changed `IsWindowHovered()` default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it. (#1382) +- Renamed imconfig.h's `IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS`/`IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS` to `IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS`/`IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS` for consistency. - Renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete). Other Changes: - ProgressBar: fixed rendering when straddling rounded area. (#1296) -- SliderFloat, DragFloat: Using scientific notation e.g. "%.1e" in the displayed format string doesn't - mistakenly trigger rounding of the value. [@MomentsInGraphics] -- Combo, InputFloat, InputInt: Made the small button on the right side align properly with the - equivalent colored button of ColorEdit4(). -- IO: Tweaked logic for `io.WantCaptureMouse` so it now outputs false when e.g. hovering over void - while an InputText() is active. (#621) [@pdoane] -- IO: Fixed `io.WantTextInput` from mistakenly outputting true when an activated Drag or Slider was - previously turned into an InputText(). (#1317) -- Misc: Added flags to `IsItemHovered()`, `IsWindowHovered()` to access advanced hovering-test behavior. - Generally useful for pop-ups and drag and drop behaviors: (relates to ~#439, #1013, #143, #925) +- SliderFloat, DragFloat: Using scientific notation e.g. "%.1e" in the displayed format string doesn't mistakenly trigger rounding of the value. [@MomentsInGraphics] +- Combo, InputFloat, InputInt: Made the small button on the right side align properly with the equivalent colored button of ColorEdit4(). +- IO: Tweaked logic for `io.WantCaptureMouse` so it now outputs false when e.g. hovering over void while an InputText() is active. (#621) [@pdoane] +- IO: Fixed `io.WantTextInput` from mistakenly outputting true when an activated Drag or Slider was previously turned into an InputText(). (#1317) +- Misc: Added flags to `IsItemHovered()`, `IsWindowHovered()` to access advanced hovering-test behavior. Generally useful for pop-ups and drag and drop behaviors: (relates to ~#439, #1013, #143, #925) - `ImGuiHoveredFlags_AllowWhenBlockedByPopup` - `ImGuiHoveredFlags_AllowWhenBlockedByActiveItem` - `ImGuiHoveredFlags_AllowWhenOverlapped` @@ -5751,80 +4999,54 @@ Other Changes: - CheckBox: Now rendering a tick mark instead of a full square. - ColorEdit4: Added "Copy as..." option in context menu. (#346) - ColorPicker: Improved ColorPicker hue wheel color interpolation. (#1313) [@thevaber] -- ColorButton: Reduced bordering artifact that would be particularly visible with an opaque - Col_FrameBg and FrameRounding enabled. -- ColorButton: Fixed rendering color button with a checkerboard if the transparency comes from the global - style.Alpha and not from the actual source color. -- TreeNode: Added `ImGuiTreeNodeFlags_FramePadding` flag to conveniently create a tree node with full - padding at the beginning of a line, without having to call `AlignTextToFramePadding()`. +- ColorButton: Reduced bordering artifact that would be particularly visible with an opaque Col_FrameBg and FrameRounding enabled. +- ColorButton: Fixed rendering color button with a checkerboard if the transparency comes from the global style.Alpha and not from the actual source color. +- TreeNode: Added `ImGuiTreeNodeFlags_FramePadding` flag to conveniently create a tree node with full padding at the beginning of a line, without having to call `AlignTextToFramePadding()`. - Trees: Fixed calling `SetNextTreeNodeOpen()` on a collapsed window leaking to the first tree node item of the next frame. -- Layout: Horizontal layout is automatically enforced in a menu bar, so you can use non-MenuItem elements - without calling SameLine(). -- Separator: Output a vertical separator when used inside a menu bar (or in general when horizontal layout - is active, but that isn't exposed yet!). +- Layout: Horizontal layout is automatically enforced in a menu bar, so you can use non-MenuItem elements without calling SameLine(). +- Separator: Output a vertical separator when used inside a menu bar (or in general when horizontal layout is active, but that isn't exposed yet!). - Window: Added `IsWindowAppearing()` helper (helpful e.g. as a condition before initializing some of your own things.). - Window: Added pivot parameter to `SetNextWindowPos()`, making it possible to center or right align a window. Obsoleted `SetNextWindowPosCenter()`. - Window: Fixed title bar color of top-most window under a modal window. - Window: Fixed not being able to move a window by clicking on one of its child window. (#1337, #635) -- Window: Fixed `Begin()` auto-fit calculation code that predict the presence of a scrollbar so it works - better when window size constraints are used. -- Window: Fixed calling `Begin()` more than once per frame setting `window_just_activated_by_user` which - in turn would set enable the Appearing condition for that frame. -- Window: The implicit "Debug" window now uses a "Debug##Default" identifier instead of "Debug" to allow - user creating a window called "Debug" without losing their custom flags. -- Window: Made the `ImGuiWindowFlags_NoMove` flag properly inherited from parent to child. In a setup - with ParentWindow (no flag) -> Child (NoMove) -> SubChild (no flag), the user won't be able to move - the parent window by clicking on SubChild. (#1381) +- Window: Fixed `Begin()` auto-fit calculation code that predict the presence of a scrollbar so it works better when window size constraints are used. +- Window: Fixed calling `Begin()` more than once per frame setting `window_just_activated_by_user` which in turn would set enable the Appearing condition for that frame. +- Window: The implicit "Debug" window now uses a "Debug##Default" identifier instead of "Debug" to allow user creating a window called "Debug" without losing their custom flags. +- Window: Made the `ImGuiWindowFlags_NoMove` flag properly inherited from parent to child. In a setup with ParentWindow (no flag) -> Child (NoMove) -> SubChild (no flag), the user won't be able to move the parent window by clicking on SubChild. (#1381) - Popups: Pop-ups can be closed with a right-click anywhere, without altering focus under the pop-up. (~#439) -- Popups: `BeginPopupContextItem()`, `BeginPopupContextWindow()` are now setup to allow reopening - a context menu by right-clicking again. (~#439) +- Popups: `BeginPopupContextItem()`, `BeginPopupContextWindow()` are now setup to allow reopening a context menu by right-clicking again. (~#439) - Popups: `BeginPopupContextItem()` now supports a NULL string identifier and uses the last item ID if available. - Popups: Added `OpenPopupOnItemClick()` helper which mimic `BeginPopupContextItem()` but doesn't do the BeginPopup(). - MenuItem: Only activating on mouse release. [@Urmeli0815] (was already fixed in nav branch). - MenuItem: Made tick mark thicker (thick mark?). -- MenuItem: Tweaks to be usable inside a menu bar (nb: it looks like a regular menu and thus is misleading, - prefer using Button() and regular widgets in menu bar if you need to). (#1387) +- MenuItem: Tweaks to be usable inside a menu bar (nb: it looks like a regular menu and thus is misleading, prefer using Button() and regular widgets in menu bar if you need to). (#1387) - ImDrawList: Fixed a rare draw call merging bug which could lead to undisplayed triangles. (#1172, #1368) -- ImDrawList: Fixed a rare bug in `ChannelsMerge()` when all contents has been clipped, leading to - an extraneous draw call being created. (#1172, #1368) +- ImDrawList: Fixed a rare bug in `ChannelsMerge()` when all contents has been clipped, leading to an extraneous draw call being created. (#1172, #1368) - ImFont: Added `AddGlyph()` building helper for use by custom atlas builders. -- ImFontAtlas: Added support for CustomRect API to submit custom rectangles to be packed into the atlas. - You can map them as font glyphs, or use them for custom purposes. - After the atlas is built you can query the position of your rectangles in the texture and then copy - your data there. You can use this features to create e.g. full color font-mapped icons. -- ImFontAtlas: Fixed fall-back handling when merging fonts, if a glyph was missing from the second font - input it could have used a glyph from the first one. (#1349) [@inolen] -- ImFontAtlas: Fixed memory leak on build failure case when stbtt_InitFont failed (generally due to - incorrect or supported font type). (#1391) (@Moka42) -- ImFontConfig: Added `RasterizerMultiply` option to alter the brightness of individual fonts at - rasterization time, which may help increasing readability for some. -- ImFontConfig: Added `RasterizerFlags` to pass options to custom rasterizer (e.g. the - [imgui_freetype](https://github.com/ocornut/imgui_club/tree/master/imgui_freetype) rasterizer in imgui_club has such options). +- ImFontAtlas: Added support for CustomRect API to submit custom rectangles to be packed into the atlas. You can map them as font glyphs, or use them for custom purposes. + After the atlas is built you can query the position of your rectangles in the texture and then copy your data there. You can use this features to create e.g. full color font-mapped icons. +- ImFontAtlas: Fixed fall-back handling when merging fonts, if a glyph was missing from the second font input it could have used a glyph from the first one. (#1349) [@inolen] +- ImFontAtlas: Fixed memory leak on build failure case when stbtt_InitFont failed (generally due to incorrect or supported font type). (#1391) (@Moka42) +- ImFontConfig: Added `RasterizerMultiply` option to alter the brightness of individual fonts at rasterization time, which may help increasing readability for some. +- ImFontConfig: Added `RasterizerFlags` to pass options to custom rasterizer (e.g. the [imgui_freetype](https://github.com/ocornut/imgui_club/tree/master/imgui_freetype) rasterizer in imgui_club has such options). - ImVector: added resize() variant with initialization value. -- Misc: Changed the internal name formatting of child windows identifier to use slashes - (instead of dots) as separator, more readable. +- Misc: Changed the internal name formatting of child windows identifier to use slashes (instead of dots) as separator, more readable. - Misc: Fixed compilation with `IMGUI_DISABLE_OBSOLETE_FUNCTIONS` defined. - Misc: Marked all format+va_list functions with format attribute so GCC/Clang can warn about misuses. - Misc: Fixed compilation on NetBSD due to missing alloca.h (#1319) [@RyuKojiro] - Misc: Improved warnings compilation for newer versions of Clang. (#1324) (@waywardmonkeys) -- Misc: Added `io.WantMoveMouse flags` (from Nav branch) and honored in Examples applications. - Currently unused but trying to spread Examples applications code that supports it. -- Misc: Added `IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS` support in imconfig.h to allow user - reimplementing the `ImFormatString()` functions e.g. to use stb_printf(). (#1038) -- Misc: [Windows] Fixed default Win32 `SetClipboardText()` handler leaving the Win32 clipboard - handler unclosed on failure. [@pdoane] -- Style: Added `ImGuiStyle::ScaleAllSizes(float)` helper to make it easier to have application - transition e.g. from low to high DPI with a matching style. +- Misc: Added `io.WantMoveMouse flags` (from Nav branch) and honored in Examples applications. Currently unused but trying to spread Examples applications code that supports it. +- Misc: Added `IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS` support in imconfig.h to allow user reimplementing the `ImFormatString()` functions e.g. to use stb_printf(). (#1038) +- Misc: [Windows] Fixed default Win32 `SetClipboardText()` handler leaving the Win32 clipboard handler unclosed on failure. [@pdoane] +- Style: Added `ImGuiStyle::ScaleAllSizes(float)` helper to make it easier to have application transition e.g. from low to high DPI with a matching style. - Metrics: Draw window bounding boxes when hovering Pos/Size; List all draw layers; Trimming empty commands like Render() does. - Examples: OpenGL3: Save and restore sampler state. (#1145) [@nlguillemot] - Examples: OpenGL2, OpenGL3: Save and restore polygon mode. (#1307) [@JJscott] - Examples: DirectX11: Allow creating device with feature level 10 since we don't really need much for that example. (#1333) -- Examples: DirectX9/10/12: Using the Win32 SetCapture/ReleaseCapture API to read mouse coordinates - when they are out of bounds. (#1375) [@Gargaj, @ocornut] +- Examples: DirectX9/10/12: Using the Win32 SetCapture/ReleaseCapture API to read mouse coordinates when they are out of bounds. (#1375) [@Gargaj, @ocornut] - Tools: Fixed binary_to_compressed_c tool to return 0 when successful. (#1350) [@benvanik] - Internals: Exposed more helpers and unfinished features in imgui_internal.h. (use at your own risk!). -- Internals: A bunch of internal refactoring, hopefully haven't broken anything! - Merged a bunch of internal changes from the upcoming Navigation branch. +- Internals: A bunch of internal refactoring, hopefully haven't broken anything! Merged a bunch of internal changes from the upcoming Navigation branch. - Various tweaks, fixes and documentation changes. Beta Navigation Branch: @@ -5833,16 +5055,12 @@ Beta Navigation Branch: - Nav: Added `#define IMGUI_HAS_NAV` in imgui.h to ease sharing code between both branches. (#787) - Nav: MainMenuBar now releases focus when user gets out of the menu layer. (#787) - Nav: When applying focus to a window with only menus, the menu layer is automatically activated. (#787) -- Nav: Added `ImGuiNavInput_KeyMenu` (~Alt key) aside from ImGuiNavInput_PadMenu input as it is - one differentiator of pad vs keyboard that was detrimental to the keyboard experience. - Although isn't officially supported, it makes the current experience better. (#787) +- Nav: Added `ImGuiNavInput_KeyMenu` (~Alt key) aside from ImGuiNavInput_PadMenu input as it is one differentiator of pad vs keyboard that was detrimental to the keyboard experience. Although isn't officially supported, it makes the current experience better. (#787) - Nav: Move requests now wrap vertically inside Menus and Pop-ups. (#787) - Nav: Allow to collapse tree nodes with NavLeft and open them with NavRight. (#787, #1079). -- Nav: It's now possible to navigate sibling of a menu-bar while navigating inside one of their child. - If a Left<>Right navigation request fails to find a match we forward the request to the root menu. (#787, #126) +- Nav: It's now possible to navigate sibling of a menu-bar while navigating inside one of their child. If a Left<>Right navigation request fails to find a match we forward the request to the root menu. (#787, #126) - Nav: Fixed `SetItemDefaultFocus` from stealing default focus when we are initializing default focus for a menu bar layer. (#787) -- Nav: Support for fall-back horizontal scrolling with PadLeft/PadRight (nb: fall-back scrolling - is only used to navigate windows that have no interactive items). (#787) +- Nav: Support for fall-back horizontal scrolling with PadLeft/PadRight (nb: fall-back scrolling is only used to navigate windows that have no interactive items). (#787) - Nav: Fixed tool-tip from being selectable in the window selection list. (#787) - Nav: `CollapsingHeader(bool*)` variant: fixed for `IsItemHovered()` not working properly in the nav branch. (#600, #787) - Nav: InputText: Fixed using Up/Down history callback feature when Nav is enabled. (#787) @@ -5859,14 +5077,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: -Work on dear imgui has been gradually resuming. It means that fixes and new features should be tackled at -a faster rate than last year. However, in order to move forward with the library and get rid of some cruft, -I have taken the liberty to be a little bit more aggressive than usual with API breaking changes. -Read the details below and search for those names in your code! In the grand scheme of things, -those changes are small and should not affect everyone, but this is technically our most aggressive -release so far in term of API breakage. -If you want to be extra forward-facing, you can enable `#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS` in -your imconfig.h to disable the obsolete names/redirection. +Work on dear imgui has been gradually resuming. It means that fixes and new features should be tackled at a faster rate than last year. However, in order to move forward with the library and get rid of some cruft, I have taken the liberty to be a little bit more aggressive than usual with API breaking changes. Read the details below and search for those names in your code! In the grand scheme of things, those changes are small and should not affect everyone, but this is technically our most aggressive release so far in term of API breakage. If you want to be extra forward-facing, you can enable `#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS` in your imconfig.h to disable the obsolete names/redirection. - Renamed `IsItemHoveredRect()` to `IsItemRectHovered()`. Kept inline redirection function (will obsolete). - Renamed `IsMouseHoveringWindow()` to `IsWindowRectHovered()` for consistency. Kept inline redirection function (will obsolete). @@ -5874,79 +5085,43 @@ your imconfig.h to disable the obsolete names/redirection. - Renamed `ImGuiCol_Columns***` enums to `ImGuiCol_Separator***`. Kept redirection enums (will obsolete). - Renamed `ImGuiSetCond***` types and enums to `ImGuiCond***`. Kept redirection enums (will obsolete). - Renamed `GetStyleColName()` to `GetStyleColorName()` for consistency. Unlikely to be used by end-user! -- Added `PushStyleColor(ImGuiCol idx, ImU32 col)` overload, which _might_ cause an "ambiguous call" - compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicitly to fix. +- Added `PushStyleColor(ImGuiCol idx, ImU32 col)` overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicitly to fix. - Marked the weird `IMGUI_ONCE_UPON_A_FRAME` helper macro as obsolete. Prefer using the more explicit `ImGuiOnceUponAFrame`. -- Changed `ColorEdit4(const char* label, float col[4], bool show_alpha = true)` signature to - `ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)`, where flags 0x01 is a safe no-op - (hello dodgy backward compatibility!). The new `ColorEdit4`/`ColorPicker4` functions have lots of available flags! - Check and run the demo window, under "Color/Picker Widgets", to understand the various new options. -- Changed signature of `ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)` - to `ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0))`. - This function was rarely used and was very dodgy (no explicit ID!). -- Changed `BeginPopupContextWindow(bool also_over_items=true, const char* str_id=NULL, int mouse_button=1)` - signature to `(const char* str_id=NULL, int mouse_button=1, bool also_over_items=true)`. - This is perhaps the most aggressive change in this update, but note that the majority of users relied - on default parameters completely, so this will affect only a fraction of users of this already rarely - used function. -- Removed `IsPosHoveringAnyWindow()`, which was partly broken and misleading. In the vast majority of cases, - people using that function wanted to use `io.WantCaptureMouse` flag. Replaced with IM_ASSERT + a comment - redirecting user to `io.WantCaptureMouse`. (#1237) +- Changed `ColorEdit4(const char* label, float col[4], bool show_alpha = true)` signature to `ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)`, where flags 0x01 is a safe no-op (hello dodgy backward compatibility!). The new `ColorEdit4`/`ColorPicker4` functions have lots of available flags! Check and run the demo window, under "Color/Picker Widgets", to understand the various new options. +- Changed signature of `ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)` to `ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0))`. This function was rarely used and was very dodgy (no explicit ID!). +- Changed `BeginPopupContextWindow(bool also_over_items=true, const char* str_id=NULL, int mouse_button=1)` signature to `(const char* str_id=NULL, int mouse_button=1, bool also_over_items=true)`. This is perhaps the most aggressive change in this update, but note that the majority of users relied on default parameters completely, so this will affect only a fraction of users of this already rarely used function. +- Removed `IsPosHoveringAnyWindow()`, which was partly broken and misleading. In the vast majority of cases, people using that function wanted to use `io.WantCaptureMouse` flag. Replaced with IM_ASSERT + comment redirecting user to `io.WantCaptureMouse`. (#1237) - Removed the old `ValueColor()` helpers, they are equivalent to calling `Text(label)` + `SameLine()` + `ColorButton()`. -- Removed `ColorEditMode()` and `ImGuiColorEditMode` type in favor of `ImGuiColorEditFlags` and - parameters to the various Color*() functions. The `SetColorEditOptions()` function allows to - initialize default but the user can still change them with right-click context menu. - Commenting out your old call to `ColorEditMode()` may just be fine! +- Removed `ColorEditMode()` and `ImGuiColorEditMode` type in favor of `ImGuiColorEditFlags` and parameters to the various Color*() functions. The `SetColorEditOptions()` function allows to initialize default but the user can still change them with right-click context menu. Commenting out your old call to `ColorEditMode()` may just be fine! Other Changes: -- Added flags to `ColorEdit3()`, `ColorEdit4()`. The color edit widget now has a context-menu - and access to the color picker. (#346) +- Added flags to `ColorEdit3()`, `ColorEdit4()`. The color edit widget now has a context-menu and access to the color picker. (#346) - Added flags to `ColorButton()`. (#346) -- Added `ColorPicker3()`, `ColorPicker4()`. (#346) [@r-lyeh, @nem0, @thennequin, @dariomanesku and @ocornut] - The API along with those of the updated `ColorEdit4()` was designed so you may use them in various - situation and hopefully compose your own picker if required. There are a bunch of available flags, - check the Demo window and comment for `ImGuiColorEditFlags_`. - Some of the options it supports are: two color picker types (hue bar + sat/val rectangle, - hue wheel + rotating sat/val triangle), display as u8 or float, lifting 0.0..1.0 constraints - (currently rgba only), context menus, alpha bar, background checkerboard options, preview tooltip, - basic revert. For simple use, calling the existing `ColorEdit4()` function as you did before - will be enough, as you can now open the color picker from there. -- Added `SetColorEditOptions()` to set default color options (e.g. if you want HSV over RGBA, - float over u8, select a default picker mode etc. at startup time without a user intervention. - Note that the user can still change options with the context menu unless disabled with - `ImGuiColorFlags_NoOptions` or explicitly enforcing a display type/picker mode etc.). +- Added `ColorPicker3()`, `ColorPicker4()`. The API along with those of the updated `ColorEdit4()` was designed so you may use them in various situation and hopefully compose your own picker if required. There are a bunch of available flags, check the Demo window and comment for `ImGuiColorEditFlags_`. Some of the options it supports are: two color picker types (hue bar + sat/val rectangle, hue wheel + rotating sat/val triangle), display as u8 or float, lifting 0.0..1.0 constraints (currently rgba only), context menus, alpha bar, background checkerboard options, preview tooltip, basic revert. For simple use, calling the existing `ColorEdit4()` function as you did before will be enough, as you can now open the color picker from there. (#346) [@r-lyeh, @nem0, @thennequin, @dariomanesku and @ocornut] +- Added `SetColorEditOptions()` to set default color options (e.g. if you want HSV over RGBA, float over u8, select a default picker mode etc. at startup time without a user intervention. Note that the user can still change options with the context menu unless disabled with `ImGuiColorFlags_NoOptions` or explicitly enforcing a display type/picker mode etc.). - Added user-facing `IsPopupOpen()` function. (#891) [@mkeeter] -- Added `GetColorU32(u32)` variant that perform the style alpha multiply without a floating-point - round trip, and helps makes code more consistent when using ImDrawList APIs. +- Added `GetColorU32(u32)` variant that perform the style alpha multiply without a floating-point round trip, and helps makes code more consistent when using ImDrawList APIs. - Added `PushStyleColor(ImGuiCol idx, ImU32 col)` overload. -- Added `GetStyleColorVec4(ImGuiCol idx)` which is equivalent to accessing `ImGui::GetStyle().Colors[idx]` - (aka return the raw style color without alpha alteration). -- ImFontAtlas: Added `GlyphRangesBuilder` helper class, which makes it easier to build custom glyph ranges - from your app/game localization data, or add into existing glyph ranges. +- Added `GetStyleColorVec4(ImGuiCol idx)` which is equivalent to accessing `ImGui::GetStyle().Colors[idx]` (aka return the raw style color without alpha alteration). +- ImFontAtlas: Added `GlyphRangesBuilder` helper class, which makes it easier to build custom glyph ranges from your app/game localization data, or add into existing glyph ranges. - ImFontAtlas: Added `TexGlyphPadding` option. (#1282) [@jadwallis] - ImFontAtlas: Made it possible to override size of AddFontDefault() (even if it isn't really recommended!). - ImDrawList: Added `GetClipRectMin()`, `GetClipRectMax()` helpers. - Fixed Ini saving crash if the ImGuiWindowFlags_NoSavedSettings gets removed from a window after its creation (unlikely!). (#1000) -- Fixed `PushID()`/`PopID()` from marking parent window as Accessed (which needlessly woke up the - root "Debug" window when used outside of a regular window). (#747) +- Fixed `PushID()`/`PopID()` from marking parent window as Accessed (which needlessly woke up the root "Debug" window when used outside of a regular window). (#747) - Fixed an assert when calling `CloseCurrentPopup()` twice in a row. [@nem0] - Window size can be loaded from .ini data even if ImGuiWindowFlags_NoResize flag is set. (#1048, #1056) - Columns: Added `SetColumnWidth()`. (#913) [@ggtucker] - Columns: Dragging a column preserve its width by default. (#913) [@ggtucker] - Columns: Fixed first column appearing wider than others. (#1266) -- Columns: Fixed allocating space on the right-most side with the assumption of a vertical scrollbar. - The space is only allocated when needed. (#125, #913, #893, #1138) -- Columns: Fixed the right-most column from registering its content width to the parent window, - which led to various issues when using auto-resizing window or e.g. horizontal scrolling. (#519, #125, #913) +- Columns: Fixed allocating space on the right-most side with the assumption of a vertical scrollbar. The space is only allocated when needed. (#125, #913, #893, #1138) +- Columns: Fixed the right-most column from registering its content width to the parent window, which led to various issues when using auto-resizing window or e.g. horizontal scrolling. (#519, #125, #913) - Columns: Refactored some of the columns code internally toward a better API (not yet exposed) + minor optimizations. (#913) [@ggtucker, @ocornut] -- Popups: Most pop-ups windows can be moved by the user after appearing (if they don't have explicit - positions provided by caller, or e.g. sub-menu pop-up). The previous restriction was totally arbitrary. (#1252) -- Tooltip: `SetTooltip()` is expanded immediately into a window, honoring current font / styling setting. - Add internal mechanism to override tooltips. (#862) +- Popups: Most pop-ups windows can be moved by the user after appearing (if they don't have explicit positions provided by caller, or e.g. sub-menu pop-up). The previous restriction was totally arbitrary. (#1252) +- Tooltip: `SetTooltip()` is expanded immediately into a window, honoring current font / styling setting. Add internal mechanism to override tooltips. (#862) - PlotHistogram: bars are drawn based on zero-line, so negative values are going under. (#828) -- Scrolling: Fixed return values of `GetScrollMaxX()`, `GetScrollMaxY()` when both scrollbars were enabled. - Tweak demo to display more data. (#1271) [@degracode] +- Scrolling: Fixed return values of `GetScrollMaxX()`, `GetScrollMaxY()` when both scrollbars were enabled. Tweak demo to display more data. (#1271) [@degracode] - Scrolling: Fixes for Vertical Scrollbar not automatically getting enabled if enabled Horizontal Scrollbar straddle the vertical limit. (#1271, #246) - Scrolling: `SetScrollHere()`, `SetScrollFromPosY()`: Fixed Y scroll aiming when Horizontal Scrollbar is enabled. (#665). - [Windows] Clipboard: Fixed not closing Win32 clipboard on early open failure path. (#1264) @@ -5954,8 +5129,7 @@ Other Changes: - Demo: Rearranged everything under Widgets in a more consistent way. - Demo: Columns: Added Horizontal Scrolling demo. Tweaked another Columns demo. (#519, #125, #913) - Examples: OpenGL: Various makefiles for MINGW, Linux. (#1209, #1229, #1209) [@fr500, @acda] -- Examples: Enabled vsync by default in example applications, so it doesn't confuse people that - the sample run at 2000+ fps and waste an entire CPU. (#1213, #1151). +- Examples: Enabled vsync by default in example applications, so it doesn't confuse people that the sample run at 2000+ fps and waste an entire CPU. (#1213, #1151). - Various other small fixes, tweaks, comments, optimizations. @@ -5968,16 +5142,11 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: - Added a void* user_data parameter to Clipboard function handlers. (#875) -- SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. - This was sort of always the intent and hopefully breakage should be minimal. +- SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. - Renamed ImDrawList::PathFill() - rarely used directly - to ImDrawList::PathFillConvex() for clarity and consistency. - Removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. -- Style: style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) - for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. -- BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions - as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple - times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() - and use it instead of passing string to BeginChild(). +- Style: style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. +- BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild(). Other Changes: @@ -5987,8 +5156,7 @@ Other Changes: - InputText(): Fixed pressing home key on last character when it isn't a trailing \n (#588, #815) - InputText(): Fixed state corruption/crash bug in stb_textedit.h redo logic when exhausting undo/redo char buffer. (#715. #681) - InputTextMultiline(): Fixed CTRL+DownArrow moving scrolling out of bounds. -- InputTextMultiline(): Scrollbar fix for when input and latched internal buffers differs in - a way that affects vertical scrollbar existence. (#725) +- InputTextMultiline(): Scrollbar fix for when input and latched internal buffers differs in a way that affects vertical scrollbar existence. (#725) - ImFormatString(): Fixed an overflow handling bug with implementation of vsnprintf() that do not return -1. (#793) - BeginChild(const char*) now applies stack id to provided label, consistent with other widgets. (#894, #713) - SameLine() with explicit X position is relative to left of group/columns. (ref #746, #125, #630) @@ -6007,8 +5175,7 @@ Other Changes: - Fixed PlotLines() PlotHistogram() calling with values_count == 0. - Fixed clicking on a window's void while staying still overzealously marking .ini settings as dirty. (#923) - Fixed assert triggering when a window has zero rendering but has a callback. (#810) -- Scrollbar: Fixed rendering when sizes are negative to reduce glitches (which can happen with - certain style settings and zero WindowMinSize). +- Scrollbar: Fixed rendering when sizes are negative to reduce glitches (which can happen with certain style settings and zero WindowMinSize). - EndGroup(): Made IsItemHovered() work when an item was activated within the group. (#849) - BulletText(): Fixed stopping to display formatted string after the '##' mark. - Closing the focused window restore focus to the first active root window in descending z-order .(part of #727) @@ -6018,8 +5185,7 @@ Other Changes: - ImGuiListClipper: Fixed automatic-height calc path dumbly having user display element 0 twice. (#661, #716) - ImGuiListClipper: Fix to behave within column. (#661, #662, #716) - ImDrawList: Renamed ImDrawList::PathFill() to ImDrawList::PathFillConvex() for clarity. (BREAKING API) -- Columns: End() avoid calling Columns(1) if no columns set is open, not sure why it wasn't the - case already (pros: faster, cons: exercise less code). +- Columns: End() avoid calling Columns(1) if no columns set is open, not sure why it wasn't the case already (pros: faster, cons: exercise less code). - ColorButton(): Fix ColorButton showing wrong hex value for alpha. (#1068) [@codecat] - ColorEdit4(): better preserve inputting value out of 0..255 range, display then clamped in Hexadecimal form. - Shutdown() clear out some remaining pointers for sanity. (#836) @@ -6030,8 +5196,7 @@ Other Changes: - ImFont: Added GetGlyphRangesThai() helper. [@nProtect] - ImFont: CalcWordWrapPositionA() fixed font scaling with fallback character. - ImFont: Calculate and store the approximate texture surface to get an idea of how costly each source font is. -- ImFontConfig: Added GlyphOffset to explicitly offset glyphs at font build time, useful for merged fonts. - Removed MergeGlyphCenterV. (BREAKING API) +- ImFontConfig: Added GlyphOffset to explicitly offset glyphs at font build time, useful for merged fonts. Removed MergeGlyphCenterV. (BREAKING API) - Clarified asserts in CheckStacksSize() when there is a stack mismatch. - Context: Support for #define-ing GImGui and IMGUI_SET_CURRENT_CONTEXT_FUNC to enable custom thread-based hackery (#586) - Updated stb_truetype.h to 1.14 (added OTF support, removed warnings). (#883, #976) @@ -6053,8 +5218,7 @@ Other Changes: - Examples: OpenGL*: Saving/restoring active texture number (the value modified by glActiveTexture). (#1087, #1088, #1116) - Examples: OpenGL*: Saving/restoring separate color/alpha blend functions correctly. (#1120) [@greggman] - Examples: OpenGL2: Uploading font texture as RGBA32 to increase compatibility with users shaders for beginners. (#824) -- Examples: Vulkan: Countless fixes and improvements. (#785, #804, #910, #1017, #1039, #1041, - #1042, #1043, #1080) [@martty, @Loftilus, @ParticlePeter, @SaschaWillems] +- Examples: Vulkan: Countless fixes and improvements. (#785, #804, #910, #1017, #1039, #1041, #1042, #1043, #1080) [@martty, @Loftilus, @ParticlePeter, @SaschaWillems] - Examples: DirectX9/10/10: Only call SetCursor(NULL) is io.MouseDrawCursor is set. (#585, #909) - Examples: DirectX9: Explicitly setting viewport to match that other examples are doing. (#937) - Examples: GLFW+OpenGL3: Fixed Shutdown() calling GL functions with NULL parameters if NewFrame was never called. (#800) @@ -6074,22 +5238,11 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: - Renamed `SetNextTreeNodeOpened()` to `SetNextTreeNodeOpen()` for consistency, no redirection. -- Removed confusing set of `GetInternalState()`, `GetInternalStateSize()`, `SetInternalState()` functions. - Now using `CreateContext()`, `DestroyContext()`, `GetCurrentContext()`, `SetCurrentContext()`. - If you were using multiple contexts the change should be obvious and trivial. -- Obsoleted old signature of `CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false)`, - as extra parameters were badly designed and rarely used. Most uses were using 1 parameter and shouldn't affect you. - You can replace the "default_open = true" flag in new API with `CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen)`. -- Changed `ImDrawList::PushClipRect(ImVec4 rect)` to `ImDraw::PushClipRect(ImVec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false)`. - Note that higher-level `ImGui::PushClipRect()` is preferable because it will clip at logic/widget level, whereas `ImDrawList::PushClipRect()` only affect your renderer. -- Title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background - (ImGuiCol_WindowBg color) anymore (see #655). If your TitleBg/TitleBgActive alpha was 1.0f or you are using - the default theme it will not affect you. However if your TitleBg/TitleBgActive alpha was <1.0f you need to - tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. - This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, - given the OLD color and the OLD WindowBg color. (Or If this is confusing, just pick the RGB value from - title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create - TitleBgActive from a tweaked TitleBg color.) +- Removed confusing set of `GetInternalState()`, `GetInternalStateSize()`, `SetInternalState()` functions. Now using `CreateContext()`, `DestroyContext()`, `GetCurrentContext()`, `SetCurrentContext()`. If you were using multiple contexts the change should be obvious and trivial. +- Obsoleted old signature of `CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false)`, as extra parameters were badly designed and rarely used. Most uses were using 1 parameter and shouldn't affect you. You can replace the "default_open = true" flag in new API with `CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen)`. +- Changed `ImDrawList::PushClipRect(ImVec4 rect)` to `ImDraw::PushClipRect(ImVec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false)`. Note that higher-level `ImGui::PushClipRect()` is preferable because it will clip at logic/widget level, whereas `ImDrawList::PushClipRect()` only affect your renderer. +- Title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore (see #655). If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. However if your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. + This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color. (Or If this is confusing, just pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color.) ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { @@ -6100,11 +5253,9 @@ Breaking Changes: Other changes: -- New version of ImGuiListClipper helper calculates item height automatically. - See comments and demo code. (#662, #661, #660) +- New version of ImGuiListClipper helper calculates item height automatically. See comments and demo code. (#662, #661, #660) - Added SetNextWindowSizeConstraints() to enable basic min/max and programmatic size constraints on window. Added demo. (#668) -- Added PushClipRect()/PopClipRect() (previously part of imgui_internal.h). - Changed ImDrawList::PushClipRect() prototype. (#610) +- Added PushClipRect()/PopClipRect() (previously part of imgui_internal.h). Changed ImDrawList::PushClipRect() prototype. (#610) - Added IsRootWindowOrAnyChildHovered() helper. (#615) - Added TreeNodeEx() functions. (#581, #600, #190) - Added ImGuiTreeNodeFlags_Selected flag to display TreeNode as "selected". (#581, #190) @@ -6114,38 +5265,31 @@ Other changes: - Added ImGuiTreeNodeFlags_DefaultOpen flag (previously private). - Added ImGuiTreeNodeFlags_OpenOnDoubleClick flag. - Added ImGuiTreeNodeFlags_OpenOnArrow flag. -- Added ImGuiTreeNodeFlags_Leaf flag, always opened, no arrow, for convenience. - For simple use case prefer using TreeAdvanceToLabelPos()+Text(). +- Added ImGuiTreeNodeFlags_Leaf flag, always opened, no arrow, for convenience. For simple use case prefer using TreeAdvanceToLabelPos()+Text(). - Added ImGuiTreeNodeFlags_Bullet flag, to add a bullet to Leaf node or replace Arrow with a bullet. - Added TreeAdvanceToLabelPos(), GetTreeNodeToLabelSpacing() helpers. (#581, #324) -- Added CreateContext()/DestroyContext()/GetCurrentContext()/SetCurrentContext(). - Obsoleted nearly identical GetInternalState()/SetInternalState() functions. (#586, #269) +- Added CreateContext()/DestroyContext()/GetCurrentContext()/SetCurrentContext(). Obsoleted nearly identical GetInternalState()/SetInternalState() functions. (#586, #269) - Added NewLine() to undo a SameLine() and as a shy reminder that horizontal layout support hasn't been implemented yet. - Added IsItemClicked() helper. (#581) - Added CollapsingHeader() variant with close button. (#600) - Fixed MenuBar missing lower border when borders are enabled. - InputText(): Fixed clipping of cursor rendering in case it gets out of the box (which can be forced w/ ImGuiInputTextFlags_NoHorizontalScroll. (#601) - Style: Changed default IndentSpacing from 22 to 21. (#581, #324) -- Style: Fixed TitleBg/TitleBgActive color being rendered above WindowBg color, which was - inconsistent and causing visual artifact. (#655) - This broke the meaning of TitleBg and TitleBgActive. Only affect values where Alpha<1.0f. - Fixed default theme. Read comments in "API BREAKING CHANGES" section to convert. +- Style: Fixed TitleBg/TitleBgActive color being rendered above WindowBg color, which was inconsistent and causing visual artifact. (#655) + This broke the meaning of TitleBg and TitleBgActive. Only affect values where Alpha<1.0f. Fixed default theme. Read comments in "API BREAKING CHANGES" section to convert. - Relative rendering of order of Child windows creation is preserved, to allow more control with overlapping children. (#595) - Fixed GetWindowContentRegionMax() being off by ScrollbarSize amount when explicit SizeContents is set. - Indent(), Unindent(): optional non-default indenting width. (#324, #581) - Bullet(), BulletText(): Slightly bigger. Less polygons. -- ButtonBehavior(): fixed subtle old bug when a repeating button would also return true on mouse - release (barely noticeable unless RepeatRate is set to be very slow). (#656) +- ButtonBehavior(): fixed subtle old bug when a repeating button would also return true on mouse release (barely noticeable unless RepeatRate is set to be very slow). (#656) - BeginMenu(): a menu that becomes disabled while open gets closed down, facilitate user's code. (#126) - BeginGroup(): fixed using within Columns set. (#630) - Fixed a lag in reading the currently hovered window when dragging a window. (#635) - Obsoleted 4 parameters version of CollapsingHeader(). Refactored code into TreeNodeBehavior. (#600, #579) - Scrollbar: minor fix for top-right rounding of scrollbar background when window has menu bar but no title bar. - MenuItem(): the check mark renders in disabled color when menu item is disabled. -- Fixed clipping rectangle floating point representation to ensure renderer-side floating-point - operations yield correct results in typical DirectX/GL settings. (#582, 597) -- Fixed GetFrontMostModalRootWindow(), fixing missing fade-out when a combo pop was used stacked - over a modal window. (#604) +- Fixed clipping rectangle floating point representation to ensure renderer-side float point operations yield correct results in typical DirectX/GL settings. (#582, 597) +- Fixed GetFrontMostModalRootWindow(), fixing missing fade-out when a combo pop was used stacked over a modal window. (#604) - ImDrawList: Added AddQuad(), AddQuadFilled() helpers. - ImDrawList: AddText() refactor, moving some code to ImFont, reserving less unused vertices when large vertical clipping occurs. - ImFont: Added RenderChar() helper. @@ -6156,8 +5300,7 @@ Other changes: - Renamed majority of use of the word "opened" to "open" for clarity. Renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(). (#625, #579) - Examples: OpenGL3: Saving/restoring glActiveTexture() state. (#602) - Examples: DirectX9: save/restore all device state. -- Examples: DirectX9: Removed dependency on d3dx9.h, d3dx9.lib, dxguid.lib so it can be used in - a DirectXMath.h only environment. (#611) +- Examples: DirectX9: Removed dependency on d3dx9.h, d3dx9.lib, dxguid.lib so it can be used in a DirectXMath.h only environment. (#611) - Examples: DirectX10/X11: Apply depth-stencil state (no use of depth buffer). (#640, #636) - Examples: DirectX11/X11: Added comments on removing dependency on D3DCompiler. (#638) - Examples: SDL: Initialize video+timer subsystem only. @@ -6172,53 +5315,33 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: -- Consistently honoring exact width passed to PushItemWidth() (when positive), previously it would - add extra FramePadding.x*2 over that width. Some hand-tuned layout may be affected slightly. (#346) -- Style: removed `style.WindowFillAlphaDefault` which was confusing and redundant, baked alpha into - `ImGuiCol_WindowBg` color. If you had a custom WindowBg color but didn't change WindowFillAlphaDefault, - multiply WindowBg alpha component by 0.7. Renamed `ImGuiCol_TooltipBg` to `ImGuiCol_PopupBG`, - applies to other types of pop-ups. `bg_alpha` parameter of 5-parameters version of Begin() is an override. (#337) -- InputText(): Added BufTextLen field in ImGuiTextEditCallbackData. Requesting user to update it - if the buffer is modified in the callback. Added a temporary length-check assert to minimize panic - for the 3 people using the callback. (#541) -- Renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). - Kept inline redirection function (will obsolete). (#340) +- Consistently honoring exact width passed to PushItemWidth() (when positive), previously it would add extra FramePadding.x*2 over that width. Some hand-tuned layout may be affected slightly. (#346) +- Style: removed `style.WindowFillAlphaDefault` which was confusing and redundant, baked alpha into `ImGuiCol_WindowBg` color. If you had a custom WindowBg color but didn't change WindowFillAlphaDefault, multiply WindowBg alpha component by 0.7. Renamed `ImGuiCol_TooltipBg` to `ImGuiCol_PopupBG`, applies to other types of pop-ups. `bg_alpha` parameter of 5-parameters version of Begin() is an override. (#337) +- InputText(): Added BufTextLen field in ImGuiTextEditCallbackData. Requesting user to update it if the buffer is modified in the callback. Added a temporary length-check assert to minimize panic for the 3 people using the callback. (#541) +- Renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). (#340) Other Changes: -- Consistently honoring exact width passed to PushItemWidth(), previously it would add extra - FramePadding.x*2 over that width. Some hand-tuned layout may be affected slightly. (#346) -- Fixed clipping of child windows within parent not taking account of child outer clipping - boundaries (including scrollbar, etc.). (#506) -- TextUnformatted(): Fixed rare crash bug with large blurb of text (2k+) not finished with - a '\n' and fully above the clipping Y line. (#535) +- Consistently honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. Some hand-tuned layout may be affected slightly. (#346) +- Fixed clipping of child windows within parent not taking account of child outer clipping boundaries (including scrollbar, etc.). (#506) +- TextUnformatted(): Fixed rare crash bug with large blurb of text (2k+) not finished with a '\n' and fully above the clipping Y line. (#535) - IO: Added 'KeySuper' field to hold CMD keyboard modifiers for OS X. Updated all examples accordingly. (#473) - Added ImGuiWindowFlags_ForceVerticalScrollbar, ImGuiWindowFlags_ForceHorizontalScrollbar flags. (#476) - Added IM_COL32 macros to generate a U32 packed color, convenient for direct use of ImDrawList api. (#346) - Added GetFontTexUvWhitePixel() helper, convenient for direct use of ImDrawList api. -- Selectable(): Added ImGuiSelectableFlags_AllowDoubleClick flag to allow user reacting - on double-click. (@zapolnov) (#516) +- Selectable(): Added ImGuiSelectableFlags_AllowDoubleClick flag to allow user reacting on double-click. (@zapolnov) (#516) - Begin(): made the close button explicitly set the boolean to false instead of toggling it. (#499) - BeginChild()/EndChild(): fixed incorrect layout to allow widgets submitted after an auto-fitted child window. (#540) -- BeginChild(): Added ImGuiWindowFlags_AlwaysUseWindowPadding flag to ensure non-bordered child window - uses window padding. (#462) -- Fixed InputTextMultiLine(), ListBox(), BeginChildFrame(), ProgressBar(): outer frame not - honoring bordering. (#462, #503) +- BeginChild(): Added ImGuiWindowFlags_AlwaysUseWindowPadding flag to ensure non-bordered child window uses window padding. (#462) +- Fixed InputTextMultiLine(), ListBox(), BeginChildFrame(), ProgressBar(): outer frame not honoring bordering. (#462, #503) - Fixed Image(), ImageButtion() rendering a rectangle 1 px too large on each axis. (#457) - SetItemAllowOverlap(): Promoted from imgui_internal.h to public imgui.h api. (#517) - Combo(): Right-most button stays highlighted when pop-up is open. - Combo(): Display pop-up above if there's isn't enough space below / or select largest side. (#505) -- DragFloat(), SliderFloat(), InputFloat(): fixed cases of erroneously returning true repeatedly - after a text input modification (e.g. "0.0" --> "0.000" would keep returning true). (#564) -- DragFloat(): Always apply value when mouse is held/widget active, so that an always-resetting - variable (e.g. non saved local) can be passed. -- InputText(): OS X friendly behaviors: (@zhiayang), (#473) - - Word movement uses ALT key; - - Shortcuts uses CMD key; - - Double-clicking text select a single word; - - Jumping to next word sets cursor to end of current word instead of beginning of current word. -- InputText(): Added BufTextLen in ImGuiTextEditCallbackData. Requesting user to maintain it - if buffer is modified. Zero-ing structure properly before use. (#541) +- DragFloat(), SliderFloat(), InputFloat(): fixed cases of erroneously returning true repeatedly after a text input modification (e.g. "0.0" --> "0.000" would keep returning true). (#564) +- DragFloat(): Always apply value when mouse is held/widget active, so that an always-resetting variable (e.g. non saved local) can be passed. +- InputText(): OS X friendly behaviors: Word movement uses ALT key; Shortcuts uses CMD key; Double-clicking text select a single word; Jumping to next word sets cursor to end of current word instead of beginning of current word. (@zhiayang), (#473) +- InputText(): Added BufTextLen in ImGuiTextEditCallbackData. Requesting user to maintain it if buffer is modified. Zero-ing structure properly before use. (#541) - CheckboxFlags(): Added support for testing/setting multiple flags at the same time. (@DMartinek) (#555) - TreeNode(), CollapsingHeader() fixed not being able to use "##" sequence in a formatted label. - ColorEdit4(): Empty label doesn't add InnerSpacing.x, matching behavior of other widgets. (#346) @@ -6244,13 +5367,11 @@ Other Changes: - Demo: plot code doesn't use ImVector to avoid heap allocation and be more friendly to custom allocator users. (#538) - Fixed compilation on DragonFly BSD (@mneumann) (#563) - Examples: Vulkan: Added a Vulkan example (@Loftilus) (#549) -- Examples: DX10, DX11: Saving/restoring most device state so dropping render function in your - codebase shouldn't have DX device side-effects. (#570) +- Examples: DX10, DX11: Saving/restoring most device state so dropping render function in your codebase shouldn't have DX device side-effects. (#570) - Examples: DX10, DX11: Fixed ImGui_ImplDX??_NewFrame() from recreating device objects if render isn't called (g_pVB not set). - Examples: OpenGL3: Fix BindVertexArray/BindBuffer order. (@nlguillemot) (#527) - Examples: OpenGL: skip rendering and calling glViewport() if we have zero-fixed buffer. (#486) -- Examples: SDL2+OpenGL3: Fix context creation options. Made ImGui_ImplSdlGL3_NewFrame() signature - match GL2 one. (#468, #463) +- Examples: SDL2+OpenGL3: Fix context creation options. Made ImGui_ImplSdlGL3_NewFrame() signature match GL2 one. (#468, #463) - Examples: SDL2+OpenGL2/3: Fix for high-dpi displays. (@nickgravelyn) - Various extra comments and clarification in the code. - Various other fixes and optimizations. @@ -6374,11 +5495,7 @@ Breaking Changes: are now incorporating the scrolling amount. They were incorrectly not incorporating this amount previously. It PROBABLY shouldn't break anything, but that depends on how you used them. Namely: - If you always used SetCursorPos() with values relative to GetCursorPos() there shouldn't be a problem. - However if you used absolute coordinates, note that SetCursorPosY(100.0f) will put you at +100 from the - initial Y position (which may be scrolled out of the view), NOT at +100 from the window top border. - Since there wasn't any official scrolling value on X axis (past just manually moving the cursor) this can - only affect you if you used to set absolute coordinates on the Y axis which is hopefully rare/unlikely, - and trivial to fix. + However if you used absolute coordinates, note that SetCursorPosY(100.0f) will put you at +100 from the initial Y position (which may be scrolled out of the view), NOT at +100 from the window top border. Since there wasn't any official scrolling value on X axis (past just manually moving the cursor) this can only affect you if you used to set absolute coordinates on the Y axis which is hopefully rare/unlikely, and trivial to fix. - The value of GetWindowContentRegionMax() isn't necessarily close to GetWindowWidth() if horizontally scrolling. Previously they were roughly interchangeable (roughly because the content region exclude window padding). @@ -6406,11 +5523,9 @@ Other Changes: - TreeNode(): Fixed mouse interaction padding past the node label being accounted for in layout (#282). - BeginChild(): Passing a ImGuiWindowFlags_NoMove inhibits moving parent window from this child. - BeginChild() fixed missing rounding for child sizes which leaked into layout and have items misaligned. -- Begin(): Removed default name = "Debug" parameter. We already have a "Debug" window pushed to the stack in - the first place so it's not really a useful default. +- Begin(): Removed default name = "Debug" parameter. We already have a "Debug" window pushed to the stack in the first place so it's not really a useful default. - Begin(): Minor fixes with windows main clipping rectangle (e.g. child window with border). -- Begin(): Window flags are only read on the first call of the frame. Subsequent calls ignore flags, which allows - appending to a window without worryin about flags. +- Begin(): Window flags are only read on the first call of the frame. Subsequent calls ignore flags, which allows appending to a window without worryin about flags. - InputText(): ignore character input when ctrl/alt are held. (Normally those text input are ignored by most wrappers.) (#279). - Demo: Fixed incorrectly formed string passed to Combo (#298). - Demo: Added simple Log demo. @@ -6565,13 +5680,10 @@ Other Changes: - Added TitleBgActive color in style so focused window is made visible. (#253) - Added CaptureKeyboardFromApp() / CaptureMouseFromApp() to manually enforce inputs capturing. - Added DragFloatRange2() DragIntRange2() helpers. (#76) -- Added a Y centering ratio to SetScrollFromCursorPos() which can be used to aim the top - or bottom of the window. (#150) +- Added a Y centering ratio to SetScrollFromCursorPos() which can be used to aim the top or bottom of the window. (#150) - Added SetScrollY(), SetScrollFromPos(), GetCursorStartPos() for manual scrolling manipulations. (#150). -- Added GetKeyIndex() helper for converting from ImGuiKey_\* enum to user's keycodes. - Basically pulls from io.KeysMap[]. -- Added missing ImGuiKey_PageUp, ImGuiKey_PageDown so more UI code can be written without - referring to implementation-side keycodes. +- Added GetKeyIndex() helper for converting from ImGuiKey_\* enum to user's keycodes. Basically pulls from io.KeysMap[]. +- Added missing ImGuiKey_PageUp, ImGuiKey_PageDown so more UI code can be written without referring to implementation-side keycodes. - MenuItem() can be activated on release. (#245) - Allowing NewFrame() with DeltaTime==0.0f to not assert. - Fixed IsMouseDragging(). (#260) @@ -6582,8 +5694,8 @@ Other Changes: - Fixed text baseline alignment of small button (no padding) after regular buttons. - Fixed ListBoxHeader() not honoring negative sizes the same way as BeginChild() or BeginChildFrame(). (#263) - Fixed warnings for more pedantic compiler settings (#258). -- ImVector<> cannot be re-defined anymore, cannot be replaced with std::vector<>. - Allowed us to clean up and optimize lots of code. Yeah! (#262) +- ImVector<> cannot be re-defined anymore, cannot be replaced with std::vector<>. Allowed us to clean up and optimize + lots of code. Yeah! (#262) - ImDrawList: store pointer to their owner name for easier auditing/debugging. - Examples: added scroll tracking example with SetScrollFromCursorPos(). - Examples: metrics windows render clip rectangle when hovering over a draw call. @@ -6606,12 +5718,11 @@ Breaking Changes: Other Changes: -- Added InputTextMultiline() multi-line text editor, vertical scrolling, selection, optimized - enough to handle rather big chunks of text in stateless context (thousands of lines are ok), - option for allowing Tab to be input, option for validating with Return or Ctrl+Return (#200). -- Added modal window API, BeginPopupModal(), follows the popup api scheme. Modal windows can be closed - by clicking outside. By default the rest of the screen is dimmed (using ImGuiCol_ModalWindowDarkening). - Modal windows can be stacked. +- Added InputTextMultiline() multi-line text editor, vertical scrolling, selection, optimized enough to handle rather + big chunks of text in stateless context (thousands of lines are ok), option for allowing Tab to be input, option + for validating with Return or Ctrl+Return (#200). +- Added modal window API, BeginPopupModal(), follows the popup api scheme. Modal windows can be closed by clicking + outside. By default the rest of the screen is dimmed (using ImGuiCol_ModalWindowDarkening). Modal windows can be stacked. - Added GetGlyphRangesCyrillic() helper (#237). - Added SetNextWindowPosCenter() to center a window prior to knowing its size. (#249) - Added IsWindowHovered() helper. @@ -6627,8 +5738,7 @@ Other Changes: - Selectable(): Added flag ImGuiSelectableFlags_DontClosePopups. - Selectable(): Added flag ImGuiSelectableFlags_SpanAllColumns (#125). - Combo(): Fixed issue with activating a Combo() not taking active id (#241). -- ColorButton(), ColorEdit4(): fix to ensure that the colored square stays square when - non-default padding settings are used. +- ColorButton(), ColorEdit4(): fix to ensure that the colored square stays square when non-default padding settings are used. - BeginChildFrame(): returns bool like BeginChild() for clipping. - SetScrollPosHere(): takes account of item height + more accurate centering + fixed precision issue. - ImFont: ignoring '\r'. @@ -6650,30 +5760,26 @@ Breaking Changes: - The third parameter of Button(), 'repeat_if_held' has been removed. While it's been very rarely used, some code will possibly break if you didn't rely on the default parameter. Use PushButtonRepeat()/PopButtonRepeat() to configure repeat. -- Renamed IsRectClipped() to !IsRectVisible() for consistency (opposite return value!). - Kept inline redirection function (will obsolete) -- Renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. - Kept inline indirection function (will obsolete). +- Renamed IsRectClipped() to !IsRectVisible() for consistency (opposite return value!). Kept inline redirection function (will obsolete) +- Renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline indirection function (will obsolete). Other Changes: -- Menus: Added a menu system! Menus are typically populated with menu items and sub-menus, - but you can add any sort of widgets in them (buttons, text inputs, sliders, etc.). (#126) -- Menus: Added MenuItem() to append a menu item. Optional shortcut display, acts a button & toggle - with checked/unchecked state, disabled mode. Menu items can be used in any window. +- Menus: Added a menu system! Menus are typically populated with menu items and sub-menus, but you can add any sort of + widgets in them (buttons, text inputs, sliders, etc.). (#126) +- Menus: Added MenuItem() to append a menu item. Optional shortcut display, acts a button & toggle with checked/unchecked state, + disabled mode. Menu items can be used in any window. - Menus: Added BeginMenu() to append a sub-menu. Note that you generally want to add sub-menu inside a popup or a menu-bar. They will work inside a normal window but it will be a bit unusual. - Menus: Added BeginMenuBar() to append to window menu-bar (set ImGuiWindowFlags_MenuBar to enable). - Menus: Added BeginMainMenuBar() helper to append to a fullscreen main menu-bar. - Popups: Support for stacked popups. Each popup level inhibit inputs to lower levels. The menus system is based on this. (#126). -- Popups: Added BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid() to - create a popup window on mouse-click. +- Popups: Added BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid() to create a popup window on mouse-click. - Popups: Popups have borders by default (#197), attenuated border alpha in default theme. -- Popups & Tooltip: Fit within display. Handling various positioning/sizing/scrolling edge - cases. Better hysteresis when moving in corners. Tooltip always tries to stay away from mouse-cursor. +- Popups & Tooltip: Fit within display. Handling various positioning/sizing/scrolling edge cases. Better hysteresis when moving + in corners. Tooltip always tries to stay away from mouse-cursor. - Added ImGuiStorage::GetVoidPtrRef() for manipulating stored void*. -- Added IsKeyDown() IsMouseDown() as convenience and for consistency with existing functions - (instead of reading them from IO structures). +- Added IsKeyDown() IsMouseDown() as convenience and for consistency with existing functions (instead of reading them from IO structures). - Added Dummy() helper to advance layout by a given size. Unlike InvisibleButton() this doesn't catch any click. - Added configurable io.KeyRepeatDelay, io.KeyRepeatRate keyboard and mouse repeat rate. - Added PushButtonRepeat() / PopButtonRepeat() to enable hold-button-to-repeat press on any button. @@ -6699,8 +5805,7 @@ Other Changes: - Window: Added ImGuiSetCond_Appearing to test the hidden->visible transition in SetWindow***/SetNextWindow*** functions. - Window: Auto-fitting cancel out one worth of vertical spacing for vertical symmetry (like what group and tooltip do). - Window: Default item width for auto-resizing windows expressed as a factor of font height, scales better with different font. -- Window: Fixed auto-fit calculation mismatch of whether a scrollbar will be added by maximum height - clamping. Also honor NoScrollBar in the case of height clamping, not adding extra horizontal space. +- Window: Fixed auto-fit calculation mismatch of whether a scrollbar will be added by maximum height clamping. Also honor NoScrollBar in the case of height clamping, not adding extra horizontal space. - Window: Hovering require to hover same child window. Reverted 860cf57 (December 3). Might break something if you have child overlapping items in parent window. - Window: Fixed appending multiple times to an existing child via multiple BeginChild/EndChild calls to same child name. @@ -6709,8 +5814,7 @@ Other Changes: - Metrics: Added io.MetricsActiveWindows counter. (#213. - Metrics: Added io.MetricsAllocs counter (number of active memory allocations). - Metrics: ShowMetricsWindow() shows popups stack, allocations. -- Style: Added style.DisplayWindowPadding to prevent windows from reaching edges of display - (similar to style.DisplaySafeAreaPadding which is still in effect and also affect popups/tooltips). +- Style: Added style.DisplayWindowPadding to prevent windows from reaching edges of display (similar to style.DisplaySafeAreaPadding which is still in effect and also affect popups/tooltips). - Style: Removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). - Style: Added style.ScrollbarRounding. (#212) - Style: Added ImGuiCol_TextDisabled for disabled text. Added TextDisabled() helper. @@ -6752,11 +5856,9 @@ Other Changes: Hold SHIFT/ALT to speed-up/slow-down. Double-click or CTRL+click to input text. Passing min >= max makes the widget unbounded. - Added DragFloat2(), DragFloat3(), DragFloat4(), DragInt2(), DragInt3(), DragInt4() helper variants. -- Added ShowMetricsWindow() which is mainly useful to debug ImGui internals. -- Added IO.MetricsRenderVertices counter. +- Added ShowMetricsWindow() which is mainly useful to debug ImGui internals. Added IO.MetricsRenderVertices counter. - Added ResetMouseDragDelta() for iterative dragging operations. -- Added ImFontAtlas::AddFontFromCompressedTTF() helper + binary_to_compressed_c.cpp tool to - compress a file and create a .c array from it. +- Added ImFontAtlas::AddFontFromCompressedTTF() helper + binary_to_compressed_c.cpp tool to compress a file and create a .c array from it. - Added PushId() GetId() variants that takes string range to avoid user making unnecessary copies. - Added IsItemVisible(). - Fixed IsRectClipped() incorrectly returning false when log is enabled. @@ -6778,8 +5880,7 @@ Other Changes: - ShowTestWindow(): added examples for DragFloat, DragInt and only custom label embedded in format strings. - ShowTestWindow(): fixed "manipulating titles" example not doing the right thing, broken in ff35d24 - Examples: OpenGL/GLFW: Fixed modifier key state setting in GLFW callbacks. -- Examples: OpenGL/GLFW: Added glBindTexture(0) in OpenGL fixed pipeline examples. - Save restore current program and texture in the OpenGL3 example. +- Examples: OpenGL/GLFW: Added glBindTexture(0) in OpenGL fixed pipeline examples. Save restore current program and texture in the OpenGL3 example. - Examples: DirectX11: Removed unnecessary vertices conversion and CUSTOMVERTEX types. - Comments, fixes, tweaks. @@ -6793,22 +5894,16 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Other Changes: - Added a more convenient three parameters version of Begin() which covers the common uses better. -- Added mouse cursor types handling (resize, move, text input cursors, etc.) that user - can query with GetMouseCursor(). Added demo and instructions in ShowTestWindow(). +- Added mouse cursor types handling (resize, move, text input cursors, etc.) that user can query with GetMouseCursor(). Added demo and instructions in ShowTestWindow(). - Added embedded mouse cursor data for MouseDrawCursor software cursor rendering, for consoles/tablets/etc. (#155). -- Added first version of BeginPopup/EndPopup() helper API to create popup menus. Popups automatically - lock their position to the mouse cursor when first appearing. They close automatically when clicking - outside, and inhibit hovering items from other windows when active (to allow for clicking outside). (#126) +- Added first version of BeginPopup/EndPopup() helper API to create popup menus. Popups automatically lock their position to the mouse cursor when first appearing. They close automatically when clicking outside, and inhibit hovering items from other windows when active (to allow for clicking outside). (#126) - Added thickness parameter to ImDrawList::AddLine(). - Added ImDrawList::PushClipRectFullScreen() helper. -- Added style.DisplaySafeAreaPadding which was previously hard-coded. - (useful if you can't see the edges of your display, e.g. TV screens). +- Added style.DisplaySafeAreaPadding which was previously hard-coded (useful if you can't see the edges of your display, e.g. TV screens). - Added CalcItemRectClosestPoint() helper. -- Added GetMouseDragDelta(), IsMouseDragging() helpers, given a mouse button and an optional - "unlock" threshold. Added io.MouseDragThreshold setting. (#167) +- Added GetMouseDragDelta(), IsMouseDragging() helpers, given a mouse button and an optional "unlock" threshold. Added io.MouseDragThreshold setting. (#167) - IsItemHovered() return false if another widget is active, aka we can't use what we are hovering now. -- Added IsItemHoveredRect() if old behavior of IsItemHovered() is needed (e.g. for implementing - the drop side of a drag'n drop operation). +- Added IsItemHoveredRect() if old behavior of IsItemHovered() is needed (e.g. for implementing the drop side of a drag'n drop operation). - IsItemhovered() include space taken by label and behave consistently for all widgets (#145) - Auto-filling child window feed their content size to parent (#170) - InputText() removed the odd ~ characters when clipping. @@ -6818,20 +5913,15 @@ Other Changes: - Selectable(const char*, bool) version has bool defaulting to false. - Selectable(): fixed misusage of GetContentRegionMax().x leaking into auto-fitting. - Windows starting Collapsed runs initial auto-fit to retrieve a width for their title bar (#175) -- Fixed new window from having an incorrect content size on their first frame, if queried by user. - Fixed SetWindowPos/SetNextWindowPos having a side-effect size computation (#175) +- Fixed new window from having an incorrect content size on their first frame, if queried by user. Fixed SetWindowPos/SetNextWindowPos having a side-effect size computation (#175) - InputFloat(): fixed label alignment if total widget width forcefully bigger than space available. - Auto contents size aware of enforced vertical scrollbar if window is larger than display size. -- Fixed new windows auto-fitting bigger than their .ini saved size. - This was a bug but it may be a desirable effect sometimes, may reconsider it. -- Fixed negative clipping rectangle when collapsing windows that could affect manual - submission to ImDrawList and end-user rendering function if unhandled (#177) +- Fixed new windows auto-fitting bigger than their .ini saved size. This was a bug but it may be a desirable effect sometimes, may reconsider it. +- Fixed negative clipping rectangle when collapsing windows that could affect manual submission to ImDrawList and end-user rendering function if unhandled (#177) - Fixed bounding measurement of empty groups (fix #162) -- Fixed assignment order in Begin() making auto-fit size effectively lag by one frame. Also disabling - "clamp into view" while windows are auto-fitting so that auto-fitting window in corners don't get pushed away. +- Fixed assignment order in Begin() making auto-fit size effectively lag by one frame. Also disabling "clamp into view" while windows are auto-fitting so that auto-fitting window in corners don't get pushed away. - Fixed MouseClickedPos not updated on double-click update (#167) -- Fixed MouseDrawCursor feature submitting an empty trailing command in the draw list. - Fixed unmerged draw calls for software mouse cursor. +- Fixed MouseDrawCursor feature submitting an empty trailing command in the draw list. Fixed unmerged draw calls for software mouse cursor. - Fixed double-clicking on resize grip keeping the grip active if mouse button is kept held. - Bounding box tests exclude higher bound, so touching items (zero spacing) don't report double hover when cursor is on edge. - Setting io.LogFilename to NULL disable default LogToFile() (part of #175) @@ -6862,8 +5952,7 @@ Other Changes: - Added IsRootWindowFocused(), IsRootWindowOrAnyChildFocused(). - Added io.KeyAlt + support in examples apps, in prevision for future usage of Alt modifier (was missing). - Added ImGuiStyleVar_GrabMinSize enum value for PushStyleVar(). -- Various fixes related to vertical alignment of text after widget of varied sizes. - Allow for multiple blocks of multiple lines text on the same "line". Added demos. +- Various fixes related to vertical alignment of text after widget of varied sizes. Allow for multiple blocks of multiple lines text on the same "line". Added demos. - Explicit size passed to Plot*(), Button() includes the frame padding. - Style: Changed default Border and Column border colors to be most subtle. - Renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing. @@ -6892,10 +5981,8 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Other Changes: -- Examples: refactored all examples application to make it easier to isolate and grab the - code you need for OpenGL 2/3, DirectX 9/11, and toward a more sensible format for samples. -- Scrollbar grab have a minimum size (style.GrabSizeMin), always visible even with huge - scroll amount. (#150). +- Examples: refactored all examples application to make it easier to isolate and grab the code you need for OpenGL 2/3, DirectX 9/11, and toward a more sensible format for samples. +- Scrollbar grab have a minimum size (style.GrabSizeMin), always visible even with huge scroll amount. (#150). - Scrollbar: Clicking inside the grab box doesn't modify scroll value. Subsequent movement always relative. - Added "###" labelling syntax to pass a label that isn't part of the hashed ID (#107), e.g. ("%d###static_id",rand()). - Added GetColumnIndex(), GetColumnsCount() (#154) @@ -6905,15 +5992,12 @@ Other Changes: - Fixed ListBoxHeader() incorrect handling of SkipItems early out when window is collapsed. - Fixed using IsItemHovered() after EndChild() (#151) - Fixed malformed UTF-8 decoding errors leading to infinite loops (#158) -- InputText() handles buffer limit correctly for multi-byte UTF-8 characters, won't insert - an incomplete UTF-8 character when reaching buffer limit (fix #158) -- Handle double-width space (0x3000) in various places the same as single-width spaces, - for Chinese/Japanese users. +- InputText() handles buffer limit correctly for multi-byte UTF-8 characters, won't insert an incomplete UTF-8 character when reaching buffer limit (fix #158) +- Handle double-width space (0x3000) in various places the same as single-width spaces, for Chinese/Japanese users. - Collapse triangle uses text color (not border color). - Fixed font fallback glyph width. - Renamed style.ScrollBarWidth to style.ScrollbarWidth to be consistent with other casing. -- Windows: setup a default handler for ImeSetInputScreenPosFn so the IME dialog - (for Japanese/Chinese, etc.) is positioned correctly as you input text. +- Windows: setup a default handler for ImeSetInputScreenPosFn so the IME dialog (for Japanese/Chinese, etc.) is positioned correctly as you input text. - Windows: default clipboard handlers for Windows handle UTF-8. - Examples: Fixed DirectX 9/11 examples applications handling of Microsoft IME. - Examples: Allow DirectX 9/11 examples applications to resize the window. @@ -6932,8 +6016,7 @@ Other Changes: - Added Bullet() helper - equivalent to BulletText(""), SameLine(). - Added SetWindowFocus(), SetWindowFocus(const char*), SetNextWindowFocus() (#146) - Added SetWindowPos(), SetWindowSize(), SetWindowCollaposed() given a window name. -- Added SetNextTreeNodeOpened() with optional condition flag in replacement of OpenNextNode() - and consistent with other API. +- Added SetNextTreeNodeOpened() with optional condition flag in replacement of OpenNextNode() and consistent with other API. - Renamed ImGuiSetCondition_* to ImGuiSetCond_* and ImGuiCondition_FirstUseThisSession to ImGuiCond_Once. - Added missing definition for ImGui::GetWindowCollapsed(). - Fixed GetGlyphRangesJapanese() actually missing katakana ranges and a few useful extensions. @@ -6964,23 +6047,18 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Other Changes: -- InputText: having a InputText widget active doesn't steal mouse inputs from clicking on - a button before losing focus (relate to #134) +- InputText: having a InputText widget active doesn't steal mouse inputs from clicking on a button before losing focus (relate to #134) - InputText: cursor/selection/undo stack persist when using other widgets and getting back to same (#134). -- InputText: fix effective buffer size being smaller than necessary by 1 byte (so if you give - 3 bytes you can input 2 ascii chars + zero terminator, which is correct). +- InputText: fix effective buffer size being smaller than necessary by 1 byte (so if you give 3 bytes you can input 2 ascii chars + zero terminator, which is correct). - Added IsAnyItemActive(). -- Child window explicitly inherit collapse state from parent (so if user keeps submitting items - even thought Begin has returned 'false' the child items will be clipped faster). +- Child window explicitly inherit collapse state from parent (so if user keeps submitting items even thought Begin has returned 'false' the child items will be clipped faster). - BeginChild() return a bool the same way Begin() does. if true you can skip submitting content. - Removed extraneous (1,1) padding on child window (pointed out in #125) - Columns: doesn't bail out when SkipItems is set (fix #136) - Columns: Separator() within column correctly vertical offset all cells (pointed out in #125) -- GetColumnOffset() / SetColumnOffset() handles padding values more correctly so matching columns - can be lined up between a parent and a child window (cf. #125) +- GetColumnOffset() / SetColumnOffset() handles padding values more correctly so matching columns can be lined up between a parent and a child window (cf. #125) - Fix ImFont::BuildLookupTable() potential dangling pointer dereference (fix #131) -- Fix hovering of child window extending past their parent not taking account of parent clipping - rectangle (fix #137) +- Fix hovering of child window extending past their parent not taking account of parent clipping rectangle (fix #137) - Sliders: value text is clipped inside the frame when resizing sliders to be small. - ImGuITextFilter::Draw() use regular width call rather than computing its own arbitrary width. - ImGuiTextFilter: can take a default filter string during construction. @@ -6998,13 +6076,11 @@ Other Changes: - Added ListBox() (#129). - Added ListBoxHeader(), ListBoxFooter() for customized list traversal and creating multi-selection boxes. - Fixed title bar text clipping issue (fix #128). -- InputText: added ImGuiInputTextFlags_CallbackCharFilter system for filtering/replacement (#130). - Callback now passed an "EventFlag" parameter. +- InputText: added ImGuiInputTextFlags_CallbackCharFilter system for filtering/replacement (#130). Callback now passed an "EventFlag" parameter. - InputText: Added ImGuiInputTextFlags_CharsUppercase and ImGuiInputTextFlags_CharsNoBlank stock filters. - PushItemWidth() can take negative value to right-align items. - Optimisation: Columns offsets cached to avoid unnecessary binary search. -- Optimisation: Optimized CalcTextSize() function by about 25% (they are often the bottleneck when - submitting thousands of clipped items). +- Optimisation: Optimized CalcTextSize() function by about 25% (they are often the bottleneck when submitting thousands of clipped items). - Added ImGuiCol_ChildWindowBg, ImGuiStyleVar_ChildWindowRounding for completeness and flexibility. - Added BeginChild() variant that takes an ImGuiID. - Tweak default ImGuiCol_HeaderActive color to be less bright. @@ -7020,11 +6096,9 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Other Changes: - Added ImGuiWindowFlags_NoCollapse flag. -- Added a way to replace the internal state pointer so that we can optionally share it between - modules (e.g. multiple DLLs). +- Added a way to replace the internal state pointer so that we can optionally share it between modules (e.g. multiple DLLs). - Added tint_col parameter to ImageButton(). -- Added CalcListClipping() helper to perform faster/coarse clipping on user side - (when manipulating lists with thousands of items). +- Added CalcListClipping() helper to perform faster/coarse clipping on user side (when manipulating lists with thousands of items). - Added GetCursorPosX() / GetCursorPosY() shortcuts. - Renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing(). - Combo box always appears above other child windows of a same parent. @@ -7046,8 +6120,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: -- Big update! Initialisation had to be changed. You don't need to load PNG data anymore. Th - new system gives you uncompressed texture data. +- Big update! Initialisation had to be changed. You don't need to load PNG data anymore. The new system gives you uncompressed texture data. - This sequence: const void* png_data; unsigned int png_size; @@ -7060,23 +6133,19 @@ Breaking Changes: io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // io.Fonts->TexID = (your_texture_identifier); - - PixelCenterOffset has been removed and isn't a necessary setting anymore. Offset your - projection matrix by 0.5 if you have rendering problems. + - PixelCenterOffset has been removed and isn't a necessary setting anymore. Offset your projection matrix by 0.5 if you have rendering problems. Other Changes: - Loading TTF files with stb_truetype.h. - We still embed a compressed pixel-perfect TTF version of ProggyClean for convenience. - Runtime font rendering is a little faster than previously. -- You can load multiple fonts with multiple size inside the font atlas. Rendering with multiple - fonts are still merged into a single draw call whenever possible. +- You can load multiple fonts with multiple size inside the font atlas. Rendering with multiple fonts are still merged into a single draw call whenever possible. - The system handles UTF-8 and provide ranges to easily load e.g. characters for Japanese display. - Added PushFont() / PopFont(). - Added Image() and ImageButton() to display your own texture data. -- Added callback system in command-list. This can be used if you want to do your own rendering - (e.g. render a 3D scene) inside ImGui widgets. -- Added IsItemActive() to tell if last widget is being held / modified (as opposed to just - being hovered). Useful for custom dragging behaviors. +- Added callback system in command-list. This can be used if you want to do your own rendering (e.g. render a 3D scene) inside ImGui widgets. +- Added IsItemActive() to tell if last widget is being held / modified (as opposed to just being hovered). Useful for custom dragging behaviors. - Style: Added FrameRounding setting for a more rounded look (default to 0 for now). - Window: Fixed using multiple Begin/End pair on the same wnidow. - Window: Fixed style.WindowMinSize not being honored properly. @@ -7109,8 +6178,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Dragging outside area of a widget while it is active doesn't trigger hover on other widgets. - Activating widget bring parent window to front if not already. - Checkbox and Radio buttons activate on click-release to be consistent with other widgets and most UI. -- InputText() nows consume input characters immediately so they cannot be reused if - ImGui::Update is called again with a call to ImGui::Render(). (fixes #105) +- InputText() nows consume input characters immediately so they cannot be reused if ImGui::Update is called again with a call to ImGui::Render(). (fixes #105) - Examples: Console: added support for History callbacks + some cleanup. - Various small optimisations. - Cleanup and other fixes. @@ -7128,8 +6196,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Widgets more consistently handle empty labels (starting with ## mark) for their size calculation. - Fixed crashing with zero sized frame-buffer. - Fixed ImGui::Combo() not registering its size properly when clipped out of screen. -- Renamed second parameter to Begin() to 'bool* p_opened' to be a little more self-explanatory. - Added more comments on the use of Begin(). +- Renamed second parameter to Begin() to 'bool* p_opened' to be a little more self-explanatory. Added more comments on the use of Begin(). - Logging: Added LogText() to pass text straight to the log output (tty/clipboard/file) without rendering it. - Logging: Added LogFinish() to stop logging at an arbitrary point. - Logging: Log depth padding relative to start depth. @@ -7148,10 +6215,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Added ImGuiWindowFlags_NoScrollWithMouse, disable mouse wheel scrolling on a window. - Added ImGuiWindowFlags_NoSavedSettings, disable loading/saving window state to .ini file. -- Added SetNextWindowPos(), SetNextWindowSize(), SetNextWindowCollapsed() API along - with SetWindowPos(), SetWindowSize(), SetWindowCollapsed(). All functions include an - optional second parameter to easily set current value vs session default value vs. - persistent default value. +- Added SetNextWindowPos(), SetNextWindowSize(), SetNextWindowCollapsed() API along with SetWindowPos(), SetWindowSize(), SetWindowCollapsed(). All functions include an optional second parameter to easily set current value vs session default value vs persistent default value. - Removed rarely useful SetNewWindowDefaultPos() in favor of new API. - Fixed hovering of lower-right resize grip when it is above a child window. - Fixed InputInt() writing to output when it doesn't need to. @@ -7177,8 +6241,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Increased visibility of check box and radio button with smaller size. - Smooth mouse scrolling on OSX (uses floating point scroll/wheel input). - New version of IMGUI_ONCE_UPON_A_FRAME helper macro that works with all compilers. -- Moved IO.Font*** options to inside the IO.Font-> structure. -- Added IO.FontGlobalScale setting (in addition to Font->Scale per individual font). +- Moved IO.Font*** options to inside the IO.Font-> structure.. Added IO.FontGlobalScale setting (in addition to Font->Scale per individual font). - Fixed more Clang -Weverything warnings. - Examples: Added DirectX11 example application. - Examples: Created single .sln solution for all example projects. @@ -7206,8 +6269,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Fixed unaligned memory access for Emscripten compatibility. - Various pedantic warning fixes (now testing with Clang). - Added extra asserts to catch incorrect usage. -- PushStyleColor() / PushStyleVar() can be used outside the scope of a window (namely to change - variables that are used within the Begin() call). +- PushStyleColor() / PushStyleVar() can be used outside the scope of a window (namely to change variables that are used within the Begin() call). - PushTextWrapPos() defaults to 0.0 (right-end of current drawing region). - Fixed compatibility with std::vector if user decide to #define ImVector. - MouseWheel input is now normalized. @@ -7245,8 +6307,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Comments and fixes. - Added SetKeyboardFocusHere() to set input focus from code. - Added GetWindowFont(), GetWindowFontSize() for users of the low-level ImDrawList API. -- Added a UserData void *pointer so that the callback functions can access user state - "Just in case a project has adverse reactions to adding globals or statics in their own code." +- Added a UserData void *pointer so that the callback functions can access user state "Just in case a project has adverse reactions to adding globals or statics in their own code." - Renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL @@ -7274,8 +6335,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Added IsMouseHoveringWindow(), IsMouseHoveringAnyWindow(), IsPosHoveringAnyWindow() helpers. - Added va_list variations of all functions taking ellipsis (...) parameters. - Added section in documentation to explicitly document cases of API breaking changes (e.g. renamed IM_MALLOC below). -- Moved IM_MALLOC / IM_FREE defines. to IO structure members that can be set at runtime - (also allowing precompiled ImGui to cover more use cases). +- Moved IM_MALLOC / IM_FREE defines. to IO structure members that can be set at runtime (also allowing precompiled ImGui to cover more use cases). - Fixed OpenGL samples for Retina display. - Comments and minor fixes. @@ -7315,10 +6375,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: -- The behaviour of PixelCenterOffset changed! You may need to change your value if you had set - it to non-default in your code and/or offset your projection matrix by 0.5 pixels. It is - likely that the default PixelCenterOffset value of 0.0 is now suitable unless your rendering - uses some form of multisampling. +- The behaviour of PixelCenterOffset changed! You may need to change your value if you had set it to non-default in your code and/or offset your projection matrix by 0.5 pixels. It is likely that the default PixelCenterOffset value of 0.0 is now suitable unless your rendering uses some form of multisampling. Other Changes: @@ -7349,12 +6406,10 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.07 - Added InputFloat4(), SliderFloat4() helpers. -- Added global Alpha in ImGuiStyle structure. When Alpha=0.0, ImGui skips most of logic - and all rendering processing. +- Added global Alpha in ImGuiStyle structure. When Alpha=0.0, ImGui skips most of logic and all rendering processing. - Fix clipping of title bar text. - Fix to allow the user to call NewFrame() multiple times without calling Render(). -- Reduce inner window clipping to take account for the extend of CollapsingHeader() - share - same clipping rectangle. +- Reduce inner window clipping to take account for the extend of CollapsingHeader() - share same clipping rectangle. - Fix for child windows with inverted clip rectangles (when scrolled and out of screen, Etc.). - Minor fixes, tweaks, comments. diff --git a/3rdparty/imgui/docs/EXAMPLES.md b/3rdparty/imgui/docs/EXAMPLES.md index 0df7305..4aa69a6 100644 --- a/3rdparty/imgui/docs/EXAMPLES.md +++ b/3rdparty/imgui/docs/EXAMPLES.md @@ -35,13 +35,46 @@ At shutdown: call ImGui::DestroyContext() ``` -Main resource: -- Read **[Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) wiki guide** for detailed examples of how to integrate Dear ImGui in an existing application. +Example (using [backends/imgui_impl_win32.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_win32.cpp) + [backends/imgui_impl_dx11.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_dx11.cpp)): -Additional resources: -- Read FAQ at https://www.dearimgui.com/faq -- Read 'PROGRAMMER GUIDE' section in imgui.cpp. -- Read the comments and instruction at the top of each file. +```cpp +// Create a Dear ImGui context, setup some options +ImGui::CreateContext(); +ImGuiIO& io = ImGui::GetIO(); +io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable some options + +// Initialize Platform + Renderer backends (here: using imgui_impl_win32.cpp + imgui_impl_dx11.cpp) +ImGui_ImplWin32_Init(my_hwnd); +ImGui_ImplDX11_Init(my_d3d_device, my_d3d_device_context); + +// Application main loop +while (true) +{ + // Beginning of frame: update Renderer + Platform backend, start Dear ImGui frame + ImGui_ImplDX11_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + + // Any application code here + ImGui::Text("Hello, world!"); + + // End of frame: render Dear ImGui + ImGui::Render(); + ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); + + // Swap + g_pSwapChain->Present(1, 0); +} + +// Shutdown +ImGui_ImplDX11_Shutdown(); +ImGui_ImplWin32_Shutdown(); +ImGui::DestroyContext(); +``` + +Please read 'PROGRAMMER GUIDE' in imgui.cpp for notes on how to setup Dear ImGui in your codebase. +Please read the comments and instruction at the top of each file. +Please read FAQ at https://www.dearimgui.com/faq If you are using any of the backends provided here, you can add the backends/imgui_impl_xxxx(.cpp,.h) files to your project and use as-in. Each imgui_impl_xxxx.cpp file comes with its own individual @@ -139,8 +172,8 @@ This support building with Emscripten and targeting WebGL.
Prefer using that if you are using modern GL or WebGL in your application. [example_sdl2_sdlrenderer2/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_sdlrenderer2/)
-SDL2 (Win32, Mac, Linux, etc.) + SDL_Renderer for SDL2 example.
-= main.cpp + imgui_impl_sdl2.cpp + imgui_impl_sdlrenderer2.cpp
+SDL2 (Win32, Mac, Linux, etc.) + SDL_Renderer for SDL2 (most graphics backends are supported underneath)
+= main.cpp + imgui_impl_sdl2.cpp + imgui_impl_sdlrenderer.cpp
This requires SDL 2.0.18+ (released November 2021)
[example_sdl2_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_vulkan/)
@@ -149,26 +182,6 @@ SDL2 (Win32, Mac, Linux, etc.) + Vulkan example.
This is quite long and tedious, because: Vulkan.
For this example, the main.cpp file exceptionally use helpers function from imgui_impl_vulkan.h/cpp. -[example_sdl3_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_opengl3/)
-SDL3 (Win32, Mac, Linux, etc.) + OpenGL3+/ES2/ES3 example.
-= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_opengl3.cpp
-This uses more modern GL calls and custom shaders.
-This support building with Emscripten and targeting WebGL.
- -[example_sdl3_sdlgpu3/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_sdlgpu3/)
-SDL3 (Win32, Mac, Linux, etc.) + SDL_GPU for SDL3 example.
-= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_sdlrenderer3.cpp
- -[example_sdl3_sdlrenderer3/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_sdlrenderer3/)
-SDL3 (Win32, Mac, Linux, etc.) + SDL_Renderer for SDL3 example.
-= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_sdlrenderer3.cpp
- -[example_sdl3_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_vulkan/)
-SDL3 (Win32, Mac, Linux, etc.) + Vulkan example.
-= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_vulkan.cpp
-This is quite long and tedious, because: Vulkan.
-For this example, the main.cpp file exceptionally use helpers function from imgui_impl_vulkan.h/cpp. - [example_win32_directx9/](https://github.com/ocornut/imgui/blob/master/examples/example_win32_directx9/)
DirectX9 example, Windows only.
= main.cpp + imgui_impl_win32.cpp + imgui_impl_dx9.cpp @@ -187,19 +200,15 @@ DirectX12 example, Windows only.
This is quite long and tedious, because: DirectX12. [example_win32_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_win32_opengl3/)
-Raw Windows + OpenGL3 example (modern, programmable pipeline)
+Raw Windows + OpenGL3 + example (modern, programmable pipeline)
= main.cpp + imgui_impl_win32.cpp + imgui_impl_opengl3.cpp
-[example_win32_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_win32_vulkan/)
-Raw Windows + Vulkan example
-= main.cpp + imgui_impl_win32.cpp + imgui_impl_vulkan.cpp
- ### Miscellaneous **Building** -Unfortunately, nowadays it is still tedious to create and maintain portable build files using external +Unfortunately nowadays it is still tedious to create and maintain portable build files using external libraries (the kind we're using here to create a window and render 3D triangles) without relying on third party software and build systems. For most examples here we choose to provide: - Makefiles for Linux/OSX @@ -215,22 +224,22 @@ If you are interested in using Cmake to build and links examples, see: **About mouse cursor latency** -Dear ImGui does not introduce significant extra lag for most behaviors, +Dear ImGui has no particular extra lag for most behaviors, e.g. the last value passed to 'io.AddMousePosEvent()' before NewFrame() will result in windows being moved to the right spot at the time of EndFrame()/Render(). At 60 FPS your experience should be pleasant. -However, consider that OS mouse cursors are typically rendered through a very specific hardware-accelerated -path, which makes them feel smoother than the majority of content rendered via regular graphics API (including, +However, consider that OS mouse cursors are typically drawn through a very specific hardware accelerated +path and will feel smoother than the majority of contents rendered via regular graphics API (including, but not limited to Dear ImGui windows). Because UI rendering and interaction happens on the same plane as the mouse, that disconnect may be jarring to particularly sensitive users. You may experiment with enabling the io.MouseDrawCursor flag to request Dear ImGui to draw a mouse cursor using the regular graphics API, to help you visualize the difference between a "hardware" cursor and a regularly rendered software cursor. -However, rendering a mouse cursor at 60 FPS will feel sluggish, so you likely won't want to enable that at +However, rendering a mouse cursor at 60 FPS will feel sluggish so you likely won't want to enable that at all times. It might be beneficial for the user experience to switch to a software rendered cursor _only_ when an interactive drag is in progress. -Note that some setup configurations or GPU drivers may introduce additional display lag depending on their settings. -If you notice that dragging windows is laggy and you are not sure what the cause is: try drawing a simple -2D shape directly under the mouse cursor to help identify the issue! +Note that some setup or GPU drivers are likely to be causing extra display lag depending on their settings. +If you feel that dragging windows feels laggy and you are not sure what the cause is: try to build a simple +drawing a flat 2D shape directly under the mouse cursor! diff --git a/3rdparty/imgui/docs/FAQ.md b/3rdparty/imgui/docs/FAQ.md index 8dde196..e120e8c 100644 --- a/3rdparty/imgui/docs/FAQ.md +++ b/3rdparty/imgui/docs/FAQ.md @@ -77,9 +77,9 @@ or view this file with any Markdown viewer. ### Q: Which version should I get? I occasionally tag [Releases](https://github.com/ocornut/imgui/releases) but it is generally safe and recommended to sync to master/latest. The library is fairly stable and regressions tend to be fixed fast when reported. -You may use the ['docking'](https://github.com/ocornut/imgui/tree/docking) branch which includes: -- [Docking features](https://github.com/ocornut/imgui/wiki/Docking) -- [Multi-viewport features](https://github.com/ocornut/imgui/wiki/Multi-Viewports) +You may use the [docking](https://github.com/ocornut/imgui/tree/docking) branch which includes: +- [Docking features](https://github.com/ocornut/imgui/issues/2109) +- [Multi-viewport features](https://github.com/ocornut/imgui/issues/1542) Many projects are using this branch and it is kept in sync with master regularly. @@ -204,11 +204,10 @@ ctx->RSSetScissorRects(1, &r); ### Q: How can I have multiple widgets with the same label? ### Q: How can I have multiple windows with the same label? -**USING THE SAME LABEL+ID IS THE MOST COMMON USER MISTAKE!** -
**USING AN EMPTY LABEL IS THE SAME AS USING THE SAME LABEL AS YOUR PARENT WIDGET!** +**USING THE SAME LABEL+ID IS THE MOST COMMON USER MISTAKE:** - +
 ImGui::Begin("Incorrect!");
@@ -380,9 +379,8 @@ node open/closed state differently. See what makes more sense in your situation!
 Short explanation:
 - Refer to [Image Loading and Displaying Examples](https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples) on the [Wiki](https://github.com/ocornut/imgui/wiki).
 - You may use functions such as `ImGui::Image()`, `ImGui::ImageButton()` or lower-level `ImDrawList::AddImage()` to emit draw calls that will use your own textures.
-- Actual textures are identified in a way that is up to the user/engine. Those identifiers are stored and passed as an opaque ImTextureID value.
-- By default ImTextureID can store up to 64-bits. You may `#define` it to a custom type/structure if you need.
-- Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason), but the examples linked above may be useful references.
+- Actual textures are identified in a way that is up to the user/engine. Those identifiers are stored and passed as ImTextureID (void*) value.
+- Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason).
 
 **Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward.**
 
@@ -390,27 +388,27 @@ Long explanation:
 - Dear ImGui's job is to create "meshes", defined in a renderer-agnostic format made of draw commands and vertices. At the end of the frame, those meshes (ImDrawList) will be displayed by your rendering function. They are made up of textured polygons and the code to render them is generally fairly short (a few dozen lines). In the examples/ folder, we provide functions for popular graphics APIs (OpenGL, DirectX, etc.).
 - Each rendering function decides on a data type to represent "textures". The concept of what is a "texture" is entirely tied to your underlying engine/graphics API.
  We carry the information to identify a "texture" in the ImTextureID type.
-ImTextureID default to ImU64 aka 8 bytes worth of data: just enough to store one pointer or integer of your choice.
+ImTextureID is nothing more than a void*, aka 4/8 bytes worth of data: just enough to store one pointer or integer of your choice.
 Dear ImGui doesn't know or understand what you are storing in ImTextureID, it merely passes ImTextureID values until they reach your rendering function.
 - In the [examples/](https://github.com/ocornut/imgui/tree/master/examples) backends, for each graphics API we decided on a type that is likely to be a good representation for specifying an image from the end-user perspective. This is what the _examples_ rendering functions are using:
 ```cpp
 OpenGL:
-- ImTextureID should contains 'GLuint' (GL texture identifier).
+- ImTextureID = GLuint
 - See ImGui_ImplOpenGL3_RenderDrawData() function in imgui_impl_opengl3.cpp
 ```
 ```cpp
 DirectX9:
-- ImTextureID should contain a 'LPDIRECT3DTEXTURE9' (pointer).
+- ImTextureID = LPDIRECT3DTEXTURE9
 - See ImGui_ImplDX9_RenderDrawData() function in imgui_impl_dx9.cpp
 ```
 ```cpp
 DirectX11:
-- ImTextureID should contain a 'ID3D11ShaderResourceView*' (pointer)
+- ImTextureID = ID3D11ShaderResourceView*
 - See ImGui_ImplDX11_RenderDrawData() function in imgui_impl_dx11.cpp
 ```
 ```cpp
 DirectX12:
-- ImTextureID should contain a 'D3D12_GPU_DESCRIPTOR_HANDLE' (always 64-bits)
+- ImTextureID = D3D12_GPU_DESCRIPTOR_HANDLE
 - See ImGui_ImplDX12_RenderDrawData() function in imgui_impl_dx12.cpp
 ```
 For example, in the OpenGL example backend we store raw OpenGL texture identifier (GLuint) inside ImTextureID.
@@ -422,14 +420,14 @@ If you are starting with OpenGL or DirectX or Vulkan and haven't built much of a
 
 User code may do:
 ```cpp
-// Cast our texture type to ImTextureID
+// Cast our texture type to ImTextureID / void*
 MyTexture* texture = g_CoffeeTableTexture;
-ImGui::Image((ImTextureID)(intptr_t)texture, ImVec2(texture->Width, texture->Height));
+ImGui::Image((void*)texture, ImVec2(texture->Width, texture->Height));
 ```
 The renderer function called after ImGui::Render() will receive that same value that the user code passed:
 ```cpp
-// Cast ImTextureID stored in the draw command as our texture type
-MyTexture* texture = (MyTexture*)(intptr_t)pcmd->GetTexID();
+// Cast ImTextureID / void* stored in the draw command as our texture type
+MyTexture* texture = (MyTexture*)pcmd->GetTexID();
 MyEngineBindTexture2D(texture);
 ```
 Once you understand this design, you will understand that loading image files and turning them into displayable textures is not within the scope of Dear ImGui.
@@ -438,19 +436,19 @@ If you want to display an image file (e.g. PNG file) on the screen, please refer
 
 Refer to [Image Loading and Displaying Examples](https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples) on the [Wiki](https://github.com/ocornut/imgui/wiki) to find simplified examples for loading textures with OpenGL, DirectX9 and DirectX11.
 
-C/C++ tip: a u64 is 8 bytes. You may safely store any pointer or integer into it by casting your value to ImTextureID, and vice-versa.
-Because both end-points (user code and rendering function) are under your control, you know exactly what is stored inside the ImTextureID.
+C/C++ tip: a void* is pointer-sized storage. You may safely store any pointer or integer into it by casting your value to ImTextureID / void*, and vice-versa.
+Because both end-points (user code and rendering function) are under your control, you know exactly what is stored inside the ImTextureID / void*.
 Here are some examples:
 ```cpp
 GLuint my_tex = XXX;
-ImTextureID my_imtexid;
-my_imtexid = (ImTextureID)(intptr_t)my_tex;                     // cast a GLuint into a ImTextureID (we don't take its address! we just copy the address)
-my_tex = (GLuint)(intptr_t)my_imtexid;                          // cast a ImTextureID into a GLuint
+void* my_void_ptr;
+my_void_ptr = (void*)(intptr_t)my_tex;                  // cast a GLuint into a void* (we don't take its address! we literally store the value inside the pointer)
+my_tex = (GLuint)(intptr_t)my_void_ptr;                 // cast a void* into a GLuint
 
 ID3D11ShaderResourceView* my_dx11_srv = XXX;
-ImTextureID my_imtexid;
-my_imtexid = (ImTextureID)(intptr_t)my_dx11_srv;                // cast a ID3D11ShaderResourceView* into an opaque ImTextureID
-my_dx11_srv = (ID3D11ShaderResourceView*)(intptr_t)_my_imtexid; // cast a ImTextureID into a ID3D11ShaderResourceView*
+void* my_void_ptr;
+my_void_ptr = (void*)my_dx11_srv;                       // cast a ID3D11ShaderResourceView* into an opaque void*
+my_dx11_srv = (ID3D11ShaderResourceView*)my_void_ptr;   // cast a void* into a ID3D11ShaderResourceView*
 ```
 Finally, you may call `ImGui::ShowMetricsWindow()` to explore/visualize/understand how the ImDrawList are generated.
 
@@ -641,7 +639,7 @@ The applications in examples/ are doing that.
 Windows: you can use the WM_CHAR or WM_UNICHAR or WM_IME_CHAR message (depending if your app is built using Unicode or MultiByte mode).
 You may also use `MultiByteToWideChar()` or `ToUnicode()` to retrieve Unicode codepoints from MultiByte characters or keyboard state.
 Windows: if your language is relying on an Input Method Editor (IME), you can write your HWND to ImGui::GetMainViewport()->PlatformHandleRaw
-for the default implementation of GetPlatformIO().Platform_SetImeDataFn() to set your Microsoft IME position correctly.
+for the default implementation of io.PlatformSetImeDataFn() to set your Microsoft IME position correctly.
 
 ##### [Return to Index](#index)
 
@@ -656,7 +654,7 @@ You may take a look at:
 - [Quotes](https://github.com/ocornut/imgui/wiki/Quotes)
 - [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui)
 - [Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding)
-- [Gallery](https://github.com/ocornut/imgui/issues?q=label%3Agallery)
+- [Gallery](https://github.com/ocornut/imgui/issues/7503)
 
 ##### [Return to Index](#index)
 
@@ -702,7 +700,7 @@ There is an auto-generated [c-api for Dear ImGui (cimgui)](https://github.com/ci
 - Individuals: you can support continued maintenance and development via PayPal donations. See [README](https://github.com/ocornut/imgui/blob/master/docs/README.md).
 - If you are experienced with Dear ImGui and C++, look at [GitHub Issues](https://github.com/ocornut/imgui/issues), [GitHub Discussions](https://github.com/ocornut/imgui/discussions), the [Wiki](https://github.com/ocornut/imgui/wiki), read [docs/TODO.txt](https://github.com/ocornut/imgui/blob/master/docs/TODO.txt), and see how you want to help and can help!
 - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere, etc.
-You may post screenshots or links in the [gallery threads](https://github.com/ocornut/imgui/issues?q=label%3Agallery). Visuals are ideal as they inspire other programmers. Disclosing your use of Dear ImGui helps the library grow credibility, and helps other teams and programmers with taking decisions.
+You may post screenshots or links in the [gallery threads](https://github.com/ocornut/imgui/issues/7503). Visuals are ideal as they inspire other programmers. Disclosing your use of Dear ImGui helps the library grow credibility, and helps other teams and programmers with taking decisions.
 - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues or sometimes incomplete PR.
 
 ##### [Return to Index](#index)
diff --git a/3rdparty/imgui/docs/FONTS.md b/3rdparty/imgui/docs/FONTS.md
index e36afdf..df8b610 100644
--- a/3rdparty/imgui/docs/FONTS.md
+++ b/3rdparty/imgui/docs/FONTS.md
@@ -50,9 +50,7 @@ All loaded fonts glyphs are rendered into a single texture atlas ahead of time.
 
 ### (4) Font atlas texture fails to upload to GPU.
 
-This is often of byproduct of point 3. If you have large number of glyphs or multiple fonts, the texture may become too big for your graphics API. **The typical result of failing to upload a texture is if every glyph or everything appears as empty white rectangles.** Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours.
-
-![empty squares](https://github.com/user-attachments/assets/68b50fb5-8b9d-4c38-baec-6ac384f06d26)
+This is often of byproduct of point 3. If you have large number of glyphs or multiple fonts, the texture may become too big for your graphics API. **The typical result of failing to upload a texture is if every glyph or everything appears as empty black or white rectangle.** Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours.
 
 Some solutions:
 - You may reduce oversampling, e.g. `font_config.OversampleH = 1`, this will half your texture size for a quality loss.
@@ -62,8 +60,6 @@ Some solutions:
 - Set `io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;` to disable rounding the texture height to the next power of two.
 - Set `io.Fonts.TexDesiredWidth` to specify a texture width to reduce maximum texture height (see comment in `ImFontAtlas::Build()` function).
 
-Future versions of Dear ImGui should solve this problem.
-
 ##### [Return to Index](#index)
 
 ---------------------------------------
@@ -110,6 +106,8 @@ ImGui::PopFont();
 **For advanced options create a ImFontConfig structure and pass it to the AddFont() function (it will be copied internally):**
 ```cpp
 ImFontConfig config;
+config.OversampleH = 2;
+config.OversampleV = 1;
 config.GlyphExtraSpacing.x = 1.0f;
 ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config);
 ```
diff --git a/3rdparty/imgui/docs/README.md b/3rdparty/imgui/docs/README.md
index 9b43731..78cf2fe 100644
--- a/3rdparty/imgui/docs/README.md
+++ b/3rdparty/imgui/docs/README.md
@@ -13,7 +13,7 @@ Businesses: support continued development and maintenance via invoiced sponsorin
 
  _E-mail: contact @ dearimgui dot com_
Individuals: support continued development and maintenance [here](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WGHNC6MBFLZ2S). Also see [Funding](https://github.com/ocornut/imgui/wiki/Funding) page. -| [The Pitch](#the-pitch) - [Usage](#usage) - [How it works](#how-it-works) - [Releases & Changelogs](#releases--changelogs) - [Demo](#demo) - [Getting Started & Integration](#getting-started--integration) | +| [The Pitch](#the-pitch) - [Usage](#usage) - [How it works](#how-it-works) - [Releases & Changelogs](#releases--changelogs) - [Demo](#demo) - [Integration](#integration) | :----------------------------------------------------------: | | [Gallery](#gallery) - [Support, FAQ](#support-frequently-asked-questions-faq) - [How to help](#how-to-help) - **[Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding)** - [Credits](#credits) - [License](#license) | | [Wiki](https://github.com/ocornut/imgui/wiki) - [Extensions](https://github.com/ocornut/imgui/wiki/Useful-Extensions) - [Languages bindings & frameworks backends](https://github.com/ocornut/imgui/wiki/Bindings) - [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) - [User quotes](https://github.com/ocornut/imgui/wiki/Quotes) | @@ -22,7 +22,7 @@ Businesses: support continued development and maintenance via invoiced sponsorin Dear ImGui is a **bloat-free graphical user interface library for C++**. It outputs optimized vertex buffers that you can render anytime in your 3D-pipeline-enabled application. It is fast, portable, renderer agnostic, and self-contained (no external dependencies). -Dear ImGui is designed to **enable fast iterations** and to **empower programmers** to create **content creation tools and visualization / debug tools** (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal and lacks certain features commonly found in more high-level libraries. Among other things, full internationalization (right-to-left text, bidirectional text, text shaping etc.) and accessibility features are not supported. +Dear ImGui is designed to **enable fast iterations** and to **empower programmers** to create **content creation tools and visualization / debug tools** (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal and lacks certain features commonly found in more high-level libraries. Dear ImGui is particularly suited to integration in game engines (for tooling), real-time 3D applications, fullscreen applications, embedded applications, or any applications on console platforms where operating system features are non-standard. @@ -43,7 +43,7 @@ Dear ImGui is particularly suited to integration in game engines (for tooling), **Backends for a variety of graphics API and rendering platforms** are provided in the [backends/](https://github.com/ocornut/imgui/tree/master/backends) folder, along with example applications in the [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder. You may also create your own backend. Anywhere where you can render textured triangles, you can render Dear ImGui. -See the [Getting Started & Integration](#getting-started--integration) section of this document for more details. +See the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide and [Integration](#integration) section of this document for more details. After Dear ImGui is set up in your application, you can use it from \_anywhere\_ in your program loop: ```cpp @@ -110,11 +110,11 @@ Reading the changelogs is a good way to keep up to date with the things Dear ImG Calling the `ImGui::ShowDemoWindow()` function will create a demo window showcasing a variety of features and examples. The code is always available for reference in `imgui_demo.cpp`. [Here's how the demo looks](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/v167-misc.png). You should be able to build the examples from sources. If you don't, let us know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here: -- [imgui-demo-binaries-20241211.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20241211.zip) (Windows, 1.91.6, built 2024/11/11, master) or [older binaries](https://www.dearimgui.com/binaries). +- [imgui-demo-binaries-20240105.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20240105.zip) (Windows, 1.90.1 WIP, built 2024/01/05, master) or [older binaries](https://www.dearimgui.com/binaries). The demo applications are not DPI aware so expect some blurriness on a 4K screen. For DPI awareness in your application, you can load/reload your font at a different scale and scale your style with `style.ScaleAllSizes()` (see [FAQ](https://www.dearimgui.com/faq)). -### Getting Started & Integration +### Integration See the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide for details. @@ -123,7 +123,7 @@ On most platforms and when using C++, **you should be able to use a combination Integrating Dear ImGui within your custom engine is a matter of 1) wiring mouse/keyboard/gamepad inputs 2) uploading a texture to your GPU/render engine 3) providing a render function that can bind textures and render textured triangles, which is essentially what Backends are doing. The [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder is populated with applications doing just that: setting up a window and using backends. If you follow the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide it should in theory takes you less than an hour to integrate Dear ImGui. **Make sure to spend time reading the [FAQ](https://www.dearimgui.com/faq), comments, and the examples applications!** Officially maintained backends/bindings (in repository): -- Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal, OpenGL/ES/ES2, SDL_GPU, SDL_Renderer2/3, Vulkan, WebGPU. +- Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal, OpenGL/ES/ES2, SDL_Renderer, Vulkan, WebGPU. - Platforms: GLFW, SDL2/SDL3, Win32, Glut, OSX, Android. - Frameworks: Allegro5, Emscripten. @@ -141,7 +141,7 @@ Also see [Wiki](https://github.com/ocornut/imgui/wiki) for more links and ideas. Examples projects using Dear ImGui: [Tracy](https://github.com/wolfpld/tracy) (profiler), [ImHex](https://github.com/WerWolv/ImHex) (hex editor/data analysis), [RemedyBG](https://remedybg.itch.io/remedybg) (debugger) and [hundreds of others](https://github.com/ocornut/imgui/wiki/Software-using-Dear-ImGui). -For more user-submitted screenshots of projects using Dear ImGui, check out the [Gallery Threads](https://github.com/ocornut/imgui/issues?q=label%3Agallery)! +For more user-submitted screenshots of projects using Dear ImGui, check out the [Gallery Threads](https://github.com/ocornut/imgui/issues/7503)! For a list of third-party widgets and extensions, check out the [Useful Extensions/Widgets](https://github.com/ocornut/imgui/wiki/Useful-Extensions) wiki page. @@ -170,11 +170,11 @@ Private support is available for paying business customers (E-mail: _contact @ d **Which version should I get?** -We occasionally tag [Releases](https://github.com/ocornut/imgui/releases) (with nice releases notes) but it is generally safe and recommended to sync to latest `master` or `docking` branch. The library is fairly stable and regressions tend to be fixed fast when reported. Advanced users may want to use the `docking` branch with [Multi-Viewport](https://github.com/ocornut/imgui/wiki/Multi-Viewports) and [Docking](https://github.com/ocornut/imgui/wiki/Docking) features. This branch is kept in sync with master regularly. +We occasionally tag [Releases](https://github.com/ocornut/imgui/releases) (with nice releases notes) but it is generally safe and recommended to sync to latest `master` or `docking` branch. The library is fairly stable and regressions tend to be fixed fast when reported. Advanced users may want to use the `docking` branch with [Multi-Viewport](https://github.com/ocornut/imgui/issues/1542) and [Docking](https://github.com/ocornut/imgui/issues/2109) features. This branch is kept in sync with master regularly. **Who uses Dear ImGui?** -See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes), [Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding), and [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for an idea of who is using Dear ImGui. Please add your game/software if you can! Also, see the [Gallery Threads](https://github.com/ocornut/imgui/issues?q=label%3Agallery)! +See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes), [Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding), and [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for an idea of who is using Dear ImGui. Please add your game/software if you can! Also, see the [Gallery Threads](https://github.com/ocornut/imgui/issues/7503)! How to help ----------- @@ -196,7 +196,7 @@ Ongoing Dear ImGui development is and has been financially supported by users an **THANK YOU to all past and present supporters for helping to keep this project alive and thriving!** Dear ImGui is using software and services provided free of charge for open source projects: -- [PVS-Studio](https://pvs-studio.com/en/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) for static analysis (supports C/C++/C#/Java). +- [PVS-Studio](https://www.viva64.com/en/b/0570/) for static analysis. - [GitHub actions](https://github.com/features/actions) for continuous integration systems. - [OpenCppCoverage](https://github.com/OpenCppCoverage/OpenCppCoverage) for code coverage analysis. diff --git a/3rdparty/imgui/docs/TODO.txt b/3rdparty/imgui/docs/TODO.txt index 3aec732..2a61b4c 100644 --- a/3rdparty/imgui/docs/TODO.txt +++ b/3rdparty/imgui/docs/TODO.txt @@ -9,7 +9,8 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - doc: add a proper documentation system (maybe relying on automation? #435) - doc: checklist app to verify backends/integration of imgui (test inputs, rendering, callback, etc.). - doc/tips: tips of the day: website? applet in imgui_club? - + - doc/wiki: work on the wiki https://github.com/ocornut/imgui/wiki + - window: preserve/restore relative focus ordering (persistent or not), and e.g. of multiple reappearing windows (#2304) -> also see docking reference to same #. - window: calling SetNextWindowSize() every frame with <= 0 doesn't do anything, may be useful to allow (particularly when used for a single axis). (#690) - window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. perhaps a lightweight explicit cleanup pass. @@ -43,7 +44,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - drawlist: maintaining bounding box per command would allow to merge draw command when clipping isn't relied on (typical non-scrolling window or non-overflowing column would merge with previous command). (WIP branch) - drawlist: make it easier to toggle AA per primitive, so we can use e.g. non-AA fill + AA borders more naturally - drawlist: non-AA strokes have gaps between points (#593, #288), glitch especially on RenderCheckmark() and ColorPicker4(). - - drawlist: callback: add an extra void* in ImDrawCallback to expose render state instead of pulling from Renderer_RenderState (would break API). + - drawlist: callback: add an extra void* in ImDrawCallback to allow passing render-local data to the callback (would break API). - drawlist: AddRect vs AddLine position confusing (#2441) - drawlist/opt: store rounded corners in texture to use 1 quad per corner (filled and wireframe) to lower the cost of rounding. (#1962) - drawlist/opt: AddRect() axis aligned pixel aligned (no-aa) could use 8 triangles instead of 16 and no normal calculation. @@ -64,6 +65,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - selectable: generic BeginSelectable()/EndSelectable() mechanism. (work out alongside range-select branch) - selectable: a way to visualize partial/mixed selection (e.g. parent tree node has children with mixed selection) + - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now and super fragile. (WIP branch) - input text: preserve scrolling when unfocused? - input text: reorganize event handling, allow CharFilter to modify buffers, allow multiple events? (#541) - input text: expose CursorPos in char filter event (#816) @@ -216,11 +218,11 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - tree node/opt: could avoid formatting when clipped (flag assuming we don't care about width/height, assume single line height? format only %s/%c to be able to count height?) - settings: write more decent code to allow saving/loading new fields: columns, selected tree nodes? - - settings: facilitate extension lazily calling AddSettingsHandler() while running and still getting their data call the ReadXXX handlers immediately. - settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file (#437) - settings/persistence: helpers to make TreeNodeBehavior persist (even during dev!) - may need to store some semantic and/or data type in ImGuiStoragePair - style: better default styles. (#707) + - style: PushStyleVar: allow direct access to individual float X/Y elements. - style: add a highlighted text color (for headers, etc.) - style: border types: out-screen, in-screen, etc. (#447) - style: add window shadow (fading away from the window. Paint-style calculation of vertices alpha after drawlist would be easier) @@ -302,13 +304,14 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16-bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8? - nav: some features such as PageUp/Down/Home/End should probably work without ImGuiConfigFlags_NavEnableKeyboard? (where do we draw the line? how about CTRL+Tab) + ! nav: never clear NavId on some setup (e.g. gamepad centric) + - nav: there's currently no way to completely clear focus with the keyboard. depending on patterns used by the application to dispatch inputs, it may be desirable. - nav: Home/End behavior when navigable item is not fully visible at the edge of scrolling? should be backtrack to keep item into view? - nav: NavScrollToBringItemIntoView() with item bigger than view should focus top-right? Repro: using Nav in "About Window" - - nav: expose wrap around flags/logic to allow e.g. grid based layout (pressing NavRight on the right-most element would go to the next row, etc.). see internal's NavMoveRequestTryWrapping(). + - nav: wrap around logic to allow e.g. grid based layout (pressing NavRight on the right-most element would go to the next row, etc.). see internal's NavMoveRequestTryWrapping(). - nav: patterns to make it possible for arrows key to update selection (see JustMovedTo in range_select branch) - nav: restore/find nearest NavId when current one disappear (e.g. pressed a button that disappear, or perhaps auto restoring when current button change name) - nav: SetItemDefaultFocus() level of priority, so widget like Selectable when inside a popup could claim a low-priority default focus on the first selected iem - - nav: holding space to repeat a button doesn't show button activated during hold. - nav: NavFlattened: init requests don't work properly on flattened siblings. - nav: NavFlattened: pageup/pagedown/home/end don't work properly on flattened siblings. - nav: NavFlattened: ESC on a flattened child should select something. diff --git a/3rdparty/imgui/examples/example_android_opengl3/android/app/src/main/AndroidManifest.xml b/3rdparty/imgui/examples/example_android_opengl3/android/app/src/main/AndroidManifest.xml index 5a1e2d9..a87b95b 100644 --- a/3rdparty/imgui/examples/example_android_opengl3/android/app/src/main/AndroidManifest.xml +++ b/3rdparty/imgui/examples/example_android_opengl3/android/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ android:name="imgui.example.android.MainActivity" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:configChanges="orientation|keyboardHidden|screenSize" - android:exported="true"> + android:exported="false"> diff --git a/3rdparty/imgui/examples/example_android_opengl3/main.cpp b/3rdparty/imgui/examples/example_android_opengl3/main.cpp index 42aa622..e0ad5f9 100644 --- a/3rdparty/imgui/examples/example_android_opengl3/main.cpp +++ b/3rdparty/imgui/examples/example_android_opengl3/main.cpp @@ -68,7 +68,7 @@ void android_main(struct android_app* app) struct android_poll_source* out_data; // Poll all events. If the app is not visible, this loop blocks until g_Initialized == true. - while (ALooper_pollOnce(g_Initialized ? 0 : -1, nullptr, &out_events, (void**)&out_data) >= 0) + while (ALooper_pollAll(g_Initialized ? 0 : -1, nullptr, &out_events, (void**)&out_data) >= 0) { // Process one event if (out_data != nullptr) diff --git a/3rdparty/imgui/examples/example_glfw_opengl2/main.cpp b/3rdparty/imgui/examples/example_glfw_opengl2/main.cpp index df14dca..1ed2083 100644 --- a/3rdparty/imgui/examples/example_glfw_opengl2/main.cpp +++ b/3rdparty/imgui/examples/example_glfw_opengl2/main.cpp @@ -103,11 +103,6 @@ int main(int, char**) // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. glfwPollEvents(); - if (glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0) - { - ImGui_ImplGlfw_Sleep(10); - continue; - } // Start the Dear ImGui frame ImGui_ImplOpenGL2_NewFrame(); diff --git a/3rdparty/imgui/examples/example_glfw_opengl3/Makefile.emscripten b/3rdparty/imgui/examples/example_glfw_opengl3/Makefile.emscripten index bba4ac9..bd972ab 100644 --- a/3rdparty/imgui/examples/example_glfw_opengl3/Makefile.emscripten +++ b/3rdparty/imgui/examples/example_glfw_opengl3/Makefile.emscripten @@ -35,9 +35,6 @@ EMS = EMS += -s DISABLE_EXCEPTION_CATCHING=1 LDFLAGS += -s USE_GLFW=3 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 -# Build as single file (binary text encoded in .html file) -#LDFLAGS += -sSINGLE_FILE - # Uncomment next line to fix possible rendering bugs with Emscripten version older then 1.39.0 (https://github.com/ocornut/imgui/issues/2877) #EMS += -s BINARYEN_TRAP_MODE=clamp #EMS += -s SAFE_HEAP=1 ## Adds overhead diff --git a/3rdparty/imgui/examples/example_glfw_opengl3/main.cpp b/3rdparty/imgui/examples/example_glfw_opengl3/main.cpp index d02bb09..b44c451 100644 --- a/3rdparty/imgui/examples/example_glfw_opengl3/main.cpp +++ b/3rdparty/imgui/examples/example_glfw_opengl3/main.cpp @@ -43,17 +43,11 @@ int main(int, char**) // Decide GL+GLSL versions #if defined(IMGUI_IMPL_OPENGL_ES2) - // GL ES 2.0 + GLSL 100 (WebGL 1.0) + // GL ES 2.0 + GLSL 100 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"; @@ -145,11 +139,6 @@ int main(int, char**) // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. glfwPollEvents(); - if (glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0) - { - ImGui_ImplGlfw_Sleep(10); - continue; - } // Start the Dear ImGui frame ImGui_ImplOpenGL3_NewFrame(); diff --git a/3rdparty/imgui/examples/example_glfw_vulkan/CMakeLists.txt b/3rdparty/imgui/examples/example_glfw_vulkan/CMakeLists.txt index 443a144..a6e5bf9 100644 --- a/3rdparty/imgui/examples/example_glfw_vulkan/CMakeLists.txt +++ b/3rdparty/imgui/examples/example_glfw_vulkan/CMakeLists.txt @@ -42,4 +42,4 @@ file(GLOB sources *.cpp) add_executable(example_glfw_vulkan ${sources} ${IMGUI_DIR}/backends/imgui_impl_glfw.cpp ${IMGUI_DIR}/backends/imgui_impl_vulkan.cpp ${IMGUI_DIR}/imgui.cpp ${IMGUI_DIR}/imgui_draw.cpp ${IMGUI_DIR}/imgui_demo.cpp ${IMGUI_DIR}/imgui_tables.cpp ${IMGUI_DIR}/imgui_widgets.cpp) target_link_libraries(example_glfw_vulkan ${LIBRARIES}) - +target_compile_definitions(example_glfw_vulkan PUBLIC -DImTextureID=ImU64) diff --git a/3rdparty/imgui/examples/example_glfw_vulkan/build_win32.bat b/3rdparty/imgui/examples/example_glfw_vulkan/build_win32.bat index bb54a42..be92398 100644 --- a/3rdparty/imgui/examples/example_glfw_vulkan/build_win32.bat +++ b/3rdparty/imgui/examples/example_glfw_vulkan/build_win32.bat @@ -7,8 +7,8 @@ @set OUT_DIR=Debug mkdir %OUT_DIR% -cl /nologo /Zi /MD /utf-8 %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% +cl /nologo /Zi /MD /utf-8 %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% @set OUT_DIR=Release mkdir %OUT_DIR% -cl /nologo /Zi /MD /utf-8 /Ox /Oi %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% +cl /nologo /Zi /MD /utf-8 /Ox /Oi %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% diff --git a/3rdparty/imgui/examples/example_glfw_vulkan/build_win64.bat b/3rdparty/imgui/examples/example_glfw_vulkan/build_win64.bat index ca9b788..c60b027 100644 --- a/3rdparty/imgui/examples/example_glfw_vulkan/build_win64.bat +++ b/3rdparty/imgui/examples/example_glfw_vulkan/build_win64.bat @@ -1,14 +1,13 @@ -@REM Build for Visual Studio compiler. Run your copy of vcvars64.bat or vcvarsall.bat to setup 64-bit command-line compiler. +@REM Build for Visual Studio compiler. Run your copy of amd64/vcvars32.bat to setup 64-bit command-line compiler. -@set OUT_EXE=example_glfw_vulkan @set INCLUDES=/I..\.. /I..\..\backends /I..\libs\glfw\include /I %VULKAN_SDK%\include @set SOURCES=main.cpp ..\..\backends\imgui_impl_vulkan.cpp ..\..\backends\imgui_impl_glfw.cpp ..\..\imgui*.cpp @set LIBS=/LIBPATH:..\libs\glfw\lib-vc2010-64 /libpath:%VULKAN_SDK%\lib glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib @set OUT_DIR=Debug mkdir %OUT_DIR% -cl /nologo /Zi /MD /utf-8 %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% +cl /nologo /Zi /MD /utf-8 %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% @set OUT_DIR=Release mkdir %OUT_DIR% -cl /nologo /Zi /MD /utf-8 /Ox /Oi %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% +cl /nologo /Zi /MD /utf-8 /Ox /Oi %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% diff --git a/3rdparty/imgui/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj b/3rdparty/imgui/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj index a81d328..d0d1c5f 100644 --- a/3rdparty/imgui/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj +++ b/3rdparty/imgui/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj @@ -91,7 +91,7 @@ Level4 Disabled ..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories) - _MBCS;%(PreprocessorDefinitions) + ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) @@ -107,7 +107,7 @@ Level4 Disabled ..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories) - _MBCS;%(PreprocessorDefinitions) + ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) @@ -126,7 +126,7 @@ true ..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories) false - _MBCS;%(PreprocessorDefinitions) + ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) @@ -148,7 +148,7 @@ true ..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories) false - _MBCS;%(PreprocessorDefinitions) + ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) diff --git a/3rdparty/imgui/examples/example_glfw_vulkan/main.cpp b/3rdparty/imgui/examples/example_glfw_vulkan/main.cpp index 9eb87f0..3f191f2 100644 --- a/3rdparty/imgui/examples/example_glfw_vulkan/main.cpp +++ b/3rdparty/imgui/examples/example_glfw_vulkan/main.cpp @@ -52,7 +52,7 @@ static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; static ImGui_ImplVulkanH_Window g_MainWindowData; -static uint32_t g_MinImageCount = 2; +static int g_MinImageCount = 2; static bool g_SwapChainRebuild = false; static void glfw_error_callback(int error, const char* description) @@ -61,7 +61,7 @@ static void glfw_error_callback(int error, const char* description) } static void check_vk_result(VkResult err) { - if (err == VK_SUCCESS) + if (err == 0) return; fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err); if (err < 0) @@ -85,6 +85,35 @@ static bool IsExtensionAvailable(const ImVector& properti return false; } +static VkPhysicalDevice SetupVulkan_SelectPhysicalDevice() +{ + uint32_t gpu_count; + VkResult err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, nullptr); + check_vk_result(err); + IM_ASSERT(gpu_count > 0); + + ImVector gpus; + gpus.resize(gpu_count); + err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus.Data); + check_vk_result(err); + + // If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers + // most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple + // dedicated GPUs) is out of scope of this sample. + for (VkPhysicalDevice& device : gpus) + { + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(device, &properties); + if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) + return device; + } + + // Use first GPU (Integrated) is a Discrete one is not available. + if (gpu_count > 0) + return gpus[0]; + return VK_NULL_HANDLE; +} + static void SetupVulkan(ImVector instance_extensions) { VkResult err; @@ -148,12 +177,23 @@ static void SetupVulkan(ImVector instance_extensions) } // Select Physical Device (GPU) - g_PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(g_Instance); - IM_ASSERT(g_PhysicalDevice != VK_NULL_HANDLE); + g_PhysicalDevice = SetupVulkan_SelectPhysicalDevice(); // Select graphics queue family - g_QueueFamily = ImGui_ImplVulkanH_SelectQueueFamilyIndex(g_PhysicalDevice); - IM_ASSERT(g_QueueFamily != (uint32_t)-1); + { + uint32_t count; + vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, nullptr); + VkQueueFamilyProperties* queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * count); + vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, queues); + for (uint32_t i = 0; i < count; i++) + if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + { + g_QueueFamily = i; + break; + } + free(queues); + IM_ASSERT(g_QueueFamily != (uint32_t)-1); + } // Create Logical Device (with 1 queue) { @@ -189,18 +229,17 @@ static void SetupVulkan(ImVector instance_extensions) } // Create Descriptor Pool - // If you wish to load e.g. additional textures you may need to alter pools sizes and maxSets. + // The example only requires a single combined image sampler descriptor for the font image and only uses one descriptor set (for that) + // If you wish to load e.g. additional textures you may need to alter pools sizes. { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = 0; - for (VkDescriptorPoolSize& pool_size : pool_sizes) - pool_info.maxSets += pool_size.descriptorCount; + pool_info.maxSets = 1; pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); pool_info.pPoolSizes = pool_sizes; err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool); @@ -263,15 +302,17 @@ static void CleanupVulkanWindow() static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) { + VkResult err; + VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore; VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; - VkResult err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); + err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) + { g_SwapChainRebuild = true; - if (err == VK_ERROR_OUT_OF_DATE_KHR) return; - if (err != VK_SUBOPTIMAL_KHR) - check_vk_result(err); + } + check_vk_result(err); ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; { @@ -340,11 +381,11 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd) info.pImageIndices = &wd->FrameIndex; VkResult err = vkQueuePresentKHR(g_Queue, &info); if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) + { g_SwapChainRebuild = true; - if (err == VK_ERROR_OUT_OF_DATE_KHR) return; - if (err != VK_SUBOPTIMAL_KHR) - check_vk_result(err); + } + check_vk_result(err); wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores } @@ -465,11 +506,6 @@ int main(int, char**) g_MainWindowData.FrameIndex = 0; g_SwapChainRebuild = false; } - if (glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0) - { - ImGui_ImplGlfw_Sleep(10); - continue; - } // Start the Dear ImGui frame ImGui_ImplVulkan_NewFrame(); diff --git a/3rdparty/imgui/examples/example_glfw_wgpu/CMakeLists.txt b/3rdparty/imgui/examples/example_glfw_wgpu/CMakeLists.txt index 8e164e4..77b492f 100644 --- a/3rdparty/imgui/examples/example_glfw_wgpu/CMakeLists.txt +++ b/3rdparty/imgui/examples/example_glfw_wgpu/CMakeLists.txt @@ -79,11 +79,6 @@ add_executable(example_glfw_wgpu ${IMGUI_DIR}/imgui_tables.cpp ${IMGUI_DIR}/imgui_widgets.cpp ) -IF(NOT EMSCRIPTEN) - target_compile_definitions(example_glfw_wgpu PUBLIC - "IMGUI_IMPL_WEBGPU_BACKEND_DAWN" - ) -endif() target_include_directories(example_glfw_wgpu PUBLIC ${IMGUI_DIR} ${IMGUI_DIR}/backends @@ -96,6 +91,7 @@ if(EMSCRIPTEN) if("${IMGUI_EMSCRIPTEN_GLFW3}" STREQUAL "--use-port=contrib.glfw3") target_compile_options(example_glfw_wgpu PUBLIC "${IMGUI_EMSCRIPTEN_GLFW3}" + "-DEMSCRIPTEN_USE_PORT_CONTRIB_GLFW3" # unnecessary beyond emscripten 3.1.59 ) endif() message(STATUS "Using ${IMGUI_EMSCRIPTEN_GLFW3} GLFW implementation") diff --git a/3rdparty/imgui/examples/example_glfw_wgpu/Makefile.emscripten b/3rdparty/imgui/examples/example_glfw_wgpu/Makefile.emscripten index 78d64b4..5c79f0c 100644 --- a/3rdparty/imgui/examples/example_glfw_wgpu/Makefile.emscripten +++ b/3rdparty/imgui/examples/example_glfw_wgpu/Makefile.emscripten @@ -36,9 +36,6 @@ EMS += -s DISABLE_EXCEPTION_CATCHING=1 LDFLAGS += -s USE_GLFW=3 -s USE_WEBGPU=1 LDFLAGS += -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 -# Build as single file (binary text encoded in .html file) -#LDFLAGS += -sSINGLE_FILE - # Emscripten allows preloading a file or folder to be accessible at runtime. # The Makefile for this example project suggests embedding the misc/fonts/ folder into our application, it will then be accessible as "/fonts" # See documentation for more details: https://emscripten.org/docs/porting/files/packaging_files.html diff --git a/3rdparty/imgui/examples/example_glfw_wgpu/main.cpp b/3rdparty/imgui/examples/example_glfw_wgpu/main.cpp index 723b69d..fd31318 100644 --- a/3rdparty/imgui/examples/example_glfw_wgpu/main.cpp +++ b/3rdparty/imgui/examples/example_glfw_wgpu/main.cpp @@ -152,11 +152,6 @@ int main(int, char**) // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. glfwPollEvents(); - if (glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0) - { - ImGui_ImplGlfw_Sleep(10); - continue; - } // React to changes in screen size int width, height; diff --git a/3rdparty/imgui/examples/example_null/Makefile b/3rdparty/imgui/examples/example_null/Makefile index 4a67cec..9ceb353 100644 --- a/3rdparty/imgui/examples/example_null/Makefile +++ b/3rdparty/imgui/examples/example_null/Makefile @@ -1,6 +1,6 @@ # # Cross Platform Makefile -# Compatible with MSYS2/MINGW, Ubuntu 14.04.1+ and Mac OS X +# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X # # Important: This is a "null backend" application, with no visible output or interaction! # This is used for testing purpose and continuous integration, and has little use for end-user. diff --git a/3rdparty/imgui/examples/example_sdl2_directx11/main.cpp b/3rdparty/imgui/examples/example_sdl2_directx11/main.cpp index 7b7de21..70fc5f8 100644 --- a/3rdparty/imgui/examples/example_sdl2_directx11/main.cpp +++ b/3rdparty/imgui/examples/example_sdl2_directx11/main.cpp @@ -138,11 +138,6 @@ int main(int, char**) CreateRenderTarget(); } } - if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) - { - SDL_Delay(10); - continue; - } // Start the Dear ImGui frame ImGui_ImplDX11_NewFrame(); diff --git a/3rdparty/imgui/examples/example_sdl2_opengl2/main.cpp b/3rdparty/imgui/examples/example_sdl2_opengl2/main.cpp index 4c537c3..f92c54e 100644 --- a/3rdparty/imgui/examples/example_sdl2_opengl2/main.cpp +++ b/3rdparty/imgui/examples/example_sdl2_opengl2/main.cpp @@ -117,11 +117,6 @@ int main(int, char**) if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) done = true; } - if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) - { - SDL_Delay(10); - continue; - } // Start the Dear ImGui frame ImGui_ImplOpenGL2_NewFrame(); diff --git a/3rdparty/imgui/examples/example_sdl2_opengl3/Makefile.emscripten b/3rdparty/imgui/examples/example_sdl2_opengl3/Makefile.emscripten index bc06ade..da03484 100644 --- a/3rdparty/imgui/examples/example_sdl2_opengl3/Makefile.emscripten +++ b/3rdparty/imgui/examples/example_sdl2_opengl3/Makefile.emscripten @@ -36,9 +36,6 @@ EMS += -s USE_SDL=2 EMS += -s DISABLE_EXCEPTION_CATCHING=1 LDFLAGS += -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 -# Build as single file (binary text encoded in .html file) -#LDFLAGS += -sSINGLE_FILE - # Uncomment next line to fix possible rendering bugs with Emscripten version older then 1.39.0 (https://github.com/ocornut/imgui/issues/2877) #EMS += -s BINARYEN_TRAP_MODE=clamp #EMS += -s SAFE_HEAP=1 ## Adds overhead diff --git a/3rdparty/imgui/examples/example_sdl2_opengl3/main.cpp b/3rdparty/imgui/examples/example_sdl2_opengl3/main.cpp index 4fc75c3..9f983d9 100644 --- a/3rdparty/imgui/examples/example_sdl2_opengl3/main.cpp +++ b/3rdparty/imgui/examples/example_sdl2_opengl3/main.cpp @@ -35,19 +35,12 @@ int main(int, char**) // Decide GL+GLSL versions #if defined(IMGUI_IMPL_OPENGL_ES2) - // GL ES 2.0 + GLSL 100 (WebGL 1.0) + // GL ES 2.0 + GLSL 100 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"; @@ -82,12 +75,6 @@ int main(int, char**) } SDL_GLContext gl_context = SDL_GL_CreateContext(window); - if (gl_context == nullptr) - { - printf("Error: SDL_GL_CreateContext(): %s\n", SDL_GetError()); - return -1; - } - SDL_GL_MakeCurrent(window, gl_context); SDL_GL_SetSwapInterval(1); // Enable vsync @@ -165,11 +152,6 @@ int main(int, char**) if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) done = true; } - if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) - { - SDL_Delay(10); - continue; - } // Start the Dear ImGui frame ImGui_ImplOpenGL3_NewFrame(); diff --git a/3rdparty/imgui/examples/example_sdl2_sdlrenderer2/main.cpp b/3rdparty/imgui/examples/example_sdl2_sdlrenderer2/main.cpp index e922873..4d0ebff 100644 --- a/3rdparty/imgui/examples/example_sdl2_sdlrenderer2/main.cpp +++ b/3rdparty/imgui/examples/example_sdl2_sdlrenderer2/main.cpp @@ -47,7 +47,7 @@ int main(int, char**) if (renderer == nullptr) { SDL_Log("Error creating SDL_Renderer!"); - return -1; + return 0; } //SDL_RendererInfo info; //SDL_GetRendererInfo(renderer, &info); @@ -108,11 +108,6 @@ int main(int, char**) if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) done = true; } - if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) - { - SDL_Delay(10); - continue; - } // Start the Dear ImGui frame ImGui_ImplSDLRenderer2_NewFrame(); diff --git a/3rdparty/imgui/examples/example_sdl2_vulkan/build_win32.bat b/3rdparty/imgui/examples/example_sdl2_vulkan/build_win32.bat index f634aba..8a4aefc 100644 --- a/3rdparty/imgui/examples/example_sdl2_vulkan/build_win32.bat +++ b/3rdparty/imgui/examples/example_sdl2_vulkan/build_win32.bat @@ -7,8 +7,4 @@ @set OUT_DIR=Debug mkdir %OUT_DIR% -cl /nologo /Zi /MD /utf-8 %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console - -@set OUT_DIR=Release -@REM mkdir %OUT_DIR% -@REM cl /nologo /Zi /MD /utf-8 /Ox /Oi %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console +cl /nologo /Zi /MD /utf-8 %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console diff --git a/3rdparty/imgui/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj b/3rdparty/imgui/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj index bcf99a4..ba6afaf 100644 --- a/3rdparty/imgui/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj +++ b/3rdparty/imgui/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj @@ -91,7 +91,7 @@ Level4 Disabled ..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) - _MBCS;%(PreprocessorDefinitions) + ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) @@ -107,7 +107,7 @@ Level4 Disabled ..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) - _MBCS;%(PreprocessorDefinitions) + ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) @@ -126,7 +126,7 @@ true ..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) false - _MBCS;%(PreprocessorDefinitions) + ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) @@ -148,7 +148,7 @@ true ..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories) false - _MBCS;%(PreprocessorDefinitions) + ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) @@ -187,4 +187,4 @@ - + \ No newline at end of file diff --git a/3rdparty/imgui/examples/example_sdl2_vulkan/main.cpp b/3rdparty/imgui/examples/example_sdl2_vulkan/main.cpp index 15cd655..8b4da9a 100644 --- a/3rdparty/imgui/examples/example_sdl2_vulkan/main.cpp +++ b/3rdparty/imgui/examples/example_sdl2_vulkan/main.cpp @@ -49,7 +49,7 @@ static bool g_SwapChainRebuild = false; static void check_vk_result(VkResult err) { - if (err == VK_SUCCESS) + if (err == 0) return; fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err); if (err < 0) @@ -73,6 +73,35 @@ static bool IsExtensionAvailable(const ImVector& properti return false; } +static VkPhysicalDevice SetupVulkan_SelectPhysicalDevice() +{ + uint32_t gpu_count; + VkResult err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, nullptr); + check_vk_result(err); + IM_ASSERT(gpu_count > 0); + + ImVector gpus; + gpus.resize(gpu_count); + err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus.Data); + check_vk_result(err); + + // If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers + // most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple + // dedicated GPUs) is out of scope of this sample. + for (VkPhysicalDevice& device : gpus) + { + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(device, &properties); + if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) + return device; + } + + // Use first GPU (Integrated) is a Discrete one is not available. + if (gpu_count > 0) + return gpus[0]; + return VK_NULL_HANDLE; +} + static void SetupVulkan(ImVector instance_extensions) { VkResult err; @@ -136,12 +165,23 @@ static void SetupVulkan(ImVector instance_extensions) } // Select Physical Device (GPU) - g_PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(g_Instance); - IM_ASSERT(g_PhysicalDevice != VK_NULL_HANDLE); + g_PhysicalDevice = SetupVulkan_SelectPhysicalDevice(); // Select graphics queue family - g_QueueFamily = ImGui_ImplVulkanH_SelectQueueFamilyIndex(g_PhysicalDevice); - IM_ASSERT(g_QueueFamily != (uint32_t)-1); + { + uint32_t count; + vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, nullptr); + VkQueueFamilyProperties* queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * count); + vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, queues); + for (uint32_t i = 0; i < count; i++) + if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + { + g_QueueFamily = i; + break; + } + free(queues); + IM_ASSERT(g_QueueFamily != (uint32_t)-1); + } // Create Logical Device (with 1 queue) { @@ -177,18 +217,17 @@ static void SetupVulkan(ImVector instance_extensions) } // Create Descriptor Pool - // If you wish to load e.g. additional textures you may need to alter pools sizes and maxSets. + // The example only requires a single combined image sampler descriptor for the font image and only uses one descriptor set (for that) + // If you wish to load e.g. additional textures you may need to alter pools sizes. { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = 0; - for (VkDescriptorPoolSize& pool_size : pool_sizes) - pool_info.maxSets += pool_size.descriptorCount; + pool_info.maxSets = 1; pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); pool_info.pPoolSizes = pool_sizes; err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool); @@ -217,7 +256,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), requestSurfaceColorSpace); // Select Present Mode -#ifdef APP_USE_UNLIMITED_FRAME_RATE +#ifdef APP_UNLIMITED_FRAME_RATE VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR }; #else VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR }; @@ -251,15 +290,17 @@ static void CleanupVulkanWindow() static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) { + VkResult err; + VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore; VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; - VkResult err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); + err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) + { g_SwapChainRebuild = true; - if (err == VK_ERROR_OUT_OF_DATE_KHR) return; - if (err != VK_SUBOPTIMAL_KHR) - check_vk_result(err); + } + check_vk_result(err); ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; { @@ -328,11 +369,11 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd) info.pImageIndices = &wd->FrameIndex; VkResult err = vkQueuePresentKHR(g_Queue, &info); if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) + { g_SwapChainRebuild = true; - if (err == VK_ERROR_OUT_OF_DATE_KHR) return; - if (err != VK_SUBOPTIMAL_KHR) - check_vk_result(err); + } + check_vk_result(err); wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores } @@ -463,11 +504,6 @@ int main(int, char**) if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window)) done = true; } - if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) - { - SDL_Delay(10); - continue; - } // Resize swap chain? int fb_width, fb_height; diff --git a/3rdparty/imgui/examples/example_sdl3_opengl3/Makefile.emscripten b/3rdparty/imgui/examples/example_sdl3_opengl3/Makefile.emscripten index 57247ff..9e9ffd6 100644 --- a/3rdparty/imgui/examples/example_sdl3_opengl3/Makefile.emscripten +++ b/3rdparty/imgui/examples/example_sdl3_opengl3/Makefile.emscripten @@ -40,9 +40,6 @@ EMS += -s USE_SDL=2 EMS += -s DISABLE_EXCEPTION_CATCHING=1 LDFLAGS += -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 -# Build as single file (binary text encoded in .html file) -#LDFLAGS += -sSINGLE_FILE - # Uncomment next line to fix possible rendering bugs with Emscripten version older then 1.39.0 (https://github.com/ocornut/imgui/issues/2877) #EMS += -s BINARYEN_TRAP_MODE=clamp #EMS += -s SAFE_HEAP=1 ## Adds overhead diff --git a/3rdparty/imgui/examples/example_sdl3_opengl3/README.md b/3rdparty/imgui/examples/example_sdl3_opengl3/README.md index a032f87..5828e4b 100644 --- a/3rdparty/imgui/examples/example_sdl3_opengl3/README.md +++ b/3rdparty/imgui/examples/example_sdl3_opengl3/README.md @@ -9,11 +9,11 @@ Use the provided project file (.vcxproj). Add to solution (imgui_examples.sln) i Use build_win32.bat or directly: ``` -set SDL3_DIR=path_to_your_sdl3_folder -cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL3_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl3_opengl3.exe /FoDebug/ /link /libpath:%SDL3_DIR%\lib\x86 SDL3.lib opengl32.lib /subsystem:console +set SDL2_DIR=path_to_your_sdl3_folder +cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL2_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl3_opengl3.exe /FoDebug/ /link /libpath:%SDL2_DIR%\lib\x86 SDL3.lib opengl32.lib /subsystem:console # ^^ include paths ^^ source files ^^ output exe ^^ output dir ^^ libraries # or for 64-bit: -cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL3_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl3_opengl3.exe /FoDebug/ /link /libpath:%SDL3_DIR%\lib\x64 SDL3.lib SDL2mainopengl32.lib /subsystem:console +cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL2_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl3_opengl3.exe /FoDebug/ /link /libpath:%SDL2_DIR%\lib\x64 SDL3.lib SDL2mainopengl32.lib /subsystem:console ``` ## Linux and similar Unixes diff --git a/3rdparty/imgui/examples/example_sdl3_opengl3/build_win32.bat b/3rdparty/imgui/examples/example_sdl3_opengl3/build_win32.bat index 5bed40a..5b8d5f8 100644 --- a/3rdparty/imgui/examples/example_sdl3_opengl3/build_win32.bat +++ b/3rdparty/imgui/examples/example_sdl3_opengl3/build_win32.bat @@ -1,14 +1,8 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. - +@set OUT_DIR=Debug @set OUT_EXE=example_sdl3_opengl3 @set INCLUDES=/I..\.. /I..\..\backends /I%SDL3_DIR%\include @set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp @set LIBS=/LIBPATH:%SDL3_DIR%\lib\x86 SDL3.lib opengl32.lib shell32.lib - -@set OUT_DIR=Debug mkdir %OUT_DIR% cl /nologo /Zi /MD /utf-8 %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console - -@set OUT_DIR=Release -@REM mkdir %OUT_DIR% -@REM cl /nologo /Zi /MD /utf-8 /Ox /Oi %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console diff --git a/3rdparty/imgui/examples/example_sdl3_opengl3/main.cpp b/3rdparty/imgui/examples/example_sdl3_opengl3/main.cpp index 11a30c9..e727475 100644 --- a/3rdparty/imgui/examples/example_sdl3_opengl3/main.cpp +++ b/3rdparty/imgui/examples/example_sdl3_opengl3/main.cpp @@ -18,6 +18,7 @@ #include #endif +// This example doesn't compile with Emscripten yet! Awaiting SDL3 support. #ifdef __EMSCRIPTEN__ #include "../libs/emscripten/emscripten_mainloop_stub.h" #endif @@ -26,7 +27,7 @@ int main(int, char**) { // Setup SDL - if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMEPAD) != 0) { printf("Error: SDL_Init(): %s\n", SDL_GetError()); return -1; @@ -34,19 +35,12 @@ int main(int, char**) // Decide GL+GLSL versions #if defined(IMGUI_IMPL_OPENGL_ES2) - // GL ES 2.0 + GLSL 100 (WebGL 1.0) + // GL ES 2.0 + GLSL 100 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"; @@ -76,12 +70,6 @@ int main(int, char**) } SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); SDL_GLContext gl_context = SDL_GL_CreateContext(window); - if (gl_context == nullptr) - { - printf("Error: SDL_GL_CreateContext(): %s\n", SDL_GetError()); - return -1; - } - SDL_GL_MakeCurrent(window, gl_context); SDL_GL_SetSwapInterval(1); // Enable vsync SDL_ShowWindow(window); @@ -160,11 +148,6 @@ int main(int, char**) if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) done = true; } - if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) - { - SDL_Delay(10); - continue; - } // Start the Dear ImGui frame ImGui_ImplOpenGL3_NewFrame(); diff --git a/3rdparty/imgui/examples/example_sdl3_sdlrenderer3/main.cpp b/3rdparty/imgui/examples/example_sdl3_sdlrenderer3/main.cpp index 6eade48..64c82ca 100644 --- a/3rdparty/imgui/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/3rdparty/imgui/examples/example_sdl3_sdlrenderer3/main.cpp @@ -21,15 +21,11 @@ #include #endif -#ifdef __EMSCRIPTEN__ -#include "../libs/emscripten/emscripten_mainloop_stub.h" -#endif - // Main code int main(int, char**) { // Setup SDL - if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMEPAD) != 0) { printf("Error: SDL_Init(): %s\n", SDL_GetError()); return -1; @@ -116,11 +112,6 @@ int main(int, char**) if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) done = true; } - if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) - { - SDL_Delay(10); - continue; - } // Start the Dear ImGui frame ImGui_ImplSDLRenderer3_NewFrame(); @@ -172,9 +163,6 @@ int main(int, char**) ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer); SDL_RenderPresent(renderer); } -#ifdef __EMSCRIPTEN__ - EMSCRIPTEN_MAINLOOP_END; -#endif // Cleanup ImGui_ImplSDLRenderer3_Shutdown(); diff --git a/3rdparty/imgui/examples/example_win32_directx12/build_win32.bat b/3rdparty/imgui/examples/example_win32_directx12/build_win32.bat index cb5e8e2..68e3c92 100644 --- a/3rdparty/imgui/examples/example_win32_directx12/build_win32.bat +++ b/3rdparty/imgui/examples/example_win32_directx12/build_win32.bat @@ -1,8 +1,9 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. +@REM Important: to build on 32-bit systems, the DX12 backends needs '#define ImTextureID ImU64', so we pass it here. @set OUT_DIR=Debug @set OUT_EXE=example_win32_directx12 @set INCLUDES=/I..\.. /I..\..\backends /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" @set SOURCES=main.cpp ..\..\backends\imgui_impl_dx12.cpp ..\..\backends\imgui_impl_win32.cpp ..\..\imgui*.cpp @set LIBS=d3d12.lib d3dcompiler.lib dxgi.lib mkdir Debug -cl /nologo /Zi /MD /utf-8 %INCLUDES% /D UNICODE /D _UNICODE %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% +cl /nologo /Zi /MD /utf-8 %INCLUDES% /D ImTextureID=ImU64 /D UNICODE /D _UNICODE %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% diff --git a/3rdparty/imgui/examples/example_win32_directx12/example_win32_directx12.vcxproj b/3rdparty/imgui/examples/example_win32_directx12/example_win32_directx12.vcxproj index bb98c41..7b64371 100644 --- a/3rdparty/imgui/examples/example_win32_directx12/example_win32_directx12.vcxproj +++ b/3rdparty/imgui/examples/example_win32_directx12/example_win32_directx12.vcxproj @@ -21,7 +21,7 @@ {b4cf9797-519d-4afe-a8f4-5141a6b521d3} example_win32_directx12 - 10.0.20348.0 + 10.0.18362.0 @@ -87,7 +87,7 @@ Level4 Disabled ..\..;..\..\backends;%(AdditionalIncludeDirectories) - _UNICODE;UNICODE;%(PreprocessorDefinitions) + ImTextureID=ImU64;_UNICODE;UNICODE;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) @@ -102,7 +102,7 @@ Level4 Disabled ..\..;..\..\backends;%(AdditionalIncludeDirectories) - _UNICODE;UNICODE;%(PreprocessorDefinitions) + ImTextureID=ImU64;_UNICODE;UNICODE;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) @@ -119,7 +119,7 @@ true true ..\..;..\..\backends;%(AdditionalIncludeDirectories) - _UNICODE;UNICODE;%(PreprocessorDefinitions) + ImTextureID=ImU64;_UNICODE;UNICODE;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) @@ -138,7 +138,7 @@ true true ..\..;..\..\backends;%(AdditionalIncludeDirectories) - _UNICODE;UNICODE;%(PreprocessorDefinitions) + ImTextureID=ImU64;_UNICODE;UNICODE;%(PreprocessorDefinitions) /utf-8 %(AdditionalOptions) diff --git a/3rdparty/imgui/examples/example_win32_directx12/main.cpp b/3rdparty/imgui/examples/example_win32_directx12/main.cpp index d0a3a42..9479b43 100644 --- a/3rdparty/imgui/examples/example_win32_directx12/main.cpp +++ b/3rdparty/imgui/examples/example_win32_directx12/main.cpp @@ -6,6 +6,10 @@ // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). // - Introduction, links and more at the top of imgui.cpp +// Important: to compile on 32-bit systems, the DirectX12 backend requires code to be compiled with '#define ImTextureID ImU64'. +// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*. +// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file. + #include "imgui.h" #include "imgui_impl_win32.h" #include "imgui_impl_dx12.h" @@ -22,70 +26,23 @@ #pragma comment(lib, "dxguid.lib") #endif -// Config for example app -static const int APP_NUM_FRAMES_IN_FLIGHT = 2; -static const int APP_NUM_BACK_BUFFERS = 2; -static const int APP_SRV_HEAP_SIZE = 64; +#include "imgui_internal.h" struct FrameContext { - ID3D12CommandAllocator* CommandAllocator; - UINT64 FenceValue; -}; - -// Simple free list based allocator -struct ExampleDescriptorHeapAllocator -{ - ID3D12DescriptorHeap* Heap = nullptr; - D3D12_DESCRIPTOR_HEAP_TYPE HeapType = D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; - D3D12_CPU_DESCRIPTOR_HANDLE HeapStartCpu; - D3D12_GPU_DESCRIPTOR_HANDLE HeapStartGpu; - UINT HeapHandleIncrement; - ImVector FreeIndices; - - void Create(ID3D12Device* device, ID3D12DescriptorHeap* heap) - { - IM_ASSERT(Heap == nullptr && FreeIndices.empty()); - Heap = heap; - D3D12_DESCRIPTOR_HEAP_DESC desc = heap->GetDesc(); - HeapType = desc.Type; - HeapStartCpu = Heap->GetCPUDescriptorHandleForHeapStart(); - HeapStartGpu = Heap->GetGPUDescriptorHandleForHeapStart(); - HeapHandleIncrement = device->GetDescriptorHandleIncrementSize(HeapType); - FreeIndices.reserve((int)desc.NumDescriptors); - for (int n = desc.NumDescriptors; n > 0; n--) - FreeIndices.push_back(n); - } - void Destroy() - { - Heap = nullptr; - FreeIndices.clear(); - } - void Alloc(D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_desc_handle) - { - IM_ASSERT(FreeIndices.Size > 0); - int idx = FreeIndices.back(); - FreeIndices.pop_back(); - out_cpu_desc_handle->ptr = HeapStartCpu.ptr + (idx * HeapHandleIncrement); - out_gpu_desc_handle->ptr = HeapStartGpu.ptr + (idx * HeapHandleIncrement); - } - void Free(D3D12_CPU_DESCRIPTOR_HANDLE out_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE out_gpu_desc_handle) - { - int cpu_idx = (int)((out_cpu_desc_handle.ptr - HeapStartCpu.ptr) / HeapHandleIncrement); - int gpu_idx = (int)((out_gpu_desc_handle.ptr - HeapStartGpu.ptr) / HeapHandleIncrement); - IM_ASSERT(cpu_idx == gpu_idx); - FreeIndices.push_back(cpu_idx); - } + ID3D12CommandAllocator* CommandAllocator; + UINT64 FenceValue; }; // Data -static FrameContext g_frameContext[APP_NUM_FRAMES_IN_FLIGHT] = {}; +static int const NUM_FRAMES_IN_FLIGHT = 3; +static FrameContext g_frameContext[NUM_FRAMES_IN_FLIGHT] = {}; static UINT g_frameIndex = 0; +static int const NUM_BACK_BUFFERS = 3; static ID3D12Device* g_pd3dDevice = nullptr; static ID3D12DescriptorHeap* g_pd3dRtvDescHeap = nullptr; static ID3D12DescriptorHeap* g_pd3dSrvDescHeap = nullptr; -static ExampleDescriptorHeapAllocator g_pd3dSrvDescHeapAlloc; static ID3D12CommandQueue* g_pd3dCommandQueue = nullptr; static ID3D12GraphicsCommandList* g_pd3dCommandList = nullptr; static ID3D12Fence* g_fence = nullptr; @@ -94,8 +51,8 @@ static UINT64 g_fenceLastSignaledValue = 0; static IDXGISwapChain3* g_pSwapChain = nullptr; static bool g_SwapChainOccluded = false; static HANDLE g_hSwapChainWaitableObject = nullptr; -static ID3D12Resource* g_mainRenderTargetResource[APP_NUM_BACK_BUFFERS] = {}; -static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[APP_NUM_BACK_BUFFERS] = {}; +static ID3D12Resource* g_mainRenderTargetResource[NUM_BACK_BUFFERS] = {}; +static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[NUM_BACK_BUFFERS] = {}; // Forward declarations of helper functions bool CreateDeviceD3D(HWND hWnd); @@ -152,19 +109,10 @@ int main(int, char**) // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); - - ImGui_ImplDX12_InitInfo init_info = {}; - init_info.Device = g_pd3dDevice; - init_info.CommandQueue = g_pd3dCommandQueue; - init_info.NumFramesInFlight = APP_NUM_FRAMES_IN_FLIGHT; - init_info.RTVFormat = DXGI_FORMAT_R8G8B8A8_UNORM; - init_info.DSVFormat = DXGI_FORMAT_UNKNOWN; - // Allocating SRV descriptors (for textures) is up to the application, so we provide callbacks. - // (current version of the backend will only allocate one descriptor, future versions will need to allocate more) - init_info.SrvDescriptorHeap = g_pd3dSrvDescHeap; - init_info.SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_handle) { return g_pd3dSrvDescHeapAlloc.Alloc(out_cpu_handle, out_gpu_handle); }; - init_info.SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle) { return g_pd3dSrvDescHeapAlloc.Free(cpu_handle, gpu_handle); }; - ImGui_ImplDX12_Init(&init_info); + ImGui_ImplDX12_Init(g_pd3dDevice, NUM_FRAMES_IN_FLIGHT, + DXGI_FORMAT_R8G8B8A8_UNORM, g_pd3dSrvDescHeap, + g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(), + g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart()); // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. @@ -288,7 +236,7 @@ int main(int, char**) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { ImGui::UpdatePlatformWindows(); - ImGui::RenderPlatformWindowsDefault(); + ImGui::RenderPlatformWindowsDefault(nullptr, (void*)g_pd3dCommandList); } // Present @@ -323,7 +271,7 @@ bool CreateDeviceD3D(HWND hWnd) DXGI_SWAP_CHAIN_DESC1 sd; { ZeroMemory(&sd, sizeof(sd)); - sd.BufferCount = APP_NUM_BACK_BUFFERS; + sd.BufferCount = NUM_BACK_BUFFERS; sd.Width = 0; sd.Height = 0; sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; @@ -366,7 +314,7 @@ bool CreateDeviceD3D(HWND hWnd) { D3D12_DESCRIPTOR_HEAP_DESC desc = {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; - desc.NumDescriptors = APP_NUM_BACK_BUFFERS; + desc.NumDescriptors = NUM_BACK_BUFFERS; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; desc.NodeMask = 1; if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dRtvDescHeap)) != S_OK) @@ -374,7 +322,7 @@ bool CreateDeviceD3D(HWND hWnd) SIZE_T rtvDescriptorSize = g_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->GetCPUDescriptorHandleForHeapStart(); - for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++) + for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) { g_mainRenderTargetDescriptor[i] = rtvHandle; rtvHandle.ptr += rtvDescriptorSize; @@ -384,11 +332,10 @@ bool CreateDeviceD3D(HWND hWnd) { D3D12_DESCRIPTOR_HEAP_DESC desc = {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - desc.NumDescriptors = APP_SRV_HEAP_SIZE; + desc.NumDescriptors = 1; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dSrvDescHeap)) != S_OK) return false; - g_pd3dSrvDescHeapAlloc.Create(g_pd3dDevice, g_pd3dSrvDescHeap); } { @@ -400,7 +347,7 @@ bool CreateDeviceD3D(HWND hWnd) return false; } - for (UINT i = 0; i < APP_NUM_FRAMES_IN_FLIGHT; i++) + for (UINT i = 0; i < NUM_FRAMES_IN_FLIGHT; i++) if (g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&g_frameContext[i].CommandAllocator)) != S_OK) return false; @@ -426,7 +373,7 @@ bool CreateDeviceD3D(HWND hWnd) return false; swapChain1->Release(); dxgiFactory->Release(); - g_pSwapChain->SetMaximumFrameLatency(APP_NUM_BACK_BUFFERS); + g_pSwapChain->SetMaximumFrameLatency(NUM_BACK_BUFFERS); g_hSwapChainWaitableObject = g_pSwapChain->GetFrameLatencyWaitableObject(); } @@ -439,7 +386,7 @@ void CleanupDeviceD3D() CleanupRenderTarget(); if (g_pSwapChain) { g_pSwapChain->SetFullscreenState(false, nullptr); g_pSwapChain->Release(); g_pSwapChain = nullptr; } if (g_hSwapChainWaitableObject != nullptr) { CloseHandle(g_hSwapChainWaitableObject); } - for (UINT i = 0; i < APP_NUM_FRAMES_IN_FLIGHT; i++) + for (UINT i = 0; i < NUM_FRAMES_IN_FLIGHT; i++) if (g_frameContext[i].CommandAllocator) { g_frameContext[i].CommandAllocator->Release(); g_frameContext[i].CommandAllocator = nullptr; } if (g_pd3dCommandQueue) { g_pd3dCommandQueue->Release(); g_pd3dCommandQueue = nullptr; } if (g_pd3dCommandList) { g_pd3dCommandList->Release(); g_pd3dCommandList = nullptr; } @@ -461,7 +408,7 @@ void CleanupDeviceD3D() void CreateRenderTarget() { - for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++) + for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) { ID3D12Resource* pBackBuffer = nullptr; g_pSwapChain->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer)); @@ -474,13 +421,13 @@ void CleanupRenderTarget() { WaitForLastSubmittedFrame(); - for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++) + for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) if (g_mainRenderTargetResource[i]) { g_mainRenderTargetResource[i]->Release(); g_mainRenderTargetResource[i] = nullptr; } } void WaitForLastSubmittedFrame() { - FrameContext* frameCtx = &g_frameContext[g_frameIndex % APP_NUM_FRAMES_IN_FLIGHT]; + FrameContext* frameCtx = &g_frameContext[g_frameIndex % NUM_FRAMES_IN_FLIGHT]; UINT64 fenceValue = frameCtx->FenceValue; if (fenceValue == 0) @@ -502,7 +449,7 @@ FrameContext* WaitForNextFrameResources() HANDLE waitableObjects[] = { g_hSwapChainWaitableObject, nullptr }; DWORD numWaitableObjects = 1; - FrameContext* frameCtx = &g_frameContext[nextFrameIndex % APP_NUM_FRAMES_IN_FLIGHT]; + FrameContext* frameCtx = &g_frameContext[nextFrameIndex % NUM_FRAMES_IN_FLIGHT]; UINT64 fenceValue = frameCtx->FenceValue; if (fenceValue != 0) // means no fence was signaled { diff --git a/3rdparty/imgui/examples/example_win32_opengl3/main.cpp b/3rdparty/imgui/examples/example_win32_opengl3/main.cpp index ffc6e3d..a6af3fd 100644 --- a/3rdparty/imgui/examples/example_win32_opengl3/main.cpp +++ b/3rdparty/imgui/examples/example_win32_opengl3/main.cpp @@ -168,11 +168,6 @@ int main(int, char**) } if (done) break; - if (::IsIconic(hwnd)) - { - ::Sleep(10); - continue; - } // Start the Dear ImGui frame ImGui_ImplOpenGL3_NewFrame(); diff --git a/3rdparty/imgui/examples/imgui_examples.sln b/3rdparty/imgui/examples/imgui_examples.sln index cf1c5ad..9aee4a9 100644 --- a/3rdparty/imgui/examples/imgui_examples.sln +++ b/3rdparty/imgui/examples/imgui_examples.sln @@ -33,12 +33,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_opengl3", "exa EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_sdlrenderer3", "example_sdl3_sdlrenderer3\example_sdl3_sdlrenderer3.vcxproj", "{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_vulkan", "example_sdl3_vulkan\example_sdl3_vulkan.vcxproj", "{663A7E89-1E42-4222-921C-177F5B5910DF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_win32_vulkan", "example_win32_vulkan\example_win32_vulkan.vcxproj", "{0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_sdlgpu3", "example_sdl3_sdlgpu3\example_sdl3_sdlgpu3.vcxproj", "{C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -167,30 +161,6 @@ Global {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|Win32.Build.0 = Release|Win32 {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|x64.ActiveCfg = Release|x64 {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|x64.Build.0 = Release|x64 - {663A7E89-1E42-4222-921C-177F5B5910DF}.Debug|Win32.ActiveCfg = Debug|Win32 - {663A7E89-1E42-4222-921C-177F5B5910DF}.Debug|Win32.Build.0 = Debug|Win32 - {663A7E89-1E42-4222-921C-177F5B5910DF}.Debug|x64.ActiveCfg = Debug|x64 - {663A7E89-1E42-4222-921C-177F5B5910DF}.Debug|x64.Build.0 = Debug|x64 - {663A7E89-1E42-4222-921C-177F5B5910DF}.Release|Win32.ActiveCfg = Release|Win32 - {663A7E89-1E42-4222-921C-177F5B5910DF}.Release|Win32.Build.0 = Release|Win32 - {663A7E89-1E42-4222-921C-177F5B5910DF}.Release|x64.ActiveCfg = Release|x64 - {663A7E89-1E42-4222-921C-177F5B5910DF}.Release|x64.Build.0 = Release|x64 - {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Debug|Win32.ActiveCfg = Debug|Win32 - {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Debug|Win32.Build.0 = Debug|Win32 - {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Debug|x64.ActiveCfg = Debug|x64 - {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Debug|x64.Build.0 = Debug|x64 - {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Release|Win32.ActiveCfg = Release|Win32 - {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Release|Win32.Build.0 = Release|Win32 - {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Release|x64.ActiveCfg = Release|x64 - {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Release|x64.Build.0 = Release|x64 - {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Debug|Win32.ActiveCfg = Debug|Win32 - {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Debug|Win32.Build.0 = Debug|Win32 - {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Debug|x64.ActiveCfg = Debug|x64 - {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Debug|x64.Build.0 = Debug|x64 - {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Release|Win32.ActiveCfg = Release|Win32 - {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Release|Win32.Build.0 = Release|Win32 - {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Release|x64.ActiveCfg = Release|x64 - {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/3rdparty/imgui/examples/libs/emscripten/emscripten_mainloop_stub.h b/3rdparty/imgui/examples/libs/emscripten/emscripten_mainloop_stub.h index 8c4c48e..05cf60f 100644 --- a/3rdparty/imgui/examples/libs/emscripten/emscripten_mainloop_stub.h +++ b/3rdparty/imgui/examples/libs/emscripten/emscripten_mainloop_stub.h @@ -17,21 +17,20 @@ // - So the next logical step was to refactor all examples to follow that layout of using a "main loop" function. // This worked, but it made us lose all the nice things we had... -// Since only about 4 examples really need to run with Emscripten, here's our solution: +// Since only about 3 examples really need to run with Emscripten, here's our solution: // - Use some weird macros and capturing lambda to turn a loop in main() into a function. // - Hide all that crap in this file so it doesn't make our examples unusually ugly. // As a stance and principle of Dear ImGui development we don't use C++ headers and we don't // want to suggest to the newcomer that we would ever use C++ headers as this would affect // the initial judgment of many of our target audience. // - Technique is based on this idea: https://github.com/ocornut/imgui/pull/2492/ -// - The do { } while (0) is to allow our code calling continue in the main loop. #ifdef __EMSCRIPTEN__ #include #include static std::function MainLoopForEmscriptenP; static void MainLoopForEmscripten() { MainLoopForEmscriptenP(); } -#define EMSCRIPTEN_MAINLOOP_BEGIN MainLoopForEmscriptenP = [&]() { do -#define EMSCRIPTEN_MAINLOOP_END while (0); }; emscripten_set_main_loop(MainLoopForEmscripten, 0, true) +#define EMSCRIPTEN_MAINLOOP_BEGIN MainLoopForEmscriptenP = [&]() +#define EMSCRIPTEN_MAINLOOP_END ; emscripten_set_main_loop(MainLoopForEmscripten, 0, true) #else #define EMSCRIPTEN_MAINLOOP_BEGIN #define EMSCRIPTEN_MAINLOOP_END diff --git a/3rdparty/imgui/imconfig.h b/3rdparty/imgui/imconfig.h index 8f8bc3b..62365fb 100644 --- a/3rdparty/imgui/imconfig.h +++ b/3rdparty/imgui/imconfig.h @@ -21,14 +21,14 @@ //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. -// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() -// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. -//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export -//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import -//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden +// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions() +// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details. +//#define IMGUI_API __declspec( dllexport ) +//#define IMGUI_API __declspec( dllimport ) //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names. //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS +//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS. //---- Disable all of Dear ImGui or don't implement standard windows/tools. // It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp. @@ -42,13 +42,12 @@ //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a) //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME). //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). -//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")). +//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default io.PlatformOpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")). //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). -//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded font (ProggyClean.ttf), remove ~9.5 KB from output binary. AddFontDefault() will assert. //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available //---- Enable Test Engine / Automation features. @@ -59,12 +58,9 @@ //#define IMGUI_INCLUDE_IMGUI_USER_H //#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h" -//---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support. +//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) //#define IMGUI_USE_BGRA_PACKED_COLOR -//---- Use legacy CRC32-adler tables (used before 1.91.6), in order to preserve old .ini data that you cannot afford to invalidate. -//#define IMGUI_USE_LEGACY_CRC32_ADLER - //---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) //#define IMGUI_USE_WCHAR32 @@ -86,13 +82,10 @@ // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. //#define IMGUI_ENABLE_FREETYPE -//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT) +//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT) +// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided). // Only works in combination with IMGUI_ENABLE_FREETYPE. -// - lunasvg is currently easier to acquire/install, as e.g. it is part of vcpkg. -// - plutosvg will support more fonts and may load them faster. It currently requires to be built manually but it is fairly easy. See misc/freetype/README for instructions. -// - Both require headers to be available in the include path + program to be linked with the library code (not provided). -// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) -//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG +// (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) //#define IMGUI_ENABLE_FREETYPE_LUNASVG //---- Use stb_truetype to build and rasterize the font atlas (default) diff --git a/3rdparty/imgui/imgui.cpp b/3rdparty/imgui/imgui.cpp index 03674e3..3a94560 100644 --- a/3rdparty/imgui/imgui.cpp +++ b/3rdparty/imgui/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.0 WIP // (main code and documentation) // Help: @@ -10,7 +10,7 @@ // - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md) // - Homepage ................... https://github.com/ocornut/imgui // - Releases & changelog ....... https://github.com/ocornut/imgui/releases -// - Gallery .................... https://github.com/ocornut/imgui/issues?q=label%3Agallery (please post your screenshots/video there!) +// - Gallery .................... https://github.com/ocornut/imgui/issues/7503 (please post your screenshots/video there!) // - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there) // - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code) // - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more) @@ -25,7 +25,7 @@ // please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. // Everything else should be asked in 'Issues'! We are building a database of cross-linked knowledge there. -// Copyright (c) 2014-2025 Omar Cornut +// Copyright (c) 2014-2024 Omar Cornut // Developed by Omar Cornut and every direct or indirect contributors to the GitHub. // See LICENSE.txt for copyright and licensing details (standard MIT License). // This library is free but needs your support to sustain development and maintenance. @@ -63,7 +63,7 @@ CODE // [SECTION] INCLUDES // [SECTION] FORWARD DECLARATIONS // [SECTION] CONTEXT AND MEMORY ALLOCATORS -// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO, ImGuiPlatformIO) +// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) // [SECTION] MISC HELPERS/UTILITIES (Geometry functions) // [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions) // [SECTION] MISC HELPERS/UTILITIES (File functions) @@ -79,13 +79,12 @@ CODE // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) // [SECTION] ID STACK // [SECTION] INPUTS -// [SECTION] ERROR CHECKING, STATE RECOVERY +// [SECTION] ERROR CHECKING // [SECTION] ITEM SUBMISSION // [SECTION] LAYOUT // [SECTION] SCROLLING // [SECTION] TOOLTIPS // [SECTION] POPUPS -// [SECTION] WINDOW FOCUS // [SECTION] KEYBOARD/GAMEPAD NAVIGATION // [SECTION] DRAG AND DROP // [SECTION] LOGGING/CAPTURING @@ -176,6 +175,7 @@ CODE - Set 'io.BackendFlags |= ImGuiBackendFlags_HasGamepad' + call io.AddKeyEvent/AddKeyAnalogEvent() with ImGuiKey_Gamepad_XXX keys. - For analog values (0.0f to 1.0f), backend is responsible to handling a dead-zone and rescaling inputs accordingly. Backend code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). + - BEFORE 1.87, BACKENDS USED TO WRITE TO io.NavInputs[]. This is now obsolete. Please call io functions instead! - If you need to share inputs between your game and the Dear ImGui interface, the easiest approach is to go all-or-nothing, with a buttons combo to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. @@ -184,8 +184,8 @@ CODE - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + run examples/libs/synergy/uSynergy.c (on your console/tablet/phone app) in order to share your PC mouse/keyboard. - See https://github.com/ocornut/imgui/wiki/Useful-Extensions#remoting for other remoting solutions. - - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the io.ConfigNavMoveSetMousePos flag. - Enabling io.ConfigNavMoveSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs Dear ImGui to move your mouse cursor along with navigation movements. + - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag. + Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs Dear ImGui to move your mouse cursor along with navigation movements. When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved. When that happens your backend NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the backends in examples/ do that. (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, Dear ImGui will misbehave as it will see your mouse moving back & forth!) @@ -432,72 +432,12 @@ CODE You can read releases logs https://github.com/ocornut/imgui/releases for more details. (Docking/Viewport Branch) - - 2025/XX/XX (1.XXXX) - when multi-viewports are enabled, all positions will be in your natural OS coordinates space. It means that: + - 2024/XX/XX (1.XXXX) - when multi-viewports are enabled, all positions will be in your natural OS coordinates space. It means that: - reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are probably not what you want anymore. you may use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos) - likewise io.MousePos and GetMousePos() will use OS coordinates. If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos. - - 2025/01/22 (1.91.8) - removed ImGuiColorEditFlags_AlphaPreview (made value 0): it is now the default behavior. - prior to 1.91.8: alpha was made opaque in the preview by default _unless_ using ImGuiColorEditFlags_AlphaPreview. We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior. - the new flags (ImGuiColorEditFlags_AlphaOpaque, ImGuiColorEditFlags_AlphaNoBg + existing ImGuiColorEditFlags_AlphaPreviewHalf) may be combined better and allow finer controls: - - 2025/01/14 (1.91.7) - renamed ImGuiTreeNodeFlags_SpanTextWidth to ImGuiTreeNodeFlags_SpanLabelWidth for consistency with other names. Kept redirection enum (will obsolete). (#6937) - - 2024/11/27 (1.91.6) - changed CRC32 table from CRC32-adler to CRC32c polynomial in order to be compatible with the result of SSE 4.2 instructions. - As a result, old .ini data may be partially lost (docking and tables information particularly). - Because some users have crafted and storing .ini data as a way to workaround limitations of the docking API, we are providing a '#define IMGUI_USE_LEGACY_CRC32_ADLER' compile-time option to keep using old CRC32 tables if you cannot afford invalidating old .ini data. - - 2024/11/06 (1.91.5) - commented/obsoleted out pre-1.87 IO system (equivalent to using IMGUI_DISABLE_OBSOLETE_KEYIO or IMGUI_DISABLE_OBSOLETE_FUNCTIONS before) - - io.KeyMap[] and io.KeysDown[] are removed (obsoleted February 2022). - - io.NavInputs[] and ImGuiNavInput are removed (obsoleted July 2022). - - pre-1.87 backends are not supported: - - backends need to call io.AddKeyEvent(), io.AddMouseEvent() instead of writing to io.KeysDown[], io.MouseDown[] fields. - - backends need to call io.AddKeyAnalogEvent() for gamepad values instead of writing to io.NavInputs[] fields. - - for more reference: - - read 1.87 and 1.88 part of this section or read Changelog for 1.87 and 1.88. - - read https://github.com/ocornut/imgui/issues/4921 - - if you have trouble updating a very old codebase using legacy backend-specific key codes: consider updating to 1.91.4 first, then #define IMGUI_DISABLE_OBSOLETE_KEYIO, then update to latest. - - obsoleted ImGuiKey_COUNT (it is unusually error-prone/misleading since valid keys don't start at 0). probably use ImGuiKey_NamedKey_BEGIN/ImGuiKey_NamedKey_END? - - fonts: removed const qualifiers from most font functions in prevision for upcoming font improvements. - - 2024/10/18 (1.91.4) - renamed ImGuiCol_NavHighlight to ImGuiCol_NavCursor (for consistency with newly exposed and reworked features). Kept inline redirection enum (will obsolete). - - 2024/10/14 (1.91.4) - moved ImGuiConfigFlags_NavEnableSetMousePos to standalone io.ConfigNavMoveSetMousePos bool. - moved ImGuiConfigFlags_NavNoCaptureKeyboard to standalone io.ConfigNavCaptureKeyboard bool (note the inverted value!). - kept legacy names (will obsolete) + code that copies settings once the first time. Dynamically changing the old value won't work. Switch to using the new value! - - 2024/10/10 (1.91.4) - the typedef for ImTextureID now defaults to ImU64 instead of void*. (#1641) - this removes the requirement to redefine it for backends which are e.g. storing descriptor sets or other 64-bits structures when building on 32-bits archs. It therefore simplify various building scripts/helpers. - you may have compile-time issues if you were casting to 'void*' instead of 'ImTextureID' when passing your types to functions taking ImTextureID values, e.g. ImGui::Image(). - in doubt it is almost always better to do an intermediate intptr_t cast, since it allows casting any pointer/integer type without warning: - - May warn: ImGui::Image((void*)MyTextureData, ...); - - May warn: ImGui::Image((void*)(intptr_t)MyTextureData, ...); - - Won't warn: ImGui::Image((ImTextureID)(intptr_t)MyTextureData), ...); - - note that you can always define ImTextureID to be your own high-level structures (with dedicated constructors) if you like. - - 2024/10/03 (1.91.3) - drags: treat v_min==v_max as a valid clamping range when != 0.0f. Zero is a still special value due to legacy reasons, unless using ImGuiSliderFlags_ClampZeroRange. (#7968, #3361, #76) - - drags: extended behavior of ImGuiSliderFlags_AlwaysClamp to include _ClampZeroRange. It considers v_min==v_max==0.0f as a valid clamping range (aka edits not allowed). - although unlikely, it you wish to only clamp on text input but want v_min==v_max==0.0f to mean unclamped drags, you can use _ClampOnInput instead of _AlwaysClamp. (#7968, #3361, #76) - - 2024/09/10 (1.91.2) - internals: using multiple overlayed ButtonBehavior() with same ID will now have io.ConfigDebugHighlightIdConflicts=true feature emit a warning. (#8030) - it was one of the rare case where using same ID is legal. workarounds: (1) use single ButtonBehavior() call with multiple _MouseButton flags, or (2) surround the calls with PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); ... PopItemFlag() - - 2024/08/23 (1.91.1) - renamed ImGuiChildFlags_Border to ImGuiChildFlags_Borders for consistency. kept inline redirection flag. - - 2024/08/22 (1.91.1) - moved some functions from ImGuiIO to ImGuiPlatformIO structure: - - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn + changed 'void* user_data' to 'ImGuiContext* ctx'. Pull your user data from platform_io.ClipboardUserData. - - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn + same as above line. - - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn (#7660) - - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn - - io.PlatformLocaleDecimalPoint -> platform_io.Platform_LocaleDecimalPoint (#7389, #6719, #2278) - - access those via GetPlatformIO() instead of GetIO(). - some were introduced very recently and often automatically setup by core library and backends, so for those we are exceptionally not maintaining a legacy redirection symbol. - - commented the old ImageButton() signature obsoleted in 1.89 (~August 2022). As a reminder: - - old ImageButton() before 1.89 used ImTextureId as item id (created issue with e.g. multiple buttons in same scope, transient texture id values, opaque computation of ID) - - new ImageButton() since 1.89 requires an explicit 'const char* str_id' - - old ImageButton() before 1.89 had frame_padding' override argument. - - new ImageButton() since 1.89 always use style.FramePadding, which you can freely override with PushStyleVar()/PopStyleVar(). - - 2024/07/25 (1.91.0) - obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). (see #7838 on GitHub for more info) - you should never need those functions. you can do everything with GetCursorScreenPos() and GetContentRegionAvail() in a more simple way. - - instead of: GetWindowContentRegionMax().x - GetCursorPos().x - - you can use: GetContentRegionAvail().x - - instead of: GetWindowContentRegionMax().x + GetWindowPos().x - - you can use: GetCursorScreenPos().x + GetContentRegionAvail().x // when called from left edge of window - - instead of: GetContentRegionMax() - - you can use: GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos() // right edge in local coordinates - - instead of: GetWindowContentRegionMax().x - GetWindowContentRegionMin().x - - you can use: GetContentRegionAvail() // when called from left edge of window - 2024/07/15 (1.91.0) - renamed ImGuiSelectableFlags_DontClosePopups to ImGuiSelectableFlags_NoAutoClosePopups. (#1379, #1468, #2200, #4936, #5216, #7302, #7573) (internals: also renamed ImGuiItemFlags_SelectableDontClosePopup into ImGuiItemFlags_AutoClosePopups with inverted behaviors) - 2024/07/15 (1.91.0) - obsoleted PushButtonRepeat()/PopButtonRepeat() in favor of using new PushItemFlag(ImGuiItemFlags_ButtonRepeat, ...)/PopItemFlag(). @@ -562,7 +502,6 @@ CODE - new: BeginChild("Name", size, ImGuiChildFlags_Border) - old: BeginChild("Name", size, false) - new: BeginChild("Name", size) or BeginChild("Name", 0) or BeginChild("Name", size, ImGuiChildFlags_None) - **AMEND FROM THE FUTURE: from 1.91.1, 'ImGuiChildFlags_Border' is called 'ImGuiChildFlags_Borders'** - 2023/11/02 (1.90.0) - BeginChild: added child-flag ImGuiChildFlags_AlwaysUseWindowPadding as a replacement for the window-flag ImGuiWindowFlags_AlwaysUseWindowPadding: the feature only ever made sense for BeginChild() anyhow. - old: BeginChild("Name", size, 0, ImGuiWindowFlags_AlwaysUseWindowPadding); - new: BeginChild("Name", size, ImGuiChildFlags_AlwaysUseWindowPadding, 0); @@ -662,7 +601,7 @@ CODE - Backend writing to io.MouseHoveredViewport -> backend should call io.AddMouseViewportEvent() [Docking branch w/ multi-viewports only] note: for all calls to IO new functions, the Dear ImGui context should be bound/current. read https://github.com/ocornut/imgui/issues/4921 for details. - - 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(), ImGui::IsKeyDown(). Removed GetKeyIndex(), now unnecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details. + - 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(). Removed GetKeyIndex(), now unnecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details. - IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX) - IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX) - Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent() (+ call io.SetKeyEventNativeData() if you want legacy user code to stil function with legacy key codes). @@ -1111,7 +1050,7 @@ CODE #else #include #endif -#if defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_APP) && WINAPI_FAMILY == WINAPI_FAMILY_APP) || (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES)) +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP || WINAPI_FAMILY == WINAPI_FAMILY_GAMES) // The UWP and GDK Win32 API subsets don't support clipboard nor IME functions #define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS #define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS @@ -1154,20 +1093,17 @@ CODE #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access -#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) // We disable -Wpragmas because GCC doesn't provide a has_warning equivalent and some forks/patches may not follow the warning/version association. -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used -#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size -#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe -#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' -#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function -#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value -#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked -#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead -#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif // Debug options @@ -1186,9 +1122,7 @@ static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduc static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 0.70f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved. // Tooltip offset -static const ImVec2 TOOLTIP_DEFAULT_OFFSET_MOUSE = ImVec2(16, 10); // Multiplied by g.Style.MouseCursorScale -static const ImVec2 TOOLTIP_DEFAULT_OFFSET_TOUCH = ImVec2(0, -20); // Multiplied by g.Style.MouseCursorScale -static const ImVec2 TOOLTIP_DEFAULT_PIVOT_TOUCH = ImVec2(0.5f, 1.0f); // Multiplied by g.Style.MouseCursorScale +static const ImVec2 TOOLTIP_DEFAULT_OFFSET = ImVec2(16, 10); // Multiplied by g.Style.MouseCursorScale // Docking static const float DOCKING_TRANSPARENT_PAYLOAD_ALPHA = 0.50f; // For use with io.ConfigDockingTransparentPayload. Apply to Viewport _or_ WindowBg in host viewport. @@ -1210,21 +1144,17 @@ static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSetti static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*); static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf); -// Platform Dependents default implementation for ImGuiPlatformIO functions -static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx); -static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext* ctx, const char* text); -static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); -static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext* ctx, const char* path); +// Platform Dependents default implementation for IO functions +static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx); +static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text); +static void PlatformSetImeDataFn_DefaultImpl(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); +static bool PlatformOpenInShellFn_DefaultImpl(ImGuiContext* ctx, const char* path); namespace ImGui { // Item static void ItemHandleShortcut(ImGuiID id); -// Window Focus -static int FindWindowFocusIndex(ImGuiWindow* window); -static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags); - // Navigation static void NavUpdate(); static void NavUpdateWindowing(); @@ -1240,20 +1170,18 @@ static bool NavScoreItem(ImGuiNavItemData* result); static void NavApplyItemToResult(ImGuiNavItemData* result); static void NavProcessItem(); static void NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags); -static ImGuiInputSource NavCalcPreferredRefPosSource(); static ImVec2 NavCalcPreferredRefPos(); static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); static void NavRestoreLayer(ImGuiNavLayer layer); +static int FindWindowFocusIndex(ImGuiWindow* window); // Error Checking and Debug Tools static void ErrorCheckNewFrameSanityChecks(); static void ErrorCheckEndFrameSanityChecks(); -#ifndef IMGUI_DISABLE_DEBUG_TOOLS static void UpdateDebugToolItemPicker(); static void UpdateDebugToolStackQueries(); static void UpdateDebugToolFlashStyleColor(); -#endif // Inputs static void UpdateKeyboardInputs(); @@ -1270,7 +1198,6 @@ static void RenderWindowTitleBarContents(ImGuiWindow* window, const static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col); static void RenderDimmedBackgrounds(); static void SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect); -static void SetLastItemDataForChildWindowItem(ImGuiWindow* window, const ImRect& rect); // Viewports const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111; // Using an arbitrary constant instead of e.g. ImHashStr("ViewportDefault", 0); so it's easier to spot in the debugger. The exact value doesn't matter. @@ -1332,7 +1259,7 @@ static ImGuiMemFreeFunc GImAllocatorFreeFunc = FreeWrapper; static void* GImAllocatorUserData = NULL; //----------------------------------------------------------------------------- -// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO, ImGuiPlatformIO) +// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) //----------------------------------------------------------------------------- ImGuiStyle::ImGuiStyle() @@ -1362,18 +1289,18 @@ ImGuiStyle::ImGuiStyle() ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + LayoutAlign = 0.5f; // Element alignment inside horizontal and vertical layouts (0.0f - left/top, 1.0f - right/bottom, 0.5f - center). LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. - TabRounding = 5.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. TabBorderSize = 0.0f; // Thickness of border around tabs. TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. - TabBarOverlineSize = 1.0f; // Thickness of tab-bar overline, which highlights the selected tab-bar. TableAngledHeadersAngle = 35.0f * (IM_PI / 180.0f); // Angle of angled headers (supported values range from -50 degrees to +50 degrees). TableAngledHeadersTextAlign = ImVec2(0.5f,0.0f);// Alignment of angled headers within the cell 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; // Thickness of border in SeparatorText() + 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. @@ -1421,7 +1348,6 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) LogSliderDeadzone = ImTrunc(LogSliderDeadzone * scale_factor); TabRounding = ImTrunc(TabRounding * scale_factor); TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImTrunc(TabMinWidthForCloseButton * scale_factor) : FLT_MAX; - TabBarOverlineSize = ImTrunc(TabBarOverlineSize * scale_factor); SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor); DockingSeparatorSize = ImTrunc(DockingSeparatorSize * scale_factor); DisplayWindowPadding = ImTrunc(DisplayWindowPadding * scale_factor); @@ -1443,6 +1369,10 @@ ImGuiIO::ImGuiIO() IniSavingRate = 5.0f; IniFilename = "imgui.ini"; // Important: "imgui.ini" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same path as executables). LogFilename = "imgui_log.txt"; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + for (int i = 0; i < ImGuiKey_COUNT; i++) + KeyMap[i] = -1; +#endif UserData = NULL; Fonts = NULL; @@ -1451,15 +1381,6 @@ ImGuiIO::ImGuiIO() FontAllowUserScaling = false; DisplayFramebufferScale = ImVec2(1.0f, 1.0f); - // Keyboard/Gamepad Navigation options - ConfigNavSwapGamepadButtons = false; - ConfigNavMoveSetMousePos = false; - ConfigNavCaptureKeyboard = true; - ConfigNavEscapeClearFocusItem = true; - ConfigNavEscapeClearFocusWindow = false; - ConfigNavCursorVisibleAuto = true; - ConfigNavCursorVisibleAlways = false; - // Docking options (when ImGuiConfigFlags_DockingEnable is set) ConfigDockingNoSplit = false; ConfigDockingWithShift = false; @@ -1485,19 +1406,10 @@ ImGuiIO::ImGuiIO() ConfigDragClickToInputText = false; ConfigWindowsResizeFromEdges = true; ConfigWindowsMoveFromTitleBarOnly = false; - ConfigWindowsCopyContentsWithCtrlC = false; - ConfigScrollbarScrollByPage = true; ConfigMemoryCompactTimer = 60.0f; - ConfigDebugIsDebuggerPresent = false; - ConfigDebugHighlightIdConflicts = true; ConfigDebugBeginReturnValueOnce = false; ConfigDebugBeginReturnValueLoop = false; - ConfigErrorRecovery = true; - ConfigErrorRecoveryEnableAssert = true; - ConfigErrorRecoveryEnableDebugLog = true; - ConfigErrorRecoveryEnableTooltip = true; - // Inputs Behaviors MouseDoubleClickTime = 0.30f; MouseDoubleClickMaxDist = 6.0f; @@ -1509,6 +1421,8 @@ ImGuiIO::ImGuiIO() // Note: Initialize() will setup default clipboard/ime handlers. BackendPlatformName = BackendRendererName = NULL; BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; + PlatformOpenInShellUserData = NULL; + PlatformLocaleDecimalPoint = '.'; // Input (NB: we already have memset zero the entire structure!) MousePos = ImVec2(-FLT_MAX, -FLT_MAX); @@ -1517,6 +1431,8 @@ ImGuiIO::ImGuiIO() for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f; for (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; } AppAcceptingEvents = true; + BackendUsingLegacyKeyArrays = (ImS8)-1; + BackendUsingLegacyNavInputArray = true; // assume using legacy array until proven wrong } // Pass in translated ASCII characters for text input. @@ -1597,15 +1513,16 @@ void ImGuiIO::ClearEventsQueue() // Clear current keyboard/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons. void ImGuiIO::ClearInputKeys() { - ImGuiContext& g = *Ctx; - for (int key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key++) +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + memset(KeysDown, 0, sizeof(KeysDown)); +#endif + for (int n = 0; n < IM_ARRAYSIZE(KeysData); n++) { - if (ImGui::IsMouseKey((ImGuiKey)key)) + if (ImGui::IsMouseKey((ImGuiKey)(n + ImGuiKey_KeysData_OFFSET))) continue; - ImGuiKeyData* key_data = &g.IO.KeysData[key - ImGuiKey_NamedKey_BEGIN]; - key_data->Down = false; - key_data->DownDuration = -1.0f; - key_data->DownDurationPrev = -1.0f; + KeysData[n].Down = false; + KeysData[n].DownDuration = -1.0f; + KeysData[n].DownDurationPrev = -1.0f; } KeyCtrl = KeyShift = KeyAlt = KeySuper = false; KeyMods = ImGuiMod_None; @@ -1616,7 +1533,7 @@ void ImGuiIO::ClearInputMouse() { for (ImGuiKey key = ImGuiKey_Mouse_BEGIN; key < ImGuiKey_Mouse_END; key = (ImGuiKey)(key + 1)) { - ImGuiKeyData* key_data = &KeysData[key - ImGuiKey_NamedKey_BEGIN]; + ImGuiKeyData* key_data = &KeysData[key - ImGuiKey_KeysData_OFFSET]; key_data->Down = false; key_data->DownDuration = -1.0f; key_data->DownDurationPrev = -1.0f; @@ -1683,6 +1600,17 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) else if (key == ImGuiKey_RightCtrl) { key = ImGuiKey_RightSuper; } } + // Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data. +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + IM_ASSERT((BackendUsingLegacyKeyArrays == -1 || BackendUsingLegacyKeyArrays == 0) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); + if (BackendUsingLegacyKeyArrays == -1) + for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++) + IM_ASSERT(KeyMap[n] == -1 && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); + BackendUsingLegacyKeyArrays = 0; +#endif + if (ImGui::IsGamepadKey(key)) + BackendUsingLegacyNavInputArray = false; + // Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed) const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)key); const ImGuiKeyData* key_data = ImGui::GetKeyData(&g, key); @@ -1718,10 +1646,20 @@ void ImGuiIO::SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native return; IM_ASSERT(ImGui::IsNamedKey(key)); // >= 512 IM_ASSERT(native_legacy_index == -1 || ImGui::IsLegacyKey((ImGuiKey)native_legacy_index)); // >= 0 && <= 511 - IM_UNUSED(key); // Yet unused - IM_UNUSED(native_keycode); // Yet unused - IM_UNUSED(native_scancode); // Yet unused - IM_UNUSED(native_legacy_index); // Yet unused + IM_UNUSED(native_keycode); // Yet unused + IM_UNUSED(native_scancode); // Yet unused + + // Build native->imgui map so old user code can still call key functions with native 0..511 values. +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + const int legacy_key = (native_legacy_index != -1) ? native_legacy_index : native_keycode; + if (!ImGui::IsLegacyKey((ImGuiKey)legacy_key)) + return; + KeyMap[legacy_key] = key; + KeyMap[key] = legacy_key; +#else + IM_UNUSED(key); + IM_UNUSED(native_legacy_index); +#endif } // Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen. @@ -1873,13 +1811,6 @@ void ImGuiIO::AddFocusEvent(bool focused) g.InputEventsQueue.push_back(e); } -ImGuiPlatformIO::ImGuiPlatformIO() -{ - // Most fields are initialized with zero - memset(this, 0, sizeof(*this)); - Platform_LocaleDecimalPoint = '.'; -} - //----------------------------------------------------------------------------- // [SECTION] MISC HELPERS/UTILITIES (Geometry functions) //----------------------------------------------------------------------------- @@ -2070,7 +2001,7 @@ const char* ImStreolRange(const char* str, const char* str_end) return p ? p : str_end; } -const char* ImStrbol(const char* buf_mid_line, const char* buf_begin) // find beginning-of-line +const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line { while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n') buf_mid_line--; @@ -2223,14 +2154,11 @@ void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, } } -#ifndef IMGUI_ENABLE_SSE4_2_CRC // CRC32 needs a 1KB lookup table (not cache friendly) // Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: // - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe. static const ImU32 GCrc32LookupTable[256] = { -#ifdef IMGUI_USE_LEGACY_CRC32_ADLER - // Legacy CRC32-adler table used pre 1.91.6 (before 2024/11/27). Only use if you cannot afford invalidating old .ini data. 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, @@ -2247,27 +2175,7 @@ static const ImU32 GCrc32LookupTable[256] = 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, -#else - // CRC32c table compatible with SSE 4.2 instructions - 0x00000000,0xF26B8303,0xE13B70F7,0x1350F3F4,0xC79A971F,0x35F1141C,0x26A1E7E8,0xD4CA64EB,0x8AD958CF,0x78B2DBCC,0x6BE22838,0x9989AB3B,0x4D43CFD0,0xBF284CD3,0xAC78BF27,0x5E133C24, - 0x105EC76F,0xE235446C,0xF165B798,0x030E349B,0xD7C45070,0x25AFD373,0x36FF2087,0xC494A384,0x9A879FA0,0x68EC1CA3,0x7BBCEF57,0x89D76C54,0x5D1D08BF,0xAF768BBC,0xBC267848,0x4E4DFB4B, - 0x20BD8EDE,0xD2D60DDD,0xC186FE29,0x33ED7D2A,0xE72719C1,0x154C9AC2,0x061C6936,0xF477EA35,0xAA64D611,0x580F5512,0x4B5FA6E6,0xB93425E5,0x6DFE410E,0x9F95C20D,0x8CC531F9,0x7EAEB2FA, - 0x30E349B1,0xC288CAB2,0xD1D83946,0x23B3BA45,0xF779DEAE,0x05125DAD,0x1642AE59,0xE4292D5A,0xBA3A117E,0x4851927D,0x5B016189,0xA96AE28A,0x7DA08661,0x8FCB0562,0x9C9BF696,0x6EF07595, - 0x417B1DBC,0xB3109EBF,0xA0406D4B,0x522BEE48,0x86E18AA3,0x748A09A0,0x67DAFA54,0x95B17957,0xCBA24573,0x39C9C670,0x2A993584,0xD8F2B687,0x0C38D26C,0xFE53516F,0xED03A29B,0x1F682198, - 0x5125DAD3,0xA34E59D0,0xB01EAA24,0x42752927,0x96BF4DCC,0x64D4CECF,0x77843D3B,0x85EFBE38,0xDBFC821C,0x2997011F,0x3AC7F2EB,0xC8AC71E8,0x1C661503,0xEE0D9600,0xFD5D65F4,0x0F36E6F7, - 0x61C69362,0x93AD1061,0x80FDE395,0x72966096,0xA65C047D,0x5437877E,0x4767748A,0xB50CF789,0xEB1FCBAD,0x197448AE,0x0A24BB5A,0xF84F3859,0x2C855CB2,0xDEEEDFB1,0xCDBE2C45,0x3FD5AF46, - 0x7198540D,0x83F3D70E,0x90A324FA,0x62C8A7F9,0xB602C312,0x44694011,0x5739B3E5,0xA55230E6,0xFB410CC2,0x092A8FC1,0x1A7A7C35,0xE811FF36,0x3CDB9BDD,0xCEB018DE,0xDDE0EB2A,0x2F8B6829, - 0x82F63B78,0x709DB87B,0x63CD4B8F,0x91A6C88C,0x456CAC67,0xB7072F64,0xA457DC90,0x563C5F93,0x082F63B7,0xFA44E0B4,0xE9141340,0x1B7F9043,0xCFB5F4A8,0x3DDE77AB,0x2E8E845F,0xDCE5075C, - 0x92A8FC17,0x60C37F14,0x73938CE0,0x81F80FE3,0x55326B08,0xA759E80B,0xB4091BFF,0x466298FC,0x1871A4D8,0xEA1A27DB,0xF94AD42F,0x0B21572C,0xDFEB33C7,0x2D80B0C4,0x3ED04330,0xCCBBC033, - 0xA24BB5A6,0x502036A5,0x4370C551,0xB11B4652,0x65D122B9,0x97BAA1BA,0x84EA524E,0x7681D14D,0x2892ED69,0xDAF96E6A,0xC9A99D9E,0x3BC21E9D,0xEF087A76,0x1D63F975,0x0E330A81,0xFC588982, - 0xB21572C9,0x407EF1CA,0x532E023E,0xA145813D,0x758FE5D6,0x87E466D5,0x94B49521,0x66DF1622,0x38CC2A06,0xCAA7A905,0xD9F75AF1,0x2B9CD9F2,0xFF56BD19,0x0D3D3E1A,0x1E6DCDEE,0xEC064EED, - 0xC38D26C4,0x31E6A5C7,0x22B65633,0xD0DDD530,0x0417B1DB,0xF67C32D8,0xE52CC12C,0x1747422F,0x49547E0B,0xBB3FFD08,0xA86F0EFC,0x5A048DFF,0x8ECEE914,0x7CA56A17,0x6FF599E3,0x9D9E1AE0, - 0xD3D3E1AB,0x21B862A8,0x32E8915C,0xC083125F,0x144976B4,0xE622F5B7,0xF5720643,0x07198540,0x590AB964,0xAB613A67,0xB831C993,0x4A5A4A90,0x9E902E7B,0x6CFBAD78,0x7FAB5E8C,0x8DC0DD8F, - 0xE330A81A,0x115B2B19,0x020BD8ED,0xF0605BEE,0x24AA3F05,0xD6C1BC06,0xC5914FF2,0x37FACCF1,0x69E9F0D5,0x9B8273D6,0x88D28022,0x7AB90321,0xAE7367CA,0x5C18E4C9,0x4F48173D,0xBD23943E, - 0xF36E6F75,0x0105EC76,0x12551F82,0xE03E9C81,0x34F4F86A,0xC69F7B69,0xD5CF889D,0x27A40B9E,0x79B737BA,0x8BDCB4B9,0x988C474D,0x6AE7C44E,0xBE2DA0A5,0x4C4623A6,0x5F16D052,0xAD7D5351 -#endif }; -#endif // Known size hash // It is ok to call ImHashData on a string with known length but the ### operator won't be supported. @@ -2276,22 +2184,10 @@ ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed) { ImU32 crc = ~seed; const unsigned char* data = (const unsigned char*)data_p; - const unsigned char *data_end = (const unsigned char*)data_p + data_size; -#ifndef IMGUI_ENABLE_SSE4_2_CRC const ImU32* crc32_lut = GCrc32LookupTable; - while (data < data_end) + while (data_size-- != 0) crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++]; return ~crc; -#else - while (data + 4 <= data_end) - { - crc = _mm_crc32_u32(crc, *(ImU32*)data); - data += 4; - } - while (data < data_end) - crc = _mm_crc32_u8(crc, *data++); - return ~crc; -#endif } // Zero-terminated string hash, with support for ### to reset back to seed value @@ -2305,9 +2201,7 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) seed = ~seed; ImU32 crc = seed; const unsigned char* data = (const unsigned char*)data_p; -#ifndef IMGUI_ENABLE_SSE4_2_CRC const ImU32* crc32_lut = GCrc32LookupTable; -#endif if (data_size != 0) { while (data_size-- != 0) @@ -2315,11 +2209,7 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) unsigned char c = *data++; if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#') crc = seed; -#ifndef IMGUI_ENABLE_SSE4_2_CRC crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; -#else - crc = _mm_crc32_u8(crc, c); -#endif } } else @@ -2328,11 +2218,7 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) { if (c == '#' && data[0] == '#' && data[1] == '#') crc = seed; -#ifndef IMGUI_ENABLE_SSE4_2_CRC crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; -#else - crc = _mm_crc32_u8(crc, c); -#endif } } return ~crc; @@ -2347,7 +2233,7 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) ImFileHandle ImFileOpen(const char* filename, const char* mode) { -#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && (defined(__MINGW32__) || (!defined(__CYGWIN__) && !defined(__GNUC__))) +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__) // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32! const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); @@ -2748,11 +2634,12 @@ void ImGuiStorage::BuildSortByKey() { ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), PairComparerByID); } +IM_MSVC_RUNTIME_CHECKS_RESTORE int ImGuiStorage::GetInt(ImGuiID key, int default_val) const { ImGuiStoragePair* it = ImLowerBound(const_cast(Data.Data), const_cast(Data.Data + Data.Size), key); - if (it == Data.Data + Data.Size || it->key != key) + if (it == Data.end() || it->key != key) return default_val; return it->val_i; } @@ -2765,7 +2652,7 @@ bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const { ImGuiStoragePair* it = ImLowerBound(const_cast(Data.Data), const_cast(Data.Data + Data.Size), key); - if (it == Data.Data + Data.Size || it->key != key) + if (it == Data.end() || it->key != key) return default_val; return it->val_f; } @@ -2773,7 +2660,7 @@ float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const void* ImGuiStorage::GetVoidPtr(ImGuiID key) const { ImGuiStoragePair* it = ImLowerBound(const_cast(Data.Data), const_cast(Data.Data + Data.Size), key); - if (it == Data.Data + Data.Size || it->key != key) + if (it == Data.end() || it->key != key) return NULL; return it->val_p; } @@ -2782,7 +2669,7 @@ void* ImGuiStorage::GetVoidPtr(ImGuiID key) const int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val) { ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key); - if (it == Data.Data + Data.Size || it->key != key) + if (it == Data.end() || it->key != key) it = Data.insert(it, ImGuiStoragePair(key, default_val)); return &it->val_i; } @@ -2795,7 +2682,7 @@ bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val) float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) { ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key); - if (it == Data.Data + Data.Size || it->key != key) + if (it == Data.end() || it->key != key) it = Data.insert(it, ImGuiStoragePair(key, default_val)); return &it->val_f; } @@ -2803,7 +2690,7 @@ float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) { ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key); - if (it == Data.Data + Data.Size || it->key != key) + if (it == Data.end() || it->key != key) it = Data.insert(it, ImGuiStoragePair(key, default_val)); return &it->val_p; } @@ -2812,7 +2699,7 @@ void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) void ImGuiStorage::SetInt(ImGuiID key, int val) { ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key); - if (it == Data.Data + Data.Size || it->key != key) + if (it == Data.end() || it->key != key) Data.insert(it, ImGuiStoragePair(key, val)); else it->val_i = val; @@ -2826,7 +2713,7 @@ void ImGuiStorage::SetBool(ImGuiID key, bool val) void ImGuiStorage::SetFloat(ImGuiID key, float val) { ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key); - if (it == Data.Data + Data.Size || it->key != key) + if (it == Data.end() || it->key != key) Data.insert(it, ImGuiStoragePair(key, val)); else it->val_f = val; @@ -2835,7 +2722,7 @@ void ImGuiStorage::SetFloat(ImGuiID key, float val) void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val) { ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key); - if (it == Data.Data + Data.Size || it->key != key) + if (it == Data.end() || it->key != key) Data.insert(it, ImGuiStoragePair(key, val)); else it->val_p = val; @@ -2846,7 +2733,6 @@ void ImGuiStorage::SetAllInt(int v) for (int i = 0; i < Data.Size; i++) Data[i].val_i = v; } -IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- // [SECTION] ImGuiTextFilter @@ -2914,15 +2800,15 @@ void ImGuiTextFilter::Build() bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const { - if (Filters.Size == 0) + if (Filters.empty()) return true; if (text == NULL) - text = text_end = ""; + text = ""; for (const ImGuiTextRange& f : Filters) { - if (f.b == f.e) + if (f.empty()) continue; if (f.b[0] == '-') { @@ -3225,8 +3111,7 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision(clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y); if (affected_by_floating_point_precision) clipper->ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries. - if (clipper->ItemsHeight == 0.0f && clipper->ItemsCount == INT_MAX) // Accept that no item have been submitted if in indeterminate mode. - return false; + IM_ASSERT(clipper->ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!"); calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards. } @@ -3412,7 +3297,7 @@ void ImGui::PopStyleColor(int count) ImGuiContext& g = *GImGui; if (g.ColorStack.Size < count) { - IM_ASSERT_USER_ERROR(0, "Calling PopStyleColor() too many times!"); + IM_ASSERT_USER_ERROR(g.ColorStack.Size > count, "Calling PopStyleColor() too many times!"); count = g.ColorStack.Size; } while (count > 0) @@ -3453,10 +3338,10 @@ static const ImGuiDataVarInfo GStyleVarInfo[] = { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding + { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, LayoutAlign) }, // ImGuiStyleVar_LayoutAlign { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBorderSize) }, // ImGuiStyleVar_TabBorderSize { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBarBorderSize) }, // ImGuiStyleVar_TabBarBorderSize - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBarOverlineSize) }, // ImGuiStyleVar_TabBarOverlineSize { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersAngle)}, // ImGuiStyleVar_TableAngledHeadersAngle { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign @@ -3478,56 +3363,28 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { ImGuiContext& g = *GImGui; const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type != ImGuiDataType_Float || var_info->Count != 1) + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) { - IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); + float* pvar = (float*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; return; } - float* pvar = (float*)var_info->GetVarPtr(&g.Style); - g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); - *pvar = val; -} - -void ImGui::PushStyleVarX(ImGuiStyleVar idx, float val_x) -{ - ImGuiContext& g = *GImGui; - const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type != ImGuiDataType_Float || var_info->Count != 2) - { - IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); - return; - } - ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); - g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); - pvar->x = val_x; -} - -void ImGui::PushStyleVarY(ImGuiStyleVar idx, float val_y) -{ - ImGuiContext& g = *GImGui; - const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type != ImGuiDataType_Float || var_info->Count != 2) - { - IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); - return; - } - ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); - g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); - pvar->y = val_y; + IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); } void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { ImGuiContext& g = *GImGui; const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type != ImGuiDataType_Float || var_info->Count != 2) + if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2) { - IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); + ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); + g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); + *pvar = val; return; } - ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style); - g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar)); - *pvar = val; + IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); } void ImGui::PopStyleVar(int count) @@ -3535,7 +3392,7 @@ void ImGui::PopStyleVar(int count) ImGuiContext& g = *GImGui; if (g.StyleVarStack.Size < count) { - IM_ASSERT_USER_ERROR(0, "Calling PopStyleVar() too many times!"); + IM_ASSERT_USER_ERROR(g.StyleVarStack.Size > count, "Calling PopStyleVar() too many times!"); count = g.StyleVarStack.Size; } while (count > 0) @@ -3610,7 +3467,7 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx) case ImGuiCol_TextLink: return "TextLink"; case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; case ImGuiCol_DragDropTarget: return "DragDropTarget"; - case ImGuiCol_NavCursor: return "NavCursor"; + case ImGuiCol_NavHighlight: return "NavHighlight"; case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg"; case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg"; @@ -3619,6 +3476,7 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx) return "Unknown"; } + //----------------------------------------------------------------------------- // [SECTION] RENDER HELPERS // Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change, @@ -3750,7 +3608,7 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con // min max ellipsis_max // <-> this is generally some padding value - ImFont* font = draw_list->_Data->Font; + const ImFont* font = draw_list->_Data->Font; const float font_size = draw_list->_Data->FontSize; const float font_scale = draw_list->_Data->FontScale; const char* text_end_ellipsis = NULL; @@ -3789,13 +3647,13 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con } // Render a rectangle shaped with optional rounding and borders -void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders, float rounding) +void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding); const float border_size = g.Style.FrameBorderSize; - if (borders && border_size > 0.0f) + if (border && border_size > 0.0f) { window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size); window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size); @@ -3814,26 +3672,24 @@ void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding) } } -void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags) +void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags) { ImGuiContext& g = *GImGui; if (id != g.NavId) return; - if (!g.NavCursorVisible && !(flags & ImGuiNavRenderCursorFlags_AlwaysDraw)) - return; - if (id == g.LastItemData.ID && (g.LastItemData.ItemFlags & ImGuiItemFlags_NoNav)) + if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw)) return; ImGuiWindow* window = g.CurrentWindow; if (window->DC.NavHideHighlightOneFrame) return; - float rounding = (flags & ImGuiNavRenderCursorFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; + float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding; ImRect display_rect = bb; display_rect.ClipWith(window->ClipRect); const float thickness = 2.0f; - if (flags & ImGuiNavRenderCursorFlags_Compact) + if (flags & ImGuiNavHighlightFlags_Compact) { - window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavCursor), rounding, 0, thickness); + window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, thickness); } else { @@ -3842,7 +3698,7 @@ void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFl bool fully_visible = window->ClipRect.Contains(display_rect); if (!fully_visible) window->DrawList->PushClipRect(display_rect.Min, display_rect.Max); - window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavCursor), rounding, 0, thickness); + window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, thickness); if (!fully_visible) window->DrawList->PopClipRect(); } @@ -3851,8 +3707,7 @@ void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFl void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow) { ImGuiContext& g = *GImGui; - if (mouse_cursor <= ImGuiMouseCursor_None || mouse_cursor >= ImGuiMouseCursor_COUNT) // We intentionally accept out of bound values. - mouse_cursor = ImGuiMouseCursor_Arrow; + IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT); ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas; for (ImGuiViewportP* viewport : g.Viewports) { @@ -3932,7 +3787,7 @@ void ImGui::DestroyContext(ImGuiContext* ctx) IM_DELETE(ctx); } -// IMPORTANT: interactive elements requires a fixed ###xxx suffix, it must be same in ALL languages to allow for automation. +// IMPORTANT: ###xxx suffixes must be same in ALL languages to allow for automation. static const ImGuiLocEntry GLocalizationEntriesEnUS[] = { { ImGuiLocKey_VersionStr, "Dear ImGui " IMGUI_VERSION " (" IM_STRINGIFY(IMGUI_VERSION_NUM) ")" }, @@ -3943,240 +3798,12 @@ static const ImGuiLocEntry GLocalizationEntriesEnUS[] = { ImGuiLocKey_WindowingMainMenuBar, "(Main menu bar)" }, { ImGuiLocKey_WindowingPopup, "(Popup)" }, { ImGuiLocKey_WindowingUntitled, "(Untitled)" }, - { ImGuiLocKey_OpenLink_s, "Open '%s'" }, { ImGuiLocKey_CopyLink, "Copy Link###CopyLink" }, - { ImGuiLocKey_DockingHideTabBar, "Hide tab bar###HideTabBar" }, + { ImGuiLocKey_DockingHideTabBar, "Hide tab bar###HideTabBar" }, { ImGuiLocKey_DockingHoldShiftToDock, "Hold SHIFT to enable Docking window." }, { ImGuiLocKey_DockingDragToUndockOrMoveNode,"Click and drag to move or undock whole node." }, }; -ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) -{ - IO.Ctx = this; - InputTextState.Ctx = this; - - Initialized = false; - ConfigFlagsCurrFrame = ConfigFlagsLastFrame = ImGuiConfigFlags_None; - FontAtlasOwnedByContext = shared_font_atlas ? false : true; - Font = NULL; - FontSize = FontBaseSize = FontScale = CurrentDpiScale = 0.0f; - IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); - Time = 0.0f; - FrameCount = 0; - FrameCountEnded = FrameCountPlatformEnded = FrameCountRendered = -1; - WithinEndChildID = 0; - WithinFrameScope = WithinFrameScopeWithImplicitWindow = false; - GcCompactAll = false; - TestEngineHookItems = false; - TestEngine = NULL; - memset(ContextName, 0, sizeof(ContextName)); - - InputEventsNextMouseSource = ImGuiMouseSource_Mouse; - InputEventsNextEventId = 1; - - WindowsActiveCount = 0; - CurrentWindow = NULL; - HoveredWindow = NULL; - HoveredWindowUnderMovingWindow = NULL; - HoveredWindowBeforeClear = NULL; - MovingWindow = NULL; - WheelingWindow = NULL; - WheelingWindowStartFrame = WheelingWindowScrolledFrame = -1; - WheelingWindowReleaseTimer = 0.0f; - - DebugDrawIdConflicts = 0; - DebugHookIdInfo = 0; - HoveredId = HoveredIdPreviousFrame = 0; - HoveredIdPreviousFrameItemCount = 0; - HoveredIdAllowOverlap = false; - HoveredIdIsDisabled = false; - HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f; - ItemUnclipByLog = false; - ActiveId = 0; - ActiveIdIsAlive = 0; - ActiveIdTimer = 0.0f; - ActiveIdIsJustActivated = false; - ActiveIdAllowOverlap = false; - ActiveIdNoClearOnFocusLoss = false; - ActiveIdHasBeenPressedBefore = false; - ActiveIdHasBeenEditedBefore = false; - ActiveIdHasBeenEditedThisFrame = false; - ActiveIdFromShortcut = false; - ActiveIdClickOffset = ImVec2(-1, -1); - ActiveIdWindow = NULL; - ActiveIdSource = ImGuiInputSource_None; - ActiveIdMouseButton = -1; - ActiveIdPreviousFrame = 0; - memset(&DeactivatedItemData, 0, sizeof(DeactivatedItemData)); - memset(&ActiveIdValueOnActivation, 0, sizeof(ActiveIdValueOnActivation)); - LastActiveId = 0; - LastActiveIdTimer = 0.0f; - - LastKeyboardKeyPressTime = LastKeyModsChangeTime = LastKeyModsChangeFromNoneTime = -1.0; - - ActiveIdUsingNavDirMask = 0x00; - ActiveIdUsingAllKeyboardKeys = false; - - CurrentFocusScopeId = 0; - CurrentItemFlags = ImGuiItemFlags_None; - DebugShowGroupRects = false; - - CurrentViewport = NULL; - MouseViewport = MouseLastHoveredViewport = NULL; - PlatformLastFocusedViewportId = 0; - ViewportCreatedCount = PlatformWindowsCreatedCount = 0; - ViewportFocusedStampCount = 0; - - NavCursorVisible = false; - NavHighlightItemUnderNav = false; - NavMousePosDirty = false; - NavIdIsAlive = false; - NavId = 0; - NavWindow = NULL; - NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0; - NavLayer = ImGuiNavLayer_Main; - NavNextActivateId = 0; - NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None; - NavHighlightActivatedId = 0; - NavHighlightActivatedTimer = 0.0f; - NavInputSource = ImGuiInputSource_Keyboard; - NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid; - NavCursorHideFrames = 0; - - NavAnyRequest = false; - NavInitRequest = false; - NavInitRequestFromMove = false; - NavMoveSubmitted = false; - NavMoveScoringItems = false; - NavMoveForwardToNextFrame = false; - NavMoveFlags = ImGuiNavMoveFlags_None; - NavMoveScrollFlags = ImGuiScrollFlags_None; - NavMoveKeyMods = ImGuiMod_None; - NavMoveDir = NavMoveDirForDebug = NavMoveClipDir = ImGuiDir_None; - NavScoringDebugCount = 0; - NavTabbingDir = 0; - NavTabbingCounter = 0; - - NavJustMovedFromFocusScopeId = NavJustMovedToId = NavJustMovedToFocusScopeId = 0; - NavJustMovedToKeyMods = ImGuiMod_None; - NavJustMovedToIsTabbing = false; - NavJustMovedToHasSelectionData = false; - - // All platforms use Ctrl+Tab but Ctrl<>Super are swapped on Mac... - // FIXME: Because this value is stored, it annoyingly interfere with toggling io.ConfigMacOSXBehaviors updating this.. - ConfigNavWindowingKeyNext = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiKey_Tab); - ConfigNavWindowingKeyPrev = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiMod_Shift | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab); - NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL; - NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; - NavWindowingToggleLayer = false; - NavWindowingToggleKey = ImGuiKey_None; - - DimBgRatio = 0.0f; - - DragDropActive = DragDropWithinSource = DragDropWithinTarget = false; - DragDropSourceFlags = ImGuiDragDropFlags_None; - DragDropSourceFrameCount = -1; - DragDropMouseButton = -1; - DragDropTargetId = 0; - DragDropAcceptFlags = ImGuiDragDropFlags_None; - DragDropAcceptIdCurrRectSurface = 0.0f; - DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0; - DragDropAcceptFrameCount = -1; - DragDropHoldJustPressedId = 0; - memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); - - ClipperTempDataStacked = 0; - - CurrentTable = NULL; - TablesTempDataStacked = 0; - CurrentTabBar = NULL; - CurrentMultiSelect = NULL; - MultiSelectTempDataStacked = 0; - - HoverItemDelayId = HoverItemDelayIdPreviousFrame = HoverItemUnlockedStationaryId = HoverWindowUnlockedStationaryId = 0; - HoverItemDelayTimer = HoverItemDelayClearTimer = 0.0f; - - MouseCursor = ImGuiMouseCursor_Arrow; - MouseStationaryTimer = 0.0f; - - TempInputId = 0; - memset(&DataTypeZeroValue, 0, sizeof(DataTypeZeroValue)); - BeginMenuDepth = BeginComboDepth = 0; - ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_; - ColorEditCurrentID = ColorEditSavedID = 0; - ColorEditSavedHue = ColorEditSavedSat = 0.0f; - ColorEditSavedColor = 0; - WindowResizeRelativeMode = false; - ScrollbarSeekMode = 0; - ScrollbarClickDeltaToGrabCenter = 0.0f; - SliderGrabClickOffset = 0.0f; - SliderCurrentAccum = 0.0f; - SliderCurrentAccumDirty = false; - DragCurrentAccumDirty = false; - DragCurrentAccum = 0.0f; - DragSpeedDefaultRatio = 1.0f / 100.0f; - DisabledAlphaBackup = 0.0f; - DisabledStackSize = 0; - TooltipOverrideCount = 0; - TooltipPreviousWindow = NULL; - - PlatformImeData.InputPos = ImVec2(0.0f, 0.0f); - PlatformImeDataPrev.InputPos = ImVec2(-1.0f, -1.0f); // Different to ensure initial submission - PlatformImeViewport = 0; - - DockNodeWindowMenuHandler = NULL; - - SettingsLoaded = false; - SettingsDirtyTimer = 0.0f; - HookIdNext = 0; - - memset(LocalizationTable, 0, sizeof(LocalizationTable)); - - LogEnabled = false; - LogFlags = ImGuiLogFlags_None; - LogWindow = NULL; - LogNextPrefix = LogNextSuffix = NULL; - LogFile = NULL; - LogLinePosY = FLT_MAX; - LogLineFirstItem = false; - LogDepthRef = 0; - LogDepthToExpand = LogDepthToExpandDefault = 2; - - ErrorCallback = NULL; - ErrorCallbackUserData = NULL; - ErrorFirst = true; - ErrorCountCurrentFrame = 0; - StackSizesInBeginForCurrentWindow = NULL; - - DebugDrawIdConflictsCount = 0; - DebugLogFlags = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_OutputToTTY; - DebugLocateId = 0; - DebugLogSkippedErrors = 0; - DebugLogAutoDisableFlags = ImGuiDebugLogFlags_None; - DebugLogAutoDisableFrames = 0; - DebugLocateFrames = 0; - DebugBeginReturnValueCullDepth = -1; - DebugItemPickerActive = false; - DebugItemPickerMouseButton = ImGuiMouseButton_Left; - DebugItemPickerBreakId = 0; - DebugFlashStyleColorTime = 0.0f; - DebugFlashStyleColorIdx = ImGuiCol_COUNT; - DebugHoveredDockNode = NULL; - - // Same as DebugBreakClearData(). Those fields are scattered in their respective subsystem to stay in hot-data locations - DebugBreakInWindow = 0; - DebugBreakInTable = 0; - DebugBreakInLocateId = false; - DebugBreakKeyChord = ImGuiKey_Pause; - DebugBreakInShortcutRouting = ImGuiKey_None; - - memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); - FramerateSecPerFrameIdx = FramerateSecPerFrameCount = 0; - FramerateSecPerFrameAccum = 0.0f; - WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1; - memset(TempKeychordName, 0, sizeof(TempKeychordName)); -} - void ImGui::Initialize() { ImGuiContext& g = *GImGui; @@ -4199,11 +3826,12 @@ void ImGui::Initialize() // Setup default localization table LocalizeRegisterEntries(GLocalizationEntriesEnUS, IM_ARRAYSIZE(GLocalizationEntriesEnUS)); - // Setup default ImGuiPlatformIO clipboard/IME handlers. - g.PlatformIO.Platform_GetClipboardTextFn = Platform_GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations - g.PlatformIO.Platform_SetClipboardTextFn = Platform_SetClipboardTextFn_DefaultImpl; - g.PlatformIO.Platform_OpenInShellFn = Platform_OpenInShellFn_DefaultImpl; - g.PlatformIO.Platform_SetImeDataFn = Platform_SetImeDataFn_DefaultImpl; + // Setup default platform clipboard/IME handlers. + g.IO.GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations + g.IO.SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; + g.IO.ClipboardUserData = (void*)&g; // Default implementation use the ImGuiContext as user data (ideally those would be arguments to the function) + g.IO.PlatformOpenInShellFn = PlatformOpenInShellFn_DefaultImpl; + g.IO.PlatformSetImeDataFn = PlatformSetImeDataFn_DefaultImpl; // Create default viewport ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)(); @@ -4273,7 +3901,7 @@ void ImGui::Shutdown() g.WindowsById.Clear(); g.NavWindow = NULL; g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; - g.ActiveIdWindow = NULL; + g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; g.MovingWindow = NULL; g.KeysRoutingTable.Clear(); @@ -4354,6 +3982,7 @@ void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type) hook.Callback(&g, &hook); } + //----------------------------------------------------------------------------- // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) //----------------------------------------------------------------------------- @@ -4380,13 +4009,12 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NUL LastFrameActive = -1; LastFrameJustFocused = -1; LastTimeActive = -1.0f; - FontRefSize = 0.0f; - FontWindowScale = FontWindowScaleParents = FontDpiScale = 1.0f; + FontWindowScale = FontDpiScale = 1.0f; SettingsOffset = -1; DockOrder = -1; DrawList = &DrawListInst; - DrawList->_OwnerName = Name; DrawList->_Data = &Ctx->DrawListSharedData; + DrawList->_OwnerName = Name; NavPreferredScoringPosRel[0] = NavPreferredScoringPosRel[1] = ImVec2(FLT_MAX, FLT_MAX); IM_PLACEMENT_NEW(&WindowClass) ImGuiWindowClass(); } @@ -4402,12 +4030,11 @@ static void SetCurrentWindow(ImGuiWindow* window) { ImGuiContext& g = *GImGui; g.CurrentWindow = window; - g.StackSizesInBeginForCurrentWindow = g.CurrentWindow ? &g.CurrentWindowStack.back().StackSizesInBegin : NULL; g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL; if (window) { g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); - g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize; + g.FontScale = g.FontSize / g.Font->FontSize; ImGui::NavUpdateCurrentWindowIsScrollPushableX(); } } @@ -4464,16 +4091,9 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) g.MovingWindow = NULL; } - // Store deactivate data - ImGuiDeactivatedItemData* deactivated_data = &g.DeactivatedItemData; - deactivated_data->ID = g.ActiveId; - deactivated_data->ElapseFrame = (g.LastItemData.ID == g.ActiveId) ? g.FrameCount : g.FrameCount + 1; // FIXME: OK to use LastItemData? - deactivated_data->HasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore; - deactivated_data->IsAlive = (g.ActiveIdIsAlive == g.ActiveId); - // This could be written in a more general way (e.g associate a hook to ActiveId), // but since this is currently quite an exception we'll leave it as is. - // One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveID() + // One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveId() if (g.InputTextState.ID == g.ActiveId) InputTextDeactivateHook(g.ActiveId); } @@ -4510,6 +4130,9 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet) g.ActiveIdUsingNavDirMask = 0x00; g.ActiveIdUsingAllKeyboardKeys = false; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + g.ActiveIdUsingNavInputMask = 0x00; +#endif } void ImGui::ClearActiveID() @@ -4534,10 +4157,10 @@ ImGuiID ImGui::GetHoveredID() void ImGui::MarkItemEdited(ImGuiID id) { - // This marking is to be able to provide info for IsItemDeactivatedAfterEdit(). + // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit(). // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data. ImGuiContext& g = *GImGui; - if (g.LastItemData.ItemFlags & ImGuiItemFlags_NoMarkEdited) + if (g.LockMarkEdited > 0) return; if (g.ActiveId == id || g.ActiveId == 0) { @@ -4609,13 +4232,13 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - IM_ASSERT_USER_ERROR((flags & ~ImGuiHoveredFlags_AllowedMaskForIsItemHovered) == 0, "Invalid flags for IsItemHovered()!"); + IM_ASSERT((flags & ~ImGuiHoveredFlags_AllowedMaskForIsItemHovered) == 0 && "Invalid flags for IsItemHovered()!"); - if (g.NavHighlightItemUnderNav && g.NavCursorVisible && !(flags & ImGuiHoveredFlags_NoNavOverride)) + if (g.NavDisableMouseHover && !g.NavDisableHighlight && !(flags & ImGuiHoveredFlags_NoNavOverride)) { - if (!IsItemFocused()) + if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) return false; - if ((g.LastItemData.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + if (!IsItemFocused()) return false; if (flags & ImGuiHoveredFlags_ForTooltip) @@ -4631,6 +4254,8 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) if (flags & ImGuiHoveredFlags_ForTooltip) flags = ApplyHoverFlagsForTooltip(flags, g.Style.HoverFlagsForTooltipMouse); + IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_DockHierarchy)) == 0); // Flags not supported by this function + // Done with rectangle culling so we can perform heavier checks now // Test if we are hovering the right window (our window could be behind another window) // [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851) @@ -4650,11 +4275,11 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) // Test if interactions on this window are blocked by an active popup or modal. // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here. - if (!IsWindowContentHoverable(window, flags) && !(g.LastItemData.ItemFlags & ImGuiItemFlags_NoWindowHoverableCheck)) + if (!IsWindowContentHoverable(window, flags) && !(g.LastItemData.InFlags & ImGuiItemFlags_NoWindowHoverableCheck)) return false; // Test if the item is disabled - if ((g.LastItemData.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) + if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled)) return false; // Special handling for calling after Begin() which represent the title bar or tab. @@ -4664,7 +4289,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) return false; // Test if using AllowOverlap and overlapped - if ((g.LastItemData.ItemFlags & ImGuiItemFlags_AllowOverlap) && id != 0) + if ((g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap) && id != 0) if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByItem) == 0) if (g.HoveredIdPreviousFrame != g.LastItemData.ID) return false; @@ -4675,7 +4300,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) const float delay = CalcDelayFromHoveredFlags(flags); if (delay > 0.0f || (flags & ImGuiHoveredFlags_Stationary)) { - ImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromPos(g.LastItemData.Rect.Min); + ImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromRectangle(g.LastItemData.Rect); if ((flags & ImGuiHoveredFlags_NoSharedDelay) && (g.HoverItemDelayIdPreviousFrame != hover_delay_id)) g.HoverItemDelayTimer = 0.0f; g.HoverItemDelayId = hover_delay_id; @@ -4697,23 +4322,12 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) // (this does not rely on LastItemData it can be called from a ButtonBehavior() call not following an ItemAdd() call) // FIXME-LEGACY: the 'ImGuiItemFlags item_flags' parameter was added on 2023-06-28. // If you used this in your legacy/custom widgets code: -// - Commonly: if your ItemHoverable() call comes after an ItemAdd() call: pass 'item_flags = g.LastItemData.ItemFlags'. +// - Commonly: if your ItemHoverable() call comes after an ItemAdd() call: pass 'item_flags = g.LastItemData.InFlags'. // - Rare: otherwise you may pass 'item_flags = 0' (ImGuiItemFlags_None) unless you want to benefit from special behavior handled by ItemHoverable. bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - - // Detect ID conflicts -#ifndef IMGUI_DISABLE_DEBUG_TOOLS - if (id != 0 && g.HoveredIdPreviousFrame == id && (item_flags & ImGuiItemFlags_AllowDuplicateId) == 0) - { - g.HoveredIdPreviousFrameItemCount++; - if (g.DebugDrawIdConflicts == id) - window->DrawList->AddRect(bb.Min - ImVec2(1,1), bb.Max + ImVec2(1,1), IM_COL32(255, 0, 0, 255), 0.0f, ImDrawFlags_None, 2.0f); - } -#endif - if (g.HoveredWindow != window) return false; if (!IsMouseHoveringRect(bb.Min, bb.Max)) @@ -4753,7 +4367,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag // Display shortcut (only works with mouse) // (ImGuiItemStatusFlags_HasShortcut in LastItemData denotes we want a tooltip) - if (id == g.LastItemData.ID && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasShortcut) && g.ActiveId != id) + if (id == g.LastItemData.ID && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasShortcut)) if (IsItemHovered(ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_DelayNormal)) SetTooltip("%s", GetKeyChordName(g.LastItemData.Shortcut)); } @@ -4782,7 +4396,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag } #endif - if (g.NavHighlightItemUnderNav && (item_flags & ImGuiItemFlags_NoNavDisableMouseHover) == 0) + if (g.NavDisableMouseHover) return false; return true; @@ -4803,30 +4417,15 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id) // This is also inlined in ItemAdd() // Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set g.LastItemData.DisplayRect. -void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags item_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect) +void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect) { ImGuiContext& g = *GImGui; g.LastItemData.ID = item_id; - g.LastItemData.ItemFlags = item_flags; - g.LastItemData.StatusFlags = status_flags; + g.LastItemData.InFlags = in_flags; + g.LastItemData.StatusFlags = item_flags; g.LastItemData.Rect = g.LastItemData.NavRect = item_rect; } -static void ImGui::SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect) -{ - ImGuiContext& g = *GImGui; - if (window->DockIsActive) - SetLastItemData(window->MoveId, g.CurrentItemFlags, window->DC.DockTabItemStatusFlags, window->DC.DockTabItemRect); - else - SetLastItemData(window->MoveId, g.CurrentItemFlags, window->DC.WindowItemStatusFlags, rect); -} - -static void ImGui::SetLastItemDataForChildWindowItem(ImGuiWindow* window, const ImRect& rect) -{ - ImGuiContext& g = *GImGui; - SetLastItemData(window->ChildId, g.CurrentItemFlags, window->DC.ChildItemStatusFlags, rect); -} - float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) { if (wrap_pos_x < 0.0f) @@ -4887,29 +4486,29 @@ void ImGui::DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr } if (size != (size_t)-1) { - //printf("[%05d] MemAlloc(%d) -> 0x%p\n", frame_count, (int)size, ptr); entry->AllocCount++; info->TotalAllocCount++; + //printf("[%05d] MemAlloc(%d) -> 0x%p\n", frame_count, size, ptr); } else { - //printf("[%05d] MemFree(0x%p)\n", frame_count, ptr); entry->FreeCount++; info->TotalFreeCount++; + //printf("[%05d] MemFree(0x%p)\n", frame_count, ptr); } } const char* ImGui::GetClipboardText() { ImGuiContext& g = *GImGui; - return g.PlatformIO.Platform_GetClipboardTextFn ? g.PlatformIO.Platform_GetClipboardTextFn(&g) : ""; + return g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : ""; } void ImGui::SetClipboardText(const char* text) { ImGuiContext& g = *GImGui; - if (g.PlatformIO.Platform_SetClipboardTextFn != NULL) - g.PlatformIO.Platform_SetClipboardTextFn(&g, text); + if (g.IO.SetClipboardTextFn) + g.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text); } const char* ImGui::GetVersion() @@ -4923,26 +4522,12 @@ ImGuiIO& ImGui::GetIO() return GImGui->IO; } -// This variant exists to facilitate backends experimenting with multi-threaded parallel context. (#8069, #6293, #5856) -ImGuiIO& ImGui::GetIOEx(ImGuiContext* ctx) -{ - IM_ASSERT(ctx != NULL); - return ctx->IO; -} - ImGuiPlatformIO& ImGui::GetPlatformIO() { IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext()?"); return GImGui->PlatformIO; } -// This variant exists to facilitate backends experimenting with multi-threaded parallel context. (#8069, #6293, #5856) -ImGuiPlatformIO& ImGui::GetPlatformIOEx(ImGuiContext* ctx) -{ - IM_ASSERT(ctx != NULL); - return ctx->PlatformIO; -} - // Pass this to your backend rendering function! Valid after Render() and until the next call to NewFrame() ImDrawData* ImGui::GetDrawData() { @@ -5012,8 +4597,7 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window) ImGuiContext& g = *GImGui; FocusWindow(window); SetActiveID(window->MoveId, window); - if (g.IO.ConfigNavCursorVisibleAuto) - g.NavCursorVisible = false; + g.NavDisableHighlight = true; g.ActiveIdClickOffset = g.IO.MouseClickedPos[0] - window->RootWindowDockTree->Pos; g.ActiveIdNoClearOnFocusLoss = true; SetActiveIdUsingAllKeyboardKeys(); @@ -5037,7 +4621,7 @@ void ImGui::StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* nod { // Can undock if: // - part of a hierarchy with more than one visible node (if only one is visible, we'll just move the root window) - // - part of a dockspace node hierarchy: so we can undock the last single visible node too. Undocking from a fixed/central node will create a new node and copy windows. + // - part of a dockspace node hierarchy: so we can undock the last single visible node too (trivia: undocking from a fixed/central node will create a new node and copy windows) ImGuiDockNode* root_node = DockNodeGetRootNode(node); if (root_node->OnlyNodeWithWindows != node || root_node->CentralNode != NULL) // -V1051 PVS-Studio thinks node should be root_node and is wrong about that. can_undock_node = true; @@ -5117,13 +4701,12 @@ void ImGui::UpdateMouseMovingWindowNewFrame() } } -// Initiate focusing and moving window when clicking on empty space or title bar. -// Initiate focusing window when clicking on a disabled item. +// Initiate moving window when clicking on empty space or title bar. // Handle left-click and right-click focus. void ImGui::UpdateMouseMovingWindowEndFrame() { ImGuiContext& g = *GImGui; - if (g.ActiveId != 0 || (g.HoveredId != 0 && !g.HoveredIdIsDisabled)) + if (g.ActiveId != 0 || g.HoveredId != 0) return; // Unless we just made a window/popup appear @@ -5149,8 +4732,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame() if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0])) g.MovingWindow = NULL; - // Cancel moving if clicked over an item which was disabled or inhibited by popups - // (when g.HoveredIdIsDisabled == true && g.HoveredId == 0 we are inhibited by popups, when g.HoveredIdIsDisabled == true && g.HoveredId != 0 we are over a disabled item)0 already) + // Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already) if (g.HoveredIdIsDisabled) g.MovingWindow = NULL; } @@ -5164,7 +4746,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame() // With right mouse button we close popups without changing focus based on where the mouse is aimed // Instead, focus will be restored to the window under the bottom-most closed popup. // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger) - if (g.IO.MouseClicked[1] && g.HoveredId == 0) + if (g.IO.MouseClicked[1]) { // Find the top-most window between HoveredWindow and the top-most Modal Window. // This is where we can trim the popup stack. @@ -5273,14 +4855,9 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags() } // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to Dear ImGui only, false = dispatch keyboard info to Dear ImGui + underlying app) - io.WantCaptureKeyboard = false; - if ((io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) == 0) - { - if ((g.ActiveId != 0) || (modal_window != NULL)) - io.WantCaptureKeyboard = true; - else if (io.NavActive && (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && io.ConfigNavCaptureKeyboard) - io.WantCaptureKeyboard = true; - } + io.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL); + if (io.NavActive && (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)) + io.WantCaptureKeyboard = true; if (g.WantCaptureKeyboardNextFrame != -1) // Manual override io.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0); @@ -5288,8 +4865,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags() io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; } -// Called once a frame. Followed by SetCurrentFont() which sets up the remaining data. -// FIXME-VIEWPORT: the concept of a single ClipRectFullscreen is not ideal! +// Calling SetupDrawListSharedData() is followed by SetCurrentFont() which sets up the remaining data. static void SetupDrawListSharedData() { ImGuiContext& g = *GImGui; @@ -5370,12 +4946,6 @@ void ImGui::NewFrame() if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId) KeepAliveID(g.DragDropPayload.SourceId); - // [DEBUG] - if (!g.IO.ConfigDebugHighlightIdConflicts || !g.IO.KeyCtrl) // Count is locked while holding CTRL - g.DebugDrawIdConflicts = 0; - if (g.IO.ConfigDebugHighlightIdConflicts && g.HoveredIdPreviousFrameItemCount > 1) - g.DebugDrawIdConflicts = g.HoveredIdPreviousFrame; - // Update HoveredId data if (!g.HoveredIdPreviousFrame) g.HoveredIdTimer = 0.0f; @@ -5386,7 +4956,6 @@ void ImGui::NewFrame() if (g.HoveredId && g.ActiveId != g.HoveredId) g.HoveredIdNotActiveTimer += g.IO.DeltaTime; g.HoveredIdPreviousFrame = g.HoveredId; - g.HoveredIdPreviousFrameItemCount = 0; g.HoveredId = 0; g.HoveredIdAllowOverlap = false; g.HoveredIdIsDisabled = false; @@ -5405,8 +4974,11 @@ void ImGui::NewFrame() g.ActiveIdTimer += g.IO.DeltaTime; g.LastActiveIdTimer += g.IO.DeltaTime; g.ActiveIdPreviousFrame = g.ActiveId; + g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow; + g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore; g.ActiveIdIsAlive = 0; g.ActiveIdHasBeenEditedThisFrame = false; + g.ActiveIdPreviousFrameIsAlive = false; g.ActiveIdIsJustActivated = false; if (g.TempInputId != 0 && g.ActiveId != g.TempInputId) g.TempInputId = 0; @@ -5414,10 +4986,24 @@ void ImGui::NewFrame() { g.ActiveIdUsingNavDirMask = 0x00; g.ActiveIdUsingAllKeyboardKeys = false; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + g.ActiveIdUsingNavInputMask = 0x00; +#endif } - if (g.DeactivatedItemData.ElapseFrame < g.FrameCount) - g.DeactivatedItemData.ID = 0; - g.DeactivatedItemData.IsAlive = false; + +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + if (g.ActiveId == 0) + g.ActiveIdUsingNavInputMask = 0; + else if (g.ActiveIdUsingNavInputMask != 0) + { + // If your custom widget code used: { g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); } + // Since IMGUI_VERSION_NUM >= 18804 it should be: { SetKeyOwner(ImGuiKey_Escape, g.ActiveId); SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId); } + if (g.ActiveIdUsingNavInputMask & (1 << ImGuiNavInput_Cancel)) + SetKeyOwner(ImGuiKey_Escape, g.ActiveId); + if (g.ActiveIdUsingNavInputMask & ~(1 << ImGuiNavInput_Cancel)) + IM_ASSERT(0); // Other values unsupported + } +#endif // Record when we have been stationary as this state is preserved while over same item. // FIXME: The way this is expressed means user cannot alter HoverStationaryDelay during the frame to use varying values. @@ -5455,7 +5041,6 @@ void ImGui::NewFrame() g.DragDropWithinSource = false; g.DragDropWithinTarget = false; g.DragDropHoldJustPressedId = 0; - g.TooltipPreviousWindow = NULL; // Close popups on focus lost (currently wip/opt-in) //if (g.IO.AppFocusLost) @@ -5469,7 +5054,7 @@ void ImGui::NewFrame() //IM_ASSERT(g.IO.KeyAlt == IsKeyDown(ImGuiKey_LeftAlt) || IsKeyDown(ImGuiKey_RightAlt)); //IM_ASSERT(g.IO.KeySuper == IsKeyDown(ImGuiKey_LeftSuper) || IsKeyDown(ImGuiKey_RightSuper)); - // Update keyboard/gamepad navigation + // Update gamepad/keyboard navigation NavUpdate(); // Update mouse input state @@ -5479,25 +5064,8 @@ void ImGui::NewFrame() // (needs to be before UpdateMouseMovingWindowNewFrame so the window is already offset and following the mouse on the detaching frame) DockContextNewFrameUpdateUndocking(&g); - // Mark all windows as not visible and compact unused memory. - IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size); - const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer; - for (ImGuiWindow* window : g.Windows) - { - window->WasActive = window->Active; - window->Active = false; - window->WriteAccessed = false; - window->BeginCountPreviousFrame = window->BeginCount; - window->BeginCount = 0; - - // Garbage collect transient buffers of recently unused windows - if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time) - GcCompactTransientWindowBuffers(window); - } - // Find hovered window // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame) - // (currently needs to be done after the WasActive=Active loop and FindHoveredWindowEx uses ->Active) UpdateHoveredWindowAndCaptureFlags(); // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering) @@ -5519,6 +5087,22 @@ void ImGui::NewFrame() // Mouse wheel scrolling, scale UpdateMouseWheel(); + // Mark all windows as not visible and compact unused memory. + IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size); + const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer; + for (ImGuiWindow* window : g.Windows) + { + window->WasActive = window->Active; + window->Active = false; + window->WriteAccessed = false; + window->BeginCountPreviousFrame = window->BeginCount; + window->BeginCount = 0; + + // Garbage collect transient buffers of recently unused windows + if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time) + GcCompactTransientWindowBuffers(window); + } + // Garbage collect transient buffers of recently unused tables for (int i = 0; i < g.TablesLastTimeActive.Size; i++) if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time) @@ -5572,10 +5156,6 @@ void ImGui::NewFrame() Begin("Debug##Default"); IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true); - // Store stack sizes - g.ErrorCountCurrentFrame = 0; - ErrorRecoveryStoreState(&g.StackSizesInNewFrame); - // [DEBUG] When io.ConfigDebugBeginReturnValue is set, we make Begin()/BeginChild() return false at different level of the window-stack, // allowing to validate correct Begin/End behavior in user code. #ifndef IMGUI_DISABLE_DEBUG_TOOLS @@ -5692,8 +5272,6 @@ static void InitViewportDrawData(ImGuiViewportP* viewport) // - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect(): // some frequently called functions which to modify both channels and clipping simultaneously tend to use the // more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds. -// - This is analoguous to PushFont()/PopFont() in the sense that are a mixing a global stack and a window stack, -// which in the case of ClipRect is not so problematic but tends to be more restrictive for fonts. void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) { ImGuiWindow* window = GetCurrentWindow(); @@ -5844,21 +5422,17 @@ void ImGui::EndFrame() CallContextHooks(&g, ImGuiContextHookType_EndFramePre); - // [EXPERIMENTAL] Recover from errors - if (g.IO.ConfigErrorRecovery) - ErrorRecoveryTryToRecoverState(&g.StackSizesInNewFrame); ErrorCheckEndFrameSanityChecks(); - ErrorCheckEndFrameFinalizeErrorTooltip(); // Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME) ImGuiPlatformImeData* ime_data = &g.PlatformImeData; - if (g.PlatformIO.Platform_SetImeDataFn != NULL && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0) + if (g.IO.PlatformSetImeDataFn != NULL && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0) { ImGuiViewport* viewport = FindViewportByID(g.PlatformImeViewport); - IMGUI_DEBUG_LOG_IO("[io] Calling Platform_SetImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y); + IMGUI_DEBUG_LOG_IO("[io] Calling io.PlatformSetImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y); if (viewport == NULL) viewport = GetMainViewport(); - g.PlatformIO.Platform_SetImeDataFn(&g, viewport, ime_data); + g.IO.PlatformSetImeDataFn(&g, viewport, ime_data); } // Hide implicit/fallback "Debug" window if it hasn't been used @@ -5889,7 +5463,7 @@ void ImGui::EndFrame() // in the BeginDragDropSource() block of the dragged item, you can submit them from a safe single spot // (e.g. end of your item loop, or before EndFrame) by reading payload data. // In the typical case, the contents of drag tooltip should be possible to infer solely from payload data. - if (g.DragDropActive && g.DragDropSourceFrameCount + 1 < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) + if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) { g.DragDropWithinSource = true; SetTooltip("..."); @@ -6059,7 +5633,7 @@ void ImGui::FindHoveredWindowEx(const ImVec2& pos, bool find_first_and_in_any_vi { ImGuiWindow* window = g.Windows[i]; IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer. - if (!window->WasActive || window->Hidden) + if (!window->Active || window->Hidden) continue; if (window->Flags & ImGuiWindowFlags_NoMouseInputs) continue; @@ -6128,16 +5702,16 @@ bool ImGui::IsItemDeactivated() ImGuiContext& g = *GImGui; if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDeactivated) return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Deactivated) != 0; - return (g.DeactivatedItemData.ID == g.LastItemData.ID && g.LastItemData.ID != 0 && g.DeactivatedItemData.ElapseFrame >= g.FrameCount); + return (g.ActiveIdPreviousFrame == g.LastItemData.ID && g.ActiveIdPreviousFrame != 0 && g.ActiveId != g.LastItemData.ID); } bool ImGui::IsItemDeactivatedAfterEdit() { ImGuiContext& g = *GImGui; - return IsItemDeactivated() && g.DeactivatedItemData.HasBeenEditedBefore; + return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore)); } -// == (GetItemID() == GetFocusID() && GetFocusID() != 0) +// == GetItemID() == GetFocusID() bool ImGui::IsItemFocused() { ImGuiContext& g = *GImGui; @@ -6196,7 +5770,7 @@ bool ImGui::IsAnyItemActive() bool ImGui::IsAnyItemFocused() { ImGuiContext& g = *GImGui; - return g.NavId != 0 && g.NavCursorVisible; + return g.NavId != 0 && !g.NavDisableHighlight; } bool ImGui::IsItemVisible() @@ -6270,7 +5844,7 @@ ImVec2 ImGui::GetItemRectSize() } // Prior to v1.90 2023/10/16, the BeginChild() function took a 'bool border = false' parameter instead of 'ImGuiChildFlags child_flags = 0'. -// ImGuiChildFlags_Borders is defined as always == 1 in order to allow old code passing 'true'. Read comments in imgui.h for details! +// ImGuiChildFlags_Border is defined as always == 1 in order to allow old code passing 'true'. Read comments in imgui.h for details! bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags) { ImGuiID id = GetCurrentWindow()->GetID(str_id); @@ -6289,7 +5863,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I IM_ASSERT(id != 0); // Sanity check as it is likely that some user will accidentally pass ImGuiWindowFlags into the ImGuiChildFlags argument. - const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Borders | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_FrameStyle | ImGuiChildFlags_NavFlattened; + const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_FrameStyle | ImGuiChildFlags_NavFlattened; IM_UNUSED(ImGuiChildFlags_SupportedMask_); IM_ASSERT((child_flags & ~ImGuiChildFlags_SupportedMask_) == 0 && "Illegal ImGuiChildFlags value. Did you pass ImGuiWindowFlags values instead of ImGuiChildFlags?"); IM_ASSERT((window_flags & ImGuiWindowFlags_AlwaysAutoResize) == 0 && "Cannot specify ImGuiWindowFlags_AlwaysAutoResize for BeginChild(). Use ImGuiChildFlags_AlwaysAutoResize!"); @@ -6324,42 +5898,22 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I PushStyleVar(ImGuiStyleVar_ChildRounding, g.Style.FrameRounding); PushStyleVar(ImGuiStyleVar_ChildBorderSize, g.Style.FrameBorderSize); PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.FramePadding); - child_flags |= ImGuiChildFlags_Borders | ImGuiChildFlags_AlwaysUseWindowPadding; + child_flags |= ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding; window_flags |= ImGuiWindowFlags_NoMove; } + // Forward child flags + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasChildFlags; + g.NextWindowData.ChildFlags = child_flags; + // Forward size // Important: Begin() has special processing to switch condition to ImGuiCond_FirstUseEver for a given axis when ImGuiChildFlags_ResizeXXX is set. // (the alternative would to store conditional flags per axis, which is possible but more code) const ImVec2 size_avail = GetContentRegionAvail(); const ImVec2 size_default((child_flags & ImGuiChildFlags_AutoResizeX) ? 0.0f : size_avail.x, (child_flags & ImGuiChildFlags_AutoResizeY) ? 0.0f : size_avail.y); - ImVec2 size = CalcItemSize(size_arg, size_default.x, size_default.y); - - // A SetNextWindowSize() call always has priority (#8020) - // (since the code in Begin() never supported SizeVal==0.0f aka auto-resize via SetNextWindowSize() call, we don't support it here for now) - // FIXME: We only support ImGuiCond_Always in this path. Supporting other paths would requires to obtain window pointer. - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) != 0 && (g.NextWindowData.SizeCond & ImGuiCond_Always) != 0) - { - if (g.NextWindowData.SizeVal.x > 0.0f) - { - size.x = g.NextWindowData.SizeVal.x; - child_flags &= ~ImGuiChildFlags_ResizeX; - } - if (g.NextWindowData.SizeVal.y > 0.0f) - { - size.y = g.NextWindowData.SizeVal.y; - child_flags &= ~ImGuiChildFlags_ResizeY; - } - } + const ImVec2 size = CalcItemSize(size_arg, size_default.x, size_default.y); SetNextWindowSize(size); - // Forward child flags (we allow prior settings to merge but it'll only work for adding flags) - if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasChildFlags) - g.NextWindowData.ChildFlags |= child_flags; - else - g.NextWindowData.ChildFlags = child_flags; - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasChildFlags; - // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value. // FIXME: 2023/11/14: commented out shorted version. We had an issue with multiple ### in child window path names, which the trailing hash helped workaround. // e.g. "ParentName###ParentIdentifier/ChildName###ChildIdentifier" would get hashed incorrectly by ImHashStr(), trailing _%08X somehow fixes it. @@ -6374,7 +5928,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I // Set style const float backup_border_size = g.Style.ChildBorderSize; - if ((child_flags & ImGuiChildFlags_Borders) == 0) + if ((child_flags & ImGuiChildFlags_Border) == 0) g.Style.ChildBorderSize = 0.0f; // Begin into window @@ -6416,10 +5970,10 @@ void ImGui::EndChild() ImGuiContext& g = *GImGui; ImGuiWindow* child_window = g.CurrentWindow; - const ImGuiID backup_within_end_child_id = g.WithinEndChildID; + IM_ASSERT(g.WithinEndChild == false); IM_ASSERT(child_window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() calls - g.WithinEndChildID = child_window->ID; + g.WithinEndChild = true; ImVec2 child_size = child_window->Size; End(); if (child_window->BeginCount == 1) @@ -6431,11 +5985,11 @@ void ImGui::EndChild() if ((child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY) && !nav_flattened) { ItemAdd(bb, child_window->ChildId); - RenderNavCursor(bb, child_window->ChildId); + RenderNavHighlight(bb, child_window->ChildId); // When browsing a window that has no activable items (scroll only) we keep a highlight on the child (pass g.NavId to trick into always displaying) if (child_window->DC.NavLayersActiveMask == 0 && child_window == g.NavWindow) - RenderNavCursor(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavRenderCursorFlags_Compact); + RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_Compact); } else { @@ -6450,15 +6004,8 @@ void ImGui::EndChild() } if (g.HoveredWindow == child_window) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; - child_window->DC.ChildItemStatusFlags = g.LastItemData.StatusFlags; - //SetLastItemDataForChildWindowItem(child_window, child_window->Rect()); // Not needed, effectively done by ItemAdd() } - else - { - SetLastItemDataForChildWindowItem(child_window, child_window->Rect()); - } - - g.WithinEndChildID = backup_within_end_child_id; + g.WithinEndChild = false; g.LogLinePosY = -FLT_MAX; // To enforce a carriage return } @@ -6499,6 +6046,29 @@ static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settin window->DockOrder = settings->DockOrder; } +static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags) +{ + ImGuiContext& g = *GImGui; + + const bool new_is_explicit_child = (new_flags & ImGuiWindowFlags_ChildWindow) != 0 && ((new_flags & ImGuiWindowFlags_Popup) == 0 || (new_flags & ImGuiWindowFlags_ChildMenu) != 0); + const bool child_flag_changed = new_is_explicit_child != window->IsExplicitChild; + if ((just_created || child_flag_changed) && !new_is_explicit_child) + { + IM_ASSERT(!g.WindowsFocusOrder.contains(window)); + g.WindowsFocusOrder.push_back(window); + window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1); + } + else if (!just_created && child_flag_changed && new_is_explicit_child) + { + IM_ASSERT(g.WindowsFocusOrder[window->FocusOrder] == window); + for (int n = window->FocusOrder + 1; n < g.WindowsFocusOrder.Size; n++) + g.WindowsFocusOrder[n]->FocusOrder--; + g.WindowsFocusOrder.erase(g.WindowsFocusOrder.Data + window->FocusOrder); + window->FocusOrder = -1; + } + window->IsExplicitChild = new_is_explicit_child; +} + static void InitOrLoadWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings) { // Initial window state with e.g. default/arbitrary window position @@ -6842,7 +6412,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si ButtonBehavior(resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255)); if (hovered || held) - SetMouseCursor((resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE); + g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE; if (held && g.IO.MouseDoubleClicked[0]) { @@ -6888,7 +6458,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si if (hovered && g.HoveredIdTimer <= WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) hovered = false; if (hovered || held) - SetMouseCursor((axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS); + g.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS; if (held && g.IO.MouseDoubleClicked[0]) { // Double-clicking bottom or right border auto-fit on this axis @@ -6979,7 +6549,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si g.NavWindowingAccumDeltaSize += nav_resize_dir * resize_step; g.NavWindowingAccumDeltaSize = ImMax(g.NavWindowingAccumDeltaSize, clamp_rect.Min - window->Pos - window->Size); // We need Pos+Size >= clmap_rect.Min, so Size >= clmap_rect.Min - Pos, so size_delta >= clmap_rect.Min - window->Pos - window->Size g.NavWindowingToggleLayer = false; - g.NavHighlightItemUnderNav = true; + g.NavDisableMouseHover = true; resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive); ImVec2 accum_floored = ImTrunc(g.NavWindowingAccumDeltaSize); if (accum_floored.x != 0.0f || accum_floored.y != 0.0f) @@ -7056,7 +6626,7 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive) { float y = window->Pos.y + window->TitleBarHeight - 1; - window->DrawList->AddLine(ImVec2(window->Pos.x + border_size * 0.5f, y), ImVec2(window->Pos.x + window->Size.x - border_size * 0.5f, y), border_col, g.Style.FrameBorderSize); + window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), border_col, g.Style.FrameBorderSize); } } @@ -7068,10 +6638,9 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar ImGuiStyle& style = g.Style; ImGuiWindowFlags flags = window->Flags; - // Ensure that Scrollbar() doesn't read last frame's SkipItems + // Ensure that ScrollBar doesn't read last frame's SkipItems IM_ASSERT(window->BeginCount == 0); window->SkipItems = false; - window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; // Draw window + handle manual resize // As we highlight the title bar when want_focus is set, multiple reappearing windows will have their title bar highlighted on their reappearing frame. @@ -7082,7 +6651,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar // Title bar only const float backup_border_size = style.FrameBorderSize; g.Style.FrameBorderSize = window->WindowBorderSize; - ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && g.NavCursorVisible) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); + ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed); if (window->ViewportOwned) title_bar_col |= IM_COL32_A_MASK; // No alpha (we don't support is_docking_transparent_payload here because simpler and less meaningful, but could with a bit of code shuffle/reuse) RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding); @@ -7153,9 +6722,9 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar { ImRect menu_bar_rect = window->MenuBarRect(); menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. - window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop); + window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop); if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) - window->DrawList->AddLine(menu_bar_rect.GetBL() + ImVec2(window_border_size * 0.5f, 0.0f), menu_bar_rect.GetBR() - ImVec2(window_border_size * 0.5f, 0.0f), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); + window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); } // Docking: Unhide tab bar (small triangle in the corner), drag from small triangle to quickly undock @@ -7195,10 +6764,9 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar continue; const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); - const float border_inner = IM_ROUND(window_border_size * 0.5f); - window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(border_inner, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, border_inner))); - window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, border_inner) : ImVec2(border_inner, resize_grip_draw_size))); - window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + border_inner), corner.y + grip.InnerDir.y * (window_rounding + border_inner)), window_rounding, grip.AngleMin12, grip.AngleMax12); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size))); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size))); + window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12); window->DrawList->PathFillConvex(col); } } @@ -7207,7 +6775,6 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar if (handle_borders_and_resize_grips && !window->DockNodeAsHost) RenderWindowOuterBorders(window); } - window->DC.NavLayerCurrent = ImGuiNavLayer_Main; } // When inside a dock node, this is handled in DockNodeCalcTabBarLayout() instead. @@ -7336,26 +6903,49 @@ void ImGui::UpdateWindowSkipRefresh(ImGuiWindow* window) return; if (window->Hidden) // If was hidden (previous frame) return; - if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnHover) && g.HoveredWindow) - if (window->RootWindow == g.HoveredWindow->RootWindow || IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, window)) - return; - if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnFocus) && g.NavWindow) - if (window->RootWindow == g.NavWindow->RootWindow || IsWindowWithinBeginStackOf(g.NavWindow->RootWindow, window)) - return; + if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnHover) && g.HoveredWindow && window->RootWindow == g.HoveredWindow->RootWindow) + return; + if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnFocus) && g.NavWindow && window->RootWindow == g.NavWindow->RootWindow) + return; window->DrawList = NULL; window->SkipRefresh = true; } } -static void SetWindowActiveForSkipRefresh(ImGuiWindow* window) +// When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing) +// should be positioned behind that modal window, unless the window was created inside the modal begin-stack. +// In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent. +// - WindowA // FindBlockingModal() returns Modal1 +// - WindowB // .. returns Modal1 +// - Modal1 // .. returns Modal2 +// - WindowC // .. returns Modal2 +// - WindowD // .. returns Modal2 +// - Modal2 // .. returns Modal2 +// - WindowE // .. returns NULL +// Notes: +// - FindBlockingModal(NULL) == NULL is generally equivalent to GetTopMostPopupModal() == NULL. +// Only difference is here we check for ->Active/WasActive but it may be unnecessary. +ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) { - window->Active = true; - for (ImGuiWindow* child : window->DC.ChildWindows) - if (!child->Hidden) - { - child->Active = child->SkipRefresh = true; - SetWindowActiveForSkipRefresh(child); - } + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size <= 0) + return NULL; + + // Find a modal that has common parent with specified window. Specified window should be positioned behind that modal. + for (ImGuiPopupData& popup_data : g.OpenPopupStack) + { + ImGuiWindow* popup_window = popup_data.Window; + if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal)) + continue; + if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows. + continue; + if (window == NULL) // FindBlockingModal(NULL) test for if FocusWindow(NULL) is naturally possible via a mouse click. + return popup_window; + if (IsWindowWithinBeginStackOf(window, popup_window)) // Window may be over modal + continue; + return popup_window; // Place window right below first block modal + } + return NULL; } // Push a new Dear ImGui window to add widgets to. @@ -7466,13 +7056,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Add to stack g.CurrentWindow = window; - g.CurrentWindowStack.resize(g.CurrentWindowStack.Size + 1); - ImGuiWindowStackData& window_stack_data = g.CurrentWindowStack.back(); + ImGuiWindowStackData window_stack_data; window_stack_data.Window = window; window_stack_data.ParentLastItemDataBackup = g.LastItemData; + window_stack_data.StackSizesOnBegin.SetToContextState(&g); window_stack_data.DisabledOverrideReenable = (flags & ImGuiWindowFlags_Tooltip) && (g.CurrentItemFlags & ImGuiItemFlags_Disabled); - ErrorRecoveryStoreState(&window_stack_data.StackSizesInBegin); - g.StackSizesInBeginForCurrentWindow = &window_stack_data.StackSizesInBegin; + g.CurrentWindowStack.push_back(window_stack_data); if (flags & ImGuiWindowFlags_ChildMenu) g.BeginMenuDepth++; @@ -7496,9 +7085,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->ParentWindowForFocusRoute = FindWindowByID(window->WindowClass.FocusRouteParentWindowId); IM_ASSERT(window->ParentWindowForFocusRoute != 0); // Invalid value for FocusRouteParentWindowId. } - - // Inherit SetWindowFontScale() from parent until we fix this system... - window->FontWindowScaleParents = parent_window ? parent_window->FontWindowScaleParents * parent_window->FontWindowScale : 1.0f; } // Add to focus scope stack @@ -7676,7 +7262,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y; window->TitleBarHeight = (flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : g.FontSize + g.Style.FramePadding.y * 2.0f; window->MenuBarHeight = (flags & ImGuiWindowFlags_MenuBar) ? window->DC.MenuBarOffset.y + g.FontSize + g.Style.FramePadding.y * 2.0f : 0.0f; - window->FontRefSize = g.FontSize; // Lock this to discourage calling window->CalcFontSize() outside of current window. // Depending on condition we use previous or current window size to compare against contents size to decide if a scrollbar should be visible. // Those flags will be altered further down in the function depending on more conditions. @@ -7691,10 +7276,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse) && !window->DockIsActive) { - // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), - // so verify that we don't have items over the title bar. + // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar. ImRect title_bar_rect = window->TitleBarRect(); - if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && g.ActiveId == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max)) + if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max)) if (g.IO.MouseClickedCount[0] == 2 && GetKeyOwner(ImGuiKey_MouseLeft) == ImGuiKeyOwner_NoOwner) window->WantCollapseToggle = true; if (window->WantCollapseToggle) @@ -7871,12 +7455,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { IM_ASSERT(window->IDStack.Size == 1); window->IDStack.Size = 0; // As window->IDStack[0] == window->ID here, make sure TestEngine doesn't erroneously see window as parent of itself. - window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; IMGUI_TEST_ENGINE_ITEM_ADD(window->ID, window->Rect(), NULL); IMGUI_TEST_ENGINE_ITEM_INFO(window->ID, window->Name, (g.HoveredWindow == window) ? ImGuiItemStatusFlags_HoveredRect : 0); window->IDStack.Size = 1; - window->DC.NavLayerCurrent = ImGuiNavLayer_Main; - } #endif @@ -7976,14 +7557,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Affected by window/frame border size. Used by: // - Begin() initial clip rect float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize); - - // Try to match the fact that our border is drawn centered over the window rectangle, rather than inner. - // This is why we do a *0.5f here. We don't currently even technically support large values for WindowBorderSize, - // see e.g #7887 #7888, but may do after we move the window border to become an inner border (and then we can remove the 0.5f here). - window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + window->WindowBorderSize * 0.5f); - window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size * 0.5f); - window->InnerClipRect.Max.x = ImFloor(window->InnerRect.Max.x - window->WindowBorderSize * 0.5f); - window->InnerClipRect.Max.y = ImFloor(window->InnerRect.Max.y - window->WindowBorderSize * 0.5f); + window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + window->WindowBorderSize); + window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size); + window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - window->WindowBorderSize); + window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize); window->InnerClipRect.ClipWithFull(host_rect); // Default item width. Make it proportional to window size if window manually resizes @@ -8137,24 +7714,22 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) g.NavWindowingToggleLayer = false; // Assume user mapped PlatformRequestClose on ALT-F4 so we disable ALT for menu toggle. False positive not an issue. // FIXME-NAV: Try removing. } - // Pressing CTRL+C copy window content into the clipboard - // [EXPERIMENTAL] Breaks on nested Begin/End pairs. We need to work that out and add better logging scope. - // [EXPERIMENTAL] Text outputs has many issues. - if (g.IO.ConfigWindowsCopyContentsWithCtrlC) - if (g.NavWindow && g.NavWindow->RootWindow == window && g.ActiveId == 0 && Shortcut(ImGuiMod_Ctrl | ImGuiKey_C)) - LogToClipboard(0); - // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive) RenderWindowTitleBarContents(window, ImRect(title_bar_rect.Min.x + window->WindowBorderSize, title_bar_rect.Min.y, title_bar_rect.Max.x - window->WindowBorderSize, title_bar_rect.Max.y), name, p_open); - else if (!(flags & ImGuiWindowFlags_NoTitleBar) && window->DockIsActive) - LogText("%.*s\n", (int)(FindRenderedTextEnd(window->Name) - window->Name), window->Name); // Clear hit test shape every frame window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0; - if (flags & ImGuiWindowFlags_Tooltip) - g.TooltipPreviousWindow = window; + // Pressing CTRL+C while holding on a window copy its content to the clipboard + // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. + // Maybe we can support CTRL+C on every element? + /* + //if (g.NavWindow == window && g.ActiveId == 0) + if (g.ActiveId == window->MoveId) + if (g.IO.KeyCtrl && IsKeyPressed(ImGuiKey_C)) + LogToClipboard(); + */ if (g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable) { @@ -8172,8 +7747,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). // This is useful to allow creating context menus on title bar only, etc. - window->DC.WindowItemStatusFlags = ImGuiItemStatusFlags_None; - window->DC.WindowItemStatusFlags |= IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0; SetLastItemDataForWindow(window, title_bar_rect); // [DEBUG] @@ -8185,18 +7758,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // [Test Engine] Register title bar / tab with MoveId. #ifdef IMGUI_ENABLE_TEST_ENGINE if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) - { - window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; IMGUI_TEST_ENGINE_ITEM_ADD(g.LastItemData.ID, g.LastItemData.Rect, &g.LastItemData); - window->DC.NavLayerCurrent = ImGuiNavLayer_Main; - } #endif } else { // Skip refresh always mark active if (window->SkipRefresh) - SetWindowActiveForSkipRefresh(window); + window->Active = true; // Append SetCurrentViewport(window, window->Viewport); @@ -8302,6 +7871,15 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) return !window->SkipItems; } +static void ImGui::SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect) +{ + ImGuiContext& g = *GImGui; + if (window->DockIsActive) + SetLastItemData(window->MoveId, g.CurrentItemFlags, window->DockTabItemStatusFlags, window->DockTabItemRect); + else + SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(rect.Min, rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, rect); +} + void ImGui::End() { ImGuiContext& g = *GImGui; @@ -8317,7 +7895,7 @@ void ImGui::End() // Error checking: verify that user doesn't directly call End() on a child window. if ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_DockNodeHost) && !window->DockIsActive) - IM_ASSERT_USER_ERROR(g.WithinEndChildID == window->ID, "Must call EndChild() and not End()!"); + IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!"); // Close anything that is open if (window->DC.CurrentColumns) @@ -8335,7 +7913,7 @@ void ImGui::End() } // Stop logging - if (g.LogWindow == window) // FIXME: add more options for scope of logging + if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging LogFinish(); if (window->DC.IsSetPos) @@ -8352,17 +7930,198 @@ void ImGui::End() g.BeginMenuDepth--; if (window->Flags & ImGuiWindowFlags_Popup) g.BeginPopupStack.pop_back(); - - // Error handling, state recovery - if (g.IO.ConfigErrorRecovery) - ErrorRecoveryTryToRecoverWindowState(&window_stack_data.StackSizesInBegin); - + window_stack_data.StackSizesOnBegin.CompareWithContextState(&g); g.CurrentWindowStack.pop_back(); SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window); if (g.CurrentWindow) SetCurrentViewport(g.CurrentWindow, g.CurrentWindow->Viewport); } +void ImGui::BringWindowToFocusFront(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(window == window->RootWindow); + + const int cur_order = window->FocusOrder; + IM_ASSERT(g.WindowsFocusOrder[cur_order] == window); + if (g.WindowsFocusOrder.back() == window) + return; + + const int new_order = g.WindowsFocusOrder.Size - 1; + for (int n = cur_order; n < new_order; n++) + { + g.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1]; + g.WindowsFocusOrder[n]->FocusOrder--; + IM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n); + } + g.WindowsFocusOrder[new_order] = window; + window->FocusOrder = (short)new_order; +} + +void ImGui::BringWindowToDisplayFront(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* current_front_window = g.Windows.back(); + if (current_front_window == window || current_front_window->RootWindowDockTree == window) // Cheap early out (could be better) + return; + for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window + if (g.Windows[i] == window) + { + memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*)); + g.Windows[g.Windows.Size - 1] = window; + break; + } +} + +void ImGui::BringWindowToDisplayBack(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.Windows[0] == window) + return; + for (int i = 0; i < g.Windows.Size; i++) + if (g.Windows[i] == window) + { + memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*)); + g.Windows[0] = window; + break; + } +} + +void ImGui::BringWindowToDisplayBehind(ImGuiWindow* window, ImGuiWindow* behind_window) +{ + IM_ASSERT(window != NULL && behind_window != NULL); + ImGuiContext& g = *GImGui; + window = window->RootWindow; + behind_window = behind_window->RootWindow; + int pos_wnd = FindWindowDisplayIndex(window); + int pos_beh = FindWindowDisplayIndex(behind_window); + if (pos_wnd < pos_beh) + { + size_t copy_bytes = (pos_beh - pos_wnd - 1) * sizeof(ImGuiWindow*); + memmove(&g.Windows.Data[pos_wnd], &g.Windows.Data[pos_wnd + 1], copy_bytes); + g.Windows[pos_beh - 1] = window; + } + else + { + size_t copy_bytes = (pos_wnd - pos_beh) * sizeof(ImGuiWindow*); + memmove(&g.Windows.Data[pos_beh + 1], &g.Windows.Data[pos_beh], copy_bytes); + g.Windows[pos_beh] = window; + } +} + +int ImGui::FindWindowDisplayIndex(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + return g.Windows.index_from_ptr(g.Windows.find(window)); +} + +// Moving window to front of display and set focus (which happens to be back of our sorted list) +void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags) +{ + ImGuiContext& g = *GImGui; + + // Modal check? + if ((flags & ImGuiFocusRequestFlags_UnlessBelowModal) && (g.NavWindow != window)) // Early out in common case. + if (ImGuiWindow* blocking_modal = FindBlockingModal(window)) + { + // This block would typically be reached in two situations: + // - API call to FocusWindow() with a window under a modal and ImGuiFocusRequestFlags_UnlessBelowModal flag. + // - User clicking on void or anything behind a modal while a modal is open (window == NULL) + IMGUI_DEBUG_LOG_FOCUS("[focus] FocusWindow(\"%s\", UnlessBelowModal): prevented by \"%s\".\n", window ? window->Name : "", blocking_modal->Name); + if (window && window == window->RootWindow && (window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) + BringWindowToDisplayBehind(window, blocking_modal); // Still bring right under modal. (FIXME: Could move in focus list too?) + ClosePopupsOverWindow(GetTopMostPopupModal(), false); // Note how we need to use GetTopMostPopupModal() aad NOT blocking_modal, to handle nested modals + return; + } + + // Find last focused child (if any) and focus it instead. + if ((flags & ImGuiFocusRequestFlags_RestoreFocusedChild) && window != NULL) + window = NavRestoreLastChildNavWindow(window); + + // Apply focus + if (g.NavWindow != window) + { + SetNavWindow(window); + if (window && g.NavDisableMouseHover) + g.NavMousePosDirty = true; + g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId + g.NavLayer = ImGuiNavLayer_Main; + SetNavFocusScope(window ? window->NavRootFocusScopeId : 0); + g.NavIdIsAlive = false; + g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid; + + // Close popups if any + ClosePopupsOverWindow(window, false); + } + + // Move the root window to the top of the pile + IM_ASSERT(window == NULL || window->RootWindowDockTree != NULL); + ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; + ImGuiWindow* display_front_window = window ? window->RootWindowDockTree : NULL; + ImGuiDockNode* dock_node = window ? window->DockNode : NULL; + bool active_id_window_is_dock_node_host = (g.ActiveIdWindow && dock_node && dock_node->HostWindow == g.ActiveIdWindow); + + // Steal active widgets. Some of the cases it triggers includes: + // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run. + // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId) + // - Using dock host items (tab, collapse button) can trigger this before we redirect the ActiveIdWindow toward the child window. + if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window) + if (!g.ActiveIdNoClearOnFocusLoss && !active_id_window_is_dock_node_host) + ClearActiveID(); + + // Passing NULL allow to disable keyboard focus + if (!window) + return; + window->LastFrameJustFocused = g.FrameCount; + + // Select in dock node + // For #2304 we avoid applying focus immediately before the tabbar is visible. + //if (dock_node && dock_node->TabBar) + // dock_node->TabBar->SelectedTabId = dock_node->TabBar->NextSelectedTabId = window->TabId; + + // Bring to front + BringWindowToFocusFront(focus_front_window); + if (((window->Flags | focus_front_window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) + BringWindowToDisplayFront(display_front_window); +} + +void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags) +{ + ImGuiContext& g = *GImGui; + int start_idx = g.WindowsFocusOrder.Size - 1; + if (under_this_window != NULL) + { + // Aim at root window behind us, if we are in a child window that's our own root (see #4640) + int offset = -1; + while (under_this_window->Flags & ImGuiWindowFlags_ChildWindow) + { + under_this_window = under_this_window->ParentWindow; + offset = 0; + } + start_idx = FindWindowFocusIndex(under_this_window) + offset; + } + for (int i = start_idx; i >= 0; i--) + { + // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user. + ImGuiWindow* window = g.WindowsFocusOrder[i]; + if (window == ignore_window || !window->WasActive) + continue; + if (filter_viewport != NULL && window->Viewport != filter_viewport) + continue; + if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) + { + // FIXME-DOCK: When ImGuiFocusRequestFlags_RestoreFocusedChild is set... + // This is failing (lagging by one frame) for docked windows. + // If A and B are docked into window and B disappear, at the NewFrame() call site window->NavLastChildNavWindow will still point to B. + // We might leverage the tab order implicitly stored in window->DockNodeAsHost->TabBar (essentially the 'most_recently_selected_tab' code in tab bar will do that but on next update) + // to tell which is the "previous" window. Or we may leverage 'LastFrameFocused/LastFrameJustFocused' and have this function handle child window itself? + FocusWindow(window, flags); + return; + } + } + FocusWindow(NULL, flags); +} + // Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only. void ImGui::SetCurrentFont(ImFont* font) { @@ -8382,35 +8141,22 @@ void ImGui::SetCurrentFont(ImFont* font) g.DrawListSharedData.FontScale = g.FontScale; } -// Use ImDrawList::_SetTextureID(), making our shared g.FontStack[] authorative against window-local ImDrawList. -// - Whereas ImDrawList::PushTextureID()/PopTextureID() is not to be used across Begin() calls. -// - Note that we don't propagate current texture id when e.g. Begin()-ing into a new window, we never really did... -// - Some code paths never really fully worked with multiple atlas textures. -// - The right-ish solution may be to remove _SetTextureID() and make AddText/RenderText lazily call PushTextureID()/PopTextureID() -// the same way AddImage() does, but then all other primitives would also need to? I don't think we should tackle this problem -// because we have a concrete need and a test bed for multiple atlas textures. void ImGui::PushFont(ImFont* font) { ImGuiContext& g = *GImGui; - if (font == NULL) + if (!font) font = GetDefaultFont(); - g.FontStack.push_back(font); SetCurrentFont(font); - g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); + g.FontStack.push_back(font); + g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID); } void ImGui::PopFont() { ImGuiContext& g = *GImGui; - if (g.FontStack.Size <= 0) - { - IM_ASSERT_USER_ERROR(0, "Calling PopFont() too many times!"); - return; - } + g.CurrentWindow->DrawList->PopTextureID(); g.FontStack.pop_back(); - ImFont* font = g.FontStack.Size == 0 ? GetDefaultFont() : g.FontStack.back(); - SetCurrentFont(font); - g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); + SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back()); } void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) @@ -8429,11 +8175,7 @@ void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) void ImGui::PopItemFlag() { ImGuiContext& g = *GImGui; - if (g.ItemFlagsStack.Size <= 1) - { - IM_ASSERT_USER_ERROR(0, "Calling PopItemFlag() too many times!"); - return; - } + IM_ASSERT(g.ItemFlagsStack.Size > 1); // Too many calls to PopItemFlag() - we always leave a 0 at the bottom of the stack. g.ItemFlagsStack.pop_back(); g.CurrentItemFlags = g.ItemFlagsStack.back(); } @@ -8442,9 +8184,8 @@ void ImGui::PopItemFlag() // - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled) // - Visually this is currently altering alpha, but it is expected that in a future styling system this would work differently. // - Feedback welcome at https://github.com/ocornut/imgui/issues/211 -// - BeginDisabled(false)/EndDisabled() essentially does nothing but is provided to facilitate use of boolean expressions. -// (as a micro-optimization: if you have tens of thousands of BeginDisabled(false)/EndDisabled() pairs, you might want to reformulate your code to avoid making those calls) -// - Note: mixing up BeginDisabled() and PushItemFlag(ImGuiItemFlags_Disabled) is currently NOT SUPPORTED. +// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it. +// - Optimized shortcuts instead of PushStyleVar() + PushItemFlag() void ImGui::BeginDisabled(bool disabled) { ImGuiContext& g = *GImGui; @@ -8463,11 +8204,7 @@ void ImGui::BeginDisabled(bool disabled) void ImGui::EndDisabled() { ImGuiContext& g = *GImGui; - if (g.DisabledStackSize <= 0) - { - IM_ASSERT_USER_ERROR(0, "Calling EndDisabled() too many times!"); - return; - } + IM_ASSERT(g.DisabledStackSize > 0); g.DisabledStackSize--; bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0; //PopItemFlag(); @@ -8502,21 +8239,14 @@ void ImGui::EndDisabledOverrideReenable() void ImGui::PushTextWrapPos(float wrap_pos_x) { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; + ImGuiWindow* window = GetCurrentWindow(); window->DC.TextWrapPosStack.push_back(window->DC.TextWrapPos); window->DC.TextWrapPos = wrap_pos_x; } void ImGui::PopTextWrapPos() { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - if (window->DC.TextWrapPosStack.Size <= 0) - { - IM_ASSERT_USER_ERROR(0, "Calling PopTextWrapPos() too many times!"); - return; - } + ImGuiWindow* window = GetCurrentWindow(); window->DC.TextWrapPos = window->DC.TextWrapPosStack.back(); window->DC.TextWrapPosStack.pop_back(); } @@ -8591,9 +8321,9 @@ bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_b // Refer to FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" for details. bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) { - ImGuiContext& g = *GImGui; - IM_ASSERT_USER_ERROR((flags & ~ImGuiHoveredFlags_AllowedMaskForIsWindowHovered) == 0, "Invalid flags for IsWindowHovered()!"); + IM_ASSERT((flags & ~ImGuiHoveredFlags_AllowedMaskForIsWindowHovered) == 0 && "Invalid flags for IsWindowHovered()!"); + ImGuiContext& g = *GImGui; ImGuiWindow* ref_window = g.HoveredWindow; ImGuiWindow* cur_window = g.CurrentWindow; if (ref_window == NULL) @@ -8635,6 +8365,29 @@ bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) return true; } +bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* ref_window = g.NavWindow; + ImGuiWindow* cur_window = g.CurrentWindow; + + if (ref_window == NULL) + return false; + if (flags & ImGuiFocusedFlags_AnyWindow) + return true; + + IM_ASSERT(cur_window); // Not inside a Begin()/End() + const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0; + const bool dock_hierarchy = (flags & ImGuiFocusedFlags_DockHierarchy) != 0; + if (flags & ImGuiHoveredFlags_RootWindow) + cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy, dock_hierarchy); + + if (flags & ImGuiHoveredFlags_ChildWindows) + return IsWindowChildOf(ref_window, cur_window, popup_hierarchy, dock_hierarchy); + else + return (ref_window == cur_window); +} + ImGuiID ImGui::GetWindowDockID() { ImGuiContext& g = *GImGui; @@ -8647,6 +8400,14 @@ bool ImGui::IsWindowDocked() return g.CurrentWindow->DockIsActive; } +// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext) +// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically. +// If you want a window to never be focused, you may use the e.g. NoInputs flag. +bool ImGui::IsWindowNavFocusable(ImGuiWindow* window) +{ + return window->WasActive && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus); +} + float ImGui::GetWindowWidth() { ImGuiWindow* window = GImGui->CurrentWindow; @@ -8795,6 +8556,24 @@ void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond) SetWindowCollapsed(window, collapsed, cond); } +void ImGui::SetWindowFocus() +{ + FocusWindow(GImGui->CurrentWindow); +} + +void ImGui::SetWindowFocus(const char* name) +{ + if (name) + { + if (ImGuiWindow* window = FindWindowByName(name)) + FocusWindow(window); + } + else + { + FocusWindow(NULL); + } +} + void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot) { ImGuiContext& g = *GImGui; @@ -8853,6 +8632,12 @@ void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always; } +void ImGui::SetNextWindowFocus() +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus; +} + void ImGui::SetNextWindowBgAlpha(float alpha) { ImGuiContext& g = *GImGui; @@ -8948,9 +8733,9 @@ void ImGui::PushFocusScope(ImGuiID id) void ImGui::PopFocusScope() { ImGuiContext& g = *GImGui; - if (g.FocusScopeStack.Size <= g.StackSizesInBeginForCurrentWindow->SizeOfFocusScopeStack) + if (g.FocusScopeStack.Size == 0) { - IM_ASSERT_USER_ERROR(0, "Calling PopFocusScope() too many times!"); + IM_ASSERT_USER_ERROR(g.FocusScopeStack.Size > 0, "Calling PopFocusScope() too many times!"); return; } g.FocusScopeStack.pop_back(); @@ -8996,7 +8781,7 @@ void ImGui::FocusItem() return; } - ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_FocusApi | ImGuiNavMoveFlags_NoSetNavCursorVisible | ImGuiNavMoveFlags_NoSelect; + ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_FocusApi | ImGuiNavMoveFlags_NoSetNavHighlight | ImGuiNavMoveFlags_NoSelect; ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; SetNavWindow(window); NavMoveRequestSubmit(ImGuiDir_None, ImGuiDir_Up, move_flags, scroll_flags); @@ -9031,7 +8816,7 @@ void ImGui::SetKeyboardFocusHere(int offset) SetNavWindow(window); - ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_Activate | ImGuiNavMoveFlags_FocusApi | ImGuiNavMoveFlags_NoSetNavCursorVisible; + ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_Activate | ImGuiNavMoveFlags_FocusApi | ImGuiNavMoveFlags_NoSetNavHighlight; ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; NavMoveRequestSubmit(ImGuiDir_None, offset < 0 ? ImGuiDir_Up : ImGuiDir_Down, move_flags, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable. if (offset == -1) @@ -9093,7 +8878,6 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) // This is one of the very rare legacy case where we use ImGuiWindow methods, // it should ideally be flattened at some point but it's been used a lots by widgets. -IM_MSVC_RUNTIME_CHECKS_OFF ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end) { ImGuiID seed = IDStack.back(); @@ -9131,16 +8915,6 @@ ImGuiID ImGuiWindow::GetID(int n) } // This is only used in rare/specific situations to manufacture an ID out of nowhere. -// FIXME: Consider instead storing last non-zero ID + count of successive zero-ID, and combine those? -ImGuiID ImGuiWindow::GetIDFromPos(const ImVec2& p_abs) -{ - ImGuiID seed = IDStack.back(); - ImVec2 p_rel = ImGui::WindowPosAbsToRel(this, p_abs); - ImGuiID id = ImHashData(&p_rel, sizeof(p_rel), seed); - return id; -} - -// " ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs) { ImGuiID seed = IDStack.back(); @@ -9221,11 +8995,7 @@ ImGuiID ImGui::GetIDWithSeed(int n, ImGuiID seed) void ImGui::PopID() { ImGuiWindow* window = GImGui->CurrentWindow; - if (window->IDStack.Size <= 1) - { - IM_ASSERT_USER_ERROR(0, "Calling PopID() too many times!"); - return; - } + IM_ASSERT(window->IDStack.Size > 1); // Too many PopID(), or could be popping in a wrong/different window? window->IDStack.pop_back(); } @@ -9247,17 +9017,10 @@ ImGuiID ImGui::GetID(const void* ptr_id) return window->GetID(ptr_id); } -ImGuiID ImGui::GetID(int int_id) -{ - ImGuiWindow* window = GImGui->CurrentWindow; - return window->GetID(int_id); -} -IM_MSVC_RUNTIME_CHECKS_RESTORE - //----------------------------------------------------------------------------- // [SECTION] INPUTS //----------------------------------------------------------------------------- -// - GetModForLRModKey() [Internal] +// - GetModForModKey() [Internal] // - FixupKeyChord() [Internal] // - GetKeyData() [Internal] // - GetKeyIndex() [Internal] @@ -9320,7 +9083,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE // - Shortcut() [Internal] //----------------------------------------------------------------------------- -static ImGuiKeyChord GetModForLRModKey(ImGuiKey key) +static ImGuiKeyChord GetModForModKey(ImGuiKey key) { if (key == ImGuiKey_LeftCtrl || key == ImGuiKey_RightCtrl) return ImGuiMod_Ctrl; @@ -9337,8 +9100,8 @@ ImGuiKeyChord ImGui::FixupKeyChord(ImGuiKeyChord key_chord) { // Add ImGuiMod_XXXX when a corresponding ImGuiKey_LeftXXX/ImGuiKey_RightXXX is specified. ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); - if (IsLRModKey(key)) - key_chord |= GetModForLRModKey(key); + if (IsModKey(key)) + key_chord |= GetModForModKey(key); return key_chord; } @@ -9350,10 +9113,27 @@ ImGuiKeyData* ImGui::GetKeyData(ImGuiContext* ctx, ImGuiKey key) if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(key); +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + IM_ASSERT(key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_NamedKey_END); + if (IsLegacyKey(key) && g.IO.KeyMap[key] != -1) + key = (ImGuiKey)g.IO.KeyMap[key]; // Remap native->imgui or imgui->native +#else IM_ASSERT(IsNamedKey(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend & user code."); - return &g.IO.KeysData[key - ImGuiKey_NamedKey_BEGIN]; +#endif + return &g.IO.KeysData[key - ImGuiKey_KeysData_OFFSET]; } +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO +// Formally moved to obsolete section in 1.90.5 in spite of documented as obsolete since 1.87 +ImGuiKey ImGui::GetKeyIndex(ImGuiKey key) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(IsNamedKey(key)); + const ImGuiKeyData* key_data = GetKeyData(key); + return (ImGuiKey)(key_data - g.IO.KeysData); +} +#endif + // Those names a provided for debugging purpose and are not meant to be saved persistently not compared. static const char* const GKeyNames[] = { @@ -9385,7 +9165,18 @@ const char* ImGui::GetKeyName(ImGuiKey key) { if (key == ImGuiKey_None) return "None"; +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO IM_ASSERT(IsNamedKeyOrMod(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code."); +#else + ImGuiContext& g = *GImGui; + if (IsLegacyKey(key)) + { + if (g.IO.KeyMap[key] == -1) + return "N/A"; + IM_ASSERT(IsNamedKey((ImGuiKey)g.IO.KeyMap[key])); + key = (ImGuiKey)g.IO.KeyMap[key]; + } +#endif if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(key); if (!IsNamedKey(key)) @@ -9401,8 +9192,8 @@ const char* ImGui::GetKeyChordName(ImGuiKeyChord key_chord) ImGuiContext& g = *GImGui; const ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); - if (IsLRModKey(key)) - key_chord &= ~GetModForLRModKey(key); // Return "Ctrl+LeftShift" instead of "Ctrl+Shift+LeftShift" + if (IsModKey(key)) + key_chord &= ~GetModForModKey(key); // Return "Ctrl+LeftShift" instead of "Ctrl+Shift+LeftShift" ImFormatString(g.TempKeychordName, IM_ARRAYSIZE(g.TempKeychordName), "%s%s%s%s%s", (key_chord & ImGuiMod_Ctrl) ? "Ctrl+" : "", (key_chord & ImGuiMod_Shift) ? "Shift+" : "", @@ -9602,9 +9393,8 @@ static int CalcRoutingScore(ImGuiID focus_scope_id, ImGuiID owner_id, ImGuiInput return 0; } -// - We need this to filter some Shortcut() routes when an item e.g. an InputText() is active -// e.g. ImGuiKey_G won't be considered a shortcut when item is active, but ImGuiMod|ImGuiKey_G can be. -// - This is also used by UpdateInputEvents() to avoid trickling in the most common case of e.g. pressing ImGuiKey_G also emitting a G character. +// We need this to filter some Shortcut() routes when an item e.g. an InputText() is active +// e.g. ImGuiKey_G won't be considered a shortcut when item is active, but ImGuiMod|ImGuiKey_G can be. static bool IsKeyChordPotentiallyCharInput(ImGuiKeyChord key_chord) { // Mimic 'ignore_char_inputs' logic in InputText() @@ -9618,8 +9408,6 @@ static bool IsKeyChordPotentiallyCharInput(ImGuiKeyChord key_chord) // Return true for A-Z, 0-9 and other keys associated to char inputs. Other keys such as F1-F12 won't be filtered. ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_); - if (key == ImGuiKey_None) - return false; return g.KeysMayBeCharInput.TestBit(key); } @@ -9743,7 +9531,7 @@ bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat) return IsKeyPressed(key, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None, ImGuiKeyOwner_Any); } -// Important: unlike legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat. +// Important: unless legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat. bool ImGui::IsKeyPressed(ImGuiKey key, ImGuiInputFlags flags, ImGuiID owner_id) { const ImGuiKeyData* key_data = GetKeyData(key); @@ -9853,17 +9641,6 @@ bool ImGui::IsMouseReleased(ImGuiMouseButton button, ImGuiID owner_id) return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyReleased(MouseButtonToKey(button), owner_id) } -// Use if you absolutely need to distinguish single-click from double-click by introducing a delay. -// Generally use with 'delay >= io.MouseDoubleClickTime' + combined with a 'io.MouseClickedLastCount == 1' test. -// This is a very rarely used UI idiom, but some apps use this: e.g. MS Explorer single click on an icon to rename. -bool ImGui::IsMouseReleasedWithDelay(ImGuiMouseButton button, float delay) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); - const float time_since_release = (float)(g.Time - g.IO.MouseReleasedTime[button]); - return !IsMouseDown(button) && (time_since_release - g.IO.DeltaTime < delay) && (time_since_release >= delay); -} - bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) { ImGuiContext& g = *GImGui; @@ -10006,9 +9783,6 @@ ImGuiMouseCursor ImGui::GetMouseCursor() return g.MouseCursor; } -// We intentionally accept values of ImGuiMouseCursor that are outside our bounds, in case users needs to hack-in a custom cursor value. -// Custom cursors may be handled by custom backends. If you are using a standard backend and want to hack in a custom cursor, you may -// handle it before the backend _NewFrame() call and temporarily set ImGuiConfigFlags_NoMouseCursorChange during the backend _NewFrame() call. void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) { ImGuiContext& g = *GImGui; @@ -10042,6 +9816,74 @@ static void ImGui::UpdateKeyboardInputs() if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) io.ClearInputKeys(); + // Import legacy keys or verify they are not used +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + if (io.BackendUsingLegacyKeyArrays == 0) + { + // Backend used new io.AddKeyEvent() API: Good! Verify that old arrays are never written to externally. + for (int n = 0; n < ImGuiKey_LegacyNativeKey_END; n++) + IM_ASSERT((io.KeysDown[n] == false || IsKeyDown((ImGuiKey)n)) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); + } + else + { + if (g.FrameCount == 0) + for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) + IM_ASSERT(g.IO.KeyMap[n] == -1 && "Backend is not allowed to write to io.KeyMap[0..511]!"); + + // Build reverse KeyMap (Named -> Legacy) + for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++) + if (io.KeyMap[n] != -1) + { + IM_ASSERT(IsLegacyKey((ImGuiKey)io.KeyMap[n])); + io.KeyMap[io.KeyMap[n]] = n; + } + + // Import legacy keys into new ones + for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) + if (io.KeysDown[n] || io.BackendUsingLegacyKeyArrays == 1) + { + const ImGuiKey key = (ImGuiKey)(io.KeyMap[n] != -1 ? io.KeyMap[n] : n); + IM_ASSERT(io.KeyMap[n] == -1 || IsNamedKey(key)); + io.KeysData[key].Down = io.KeysDown[n]; + if (key != n) + io.KeysDown[key] = io.KeysDown[n]; // Allow legacy code using io.KeysDown[GetKeyIndex()] with old backends + io.BackendUsingLegacyKeyArrays = 1; + } + if (io.BackendUsingLegacyKeyArrays == 1) + { + GetKeyData(ImGuiMod_Ctrl)->Down = io.KeyCtrl; + GetKeyData(ImGuiMod_Shift)->Down = io.KeyShift; + GetKeyData(ImGuiMod_Alt)->Down = io.KeyAlt; + GetKeyData(ImGuiMod_Super)->Down = io.KeySuper; + } + } +#endif + + // Import legacy ImGuiNavInput_ io inputs and convert to gamepad keys +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; + if (io.BackendUsingLegacyNavInputArray && nav_gamepad_active) + { + #define MAP_LEGACY_NAV_INPUT_TO_KEY1(_KEY, _NAV1) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f); io.KeysData[_KEY].AnalogValue = io.NavInputs[_NAV1]; } while (0) + #define MAP_LEGACY_NAV_INPUT_TO_KEY2(_KEY, _NAV1, _NAV2) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f) || (io.NavInputs[_NAV2] > 0.0f); io.KeysData[_KEY].AnalogValue = ImMax(io.NavInputs[_NAV1], io.NavInputs[_NAV2]); } while (0) + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceDown, ImGuiNavInput_Activate); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceRight, ImGuiNavInput_Cancel); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceLeft, ImGuiNavInput_Menu); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceUp, ImGuiNavInput_Input); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadLeft, ImGuiNavInput_DpadLeft); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadRight, ImGuiNavInput_DpadRight); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadUp, ImGuiNavInput_DpadUp); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadDown, ImGuiNavInput_DpadDown); + MAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadL1, ImGuiNavInput_FocusPrev, ImGuiNavInput_TweakSlow); + MAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadR1, ImGuiNavInput_FocusNext, ImGuiNavInput_TweakFast); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickLeft, ImGuiNavInput_LStickLeft); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickRight, ImGuiNavInput_LStickRight); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickUp, ImGuiNavInput_LStickUp); + MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickDown, ImGuiNavInput_LStickDown); + #undef NAV_MAP_KEY + } +#endif + // Update aliases for (int n = 0; n < ImGuiMouseButton_COUNT; n++) UpdateAliasKey(MouseButtonToKey(n), io.MouseDown[n], io.MouseDown[n] ? 1.0f : 0.0f); @@ -10065,21 +9907,22 @@ static void ImGui::UpdateKeyboardInputs() // Clear gamepad data if disabled if ((io.BackendFlags & ImGuiBackendFlags_HasGamepad) == 0) - for (int key = ImGuiKey_Gamepad_BEGIN; key < ImGuiKey_Gamepad_END; key++) + for (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++) { - io.KeysData[key - ImGuiKey_NamedKey_BEGIN].Down = false; - io.KeysData[key - ImGuiKey_NamedKey_BEGIN].AnalogValue = 0.0f; + io.KeysData[i - ImGuiKey_KeysData_OFFSET].Down = false; + io.KeysData[i - ImGuiKey_KeysData_OFFSET].AnalogValue = 0.0f; } // Update keys - for (int key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key++) + for (int i = 0; i < ImGuiKey_KeysData_SIZE; i++) { - ImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_NamedKey_BEGIN]; + ImGuiKeyData* key_data = &io.KeysData[i]; key_data->DownDurationPrev = key_data->DownDuration; key_data->DownDuration = key_data->Down ? (key_data->DownDuration < 0.0f ? 0.0f : key_data->DownDuration + io.DeltaTime) : -1.0f; if (key_data->DownDuration == 0.0f) { - if (IsKeyboardKey((ImGuiKey)key)) + ImGuiKey key = (ImGuiKey)(ImGuiKey_KeysData_OFFSET + i); + if (IsKeyboardKey(key)) g.LastKeyboardKeyPressTime = g.Time; else if (key == ImGuiKey_ReservedForModCtrl || key == ImGuiKey_ReservedForModShift || key == ImGuiKey_ReservedForModAlt || key == ImGuiKey_ReservedForModSuper) g.LastKeyboardKeyPressTime = g.Time; @@ -10089,7 +9932,7 @@ static void ImGui::UpdateKeyboardInputs() // Update keys/input owner (named keys only): one entry per key for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { - ImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_NamedKey_BEGIN]; + ImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_KeysData_OFFSET]; ImGuiKeyOwnerData* owner_data = &g.KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; owner_data->OwnerCurr = owner_data->OwnerNext; if (!key_data->Down) // Important: ownership is released on the frame after a release. Ensure a 'MouseDown -> CloseWindow -> MouseUp' chain doesn't lead to someone else seeing the MouseUp. @@ -10130,17 +9973,15 @@ static void ImGui::UpdateMouseInputs() g.MouseStationaryTimer = mouse_stationary ? (g.MouseStationaryTimer + io.DeltaTime) : 0.0f; //IMGUI_DEBUG_LOG("%.4f\n", g.MouseStationaryTimer); - // If mouse moved we re-enable mouse hovering in case it was disabled by keyboard/gamepad. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true. + // If mouse moved we re-enable mouse hovering in case it was disabled by gamepad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true. if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) - g.NavHighlightItemUnderNav = false; + g.NavDisableMouseHover = false; for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) { io.MouseClicked[i] = io.MouseDown[i] && io.MouseDownDuration[i] < 0.0f; io.MouseClickedCount[i] = 0; // Will be filled below io.MouseReleased[i] = !io.MouseDown[i] && io.MouseDownDuration[i] >= 0.0f; - if (io.MouseReleased[i]) - io.MouseReleasedTime[i] = g.Time; io.MouseDownDurationPrev[i] = io.MouseDownDuration[i]; io.MouseDownDuration[i] = io.MouseDown[i] ? (io.MouseDownDuration[i] < 0.0f ? 0.0f : io.MouseDownDuration[i] + io.DeltaTime) : -1.0f; if (io.MouseClicked[i]) @@ -10174,9 +10015,9 @@ static void ImGui::UpdateMouseInputs() // We provide io.MouseDoubleClicked[] as a legacy service io.MouseDoubleClicked[i] = (io.MouseClickedCount[i] == 2); - // Clicking any mouse button reactivate mouse hovering which may have been deactivated by keyboard/gamepad navigation + // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation if (io.MouseClicked[i]) - g.NavHighlightItemUnderNav = false; + g.NavDisableMouseHover = false; } } @@ -10312,7 +10153,7 @@ void ImGui::UpdateMouseWheel() { LockWheelingWindow(window, wheel.x); float max_step = window->InnerRect.GetWidth() * 0.67f; - float scroll_step = ImTrunc(ImMin(2 * window->FontRefSize, max_step)); + float scroll_step = ImTrunc(ImMin(2 * window->CalcFontSize(), max_step)); SetScrollX(window, window->Scroll.x - wheel.x * scroll_step); g.WheelingWindowScrolledFrame = g.FrameCount; } @@ -10320,7 +10161,7 @@ void ImGui::UpdateMouseWheel() { LockWheelingWindow(window, wheel.y); float max_step = window->InnerRect.GetHeight() * 0.67f; - float scroll_step = ImTrunc(ImMin(5 * window->FontRefSize, max_step)); + float scroll_step = ImTrunc(ImMin(5 * window->CalcFontSize(), max_step)); SetScrollY(window, window->Scroll.y - wheel.y * scroll_step); g.WheelingWindowScrolledFrame = g.FrameCount; } @@ -10377,11 +10218,11 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) // Only trickle chars<>key when working with InputText() // FIXME: InputText() could parse event trail? // FIXME: Could specialize chars<>keys trickling rules for control keys (those not typically associated to characters) - const bool trickle_interleaved_nonchar_keys_and_text = (trickle_fast_inputs && g.WantTextInputNextFrame == 1); + const bool trickle_interleaved_keys_and_text = (trickle_fast_inputs && g.WantTextInputNextFrame == 1); - bool mouse_moved = false, mouse_wheeled = false, key_changed = false, key_changed_nonchar = false, text_inputted = false; + bool mouse_moved = false, mouse_wheeled = false, key_changed = false, text_inputted = false; int mouse_button_changed = 0x00; - ImBitArray key_changed_mask; + ImBitArray key_changed_mask; int event_n = 0; for (; event_n < g.InputEventsQueue.Size; event_n++) @@ -10435,32 +10276,30 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) IM_ASSERT(key != ImGuiKey_None); ImGuiKeyData* key_data = GetKeyData(key); const int key_data_index = (int)(key_data - g.IO.KeysData); - if (trickle_fast_inputs && key_data->Down != e->Key.Down && (key_changed_mask.TestBit(key_data_index) || mouse_button_changed != 0)) + if (trickle_fast_inputs && key_data->Down != e->Key.Down && (key_changed_mask.TestBit(key_data_index) || text_inputted || mouse_button_changed != 0)) break; - - const bool key_is_potentially_for_char_input = IsKeyChordPotentiallyCharInput(GetMergedModsFromKeys() | key); - if (trickle_interleaved_nonchar_keys_and_text && (text_inputted && !key_is_potentially_for_char_input)) - break; - key_data->Down = e->Key.Down; key_data->AnalogValue = e->Key.AnalogValue; key_changed = true; key_changed_mask.SetBit(key_data_index); - if (trickle_interleaved_nonchar_keys_and_text && !key_is_potentially_for_char_input) - key_changed_nonchar = true; + + // Allow legacy code using io.KeysDown[GetKeyIndex()] with new backends +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + io.KeysDown[key_data_index] = key_data->Down; + if (io.KeyMap[key_data_index] != -1) + io.KeysDown[io.KeyMap[key_data_index]] = key_data->Down; +#endif } else if (e->Type == ImGuiInputEventType_Text) { if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) continue; // Trickling Rule: Stop processing queued events if keys/mouse have been interacted with - if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_moved || mouse_wheeled)) - break; - if (trickle_interleaved_nonchar_keys_and_text && key_changed_nonchar) + if (trickle_fast_inputs && ((key_changed && trickle_interleaved_keys_and_text) || mouse_button_changed != 0 || mouse_moved || mouse_wheeled)) break; unsigned int c = e->Text.Char; io.InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID); - if (trickle_interleaved_nonchar_keys_and_text) + if (trickle_interleaved_keys_and_text) text_inputted = true; } else if (e->Type == ImGuiInputEventType_Focus) @@ -10637,7 +10476,7 @@ bool ImGui::IsKeyChordPressed(ImGuiKeyChord key_chord, ImGuiInputFlags flags, Im void ImGui::SetNextItemShortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags) { ImGuiContext& g = *GImGui; - g.NextItemData.HasFlags |= ImGuiNextItemDataFlags_HasShortcut; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasShortcut; g.NextItemData.Shortcut = key_chord; g.NextItemData.ShortcutFlags = flags; } @@ -10649,7 +10488,7 @@ void ImGui::ItemHandleShortcut(ImGuiID id) ImGuiInputFlags flags = g.NextItemData.ShortcutFlags; IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetNextItemShortcut) == 0); // Passing flags not supported by SetNextItemShortcut()! - if (g.LastItemData.ItemFlags & ImGuiItemFlags_Disabled) + if (g.LastItemData.InFlags & ImGuiItemFlags_Disabled) return; if (flags & ImGuiInputFlags_Tooltip) { @@ -10708,17 +10547,9 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags, ImGuiID own return true; } + //----------------------------------------------------------------------------- -// [SECTION] ERROR CHECKING, STATE RECOVERY -//----------------------------------------------------------------------------- -// - DebugCheckVersionAndDataLayout() (called via IMGUI_CHECKVERSION() macros) -// - ErrorCheckUsingSetCursorPosToExtendParentBoundaries() -// - ErrorCheckNewFrameSanityChecks() -// - ErrorCheckEndFrameSanityChecks() -// - ErrorRecoveryStoreState() -// - ErrorRecoveryTryToRecoverState() -// - ErrorRecoveryTryToRecoverWindowState() -// - ErrorLog() +// [SECTION] ERROR CHECKING //----------------------------------------------------------------------------- // Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues. @@ -10808,29 +10639,13 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); 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); +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_COUNT; n++) + IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < ImGuiKey_LegacyNativeKey_END && "io.KeyMap[] contains an out of bound value (need to be 0..511, or -1 for unmapped key)"); - // Error handling: we do not accept 100% silent recovery! Please contact me if you feel this is getting in your way. - if (g.IO.ConfigErrorRecovery) - IM_ASSERT(g.IO.ConfigErrorRecoveryEnableAssert || g.IO.ConfigErrorRecoveryEnableDebugLog || g.IO.ConfigErrorRecoveryEnableTooltip || g.ErrorCallback != NULL); - -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - // Remap legacy names - if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) - { - g.IO.ConfigNavMoveSetMousePos = true; - g.IO.ConfigFlags &= ~ImGuiConfigFlags_NavEnableSetMousePos; - } - if (g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) - { - g.IO.ConfigNavCaptureKeyboard = false; - g.IO.ConfigFlags &= ~ImGuiConfigFlags_NavNoCaptureKeyboard; - } - - // Remap legacy clipboard handlers (OBSOLETED in 1.91.1, August 2024) - if (g.IO.GetClipboardTextFn != NULL && (g.PlatformIO.Platform_GetClipboardTextFn == NULL || g.PlatformIO.Platform_GetClipboardTextFn == Platform_GetClipboardTextFn_DefaultImpl)) - g.PlatformIO.Platform_GetClipboardTextFn = [](ImGuiContext* ctx) { return ctx->IO.GetClipboardTextFn(ctx->IO.ClipboardUserData); }; - if (g.IO.SetClipboardTextFn != NULL && (g.PlatformIO.Platform_SetClipboardTextFn == NULL || g.PlatformIO.Platform_SetClipboardTextFn == Platform_SetClipboardTextFn_DefaultImpl)) - g.PlatformIO.Platform_SetClipboardTextFn = [](ImGuiContext* ctx, const char* text) { return ctx->IO.SetClipboardTextFn(ctx->IO.ClipboardUserData, text); }; + // Check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only added in 1.60 WIP) + if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && g.IO.BackendUsingLegacyKeyArrays == 1) + IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); #endif // Perform simple check: error if Docking or Viewport are enabled _exactly_ on frame 1 (instead of frame 0 or later), which is a common error leading to loss of .ini data. @@ -10868,135 +10683,121 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() IM_UNUSED(mon); IM_ASSERT(mon.MainSize.x > 0.0f && mon.MainSize.y > 0.0f && "Monitor main bounds not setup properly."); IM_ASSERT(ImRect(mon.MainPos, mon.MainPos + mon.MainSize).Contains(ImRect(mon.WorkPos, mon.WorkPos + mon.WorkSize)) && "Monitor work bounds not setup properly. If you don't have work area information, just copy MainPos/MainSize into them."); - IM_ASSERT(mon.DpiScale > 0.0f && mon.DpiScale < 99.0f && "Monitor DpiScale is invalid."); // Typical correct values would be between 1.0f and 4.0f + IM_ASSERT(mon.DpiScale != 0.0f); } } } static void ImGui::ErrorCheckEndFrameSanityChecks() { + ImGuiContext& g = *GImGui; + // Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame() // One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame(). // It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs. // We silently accommodate for this case by ignoring the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0), // while still correctly asserting on mid-frame key press events. - ImGuiContext& g = *GImGui; const ImGuiKeyChord key_mods = GetMergedModsFromKeys(); - IM_UNUSED(g); - IM_UNUSED(key_mods); IM_ASSERT((key_mods == 0 || g.IO.KeyMods == key_mods) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods"); IM_UNUSED(key_mods); - IM_ASSERT(g.CurrentWindowStack.Size == 1); - IM_ASSERT(g.CurrentWindowStack[0].Window->IsFallbackWindow); -} + // [EXPERIMENTAL] Recover from errors: You may call this yourself before EndFrame(). + //ErrorCheckEndFrameRecover(); -// Save current stack sizes. Called e.g. by NewFrame() and by Begin() but may be called for manual recovery. -void ImGui::ErrorRecoveryStoreState(ImGuiErrorRecoveryState* state_out) -{ - ImGuiContext& g = *GImGui; - state_out->SizeOfWindowStack = (short)g.CurrentWindowStack.Size; - state_out->SizeOfIDStack = (short)g.CurrentWindow->IDStack.Size; - state_out->SizeOfTreeStack = (short)g.CurrentWindow->DC.TreeDepth; // NOT g.TreeNodeStack.Size which is a partial stack! - state_out->SizeOfColorStack = (short)g.ColorStack.Size; - state_out->SizeOfStyleVarStack = (short)g.StyleVarStack.Size; - state_out->SizeOfFontStack = (short)g.FontStack.Size; - state_out->SizeOfFocusScopeStack = (short)g.FocusScopeStack.Size; - state_out->SizeOfGroupStack = (short)g.GroupStack.Size; - state_out->SizeOfItemFlagsStack = (short)g.ItemFlagsStack.Size; - state_out->SizeOfBeginPopupStack = (short)g.BeginPopupStack.Size; - state_out->SizeOfDisabledStack = (short)g.DisabledStackSize; -} - -// Chosen name "Try to recover" over e.g. "Restore" to suggest this is not a 100% guaranteed recovery. -// Called by e.g. EndFrame() but may be called for manual recovery. -// Attempt to recover full window stack. -void ImGui::ErrorRecoveryTryToRecoverState(const ImGuiErrorRecoveryState* state_in) -{ - // PVS-Studio V1044 is "Loop break conditions do not depend on the number of iterations" - ImGuiContext& g = *GImGui; - while (g.CurrentWindowStack.Size > state_in->SizeOfWindowStack) //-V1044 + // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you + // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API). + if (g.CurrentWindowStack.Size != 1) { - // Recap: - // - Begin()/BeginChild() return false to indicate the window is collapsed or fully clipped. - // - Always call a matching End() for each Begin() call, regardless of its return value! - // - Begin/End and BeginChild/EndChild logic is KNOWN TO BE INCONSISTENT WITH ALL OTHER BEGIN/END FUNCTIONS. - // - We will fix that in a future major update. - ImGuiWindow* window = g.CurrentWindow; - if (window->Flags & ImGuiWindowFlags_ChildWindow) + if (g.CurrentWindowStack.Size > 1) { - if (g.CurrentTable != NULL && g.CurrentTable->InnerWindow == g.CurrentWindow) - { - IM_ASSERT_USER_ERROR(0, "Missing EndTable()"); - EndTable(); - } - else - { - IM_ASSERT_USER_ERROR(0, "Missing EndChild()"); - EndChild(); - } + ImGuiWindow* window = g.CurrentWindowStack.back().Window; // <-- This window was not Ended! + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"); + IM_UNUSED(window); + while (g.CurrentWindowStack.Size > 1) + End(); } else { - IM_ASSERT_USER_ERROR(0, "Missing End()"); + IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?"); + } + } + + IM_ASSERT_USER_ERROR(g.GroupStack.Size == 0, "Missing EndGroup call!"); +} + +// Experimental recovery from incorrect usage of BeginXXX/EndXXX/PushXXX/PopXXX calls. +// Must be called during or before EndFrame(). +// This is generally flawed as we are not necessarily End/Popping things in the right order. +// FIXME: Can't recover from inside BeginTabItem/EndTabItem yet. +// FIXME: Can't recover from interleaved BeginTabBar/Begin +void ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data) +{ + // PVS-Studio V1044 is "Loop break conditions do not depend on the number of iterations" + ImGuiContext& g = *GImGui; + while (g.CurrentWindowStack.Size > 0) //-V1044 + { + ErrorCheckEndWindowRecover(log_callback, user_data); + ImGuiWindow* window = g.CurrentWindow; + if (g.CurrentWindowStack.Size == 1) + { + IM_ASSERT(window->IsFallbackWindow); + break; + } + if (window->Flags & ImGuiWindowFlags_ChildWindow) + { + if (log_callback) log_callback(user_data, "Recovered from missing EndChild() for '%s'", window->Name); + EndChild(); + } + else + { + if (log_callback) log_callback(user_data, "Recovered from missing End() for '%s'", window->Name); End(); } } - if (g.CurrentWindowStack.Size == state_in->SizeOfWindowStack) - ErrorRecoveryTryToRecoverWindowState(state_in); } -// Called by e.g. End() but may be called for manual recovery. -// Read '// Error Handling [BETA]' block in imgui_internal.h for details. -// Attempt to recover from incorrect usage of BeginXXX/EndXXX/PushXXX/PopXXX calls. -void ImGui::ErrorRecoveryTryToRecoverWindowState(const ImGuiErrorRecoveryState* state_in) +// Must be called before End()/EndChild() +void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data) { ImGuiContext& g = *GImGui; - - while (g.CurrentTable != NULL && g.CurrentTable->InnerWindow == g.CurrentWindow) //-V1044 + while (g.CurrentTable && (g.CurrentTable->OuterWindow == g.CurrentWindow || g.CurrentTable->InnerWindow == g.CurrentWindow)) { - IM_ASSERT_USER_ERROR(0, "Missing EndTable()"); + if (log_callback) log_callback(user_data, "Recovered from missing EndTable() in '%s'", g.CurrentTable->OuterWindow->Name); EndTable(); } ImGuiWindow* window = g.CurrentWindow; - - // FIXME: Can't recover from inside BeginTabItem/EndTabItem yet. - while (g.CurrentTabBar != NULL && g.CurrentTabBar->Window == window) //-V1044 + ImGuiStackSizes* stack_sizes = &g.CurrentWindowStack.back().StackSizesOnBegin; + IM_ASSERT(window != NULL); + while (g.CurrentTabBar != NULL) //-V1044 { - IM_ASSERT_USER_ERROR(0, "Missing EndTabBar()"); + if (log_callback) log_callback(user_data, "Recovered from missing EndTabBar() in '%s'", window->Name); EndTabBar(); } - while (g.CurrentMultiSelect != NULL && g.CurrentMultiSelect->Storage->Window == window) //-V1044 + while (g.CurrentMultiSelect != NULL && g.CurrentMultiSelect->Storage->Window == window) { - IM_ASSERT_USER_ERROR(0, "Missing EndMultiSelect()"); + if (log_callback) log_callback(user_data, "Recovered from missing EndMultiSelect() in '%s'", window->Name); EndMultiSelect(); } - if (window->DC.MenuBarAppending) //-V1044 + while (window->DC.TreeDepth > 0) { - IM_ASSERT_USER_ERROR(0, "Missing EndMenuBar()"); - EndMenuBar(); - } - while (window->DC.TreeDepth > state_in->SizeOfTreeStack) //-V1044 - { - IM_ASSERT_USER_ERROR(0, "Missing TreePop()"); + if (log_callback) log_callback(user_data, "Recovered from missing TreePop() in '%s'", window->Name); TreePop(); } - while (g.GroupStack.Size > state_in->SizeOfGroupStack) //-V1044 + while (g.GroupStack.Size > stack_sizes->SizeOfGroupStack) //-V1044 { - IM_ASSERT_USER_ERROR(0, "Missing EndGroup()"); + if (log_callback) log_callback(user_data, "Recovered from missing EndGroup() in '%s'", window->Name); EndGroup(); } - IM_ASSERT(g.GroupStack.Size == state_in->SizeOfGroupStack); - while (window->IDStack.Size > state_in->SizeOfIDStack) //-V1044 + while (window->IDStack.Size > 1) { - IM_ASSERT_USER_ERROR(0, "Missing PopID()"); + if (log_callback) log_callback(user_data, "Recovered from missing PopID() in '%s'", window->Name); PopID(); } - while (g.DisabledStackSize > state_in->SizeOfDisabledStack) //-V1044 + while (g.DisabledStackSize > stack_sizes->SizeOfDisabledStack) //-V1044 { - IM_ASSERT_USER_ERROR(0, "Missing EndDisabled()"); + if (log_callback) log_callback(user_data, "Recovered from missing EndDisabled() in '%s'", window->Name); if (g.CurrentItemFlags & ImGuiItemFlags_Disabled) EndDisabled(); else @@ -11005,151 +10806,70 @@ void ImGui::ErrorRecoveryTryToRecoverWindowState(const ImGuiErrorRecoveryStat g.CurrentWindowStack.back().DisabledOverrideReenable = false; } } - IM_ASSERT(g.DisabledStackSize == state_in->SizeOfDisabledStack); - while (g.ColorStack.Size > state_in->SizeOfColorStack) //-V1044 + while (g.ColorStack.Size > stack_sizes->SizeOfColorStack) { - IM_ASSERT_USER_ERROR(0, "Missing PopStyleColor()"); + if (log_callback) log_callback(user_data, "Recovered from missing PopStyleColor() in '%s' for ImGuiCol_%s", window->Name, GetStyleColorName(g.ColorStack.back().Col)); PopStyleColor(); } - while (g.ItemFlagsStack.Size > state_in->SizeOfItemFlagsStack) //-V1044 + while (g.ItemFlagsStack.Size > stack_sizes->SizeOfItemFlagsStack) //-V1044 { - IM_ASSERT_USER_ERROR(0, "Missing PopItemFlag()"); + if (log_callback) log_callback(user_data, "Recovered from missing PopItemFlag() in '%s'", window->Name); PopItemFlag(); } - while (g.StyleVarStack.Size > state_in->SizeOfStyleVarStack) //-V1044 + while (g.StyleVarStack.Size > stack_sizes->SizeOfStyleVarStack) //-V1044 { - IM_ASSERT_USER_ERROR(0, "Missing PopStyleVar()"); + if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'", window->Name); PopStyleVar(); } - while (g.FontStack.Size > state_in->SizeOfFontStack) //-V1044 + while (g.FontStack.Size > stack_sizes->SizeOfFontStack) //-V1044 { - IM_ASSERT_USER_ERROR(0, "Missing PopFont()"); + if (log_callback) log_callback(user_data, "Recovered from missing PopFont() in '%s'", window->Name); PopFont(); } - while (g.FocusScopeStack.Size > state_in->SizeOfFocusScopeStack) //-V1044 + while (g.FocusScopeStack.Size > stack_sizes->SizeOfFocusScopeStack + 1) //-V1044 { - IM_ASSERT_USER_ERROR(0, "Missing PopFocusScope()"); + if (log_callback) log_callback(user_data, "Recovered from missing PopFocusScope() in '%s'", window->Name); PopFocusScope(); } - //IM_ASSERT(g.FocusScopeStack.Size == state_in->SizeOfFocusScopeStack); } -bool ImGui::ErrorLog(const char* msg) +// Save current stack sizes for later compare +void ImGuiStackSizes::SetToContextState(ImGuiContext* ctx) { - ImGuiContext& g = *GImGui; - - // Output to debug log -#ifndef IMGUI_DISABLE_DEBUG_TOOLS + ImGuiContext& g = *ctx; ImGuiWindow* window = g.CurrentWindow; - - if (g.IO.ConfigErrorRecoveryEnableDebugLog) - { - if (g.ErrorFirst) - IMGUI_DEBUG_LOG_ERROR("[imgui-error] (current settings: Assert=%d, Log=%d, Tooltip=%d)\n", - g.IO.ConfigErrorRecoveryEnableAssert, g.IO.ConfigErrorRecoveryEnableDebugLog, g.IO.ConfigErrorRecoveryEnableTooltip); - IMGUI_DEBUG_LOG_ERROR("[imgui-error] In window '%s': %s\n", window ? window->Name : "NULL", msg); - } - g.ErrorFirst = false; - - // Output to tooltip - if (g.IO.ConfigErrorRecoveryEnableTooltip) - { - if (g.WithinFrameScope && BeginErrorTooltip()) - { - if (g.ErrorCountCurrentFrame < 20) - { - Text("In window '%s': %s", window ? window->Name : "NULL", msg); - if (window && (!window->IsFallbackWindow || window->WasActive)) - GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 0, 0, 255)); - } - if (g.ErrorCountCurrentFrame == 20) - Text("(and more errors)"); - // EndFrame() will amend debug buttons to this window, after all errors have been submitted. - EndErrorTooltip(); - } - g.ErrorCountCurrentFrame++; - } -#endif - - // Output to callback - if (g.ErrorCallback != NULL) - g.ErrorCallback(&g, g.ErrorCallbackUserData, msg); - - // Return whether we should assert - return g.IO.ConfigErrorRecoveryEnableAssert; + SizeOfIDStack = (short)window->IDStack.Size; + SizeOfColorStack = (short)g.ColorStack.Size; + SizeOfStyleVarStack = (short)g.StyleVarStack.Size; + SizeOfFontStack = (short)g.FontStack.Size; + SizeOfFocusScopeStack = (short)g.FocusScopeStack.Size; + SizeOfGroupStack = (short)g.GroupStack.Size; + SizeOfItemFlagsStack = (short)g.ItemFlagsStack.Size; + SizeOfBeginPopupStack = (short)g.BeginPopupStack.Size; + SizeOfDisabledStack = (short)g.DisabledStackSize; } -void ImGui::ErrorCheckEndFrameFinalizeErrorTooltip() +// Compare to detect usage errors +void ImGuiStackSizes::CompareWithContextState(ImGuiContext* ctx) { -#ifndef IMGUI_DISABLE_DEBUG_TOOLS - ImGuiContext& g = *GImGui; - if (g.DebugDrawIdConflicts != 0 && g.IO.KeyCtrl == false) - g.DebugDrawIdConflictsCount = g.HoveredIdPreviousFrameItemCount; - if (g.DebugDrawIdConflicts != 0 && g.DebugItemPickerActive == false && BeginErrorTooltip()) - { - Text("Programmer error: %d visible items with conflicting ID!", g.DebugDrawIdConflictsCount); - BulletText("Code should use PushID()/PopID() in loops, or append \"##xx\" to same-label identifiers!"); - BulletText("Empty label e.g. Button(\"\") == same ID as parent widget/node. Use Button(\"##xx\") instead!"); - //BulletText("Code intending to use duplicate ID may use e.g. PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); ... PopItemFlag()"); // Not making this too visible for fear of it being abused. - BulletText("Set io.ConfigDebugHighlightIdConflicts=false to disable this warning in non-programmers builds."); - Separator(); - Text("(Hold CTRL to: use"); - SameLine(); - if (SmallButton("Item Picker")) - DebugStartItemPicker(); - SameLine(); - Text("to break in item call-stack, or"); - SameLine(); - if (SmallButton("Open FAQ->About ID Stack System") && g.PlatformIO.Platform_OpenInShellFn != NULL) - g.PlatformIO.Platform_OpenInShellFn(&g, "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#qa-usage"); - EndErrorTooltip(); - } + ImGuiContext& g = *ctx; + ImGuiWindow* window = g.CurrentWindow; + IM_UNUSED(window); - if (g.ErrorCountCurrentFrame > 0 && BeginErrorTooltip()) // Amend at end of frame - { - Separator(); - Text("(Hold CTRL to:"); - SameLine(); - if (SmallButton("Enable Asserts")) - g.IO.ConfigErrorRecoveryEnableAssert = true; - //SameLine(); - //if (SmallButton("Hide Error Tooltips")) - // g.IO.ConfigErrorRecoveryEnableTooltip = false; // Too dangerous - SameLine(0, 0); - Text(")"); - EndErrorTooltip(); - } -#endif -} + // Window stacks + // NOT checking: DC.ItemWidth, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin) + IM_ASSERT(SizeOfIDStack == window->IDStack.Size && "PushID/PopID or TreeNode/TreePop Mismatch!"); -// Pseudo-tooltip. Follow mouse until CTRL is held. When CTRL is held we lock position, allowing to click it. -bool ImGui::BeginErrorTooltip() -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = FindWindowByName("##Tooltip_Error"); - const bool use_locked_pos = (g.IO.KeyCtrl && window && window->WasActive); - PushStyleColor(ImGuiCol_PopupBg, ImLerp(g.Style.Colors[ImGuiCol_PopupBg], ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 0.15f)); - if (use_locked_pos) - SetNextWindowPos(g.ErrorTooltipLockedPos); - bool is_visible = Begin("##Tooltip_Error", NULL, ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize); - PopStyleColor(); - if (is_visible && g.CurrentWindow->BeginCount == 1) - { - SeparatorText("MESSAGE FROM DEAR IMGUI"); - BringWindowToDisplayFront(g.CurrentWindow); - BringWindowToFocusFront(g.CurrentWindow); - g.ErrorTooltipLockedPos = GetWindowPos(); - } - else if (!is_visible) - { - End(); - } - return is_visible; -} - -void ImGui::EndErrorTooltip() -{ - End(); + // Global stacks + // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them. + IM_ASSERT(SizeOfGroupStack == g.GroupStack.Size && "BeginGroup/EndGroup Mismatch!"); + IM_ASSERT(SizeOfBeginPopupStack == g.BeginPopupStack.Size && "BeginPopup/EndPopup or BeginMenu/EndMenu Mismatch!"); + IM_ASSERT(SizeOfDisabledStack == g.DisabledStackSize && "BeginDisabled/EndDisabled Mismatch!"); + IM_ASSERT(SizeOfItemFlagsStack >= g.ItemFlagsStack.Size && "PushItemFlag/PopItemFlag Mismatch!"); + IM_ASSERT(SizeOfColorStack >= g.ColorStack.Size && "PushStyleColor/PopStyleColor Mismatch!"); + IM_ASSERT(SizeOfStyleVarStack >= g.StyleVarStack.Size && "PushStyleVar/PopStyleVar Mismatch!"); + IM_ASSERT(SizeOfFontStack >= g.FontStack.Size && "PushFont/PopFont Mismatch!"); + IM_ASSERT(SizeOfFocusScopeStack == g.FocusScopeStack.Size && "PushFocusScope/PopFocusScope Mismatch!"); } //----------------------------------------------------------------------------- @@ -11165,8 +10885,8 @@ void ImGui::KeepAliveID(ImGuiID id) ImGuiContext& g = *GImGui; if (g.ActiveId == id) g.ActiveIdIsAlive = id; - if (g.DeactivatedItemData.ID == id) - g.DeactivatedItemData.IsAlive = true; + if (g.ActiveIdPreviousFrame == id) + g.ActiveIdPreviousFrameIsAlive = true; } // Declare item bounding box for clipping and interaction. @@ -11184,7 +10904,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu g.LastItemData.ID = id; g.LastItemData.Rect = bb; g.LastItemData.NavRect = nav_bb_arg ? *nav_bb_arg : bb; - g.LastItemData.ItemFlags = g.CurrentItemFlags | g.NextItemData.ItemFlags | extra_flags; + g.LastItemData.InFlags = g.CurrentItemFlags | g.NextItemData.ItemFlags | extra_flags; g.LastItemData.StatusFlags = ImGuiItemStatusFlags_None; // Note: we don't copy 'g.NextItemData.SelectionUserData' to an hypothetical g.LastItemData.SelectionUserData: since the former is not cleared. @@ -11202,7 +10922,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu // to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick). // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null. // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere. - if (!(g.LastItemData.ItemFlags & ImGuiItemFlags_NoNav)) + if (!(g.LastItemData.InFlags & ImGuiItemFlags_NoNav)) { // FIMXE-NAV: investigate changing the window tests into a simple 'if (g.NavFocusScopeId == g.CurrentFocusScopeId)' test. window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent); @@ -11212,14 +10932,18 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu NavProcessItem(); } - if (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasShortcut) + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasShortcut) ItemHandleShortcut(id); } // Lightweight clear of SetNextItemXXX data. - g.NextItemData.HasFlags = ImGuiNextItemDataFlags_None; + g.NextItemData.Flags = ImGuiNextItemDataFlags_None; g.NextItemData.ItemFlags = ImGuiItemFlags_None; +#if IMGUI_HAS_STACK_LAYOUT + ImGuiInternal::UpdateItemRect(window->ID, bb.Min, bb.Max); +#endif + #ifdef IMGUI_ENABLE_TEST_ENGINE if (id != 0) IMGUI_TEST_ENGINE_ITEM_ADD(id, g.LastItemData.NavRect, &g.LastItemData); @@ -11247,13 +10971,10 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu IM_ASSERT(id != window->ID && "Cannot have an empty ID at the root of a window. If you need an empty label, use ## and read the FAQ about how the ID Stack works!"); } //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] - //if ((g.LastItemData.ItemFlags & ImGuiItemFlags_NoNav) == 0) + //if ((g.LastItemData.InFlags & ImGuiItemFlags_NoNav) == 0) // window->DrawList->AddRect(g.LastItemData.NavRect.Min, g.LastItemData.NavRect.Max, IM_COL32(255,255,0,255)); // [DEBUG] #endif - if (id != 0 && g.DeactivatedItemData.ID == id) - g.DeactivatedItemData.ElapseFrame = g.FrameCount; - // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) if (is_rect_visible) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Visible; @@ -11286,7 +11007,9 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE // - GetFrameHeight() // - GetFrameHeightWithSpacing() // - GetContentRegionMax() +// - GetContentRegionMaxAbs() [Internal] // - GetContentRegionAvail(), +// - GetWindowContentRegionMin(), GetWindowContentRegionMax() // - BeginGroup() // - EndGroup() // Also see in imgui_widgets: tab bars, and in imgui_tables: tables, columns. @@ -11304,6 +11027,38 @@ void ImGui::ItemSize(const ImVec2& size, float text_baseline_y) if (window->SkipItems) return; +#if IMGUI_HAS_STACK_LAYOUT + ImGuiLayoutType layout_type = ImGuiInternal::GetCurrentLayoutType(window->ID); +#else + ImGuiLayoutType layout_type = window->DC.LayoutType; +#endif + + //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorPos, 3.0f, IM_COL32(255,255,0,255), 4); // [DEBUG] Widget position + + // Stack Layouts: Handle horizontal case first to simplify merge in case code handling vertical changes. + if (layout_type == ImGuiLayoutType_Horizontal) + { + const float line_width = ImMax(window->DC.CurrLineSize.x, size.x); + + // Always align ourselves on pixel boundaries + //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] + window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x; + window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y + size.y; + window->DC.CursorPos.x = IM_TRUNC(window->DC.CursorPos.x + line_width + g.Style.ItemSpacing.x); + window->DC.CursorPos.y = IM_TRUNC(window->DC.CursorPosPrevLine.y - size.y); + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x - g.Style.ItemSpacing.x); + window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPosPrevLine.y); + //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] + + window->DC.PrevLineSize.x = line_width; + window->DC.PrevLineSize.y = 0.0f; + window->DC.CurrLineSize.x = 0.0f; + window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y); + window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset; + window->DC.IsSameLine = window->DC.IsSetPos = false; + return; + } + // We increase the height in this function to accommodate for baseline offset. // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor, // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect. @@ -11322,15 +11077,12 @@ void ImGui::ItemSize(const ImVec2& size, float text_baseline_y) window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] + window->DC.PrevLineSize.x = 0.0f; window->DC.PrevLineSize.y = line_height; window->DC.CurrLineSize.y = 0.0f; window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y); window->DC.CurrLineTextBaseOffset = 0.0f; window->DC.IsSameLine = window->DC.IsSetPos = false; - - // Horizontal layout mode - if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) - SameLine(); } IM_MSVC_RUNTIME_CHECKS_RESTORE @@ -11449,7 +11201,7 @@ void ImGui::Unindent(float indent_w) void ImGui::SetNextItemWidth(float item_width) { ImGuiContext& g = *GImGui; - g.NextItemData.HasFlags |= ImGuiNextItemDataFlags_HasWidth; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth; g.NextItemData.Width = item_width; } @@ -11460,7 +11212,7 @@ void ImGui::PushItemWidth(float item_width) ImGuiWindow* window = g.CurrentWindow; window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width); - g.NextItemData.HasFlags &= ~ImGuiNextItemDataFlags_HasWidth; + g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; } void ImGui::PushMultiItemsWidths(int components, float w_full) @@ -11479,18 +11231,12 @@ void ImGui::PushMultiItemsWidths(int components, float w_full) prev_split = next_split; } window->DC.ItemWidth = ImMax(prev_split, 1.0f); - g.NextItemData.HasFlags &= ~ImGuiNextItemDataFlags_HasWidth; + g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth; } void ImGui::PopItemWidth() { - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - if (window->DC.ItemWidthStack.Size <= 0) - { - IM_ASSERT_USER_ERROR(0, "Calling PopItemWidth() too many times!"); - return; - } + ImGuiWindow* window = GetCurrentWindow(); window->DC.ItemWidth = window->DC.ItemWidthStack.back(); window->DC.ItemWidthStack.pop_back(); } @@ -11502,14 +11248,14 @@ float ImGui::CalcItemWidth() ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; float w; - if (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasWidth) + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) w = g.NextItemData.Width; else w = window->DC.ItemWidth; if (w < 0.0f) { - float region_avail_x = GetContentRegionAvail().x; - w = ImMax(1.0f, region_avail_x + w); + float region_max_x = GetContentRegionMaxAbs().x; + w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w); } w = IM_TRUNC(w); return w; @@ -11521,19 +11267,22 @@ float ImGui::CalcItemWidth() // The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable) ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h) { - ImVec2 avail; + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + + ImVec2 region_max; if (size.x < 0.0f || size.y < 0.0f) - avail = GetContentRegionAvail(); + region_max = GetContentRegionMaxAbs(); if (size.x == 0.0f) size.x = default_w; else if (size.x < 0.0f) - size.x = ImMax(4.0f, avail.x + size.x); // <-- size.x is negative here so we are subtracting + size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x); if (size.y == 0.0f) size.y = default_h; else if (size.y < 0.0f) - size.y = ImMax(4.0f, avail.y + size.y); // <-- size.y is negative here so we are subtracting + size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y); return size; } @@ -11562,23 +11311,33 @@ float ImGui::GetFrameHeightWithSpacing() return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y; } -ImVec2 ImGui::GetContentRegionAvail() +// FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience! + +// FIXME: This is in window space (not screen space!). +ImVec2 ImGui::GetContentRegionMax() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; ImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max; - return mx - window->DC.CursorPos; + return mx - window->Pos; } -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - -// You should never need those functions. Always use GetCursorScreenPos() and GetContentRegionAvail()! -// They are bizarre local-coordinates which don't play well with scrolling. -ImVec2 ImGui::GetContentRegionMax() +// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features. +ImVec2 ImGui::GetContentRegionMaxAbs() { - return GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos(); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max; + return mx; } +ImVec2 ImGui::GetContentRegionAvail() +{ + ImGuiWindow* window = GImGui->CurrentWindow; + return GetContentRegionMaxAbs() - window->DC.CursorPos; +} + +// In window space (not screen space!) ImVec2 ImGui::GetWindowContentRegionMin() { ImGuiWindow* window = GImGui->CurrentWindow; @@ -11590,7 +11349,6 @@ ImVec2 ImGui::GetWindowContentRegionMax() ImGuiWindow* window = GImGui->CurrentWindow; return window->ContentRegionRect.Max - window->Pos; } -#endif // Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.) // Groups are currently a mishmash of functionalities which should perhaps be clarified and separated. @@ -11613,7 +11371,7 @@ void ImGui::BeginGroup() group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; group_data.BackupHoveredIdIsAlive = g.HoveredId != 0; group_data.BackupIsSameLine = window->DC.IsSameLine; - group_data.BackupDeactivatedIdIsAlive = g.DeactivatedItemData.IsAlive; + group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; group_data.EmitItem = true; window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x; @@ -11636,11 +11394,11 @@ void ImGui::EndGroup() if (window->DC.IsSetPos) ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); - // Include LastItemData.Rect.Max as a workaround for e.g. EndTable() undershooting with CursorMaxPos report. (#7543) - ImRect group_bb(group_data.BackupCursorPos, ImMax(ImMax(window->DC.CursorMaxPos, g.LastItemData.Rect.Max), group_data.BackupCursorPos)); + ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos)); + window->DC.CursorPos = group_data.BackupCursorPos; window->DC.CursorPosPrevLine = group_data.BackupCursorPosPrevLine; - window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, group_bb.Max); + window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos); window->DC.Indent = group_data.BackupIndent; window->DC.GroupOffset = group_data.BackupGroupOffset; window->DC.CurrLineSize = group_data.BackupCurrLineSize; @@ -11655,7 +11413,7 @@ void ImGui::EndGroup() return; } - window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. + window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now. ItemSize(group_bb.GetSize()); ItemAdd(group_bb, 0, NULL, ImGuiItemFlags_NoTabStop); @@ -11664,11 +11422,11 @@ void ImGui::EndGroup() // Also if you grep for LastItemId you'll notice it is only used in that context. // (The two tests not the same because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.) const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId; - const bool group_contains_deactivated_id = (group_data.BackupDeactivatedIdIsAlive == false) && (g.DeactivatedItemData.IsAlive == true); + const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true); if (group_contains_curr_active_id) g.LastItemData.ID = g.ActiveId; - else if (group_contains_deactivated_id) - g.LastItemData.ID = g.DeactivatedItemData.ID; + else if (group_contains_prev_active_id) + g.LastItemData.ID = g.ActiveIdPreviousFrame; g.LastItemData.Rect = group_bb; // Forward Hovered flag @@ -11682,7 +11440,7 @@ void ImGui::EndGroup() // Forward Deactivated flag g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDeactivated; - if (group_contains_deactivated_id) + if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Deactivated; g.GroupStack.pop_back(); @@ -11952,8 +11710,7 @@ bool ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags ext { ImGuiContext& g = *GImGui; - const bool is_dragdrop_tooltip = g.DragDropWithinSource || g.DragDropWithinTarget; - if (is_dragdrop_tooltip) + if (g.DragDropWithinSource || g.DragDropWithinTarget) { // Drag and Drop tooltips are positioning differently than other tooltips: // - offset visibility to increase visibility around mouse. @@ -11961,30 +11718,23 @@ bool ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags ext // We call SetNextWindowPos() to enforce position and disable clamping. // See FindBestWindowPosForPopup() for positionning logic of other tooltips (not drag and drop ones). //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding; - const bool is_touchscreen = (g.IO.MouseSource == ImGuiMouseSource_TouchScreen); - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0) - { - ImVec2 tooltip_pos = is_touchscreen ? (g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET_TOUCH * g.Style.MouseCursorScale) : (g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET_MOUSE * g.Style.MouseCursorScale); - ImVec2 tooltip_pivot = is_touchscreen ? TOOLTIP_DEFAULT_PIVOT_TOUCH : ImVec2(0.0f, 0.0f); - SetNextWindowPos(tooltip_pos, ImGuiCond_None, tooltip_pivot); - } - + ImVec2 tooltip_pos = g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET * g.Style.MouseCursorScale; + SetNextWindowPos(tooltip_pos); SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f); //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :( tooltip_flags |= ImGuiTooltipFlags_OverridePrevious; } - const char* window_name_template = is_dragdrop_tooltip ? "##Tooltip_DragDrop_%02d" : "##Tooltip_%02d"; - char window_name[32]; - ImFormatString(window_name, IM_ARRAYSIZE(window_name), window_name_template, g.TooltipOverrideCount); - if ((tooltip_flags & ImGuiTooltipFlags_OverridePrevious) && g.TooltipPreviousWindow != NULL && g.TooltipPreviousWindow->Active) - { - // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one. - //IMGUI_DEBUG_LOG("[tooltip] '%s' already active, using +1 for this frame\n", window_name); - SetWindowHiddenAndSkipItemsForCurrentFrame(g.TooltipPreviousWindow); - ImFormatString(window_name, IM_ARRAYSIZE(window_name), window_name_template, ++g.TooltipOverrideCount); - } - + char window_name[16]; + ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount); + if (tooltip_flags & ImGuiTooltipFlags_OverridePrevious) + if (ImGuiWindow* window = FindWindowByName(window_name)) + if (window->Active) + { + // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one. + SetWindowHiddenAndSkipItemsForCurrentFrame(window); + ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); + } ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking; Begin(window_name, NULL, flags | extra_window_flags); // 2023-03-09: Added bool return value to the API, but currently always returning true. @@ -12102,43 +11852,6 @@ ImGuiWindow* ImGui::GetTopMostAndVisiblePopupModal() return NULL; } - -// When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing) -// should be positioned behind that modal window, unless the window was created inside the modal begin-stack. -// In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent. -// - WindowA // FindBlockingModal() returns Modal1 -// - WindowB // .. returns Modal1 -// - Modal1 // .. returns Modal2 -// - WindowC // .. returns Modal2 -// - WindowD // .. returns Modal2 -// - Modal2 // .. returns Modal2 -// - WindowE // .. returns NULL -// Notes: -// - FindBlockingModal(NULL) == NULL is generally equivalent to GetTopMostPopupModal() == NULL. -// Only difference is here we check for ->Active/WasActive but it may be unnecessary. -ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - if (g.OpenPopupStack.Size <= 0) - return NULL; - - // Find a modal that has common parent with specified window. Specified window should be positioned behind that modal. - for (ImGuiPopupData& popup_data : g.OpenPopupStack) - { - ImGuiWindow* popup_window = popup_data.Window; - if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal)) - continue; - if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows. - continue; - if (window == NULL) // FindBlockingModal(NULL) test for if FocusWindow(NULL) is naturally possible via a mouse click. - return popup_window; - if (IsWindowWithinBeginStackOf(window, popup_window)) // Window may be over modal - continue; - return popup_window; // Place window right below first block modal - } - return NULL; -} - void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags) { ImGuiContext& g = *GImGui; @@ -12278,9 +11991,6 @@ void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_ ImGuiContext& g = *GImGui; IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupToLevel(%d), restore_under=%d\n", remaining, restore_focus_to_window_under_popup); IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size); - if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) - for (int n = remaining; n < g.OpenPopupStack.Size; n++) - IMGUI_DEBUG_LOG_POPUP("[popup] - Closing PopupID 0x%08X Window \"%s\"\n", g.OpenPopupStack[n].PopupId, g.OpenPopupStack[n].Window ? g.OpenPopupStack[n].Window->Name : NULL); // Trim open popup stack ImGuiPopupData prev_popup = g.OpenPopupStack[remaining]; @@ -12417,11 +12127,11 @@ void ImGui::EndPopup() NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); // Child-popups don't need to be laid out - const ImGuiID backup_within_end_child_id = g.WithinEndChildID; + IM_ASSERT(g.WithinEndChild == false); if (window->Flags & ImGuiWindowFlags_ChildWindow) - g.WithinEndChildID = window->ID; + g.WithinEndChild = true; End(); - g.WithinEndChildID = backup_within_end_child_id; + g.WithinEndChild = false; } // Helper to open a popup if mouse button is released over the item @@ -12623,319 +12333,24 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) if (window->Flags & ImGuiWindowFlags_Tooltip) { // Position tooltip (always follows mouse + clamp within outer boundaries) - // FIXME: - // - Too many paths. One problem is that FindBestWindowPosForPopupEx() doesn't allow passing a suggested position (so touch screen path doesn't use it by default). - // - Drag and drop tooltips are not using this path either: BeginTooltipEx() manually sets their position. - // - Require some tidying up. In theory we could handle both cases in same location, but requires a bit of shuffling - // as drag and drop tooltips are calling SetNextWindowPos() leading to 'window_pos_set_by_api' being set in Begin(). + // Note that drag and drop tooltips are NOT using this path: BeginTooltipEx() manually sets their position. + // In theory we could handle both cases in same location, but requires a bit of shuffling as drag and drop tooltips are calling SetWindowPos() leading to 'window_pos_set_by_api' being set in Begin() IM_ASSERT(g.CurrentWindow == window); const float scale = g.Style.MouseCursorScale; const ImVec2 ref_pos = NavCalcPreferredRefPos(); - - if (g.IO.MouseSource == ImGuiMouseSource_TouchScreen && NavCalcPreferredRefPosSource() == ImGuiInputSource_Mouse) - { - ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET_TOUCH * scale - (TOOLTIP_DEFAULT_PIVOT_TOUCH * window->Size); - if (r_outer.Contains(ImRect(tooltip_pos, tooltip_pos + window->Size))) - return tooltip_pos; - } - - ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET_MOUSE * scale; + const ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET * scale; ImRect r_avoid; - if (g.NavCursorVisible && g.NavHighlightItemUnderNav && !g.IO.ConfigNavMoveSetMousePos) + if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)) r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8); else r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * scale, ref_pos.y + 24 * scale); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important. //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255, 0, 255, 255)); - return FindBestWindowPosForPopupEx(tooltip_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip); } IM_ASSERT(0); return window->Pos; } -//----------------------------------------------------------------------------- -// [SECTION] WINDOW FOCUS -//---------------------------------------------------------------------------- -// - SetWindowFocus() -// - SetNextWindowFocus() -// - IsWindowFocused() -// - UpdateWindowInFocusOrderList() [Internal] -// - BringWindowToFocusFront() [Internal] -// - BringWindowToDisplayFront() [Internal] -// - BringWindowToDisplayBack() [Internal] -// - BringWindowToDisplayBehind() [Internal] -// - FindWindowDisplayIndex() [Internal] -// - FocusWindow() [Internal] -// - FocusTopMostWindowUnderOne() [Internal] -//----------------------------------------------------------------------------- - -void ImGui::SetWindowFocus() -{ - FocusWindow(GImGui->CurrentWindow); -} - -void ImGui::SetWindowFocus(const char* name) -{ - if (name) - { - if (ImGuiWindow* window = FindWindowByName(name)) - FocusWindow(window); - } - else - { - FocusWindow(NULL); - } -} - -void ImGui::SetNextWindowFocus() -{ - ImGuiContext& g = *GImGui; - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus; -} - -// Similar to IsWindowHovered() -bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* ref_window = g.NavWindow; - ImGuiWindow* cur_window = g.CurrentWindow; - - if (ref_window == NULL) - return false; - if (flags & ImGuiFocusedFlags_AnyWindow) - return true; - - IM_ASSERT(cur_window); // Not inside a Begin()/End() - const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0; - const bool dock_hierarchy = (flags & ImGuiFocusedFlags_DockHierarchy) != 0; - if (flags & ImGuiHoveredFlags_RootWindow) - cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy, dock_hierarchy); - - if (flags & ImGuiHoveredFlags_ChildWindows) - return IsWindowChildOf(ref_window, cur_window, popup_hierarchy, dock_hierarchy); - else - return (ref_window == cur_window); -} - -static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - IM_UNUSED(g); - int order = window->FocusOrder; - IM_ASSERT(window->RootWindow == window); // No child window (not testing _ChildWindow because of docking) - IM_ASSERT(g.WindowsFocusOrder[order] == window); - return order; -} - -static void ImGui::UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags) -{ - ImGuiContext& g = *GImGui; - - const bool new_is_explicit_child = (new_flags & ImGuiWindowFlags_ChildWindow) != 0 && ((new_flags & ImGuiWindowFlags_Popup) == 0 || (new_flags & ImGuiWindowFlags_ChildMenu) != 0); - const bool child_flag_changed = new_is_explicit_child != window->IsExplicitChild; - if ((just_created || child_flag_changed) && !new_is_explicit_child) - { - IM_ASSERT(!g.WindowsFocusOrder.contains(window)); - g.WindowsFocusOrder.push_back(window); - window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1); - } - else if (!just_created && child_flag_changed && new_is_explicit_child) - { - IM_ASSERT(g.WindowsFocusOrder[window->FocusOrder] == window); - for (int n = window->FocusOrder + 1; n < g.WindowsFocusOrder.Size; n++) - g.WindowsFocusOrder[n]->FocusOrder--; - g.WindowsFocusOrder.erase(g.WindowsFocusOrder.Data + window->FocusOrder); - window->FocusOrder = -1; - } - window->IsExplicitChild = new_is_explicit_child; -} - -void ImGui::BringWindowToFocusFront(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(window == window->RootWindow); - - const int cur_order = window->FocusOrder; - IM_ASSERT(g.WindowsFocusOrder[cur_order] == window); - if (g.WindowsFocusOrder.back() == window) - return; - - const int new_order = g.WindowsFocusOrder.Size - 1; - for (int n = cur_order; n < new_order; n++) - { - g.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1]; - g.WindowsFocusOrder[n]->FocusOrder--; - IM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n); - } - g.WindowsFocusOrder[new_order] = window; - window->FocusOrder = (short)new_order; -} - -// Note technically focus related but rather adjacent and close to BringWindowToFocusFront() -void ImGui::BringWindowToDisplayFront(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* current_front_window = g.Windows.back(); - if (current_front_window == window || current_front_window->RootWindowDockTree == window) // Cheap early out (could be better) - return; - for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window - if (g.Windows[i] == window) - { - memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*)); - g.Windows[g.Windows.Size - 1] = window; - break; - } -} - -void ImGui::BringWindowToDisplayBack(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - if (g.Windows[0] == window) - return; - for (int i = 0; i < g.Windows.Size; i++) - if (g.Windows[i] == window) - { - memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*)); - g.Windows[0] = window; - break; - } -} - -void ImGui::BringWindowToDisplayBehind(ImGuiWindow* window, ImGuiWindow* behind_window) -{ - IM_ASSERT(window != NULL && behind_window != NULL); - ImGuiContext& g = *GImGui; - window = window->RootWindow; - behind_window = behind_window->RootWindow; - int pos_wnd = FindWindowDisplayIndex(window); - int pos_beh = FindWindowDisplayIndex(behind_window); - if (pos_wnd < pos_beh) - { - size_t copy_bytes = (pos_beh - pos_wnd - 1) * sizeof(ImGuiWindow*); - memmove(&g.Windows.Data[pos_wnd], &g.Windows.Data[pos_wnd + 1], copy_bytes); - g.Windows[pos_beh - 1] = window; - } - else - { - size_t copy_bytes = (pos_wnd - pos_beh) * sizeof(ImGuiWindow*); - memmove(&g.Windows.Data[pos_beh + 1], &g.Windows.Data[pos_beh], copy_bytes); - g.Windows[pos_beh] = window; - } -} - -int ImGui::FindWindowDisplayIndex(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - return g.Windows.index_from_ptr(g.Windows.find(window)); -} - -// Moving window to front of display and set focus (which happens to be back of our sorted list) -void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags) -{ - ImGuiContext& g = *GImGui; - - // Modal check? - if ((flags & ImGuiFocusRequestFlags_UnlessBelowModal) && (g.NavWindow != window)) // Early out in common case. - if (ImGuiWindow* blocking_modal = FindBlockingModal(window)) - { - // This block would typically be reached in two situations: - // - API call to FocusWindow() with a window under a modal and ImGuiFocusRequestFlags_UnlessBelowModal flag. - // - User clicking on void or anything behind a modal while a modal is open (window == NULL) - IMGUI_DEBUG_LOG_FOCUS("[focus] FocusWindow(\"%s\", UnlessBelowModal): prevented by \"%s\".\n", window ? window->Name : "", blocking_modal->Name); - if (window && window == window->RootWindow && (window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) - BringWindowToDisplayBehind(window, blocking_modal); // Still bring right under modal. (FIXME: Could move in focus list too?) - ClosePopupsOverWindow(GetTopMostPopupModal(), false); // Note how we need to use GetTopMostPopupModal() aad NOT blocking_modal, to handle nested modals - return; - } - - // Find last focused child (if any) and focus it instead. - if ((flags & ImGuiFocusRequestFlags_RestoreFocusedChild) && window != NULL) - window = NavRestoreLastChildNavWindow(window); - - // Apply focus - if (g.NavWindow != window) - { - SetNavWindow(window); - if (window && g.NavHighlightItemUnderNav) - g.NavMousePosDirty = true; - g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId - g.NavLayer = ImGuiNavLayer_Main; - SetNavFocusScope(window ? window->NavRootFocusScopeId : 0); - g.NavIdIsAlive = false; - g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid; - - // Close popups if any - ClosePopupsOverWindow(window, false); - } - - // Move the root window to the top of the pile - IM_ASSERT(window == NULL || window->RootWindowDockTree != NULL); - ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; - ImGuiWindow* display_front_window = window ? window->RootWindowDockTree : NULL; - ImGuiDockNode* dock_node = window ? window->DockNode : NULL; - bool active_id_window_is_dock_node_host = (g.ActiveIdWindow && dock_node && dock_node->HostWindow == g.ActiveIdWindow); - - // Steal active widgets. Some of the cases it triggers includes: - // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run. - // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId) - // - Using dock host items (tab, collapse button) can trigger this before we redirect the ActiveIdWindow toward the child window. - if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window) - if (!g.ActiveIdNoClearOnFocusLoss && !active_id_window_is_dock_node_host) - ClearActiveID(); - - // Passing NULL allow to disable keyboard focus - if (!window) - return; - window->LastFrameJustFocused = g.FrameCount; - - // Select in dock node - // For #2304 we avoid applying focus immediately before the tabbar is visible. - //if (dock_node && dock_node->TabBar) - // dock_node->TabBar->SelectedTabId = dock_node->TabBar->NextSelectedTabId = window->TabId; - - // Bring to front - BringWindowToFocusFront(focus_front_window); - if (((window->Flags | focus_front_window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) - BringWindowToDisplayFront(display_front_window); -} - -void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags) -{ - ImGuiContext& g = *GImGui; - int start_idx = g.WindowsFocusOrder.Size - 1; - if (under_this_window != NULL) - { - // Aim at root window behind us, if we are in a child window that's our own root (see #4640) - int offset = -1; - while (under_this_window->Flags & ImGuiWindowFlags_ChildWindow) - { - under_this_window = under_this_window->ParentWindow; - offset = 0; - } - start_idx = FindWindowFocusIndex(under_this_window) + offset; - } - for (int i = start_idx; i >= 0; i--) - { - // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user. - ImGuiWindow* window = g.WindowsFocusOrder[i]; - if (window == ignore_window || !window->WasActive) - continue; - if (filter_viewport != NULL && window->Viewport != filter_viewport) - continue; - if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) - { - // FIXME-DOCK: When ImGuiFocusRequestFlags_RestoreFocusedChild is set... - // This is failing (lagging by one frame) for docked windows. - // If A and B are docked into window and B disappear, at the NewFrame() call site window->NavLastChildNavWindow will still point to B. - // We might leverage the tab order implicitly stored in window->DockNodeAsHost->TabBar (essentially the 'most_recently_selected_tab' code in tab bar will do that but on next update) - // to tell which is the "previous" window. Or we may leverage 'LastFrameFocused/LastFrameJustFocused' and have this function handle child window itself? - FocusWindow(window, flags); - return; - } - } - FocusWindow(NULL, flags); -} - //----------------------------------------------------------------------------- // [SECTION] KEYBOARD/GAMEPAD NAVIGATION //----------------------------------------------------------------------------- @@ -12944,23 +12359,6 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind // In our terminology those should be interchangeable, yet right now this is super confusing. // Those two functions are merely a legacy artifact, so at minimum naming should be clarified. -void ImGui::SetNavCursorVisible(bool visible) -{ - ImGuiContext& g = *GImGui; - if (g.IO.ConfigNavCursorVisibleAlways) - visible = true; - g.NavCursorVisible = visible; -} - -// (was called NavRestoreHighlightAfterMove() before 1.91.4) -void ImGui::SetNavCursorVisibleAfterMove() -{ - ImGuiContext& g = *GImGui; - if (g.IO.ConfigNavCursorVisibleAuto) - g.NavCursorVisible = true; - g.NavHighlightItemUnderNav = g.NavMousePosDirty = true; -} - void ImGui::SetNavWindow(ImGuiWindow* window) { ImGuiContext& g = *GImGui; @@ -13022,9 +12420,9 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window) window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect); if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) - g.NavHighlightItemUnderNav = true; - else if (g.IO.ConfigNavCursorVisibleAuto) - g.NavCursorVisible = false; + g.NavDisableMouseHover = true; + else + g.NavDisableHighlight = true; // Clear preferred scoring position (NavMoveRequestApplyResult() will tend to restore it) NavClearPreferredPosForAxis(ImGuiAxis_X); @@ -13047,7 +12445,7 @@ static float inline NavScoreItemDistInterval(float cand_min, float cand_max, flo return 0.0f; } -// Scoring function for keyboard/gamepad directional navigation. Based on https://gist.github.com/rygorous/6981057 +// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057 static bool ImGui::NavScoreItem(ImGuiNavItemData* result) { ImGuiContext& g = *GImGui; @@ -13196,9 +12594,9 @@ static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result) result->Window = window; result->ID = g.LastItemData.ID; result->FocusScopeId = g.CurrentFocusScopeId; - result->ItemFlags = g.LastItemData.ItemFlags; + result->InFlags = g.LastItemData.InFlags; result->RectRel = WindowRectAbsToRel(window, g.LastItemData.NavRect); - if (result->ItemFlags & ImGuiItemFlags_HasSelectionUserData) + if (result->InFlags & ImGuiItemFlags_HasSelectionUserData) { IM_ASSERT(g.NextItemData.SelectionUserData != ImGuiSelectionUserData_Invalid); result->SelectionUserData = g.NextItemData.SelectionUserData; // INTENTIONAL: At this point this field is not cleared in NextItemData. Avoid unnecessary copy to LastItemData. @@ -13221,7 +12619,7 @@ static void ImGui::NavProcessItem() ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; const ImGuiID id = g.LastItemData.ID; - const ImGuiItemFlags item_flags = g.LastItemData.ItemFlags; + const ImGuiItemFlags item_flags = g.LastItemData.InFlags; // When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221) if (window->DC.NavIsScrollPushableX == false) @@ -13283,7 +12681,7 @@ static void ImGui::NavProcessItem() SetNavFocusScope(g.CurrentFocusScopeId); // Will set g.NavFocusScopeId AND store g.NavFocusScopePath g.NavFocusScopeId = g.CurrentFocusScopeId; g.NavIdIsAlive = true; - if (g.LastItemData.ItemFlags & ImGuiItemFlags_HasSelectionUserData) + if (g.LastItemData.InFlags & ImGuiItemFlags_HasSelectionUserData) { IM_ASSERT(g.NextItemData.SelectionUserData != ImGuiSelectionUserData_Invalid); g.NavLastValidSelectionUserData = g.NextItemData.SelectionUserData; // INTENTIONAL: At this point this field is not cleared in NextItemData. Avoid unnecessary copy to LastItemData. @@ -13369,7 +12767,6 @@ void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavM { ImGuiContext& g = *GImGui; IM_ASSERT(g.NavWindow != NULL); - //IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestSubmit: dir %c, window \"%s\"\n", "-WENS"[move_dir + 1], g.NavWindow->Name); if (move_flags & ImGuiNavMoveFlags_IsTabbing) move_flags |= ImGuiNavMoveFlags_AllowCurrentNavId; @@ -13404,7 +12801,7 @@ void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGu ImGuiContext& g = *GImGui; g.NavMoveScoringItems = false; g.LastItemData.ID = tree_node_data->ID; - g.LastItemData.ItemFlags = tree_node_data->ItemFlags & ~ImGuiItemFlags_HasSelectionUserData; // Losing SelectionUserData, recovered next-frame (cheaper). + g.LastItemData.InFlags = tree_node_data->InFlags & ~ImGuiItemFlags_HasSelectionUserData; // Losing SelectionUserData, recovered next-frame (cheaper). g.LastItemData.NavRect = tree_node_data->NavRect; NavApplyItemToResult(result); // Result this instead of implementing a NavApplyPastTreeNodeToResult() NavClearPreferredPosForAxis(ImGuiAxis_Y); @@ -13490,6 +12887,13 @@ void ImGui::NavRestoreLayer(ImGuiNavLayer layer) } } +void ImGui::NavRestoreHighlightAfterMove() +{ + ImGuiContext& g = *GImGui; + g.NavDisableHighlight = false; + g.NavDisableMouseHover = g.NavMousePosDirty = true; +} + static inline void ImGui::NavUpdateAnyRequestFlag() { ImGuiContext& g = *GImGui; @@ -13531,29 +12935,14 @@ void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit) } } -static ImGuiInputSource ImGui::NavCalcPreferredRefPosSource() -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.NavWindow; - const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID; - - // Testing for !activated_shortcut here could in theory be removed if we decided that activating a remote shortcut altered one of the g.NavDisableXXX flag. - if ((!g.NavCursorVisible || !g.NavHighlightItemUnderNav || !window) && !activated_shortcut) - return ImGuiInputSource_Mouse; - else - return ImGuiInputSource_Keyboard; // or Nav in general -} - static ImVec2 ImGui::NavCalcPreferredRefPos() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.NavWindow; - ImGuiInputSource source = NavCalcPreferredRefPosSource(); - const bool activated_shortcut = g.ActiveId != 0 && g.ActiveIdFromShortcut && g.ActiveId == g.LastItemData.ID; // Testing for !activated_shortcut here could in theory be removed if we decided that activating a remote shortcut altered one of the g.NavDisableXXX flag. - if (source == ImGuiInputSource_Mouse) + if ((g.NavDisableHighlight || !g.NavDisableMouseHover || !window) && !activated_shortcut) { // Mouse (we need a fallback in case the mouse becomes invalid after being used) // The +1.0f offset when stored by OpenPopupEx() allows reopening this or another popup (same or another mouse button) while not moving the mouse, it is pretty standard. @@ -13642,14 +13031,11 @@ static void ImGui::NavUpdate() NavMoveRequestApplyResult(); g.NavTabbingCounter = 0; g.NavMoveSubmitted = g.NavMoveScoringItems = false; - if (g.NavCursorHideFrames > 0) - if (--g.NavCursorHideFrames == 0) - g.NavCursorVisible = true; // Schedule mouse position update (will be done at the bottom of this function, after 1) processing all move requests and 2) updating scrolling) bool set_mouse_pos = false; if (g.NavMousePosDirty && g.NavIdIsAlive) - if (g.NavCursorVisible && g.NavHighlightItemUnderNav && g.NavWindow) + if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow) set_mouse_pos = true; g.NavMousePosDirty = false; IM_ASSERT(g.NavLayer == ImGuiNavLayer_Main || g.NavLayer == ImGuiNavLayer_Menu); @@ -13665,7 +13051,7 @@ static void ImGui::NavUpdate() // Set output flags for user application io.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs); - io.NavVisible = (io.NavActive && g.NavId != 0 && g.NavCursorVisible) || (g.NavWindowingTarget != NULL); + io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL); // Process NavCancel input (to close a popup, get back to parent, clear focus) NavUpdateCancelRequest(); @@ -13673,7 +13059,7 @@ static void ImGui::NavUpdate() // Process manual activation request g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = 0; g.NavActivateFlags = ImGuiActivateFlags_None; - if (g.NavId != 0 && g.NavCursorVisible && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) { const bool activate_down = (nav_keyboard_active && IsKeyDown(ImGuiKey_Space, ImGuiKeyOwner_NoOwner)) || (nav_gamepad_active && IsKeyDown(ImGuiKey_NavGamepadActivate, ImGuiKeyOwner_NoOwner)); const bool activate_pressed = activate_down && ((nav_keyboard_active && IsKeyPressed(ImGuiKey_Space, 0, ImGuiKeyOwner_NoOwner)) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadActivate, 0, ImGuiKeyOwner_NoOwner))); @@ -13698,9 +13084,7 @@ static void ImGui::NavUpdate() } } if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) - g.NavCursorVisible = false; - else if (g.IO.ConfigNavCursorVisibleAlways && g.NavCursorHideFrames == 0) - g.NavCursorVisible = true; + g.NavDisableHighlight = true; if (g.NavActivateId != 0) IM_ASSERT(g.NavActivateDownId == g.NavActivateId); @@ -13731,7 +13115,7 @@ static void ImGui::NavUpdate() { // *Fallback* manual-scroll with Nav directional keys when window has no navigable item ImGuiWindow* window = g.NavWindow; - const float scroll_speed = IM_ROUND(window->FontRefSize * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. + const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. const ImGuiDir move_dir = g.NavMoveDir; if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY && move_dir != ImGuiDir_None) { @@ -13757,13 +13141,13 @@ static void ImGui::NavUpdate() // Always prioritize mouse highlight if navigation is disabled if (!nav_keyboard_active && !nav_gamepad_active) { - g.NavCursorVisible = false; - g.NavHighlightItemUnderNav = set_mouse_pos = false; + g.NavDisableHighlight = true; + g.NavDisableMouseHover = set_mouse_pos = false; } // Update mouse position if requested // (This will take into account the possibility that a Scroll was queued in the window to offset our absolute mouse position before scroll has been applied) - if (set_mouse_pos && io.ConfigNavMoveSetMousePos && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) + if (set_mouse_pos && (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos)) TeleportMousePos(NavCalcPreferredRefPos()); // [DEBUG] @@ -13793,7 +13177,7 @@ void ImGui::NavInitRequestApplyResult() g.NavJustMovedToFocusScopeId = result->FocusScopeId; g.NavJustMovedToKeyMods = 0; g.NavJustMovedToIsTabbing = false; - g.NavJustMovedToHasSelectionData = (result->ItemFlags & ImGuiItemFlags_HasSelectionUserData) != 0; + g.NavJustMovedToHasSelectionData = (result->InFlags & ImGuiItemFlags_HasSelectionUserData) != 0; } // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called) @@ -13804,7 +13188,7 @@ void ImGui::NavInitRequestApplyResult() if (result->SelectionUserData != ImGuiSelectionUserData_Invalid) g.NavLastValidSelectionUserData = result->SelectionUserData; if (g.NavInitRequestFromMove) - SetNavCursorVisibleAfterMove(); + NavRestoreHighlightAfterMove(); } // Bias scoring rect ahead of scoring + update preferred pos (if missing) using source position @@ -13901,8 +13285,7 @@ void ImGui::NavUpdateCreateMoveRequest() IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", window ? window->Name : "", g.NavLayer); g.NavInitRequest = g.NavInitRequestFromMove = true; g.NavInitResult.ID = 0; - if (g.IO.ConfigNavCursorVisibleAuto) - g.NavCursorVisible = true; + g.NavDisableHighlight = false; } // When using gamepad, we project the reference nav bounding box into window visible area. @@ -13921,8 +13304,8 @@ void ImGui::NavUpdateCreateMoveRequest() if ((clamp_x || clamp_y) && !inner_rect_rel.Contains(window->NavRectRel[g.NavLayer])) { IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel for gamepad move\n"); - float pad_x = ImMin(inner_rect_rel.GetWidth(), window->FontRefSize * 0.5f); - float pad_y = ImMin(inner_rect_rel.GetHeight(), window->FontRefSize * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item + float pad_x = ImMin(inner_rect_rel.GetWidth(), window->CalcFontSize() * 0.5f); + float pad_y = ImMin(inner_rect_rel.GetHeight(), window->CalcFontSize() * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item inner_rect_rel.Min.x = clamp_x ? (inner_rect_rel.Min.x + pad_x) : -FLT_MAX; inner_rect_rel.Max.x = clamp_x ? (inner_rect_rel.Max.x - pad_x) : +FLT_MAX; inner_rect_rel.Min.y = clamp_y ? (inner_rect_rel.Min.y + pad_y) : -FLT_MAX; @@ -13966,7 +13349,7 @@ void ImGui::NavUpdateCreateTabbingRequest() // See NavProcessItemForTabbingRequest() for a description of the various forward/backward tabbing cases with and without wrapping. const bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; if (nav_keyboard_active) - g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.NavCursorVisible == false && g.ActiveId == 0) ? 0 : +1; + g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.NavDisableHighlight == true && g.ActiveId == 0) ? 0 : +1; else g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.ActiveId == 0) ? 0 : +1; ImGuiNavMoveFlags move_flags = ImGuiNavMoveFlags_IsTabbing | ImGuiNavMoveFlags_Activate; @@ -13998,9 +13381,9 @@ void ImGui::NavMoveRequestApplyResult() if (result == NULL) { if (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) - g.NavMoveFlags |= ImGuiNavMoveFlags_NoSetNavCursorVisible; - if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavCursorVisible) == 0) - SetNavCursorVisibleAfterMove(); + g.NavMoveFlags |= ImGuiNavMoveFlags_NoSetNavHighlight; + if (g.NavId != 0 && (g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavHighlight) == 0) + NavRestoreHighlightAfterMove(); NavClearPreferredPosForAxis(axis); // On a failed move, clear preferred pos for this axis. IMGUI_DEBUG_LOG_NAV("[nav] NavMoveSubmitted but not led to a result!\n"); return; @@ -14053,7 +13436,7 @@ void ImGui::NavMoveRequestApplyResult() g.NavJustMovedToFocusScopeId = result->FocusScopeId; g.NavJustMovedToKeyMods = g.NavMoveKeyMods; g.NavJustMovedToIsTabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) != 0; - g.NavJustMovedToHasSelectionData = (result->ItemFlags & ImGuiItemFlags_HasSelectionUserData) != 0; + g.NavJustMovedToHasSelectionData = (result->InFlags & ImGuiItemFlags_HasSelectionUserData) != 0; //IMGUI_DEBUG_LOG_NAV("[nav] NavJustMovedFromFocusScopeId = 0x%08X, NavJustMovedToFocusScopeId = 0x%08X\n", g.NavJustMovedFromFocusScopeId, g.NavJustMovedToFocusScopeId); } @@ -14073,7 +13456,7 @@ void ImGui::NavMoveRequestApplyResult() } // Tabbing: Activates Inputable, otherwise only Focus - if ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && (result->ItemFlags & ImGuiItemFlags_Inputable) == 0) + if ((g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && (result->InFlags & ImGuiItemFlags_Inputable) == 0) g.NavMoveFlags &= ~ImGuiNavMoveFlags_Activate; // Activate @@ -14085,12 +13468,12 @@ void ImGui::NavMoveRequestApplyResult() g.NavNextActivateFlags |= ImGuiActivateFlags_PreferInput | ImGuiActivateFlags_TryToPreserveState | ImGuiActivateFlags_FromTabbing; } - // Make nav cursor visible - if ((g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavCursorVisible) == 0) - SetNavCursorVisibleAfterMove(); + // Enable nav highlight + if ((g.NavMoveFlags & ImGuiNavMoveFlags_NoSetNavHighlight) == 0) + NavRestoreHighlightAfterMove(); } -// Process Escape/NavCancel input (to close a popup, get back to parent, clear focus) +// Process NavCancel input (to close a popup, get back to parent, clear focus) // FIXME: In order to support e.g. Escape to clear a selection we'll need: // - either to store the equivalent of ActiveIdUsingKeyInputMask for a FocusScope and test for it. // - either to move most/all of those tests to the epilogue/end functions of the scope they are dealing with (e.g. exit child window in EndChild()) or in EndFrame(), to allow an earlier intercept @@ -14111,7 +13494,7 @@ static void ImGui::NavUpdateCancelRequest() { // Leave the "menu" layer NavRestoreLayer(ImGuiNavLayer_Main); - SetNavCursorVisibleAfterMove(); + NavRestoreHighlightAfterMove(); } else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->RootWindowForNav->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->RootWindowForNav->ParentWindow) { @@ -14121,7 +13504,7 @@ static void ImGui::NavUpdateCancelRequest() IM_ASSERT(child_window->ChildId != 0); FocusWindow(parent_window); SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_window->Rect())); - SetNavCursorVisibleAfterMove(); + NavRestoreHighlightAfterMove(); } else if (g.OpenPopupStack.Size > 0 && g.OpenPopupStack.back().Window != NULL && !(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal)) { @@ -14131,16 +13514,9 @@ static void ImGui::NavUpdateCancelRequest() else { // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were - // FIXME-NAV: This should happen on window appearing. - if (g.IO.ConfigNavEscapeClearFocusItem || g.IO.ConfigNavEscapeClearFocusWindow) - if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup)))// || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) - g.NavWindow->NavLastIds[0] = 0; - - // Clear nav focus - if (g.IO.ConfigNavEscapeClearFocusItem || g.IO.ConfigNavEscapeClearFocusWindow) - g.NavId = 0; - if (g.IO.ConfigNavEscapeClearFocusWindow) - FocusWindow(NULL); + if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow))) + g.NavWindow->NavLastIds[0] = 0; + g.NavId = 0; } } @@ -14180,7 +13556,7 @@ static float ImGui::NavUpdatePageUpPageDown() else { ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; - const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->FontRefSize * 1.0f + nav_rect_rel.GetHeight()); + const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); float nav_scoring_rect_offset_y = 0.0f; if (IsKeyPressed(ImGuiKey_PageUp, true)) { @@ -14296,12 +13672,14 @@ static void ImGui::NavUpdateCreateWrappingRequest() NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags, g.NavMoveScrollFlags); } -// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext) -// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically. -// If you want a window to never be focused, you may use the e.g. NoInputs flag. -bool ImGui::IsWindowNavFocusable(ImGuiWindow* window) +static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) { - return window->WasActive && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus); + ImGuiContext& g = *GImGui; + IM_UNUSED(g); + int order = window->FocusOrder; + IM_ASSERT(window->RootWindow == window); // No child window (not testing _ChildWindow because of docking) + IM_ASSERT(g.WindowsFocusOrder[order] == window); + return order; } static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N) @@ -14313,7 +13691,7 @@ static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // return NULL; } -static void NavUpdateWindowingTarget(int focus_change_dir) +static void NavUpdateWindowingHighlightWindow(int focus_change_dir) { ImGuiContext& g = *GImGui; IM_ASSERT(g.NavWindowingTarget); @@ -14358,24 +13736,21 @@ static void ImGui::NavUpdateWindowing() // Start CTRL+Tab or Square+L/R window selection // (g.ConfigNavWindowingKeyNext/g.ConfigNavWindowingKeyPrev defaults are ImGuiMod_Ctrl|ImGuiKey_Tab and ImGuiMod_Ctrl|ImGuiMod_Shift|ImGuiKey_Tab) - const ImGuiID owner_id = ImHashStr("##NavUpdateWindowing"); + const ImGuiID owner_id = ImHashStr("###NavUpdateWindowing"); const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; const bool keyboard_next_window = allow_windowing && g.ConfigNavWindowingKeyNext && Shortcut(g.ConfigNavWindowingKeyNext, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways, owner_id); const bool keyboard_prev_window = allow_windowing && g.ConfigNavWindowingKeyPrev && Shortcut(g.ConfigNavWindowingKeyPrev, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways, owner_id); const bool start_windowing_with_gamepad = allow_windowing && nav_gamepad_active && !g.NavWindowingTarget && IsKeyPressed(ImGuiKey_NavGamepadMenu, ImGuiInputFlags_None); const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && (keyboard_next_window || keyboard_prev_window); // Note: enabled even without NavEnableKeyboard! - bool just_started_windowing_from_null_focus = false; if (start_windowing_with_gamepad || start_windowing_with_keyboard) if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) { - g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // Current location + g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f; g.NavWindowingAccumDeltaPos = g.NavWindowingAccumDeltaSize = ImVec2(0.0f, 0.0f); g.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : false; // Gamepad starts toggling layer g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad; - if (g.NavWindow == NULL) - just_started_windowing_from_null_focus = true; // Manually register ownership of our mods. Using a global route in the Shortcut() calls instead would probably be correct but may have more side-effects. if (keyboard_next_window || keyboard_prev_window) @@ -14391,9 +13766,9 @@ static void ImGui::NavUpdateWindowing() // Select window to focus const int focus_change_dir = (int)IsKeyPressed(ImGuiKey_GamepadL1) - (int)IsKeyPressed(ImGuiKey_GamepadR1); - if (focus_change_dir != 0 && !just_started_windowing_from_null_focus) + if (focus_change_dir != 0) { - NavUpdateWindowingTarget(focus_change_dir); + NavUpdateWindowingHighlightWindow(focus_change_dir); g.NavWindowingHighlightAlpha = 1.0f; } @@ -14416,25 +13791,22 @@ static void ImGui::NavUpdateWindowing() ImGuiKeyChord shared_mods = ((g.ConfigNavWindowingKeyNext ? g.ConfigNavWindowingKeyNext : ImGuiMod_Mask_) & (g.ConfigNavWindowingKeyPrev ? g.ConfigNavWindowingKeyPrev : ImGuiMod_Mask_)) & ImGuiMod_Mask_; IM_ASSERT(shared_mods != 0); // Next/Prev shortcut currently needs a shared modifier to "hold", otherwise Prev actions would keep cycling between two windows. g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f - if ((keyboard_next_window || keyboard_prev_window) && !just_started_windowing_from_null_focus) - NavUpdateWindowingTarget(keyboard_next_window ? -1 : +1); + if (keyboard_next_window || keyboard_prev_window) + NavUpdateWindowingHighlightWindow(keyboard_next_window ? -1 : +1); else if ((io.KeyMods & shared_mods) != shared_mods) apply_focus_window = g.NavWindowingTarget; } // Keyboard: Press and Release ALT to toggle menu layer const ImGuiKey windowing_toggle_keys[] = { ImGuiKey_LeftAlt, ImGuiKey_RightAlt }; - bool windowing_toggle_layer_start = false; - if (g.NavWindow != NULL && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) - for (ImGuiKey windowing_toggle_key : windowing_toggle_keys) - if (nav_keyboard_active && IsKeyPressed(windowing_toggle_key, 0, ImGuiKeyOwner_NoOwner)) - { - windowing_toggle_layer_start = true; - g.NavWindowingToggleLayer = true; - g.NavWindowingToggleKey = windowing_toggle_key; - g.NavInputSource = ImGuiInputSource_Keyboard; - break; - } + for (ImGuiKey windowing_toggle_key : windowing_toggle_keys) + if (nav_keyboard_active && IsKeyPressed(windowing_toggle_key, 0, ImGuiKeyOwner_NoOwner)) + { + g.NavWindowingToggleLayer = true; + g.NavWindowingToggleKey = windowing_toggle_key; + g.NavInputSource = ImGuiInputSource_Keyboard; + break; + } if (g.NavWindowingToggleLayer && g.NavInputSource == ImGuiInputSource_Keyboard) { // We cancel toggling nav layer when any text has been typed (generally while holding Alt). (See #370) @@ -14443,9 +13815,7 @@ static void ImGui::NavUpdateWindowing() // We cancel toggling nav layer if an owner has claimed the key. if (io.InputQueueCharacters.Size > 0 || io.KeyCtrl || io.KeyShift || io.KeySuper) g.NavWindowingToggleLayer = false; - else if (windowing_toggle_layer_start == false && g.LastKeyboardKeyPressTime == g.Time) - g.NavWindowingToggleLayer = false; - else if (TestKeyOwner(g.NavWindowingToggleKey, ImGuiKeyOwner_NoOwner) == false || TestKeyOwner(ImGuiMod_Alt, ImGuiKeyOwner_NoOwner) == false) + if (TestKeyOwner(g.NavWindowingToggleKey, ImGuiKeyOwner_NoOwner) == false || TestKeyOwner(ImGuiMod_Alt, ImGuiKeyOwner_NoOwner) == false) g.NavWindowingToggleLayer = false; // Apply layer toggle on Alt release @@ -14471,7 +13841,7 @@ static void ImGui::NavUpdateWindowing() const float NAV_MOVE_SPEED = 800.0f; const float move_step = NAV_MOVE_SPEED * io.DeltaTime * ImMin(io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); g.NavWindowingAccumDeltaPos += nav_move_dir * move_step; - g.NavHighlightItemUnderNav = true; + g.NavDisableMouseHover = true; ImVec2 accum_floored = ImTrunc(g.NavWindowingAccumDeltaPos); if (accum_floored.x != 0.0f || accum_floored.y != 0.0f) { @@ -14489,7 +13859,7 @@ static void ImGui::NavUpdateWindowing() // Investigate for each of them: ClearActiveID(), NavRestoreHighlightAfterMove(), NavRestoreLastChildNavWindow(), ClosePopupsOverWindow(), NavInitWindow() ImGuiViewport* previous_viewport = g.NavWindow ? g.NavWindow->Viewport : NULL; ClearActiveID(); - SetNavCursorVisibleAfterMove(); + NavRestoreHighlightAfterMove(); ClosePopupsOverWindow(apply_focus_window, false); FocusWindow(apply_focus_window, ImGuiFocusRequestFlags_RestoreFocusedChild); apply_focus_window = g.NavWindow; @@ -14541,7 +13911,7 @@ static void ImGui::NavUpdateWindowing() if (new_nav_layer == ImGuiNavLayer_Menu && !preserve_layer_1_nav_id) g.NavWindow->NavLastIds[new_nav_layer] = 0; NavRestoreLayer(new_nav_layer); - SetNavCursorVisibleAfterMove(); + NavRestoreHighlightAfterMove(); } } } @@ -14568,12 +13938,12 @@ void ImGui::NavUpdateWindowingOverlay() return; if (g.NavWindowingListWindow == NULL) - g.NavWindowingListWindow = FindWindowByName("##NavWindowingOverlay"); + g.NavWindowingListWindow = FindWindowByName("###NavWindowingList"); const ImGuiViewport* viewport = /*g.NavWindow ? g.NavWindow->Viewport :*/ GetMainViewport(); SetNextWindowSizeConstraints(ImVec2(viewport->Size.x * 0.20f, viewport->Size.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f); - Begin("##NavWindowingOverlay", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); + Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); if (g.ContextName[0] != 0) SeparatorText(g.ContextName); for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--) @@ -14591,6 +13961,7 @@ void ImGui::NavUpdateWindowingOverlay() PopStyleVar(); } + //----------------------------------------------------------------------------- // [SECTION] DRAG AND DROP //----------------------------------------------------------------------------- @@ -14681,7 +14052,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) // Rely on keeping other window->LastItemXXX fields intact. source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect); KeepAliveID(source_id); - bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id, g.LastItemData.ItemFlags); + bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id, g.LastItemData.InFlags); if (is_hovered && g.IO.MouseClicked[mouse_button]) { SetActiveID(source_id, window); @@ -15056,17 +14427,15 @@ void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* } // Start logging/capturing text output -void ImGui::LogBegin(ImGuiLogFlags flags, int auto_open_depth) +void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; IM_ASSERT(g.LogEnabled == false); - IM_ASSERT(g.LogFile == NULL && g.LogBuffer.empty()); - IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiLogFlags_OutputMask_)); // Check that only 1 type flag is used - + IM_ASSERT(g.LogFile == NULL); + IM_ASSERT(g.LogBuffer.empty()); g.LogEnabled = g.ItemUnclipByLog = true; - g.LogFlags = flags; - g.LogWindow = window; + g.LogType = type; g.LogNextPrefix = g.LogNextSuffix = NULL; g.LogDepthRef = window->DC.TreeDepth; g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault); @@ -15089,7 +14458,7 @@ void ImGui::LogToTTY(int auto_open_depth) return; IM_UNUSED(auto_open_depth); #ifndef IMGUI_DISABLE_TTY_FUNCTIONS - LogBegin(ImGuiLogFlags_OutputTTY, auto_open_depth); + LogBegin(ImGuiLogType_TTY, auto_open_depth); g.LogFile = stdout; #endif } @@ -15115,7 +14484,7 @@ void ImGui::LogToFile(int auto_open_depth, const char* filename) return; } - LogBegin(ImGuiLogFlags_OutputFile, auto_open_depth); + LogBegin(ImGuiLogType_File, auto_open_depth); g.LogFile = f; } @@ -15125,7 +14494,7 @@ void ImGui::LogToClipboard(int auto_open_depth) ImGuiContext& g = *GImGui; if (g.LogEnabled) return; - LogBegin(ImGuiLogFlags_OutputClipboard, auto_open_depth); + LogBegin(ImGuiLogType_Clipboard, auto_open_depth); } void ImGui::LogToBuffer(int auto_open_depth) @@ -15133,7 +14502,7 @@ void ImGui::LogToBuffer(int auto_open_depth) ImGuiContext& g = *GImGui; if (g.LogEnabled) return; - LogBegin(ImGuiLogFlags_OutputBuffer, auto_open_depth); + LogBegin(ImGuiLogType_Buffer, auto_open_depth); } void ImGui::LogFinish() @@ -15143,29 +14512,29 @@ void ImGui::LogFinish() return; LogText(IM_NEWLINE); - switch (g.LogFlags & ImGuiLogFlags_OutputMask_) + switch (g.LogType) { - case ImGuiLogFlags_OutputTTY: + case ImGuiLogType_TTY: #ifndef IMGUI_DISABLE_TTY_FUNCTIONS fflush(g.LogFile); #endif break; - case ImGuiLogFlags_OutputFile: + case ImGuiLogType_File: ImFileClose(g.LogFile); break; - case ImGuiLogFlags_OutputBuffer: + case ImGuiLogType_Buffer: break; - case ImGuiLogFlags_OutputClipboard: + case ImGuiLogType_Clipboard: if (!g.LogBuffer.empty()) SetClipboardText(g.LogBuffer.begin()); break; - default: + case ImGuiLogType_None: IM_ASSERT(0); break; } g.LogEnabled = g.ItemUnclipByLog = false; - g.LogFlags = ImGuiLogFlags_None; + g.LogType = ImGuiLogType_None; g.LogFile = NULL; g.LogBuffer.clear(); } @@ -15199,6 +14568,7 @@ void ImGui::LogButtons() LogToClipboard(); } + //----------------------------------------------------------------------------- // [SECTION] SETTINGS //----------------------------------------------------------------------------- @@ -15589,6 +14959,7 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl } } + //----------------------------------------------------------------------------- // [SECTION] LOCALIZATION //----------------------------------------------------------------------------- @@ -15600,6 +14971,7 @@ void ImGui::LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count) g.LocalizationTable[entries[n].Key] = entries[n].Text; } + //----------------------------------------------------------------------------- // [SECTION] VIEWPORTS, PLATFORM WINDOWS //----------------------------------------------------------------------------- @@ -15664,7 +15036,6 @@ void ImGui::SetCurrentViewport(ImGuiWindow* current_window, ImGuiViewportP* view return; g.CurrentDpiScale = viewport ? viewport->DpiScale : 1.0f; g.CurrentViewport = viewport; - IM_ASSERT(g.CurrentDpiScale > 0.0f && g.CurrentDpiScale < 99.0f); // Typical correct values would be between 1.0f and 4.0f //IMGUI_DEBUG_LOG_VIEWPORT("[viewport] SetCurrentViewport changed '%s' 0x%08X\n", current_window ? current_window->Name : NULL, viewport ? viewport->ID : 0); // Notify platform layer of viewport changes @@ -15742,7 +15113,7 @@ static bool ImGui::UpdateTryMergeWindowIntoHostViewports(ImGuiWindow* window) // Translate Dear ImGui windows when a Host Viewport has been moved // (This additionally keeps windows at the same place when ImGuiConfigFlags_ViewportsEnable is toggled!) -void ImGui::TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos, const ImVec2& old_size, const ImVec2& new_size) +void ImGui::TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos) { ImGuiContext& g = *GImGui; IM_ASSERT(viewport->Window == NULL && (viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows)); @@ -15756,7 +15127,7 @@ void ImGui::TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& o ImRect test_still_fit_rect(old_pos, old_pos + viewport->Size); ImVec2 delta_pos = new_pos - old_pos; for (ImGuiWindow* window : g.Windows) // FIXME-OPT - if (translate_all_windows || (window->Viewport == viewport && (old_size == new_size || test_still_fit_rect.Contains(window->Rect())))) + if (translate_all_windows || (window->Viewport == viewport && test_still_fit_rect.Contains(window->Rect()))) TranslateWindow(window, delta_pos); } @@ -15912,18 +15283,10 @@ static void ImGui::UpdateViewportsNewFrame() // Update/copy monitor info UpdateViewportPlatformMonitor(viewport); - // Lock down space taken by menu bars and status bars + query initial insets from backend - // Setup initial value for functions like BeginMainMenuBar(), DockSpaceOverViewport() etc. - viewport->WorkInsetMin = viewport->BuildWorkInsetMin; - viewport->WorkInsetMax = viewport->BuildWorkInsetMax; - viewport->BuildWorkInsetMin = viewport->BuildWorkInsetMax = ImVec2(0.0f, 0.0f); - if (g.PlatformIO.Platform_GetWindowWorkAreaInsets != NULL && platform_funcs_available) - { - ImVec4 insets = g.PlatformIO.Platform_GetWindowWorkAreaInsets(viewport); - IM_ASSERT(insets.x >= 0.0f && insets.y >= 0.0f && insets.z >= 0.0f && insets.w >= 0.0f); - viewport->BuildWorkInsetMin = ImVec2(insets.x, insets.y); - viewport->BuildWorkInsetMax = ImVec2(insets.z, insets.w); - } + // Lock down space taken by menu bars and status bars, reset the offset for functions like BeginMainMenuBar() to alter them again. + viewport->WorkOffsetMin = viewport->BuildWorkOffsetMin; + viewport->WorkOffsetMax = viewport->BuildWorkOffsetMax; + viewport->BuildWorkOffsetMin = viewport->BuildWorkOffsetMax = ImVec2(0.0f, 0.0f); viewport->UpdateWorkRect(); // Reset alpha every frame. Users of transparency (docking) needs to request a lower alpha back. @@ -15933,7 +15296,7 @@ static void ImGui::UpdateViewportsNewFrame() // (This additionally keeps windows at the same place when ImGuiConfigFlags_ViewportsEnable is toggled!) const ImVec2 viewport_delta_pos = viewport->Pos - viewport->LastPos; if ((viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows) && (viewport_delta_pos.x != 0.0f || viewport_delta_pos.y != 0.0f)) - TranslateWindowsInViewport(viewport, viewport->LastPos, viewport->Pos, viewport->LastSize, viewport->Size); + TranslateWindowsInViewport(viewport, viewport->LastPos, viewport->Pos); // Update DPI scale float new_dpi_scale; @@ -15943,7 +15306,6 @@ static void ImGui::UpdateViewportsNewFrame() new_dpi_scale = g.PlatformIO.Monitors[viewport->PlatformMonitor].DpiScale; else new_dpi_scale = (viewport->DpiScale != 0.0f) ? viewport->DpiScale : 1.0f; - IM_ASSERT(new_dpi_scale > 0.0f && new_dpi_scale < 99.0f); // Typical correct values would be between 1.0f and 4.0f if (viewport->DpiScale != 0.0f && new_dpi_scale != viewport->DpiScale) { float scale_factor = new_dpi_scale / viewport->DpiScale; @@ -15974,10 +15336,6 @@ static void ImGui::UpdateViewportsNewFrame() g.PlatformMonitorsFullWorkRect.Add(monitor->WorkPos); g.PlatformMonitorsFullWorkRect.Add(monitor->WorkPos + monitor->WorkSize); } - else - { - g.FallbackMonitor = g.PlatformIO.Monitors[0]; - } for (ImGuiPlatformMonitor& monitor : g.PlatformIO.Monitors) { g.PlatformMonitorsFullWorkRect.Add(monitor.WorkPos); @@ -16044,7 +15402,6 @@ static void ImGui::UpdateViewportsEndFrame() { ImGuiViewportP* viewport = g.Viewports[i]; viewport->LastPos = viewport->Pos; - viewport->LastSize = viewport->Size; if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0.0f || viewport->Size.y <= 0.0f) if (i > 0) // Always include main viewport in the list continue; @@ -16091,7 +15448,7 @@ ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const viewport->ID = id; viewport->Idx = g.Viewports.Size; viewport->Pos = viewport->LastPos = pos; - viewport->Size = viewport->LastSize = size; + viewport->Size = size; viewport->Flags = flags; UpdateViewportPlatformMonitor(viewport); g.Viewports.push_back(viewport); @@ -16244,7 +15601,7 @@ static void ImGui::WindowSelectViewport(ImGuiWindow* window) // We need to take account of the possibility that mouse may become invalid. // Popups/Tooltip always set ViewportAllowPlatformMonitorExtend so GetWindowAllowedExtentRect() will return full monitor bounds. ImVec2 mouse_ref = (flags & ImGuiWindowFlags_Tooltip) ? g.IO.MousePos : g.BeginPopupStack.back().OpenMousePos; - bool use_mouse_ref = (!g.NavCursorVisible || !g.NavHighlightItemUnderNav || !g.NavWindow); + bool use_mouse_ref = (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow); bool mouse_valid = IsMousePosValid(&mouse_ref); if ((window->Appearing || (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_ChildMenu))) && (!use_mouse_ref || mouse_valid)) window->ViewportAllowPlatformMonitorExtend = FindPlatformMonitorForPos((use_mouse_ref && mouse_valid) ? mouse_ref : NavCalcPreferredRefPos()); @@ -18478,7 +17835,6 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w for (int tab_n = tabs_unsorted_start; tab_n < tab_bar->Tabs.Size; tab_n++) { ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; - IM_UNUSED(tab); IMGUI_DEBUG_LOG_DOCKING("[docking] - Tab 0x%08X '%s' Order %d\n", tab->ID, TabBarGetTabName(tab_bar, tab), tab->Window ? tab->Window->DockOrder : -1); } IMGUI_DEBUG_LOG_DOCKING("[docking] SelectedTabId = 0x%08X, NavWindow->TabId = 0x%08X\n", node->SelectedTabId, g.NavWindow ? g.NavWindow->TabId : -1); @@ -18542,8 +17898,8 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w node->VisibleWindow = window; // Store last item data so it can be queried with IsItemXXX functions after the user Begin() call - window->DC.DockTabItemStatusFlags = g.LastItemData.StatusFlags; - window->DC.DockTabItemRect = g.LastItemData.Rect; + window->DockTabItemStatusFlags = g.LastItemData.StatusFlags; + window->DockTabItemRect = g.LastItemData.Rect; // Update navigation ID on menu layer if (g.NavWindow && g.NavWindow->RootWindow == window && (window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0) @@ -19462,9 +18818,7 @@ ImGuiID ImGui::DockSpace(ImGuiID dockspace_id, const ImVec2& size_arg, ImGuiDock if ((flags & ImGuiDockNodeFlags_KeepAliveOnly) == 0) window = GetCurrentWindow(); // call to set window->WriteAccessed = true; - IM_ASSERT((flags & ImGuiDockNodeFlags_DockSpace) == 0); // Flag is automatically set by DockSpace() as LocalFlags, not SharedFlags! - IM_ASSERT((flags & ImGuiDockNodeFlags_CentralNode) == 0); // Flag is automatically set by DockSpace() as LocalFlags, not SharedFlags! (#8145) - + IM_ASSERT((flags & ImGuiDockNodeFlags_DockSpace) == 0); IM_ASSERT(dockspace_id != 0); ImGuiDockNode* node = DockContextFindNodeByID(&g, dockspace_id); if (node == NULL) @@ -19573,11 +18927,6 @@ ImGuiID ImGui::DockSpaceOverViewport(ImGuiID dockspace_id, const ImGuiViewport* if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) host_window_flags |= ImGuiWindowFlags_NoBackground; - // FIXME-OPT: When using ImGuiDockNodeFlags_KeepAliveOnly with DockSpaceOverViewport() we might be able to spare submitting the window, - // since DockSpace() with that flag doesn't need a window. We'd only need to compute the default ID accordingly. - if (dockspace_flags & ImGuiDockNodeFlags_KeepAliveOnly) - host_window_flags |= ImGuiWindowFlags_NoMouseInputs; - char label[32]; ImFormatString(label, IM_ARRAYSIZE(label), "WindowOverViewport_%08X", viewport->ID); @@ -20582,9 +19931,9 @@ static void ImGui::DockSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettings // Win32 clipboard implementation // We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown() -static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx) +static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) { - ImGuiContext& g = *ctx; + ImGuiContext& g = *(ImGuiContext*)user_data_ctx; g.ClipboardHandlerData.clear(); if (!::OpenClipboard(NULL)) return NULL; @@ -20605,7 +19954,7 @@ static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx) return g.ClipboardHandlerData.Data; } -static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext*, const char* text) +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) { if (!::OpenClipboard(NULL)) return; @@ -20632,7 +19981,7 @@ static PasteboardRef main_clipboard = 0; // OSX clipboard implementation // If you enable this you will need to add '-framework ApplicationServices' to your linker command-line! -static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext*, const char* text) +static void SetClipboardTextFn_DefaultImpl(void*, const char* text) { if (!main_clipboard) PasteboardCreate(kPasteboardClipboard, &main_clipboard); @@ -20645,9 +19994,9 @@ static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext*, const char* t } } -static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx) +static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) { - ImGuiContext& g = *ctx; + ImGuiContext& g = *(ImGuiContext*)user_data_ctx; if (!main_clipboard) PasteboardCreate(kPasteboardClipboard, &main_clipboard); PasteboardSynchronize(main_clipboard); @@ -20681,15 +20030,15 @@ static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx) #else // Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers. -static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx) +static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx) { - ImGuiContext& g = *ctx; + ImGuiContext& g = *(ImGuiContext*)user_data_ctx; return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin(); } -static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext* ctx, const char* text) +static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text) { - ImGuiContext& g = *ctx; + ImGuiContext& g = *(ImGuiContext*)user_data_ctx; g.ClipboardHandlerData.clear(); const char* text_end = text + strlen(text); g.ClipboardHandlerData.resize((int)(text_end - text) + 1); @@ -20717,14 +20066,14 @@ static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext* ctx, const cha #ifdef _MSC_VER #pragma comment(lib, "shell32") #endif -static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char* path) +static bool PlatformOpenInShellFn_DefaultImpl(ImGuiContext*, const char* path) { return (INT_PTR)::ShellExecuteA(NULL, "open", path, NULL, NULL, SW_SHOWDEFAULT) > 32; } #else #include #include -static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char* path) +static bool PlatformOpenInShellFn_DefaultImpl(ImGuiContext*, const char* path) { #if defined(__APPLE__) const char* args[] { "open", "--", path, NULL }; @@ -20748,7 +20097,7 @@ static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char* path) } #endif #else -static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char*) { return false; } +static bool PlatformOpenInShellFn_DefaultImpl(ImGuiContext*, const char*) { return false; } #endif // Default shell handlers //----------------------------------------------------------------------------- @@ -20761,7 +20110,7 @@ static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char*) { ret #pragma comment(lib, "imm32") #endif -static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) +static void PlatformSetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) { // Notify OS Input Method Editor of text input position HWND hwnd = (HWND)viewport->PlatformHandleRaw; @@ -20787,7 +20136,7 @@ static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport* view #else -static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport*, ImGuiPlatformImeData*) {} +static void PlatformSetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport*, ImGuiPlatformImeData*) {} #endif // Default IME handlers @@ -20994,23 +20343,12 @@ void ImGui::UpdateDebugToolFlashStyleColor() ImGuiContext& g = *GImGui; if (g.DebugFlashStyleColorTime <= 0.0f) return; - ColorConvertHSVtoRGB(ImCos(g.DebugFlashStyleColorTime * 6.0f) * 0.5f + 0.5f, 0.5f, 0.5f, g.Style.Colors[g.DebugFlashStyleColorIdx].x, g.Style.Colors[g.DebugFlashStyleColorIdx].y, g.Style.Colors[g.DebugFlashStyleColorIdx].z); + ColorConvertHSVtoRGB(cosf(g.DebugFlashStyleColorTime * 6.0f) * 0.5f + 0.5f, 0.5f, 0.5f, g.Style.Colors[g.DebugFlashStyleColorIdx].x, g.Style.Colors[g.DebugFlashStyleColorIdx].y, g.Style.Colors[g.DebugFlashStyleColorIdx].z); g.Style.Colors[g.DebugFlashStyleColorIdx].w = 1.0f; if ((g.DebugFlashStyleColorTime -= g.IO.DeltaTime) <= 0.0f) DebugFlashStyleColorStop(); } -static const char* FormatTextureIDForDebugDisplay(char* buf, int buf_size, ImTextureID tex_id) -{ - union { void* ptr; int integer; } tex_id_opaque; - memcpy(&tex_id_opaque, &tex_id, ImMin(sizeof(void*), sizeof(tex_id))); - if (sizeof(tex_id) >= sizeof(void*)) - ImFormatString(buf, buf_size, "0x%p", tex_id_opaque.ptr); - else - ImFormatString(buf, buf_size, "0x%04X", tex_id_opaque.integer); - return buf; -} - // Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds. static void MetricsHelpMarker(const char* desc) { @@ -21065,7 +20403,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) DebugBreakClearData(); // Basic info - Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); + Text("Dear ImGui %s", GetVersion()); if (g.ContextName[0] != 0) { SameLine(); @@ -21287,11 +20625,14 @@ void ImGui::ShowMetricsWindow(bool* p_open) { for (int i = 0; i < g.PlatformIO.Monitors.Size; i++) { - DebugNodePlatformMonitor(&g.PlatformIO.Monitors[i], "Monitor", i); + const ImGuiPlatformMonitor& mon = g.PlatformIO.Monitors[i]; + BulletText("Monitor #%d: DPI %.0f%%\n MainMin (%.0f,%.0f), MainMax (%.0f,%.0f), MainSize (%.0f,%.0f)\n WorkMin (%.0f,%.0f), WorkMax (%.0f,%.0f), WorkSize (%.0f,%.0f)", + i, mon.DpiScale * 100.0f, + mon.MainPos.x, mon.MainPos.y, mon.MainPos.x + mon.MainSize.x, mon.MainPos.y + mon.MainSize.y, mon.MainSize.x, mon.MainSize.y, + mon.WorkPos.x, mon.WorkPos.y, mon.WorkPos.x + mon.WorkSize.x, mon.WorkPos.y + mon.WorkSize.y, mon.WorkSize.x, mon.WorkSize.y); if (IsItemHovered()) cfg->HighlightMonitorIdx = i; } - DebugNodePlatformMonitor(&g.FallbackMonitor, "Fallback", 0); TreePop(); } @@ -21499,12 +20840,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) for (int n = buf_size - 1; n >= 0; n--) { ImGuiDebugAllocEntry* entry = &info->LastEntriesBuf[(info->LastEntriesIdx - n + buf_size) % buf_size]; - BulletText("Frame %06d: %+3d ( %2d alloc, %2d free )", entry->FrameCount, entry->AllocCount - entry->FreeCount, entry->AllocCount, entry->FreeCount); - if (n == 0) - { - SameLine(); - Text("<- %d frames ago", g.FrameCount - entry->FrameCount); - } + BulletText("Frame %06d: %+3d ( %2d malloc, %2d free )%s", entry->FrameCount, entry->AllocCount - entry->FreeCount, entry->AllocCount, entry->FreeCount, (n == 0) ? " (most recent)" : ""); } TreePop(); } @@ -21513,11 +20849,18 @@ void ImGui::ShowMetricsWindow(bool* p_open) { Text("KEYBOARD/GAMEPAD/MOUSE KEYS"); { + // We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends. // User code should never have to go through such hoops! You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END. Indent(); - Text("Keys down:"); for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (!IsKeyDown(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); SameLine(); Text("(%.02f)", GetKeyData(key)->DownDuration); } - Text("Keys pressed:"); for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (!IsKeyPressed(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } - Text("Keys released:"); for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (!IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; +#else + struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key >= 0 && key < 512 && GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array + //Text("Legacy raw:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key++) { if (io.KeysDown[key]) { SameLine(); Text("\"%s\" %d", GetKeyName(key), key); } } +#endif + Text("Keys down:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyDown(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); SameLine(); Text("(%.02f)", GetKeyData(key)->DownDuration); } + Text("Keys pressed:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyPressed(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } + Text("Keys released:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; SameLine(); Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. DebugRenderKeyboardPreview(GetWindowDrawList()); @@ -21633,7 +20976,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); Text("NavActivateId/DownId/PressedId: %08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId); Text("NavActivateFlags: %04X", g.NavActivateFlags); - Text("NavCursorVisible: %d, NavHighlightItemUnderNav: %d", g.NavCursorVisible, g.NavHighlightItemUnderNav); + Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover); Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId); Text("NavFocusRoute[] = "); for (int path_n = g.NavFocusRoute.Size - 1; path_n >= 0; path_n--) @@ -21773,7 +21116,7 @@ bool ImGui::DebugBreakButton(const char* label, const char* description_of_locat ColorConvertRGBtoHSV(col4f.x, col4f.y, col4f.z, hsv.x, hsv.y, hsv.z); ColorConvertHSVtoRGB(hsv.x + 0.20f, hsv.y, hsv.z, col4f.x, col4f.y, col4f.z); - RenderNavCursor(bb, id); + RenderNavHighlight(bb, id); RenderFrame(bb.Min, bb.Max, GetColorU32(col4f), true, g.Style.FrameRounding); RenderTextClipped(bb.Min, bb.Max, label, NULL, &label_size, g.Style.ButtonTextAlign, &bb); @@ -21879,6 +21222,16 @@ void ImGui::DebugNodeDockNode(ImGuiDockNode* node, const char* label) } } +static void FormatTextureIDForDebugDisplay(char* buf, int buf_size, ImTextureID tex_id) +{ + union { void* ptr; int integer; } tex_id_opaque; + memcpy(&tex_id_opaque, &tex_id, ImMin(sizeof(void*), sizeof(tex_id))); + if (sizeof(tex_id) >= sizeof(void*)) + ImFormatString(buf, buf_size, "0x%p", tex_id_opaque.ptr); + else + ImFormatString(buf, buf_size, "0x%04X", tex_id_opaque.integer); +} + // [DEBUG] Display contents of ImDrawList // Note that both 'window' and 'viewport' may be NULL here. Viewport is generally null of destroyed popups which previously owned a viewport. void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label) @@ -22008,24 +21361,18 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co // [DEBUG] Display details for a single font, called by ShowStyleEditor(). void ImGui::DebugNodeFont(ImFont* font) { - bool opened = TreeNode(font, "Font: \"%s\": %.2f px, %d glyphs, %d sources(s)", + bool opened = TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)", font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); + SameLine(); + if (SmallButton("Set as default")) + GetIO().FontDefault = font; + if (!opened) + return; // Display preview text - if (!opened) - Indent(); - Indent(); PushFont(font); Text("The quick brown fox jumps over the lazy dog"); PopFont(); - if (!opened) - { - Unindent(); - Unindent(); - return; - } - if (SmallButton("Set as default")) - GetIO().FontDefault = font; // Display details SetNextItemWidth(GetFontSize() * 8); @@ -22044,69 +21391,62 @@ void ImGui::DebugNodeFont(ImFont* font) Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt); for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) if (font->ConfigData) - { - const ImFontConfig* cfg = &font->ConfigData[config_i]; - int oversample_h, oversample_v; - ImFontAtlasBuildGetOversampleFactors(cfg, &oversample_h, &oversample_v); - BulletText("Input %d: \'%s\', Oversample: (%d=>%d,%d=>%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", - config_i, cfg->Name, cfg->OversampleH, oversample_h, cfg->OversampleV, oversample_v, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y); - } + if (const ImFontConfig* cfg = &font->ConfigData[config_i]) + BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", + config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y); // Display all glyphs of the fonts in separate pages of 256 characters + if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) { - if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) + ImDrawList* draw_list = GetWindowDrawList(); + const ImU32 glyph_col = GetColorU32(ImGuiCol_Text); + const float cell_size = font->FontSize * 1; + const float cell_spacing = GetStyle().ItemSpacing.y; + for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) { - ImDrawList* draw_list = GetWindowDrawList(); - const ImU32 glyph_col = GetColorU32(ImGuiCol_Text); - const float cell_size = font->FontSize * 1; - const float cell_spacing = GetStyle().ItemSpacing.y; - for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) + // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) + // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT + // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) + if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095)) { - // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) - // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT - // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) - if (!(base & 8191) && font->IsGlyphRangeUnused(base, base + 8191)) - { - base += 8192 - 256; - continue; - } - - int count = 0; - for (unsigned int n = 0; n < 256; n++) - if (font->FindGlyphNoFallback((ImWchar)(base + n))) - count++; - if (count <= 0) - continue; - if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) - continue; - - // Draw a 16x16 grid of glyphs - ImVec2 base_pos = GetCursorScreenPos(); - for (unsigned int n = 0; n < 256; n++) - { - // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions - // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. - ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); - ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); - const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); - draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); - if (!glyph) - continue; - font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); - if (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip()) - { - DebugNodeFontGlyph(font, glyph); - EndTooltip(); - } - } - Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); - TreePop(); + base += 4096 - 256; + continue; } + + int count = 0; + for (unsigned int n = 0; n < 256; n++) + if (font->FindGlyphNoFallback((ImWchar)(base + n))) + count++; + if (count <= 0) + continue; + if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) + continue; + + // Draw a 16x16 grid of glyphs + ImVec2 base_pos = GetCursorScreenPos(); + for (unsigned int n = 0; n < 256; n++) + { + // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions + // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. + ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); + ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); + const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); + draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); + if (!glyph) + continue; + font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); + if (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip()) + { + DebugNodeFontGlyph(font, glyph); + EndTooltip(); + } + } + Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); TreePop(); } + TreePop(); } TreePop(); - Unindent(); } void ImGui::DebugNodeFontGlyph(ImFont*, const ImFontGlyph* glyph) @@ -22183,9 +21523,9 @@ void ImGui::DebugNodeViewport(ImGuiViewportP* viewport) if (open) { ImGuiWindowFlags flags = viewport->Flags; - BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Inset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f\nMonitor: %d, DpiScale: %.0f%%", + BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Offset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f\nMonitor: %d, DpiScale: %.0f%%", viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y, - viewport->WorkInsetMin.x, viewport->WorkInsetMin.y, viewport->WorkInsetMax.x, viewport->WorkInsetMax.y, + viewport->WorkOffsetMin.x, viewport->WorkOffsetMin.y, viewport->WorkOffsetMax.x, viewport->WorkOffsetMax.y, viewport->PlatformMonitor, viewport->DpiScale * 100.0f); if (viewport->Idx > 0) { SameLine(); if (SmallButton("Reset Pos")) { viewport->Pos = ImVec2(200, 200); viewport->UpdateWorkRect(); if (viewport->Window) viewport->Window->Pos = viewport->Pos; } } BulletText("Flags: 0x%04X =%s%s%s%s%s%s%s%s%s%s%s%s%s", viewport->Flags, @@ -22209,14 +21549,6 @@ void ImGui::DebugNodeViewport(ImGuiViewportP* viewport) } } -void ImGui::DebugNodePlatformMonitor(ImGuiPlatformMonitor* monitor, const char* label, int idx) -{ - BulletText("%s %d: DPI %.0f%%\n MainMin (%.0f,%.0f), MainMax (%.0f,%.0f), MainSize (%.0f,%.0f)\n WorkMin (%.0f,%.0f), WorkMax (%.0f,%.0f), WorkSize (%.0f,%.0f)", - label, idx, monitor->DpiScale * 100.0f, - monitor->MainPos.x, monitor->MainPos.y, monitor->MainPos.x + monitor->MainSize.x, monitor->MainPos.y + monitor->MainSize.y, monitor->MainSize.x, monitor->MainSize.y, - monitor->WorkPos.x, monitor->WorkPos.y, monitor->WorkPos.x + monitor->WorkSize.x, monitor->WorkPos.y + monitor->WorkSize.y, monitor->WorkSize.x, monitor->WorkSize.y); -} - void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) { if (window == NULL) @@ -22249,12 +21581,6 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "", (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "", (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : ""); - if (flags & ImGuiWindowFlags_ChildWindow) - BulletText("ChildFlags: 0x%08X (%s%s%s%s..)", window->ChildFlags, - (window->ChildFlags & ImGuiChildFlags_Borders) ? "Borders " : "", - (window->ChildFlags & ImGuiChildFlags_ResizeX) ? "ResizeX " : "", - (window->ChildFlags & ImGuiChildFlags_ResizeY) ? "ResizeY " : "", - (window->ChildFlags & ImGuiChildFlags_NavFlattened) ? "NavFlattened " : ""); BulletText("WindowClassId: 0x%08X", window->WindowClass.ClassId); BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : ""); BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1); @@ -22262,7 +21588,7 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label) for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++) { ImRect r = window->NavRectRel[layer]; - if (r.Min.x >= r.Max.x && r.Min.y >= r.Max.y) + if (r.Min.x >= r.Max.y && r.Min.y >= r.Max.y) BulletText("NavLastIds[%d]: 0x%08X", layer, window->NavLastIds[layer]); else BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y); @@ -22374,7 +21700,7 @@ static void SameLineOrWrap(const ImVec2& size) ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; ImVec2 pos(window->DC.CursorPosPrevLine.x + g.Style.ItemSpacing.x, window->DC.CursorPosPrevLine.y); - if (window->WorkRect.Contains(ImRect(pos, pos + size))) + if (window->ClipRect.Contains(ImRect(pos, pos + size))) ImGui::SameLine(); } @@ -22383,30 +21709,18 @@ static void ShowDebugLogFlag(const char* name, ImGuiDebugLogFlags flags) ImGuiContext& g = *GImGui; ImVec2 size(ImGui::GetFrameHeight() + g.Style.ItemInnerSpacing.x + ImGui::CalcTextSize(name).x, ImGui::GetFrameHeight()); SameLineOrWrap(size); // FIXME-LAYOUT: To be done automatically once we rework ItemSize/ItemAdd into ItemLayout. - - bool highlight_errors = (flags == ImGuiDebugLogFlags_EventError && g.DebugLogSkippedErrors > 0); - if (highlight_errors) - ImGui::PushStyleColor(ImGuiCol_Text, ImLerp(g.Style.Colors[ImGuiCol_Text], ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 0.30f)); if (ImGui::CheckboxFlags(name, &g.DebugLogFlags, flags) && g.IO.KeyShift && (g.DebugLogFlags & flags) != 0) { g.DebugLogAutoDisableFrames = 2; g.DebugLogAutoDisableFlags |= flags; } - if (highlight_errors) - { - ImGui::PopStyleColor(); - ImGui::SetItemTooltip("%d past errors skipped.", g.DebugLogSkippedErrors); - } - else - { - ImGui::SetItemTooltip("Hold SHIFT when clicking to enable for 2 frames only (useful for spammy log entries)"); - } + ImGui::SetItemTooltip("Hold SHIFT when clicking to enable for 2 frames only (useful for spammy log entries)"); } void ImGui::ShowDebugLogWindow(bool* p_open) { ImGuiContext& g = *GImGui; - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0) + if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)) SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 12.0f), ImGuiCond_FirstUseEver); if (!Begin("Dear ImGui Debug Log", p_open) || GetCurrentWindow()->BeginCount > 1) { @@ -22418,13 +21732,11 @@ void ImGui::ShowDebugLogWindow(bool* p_open) CheckboxFlags("All", &g.DebugLogFlags, all_enable_flags); SetItemTooltip("(except InputRouting which is spammy)"); - ShowDebugLogFlag("Errors", ImGuiDebugLogFlags_EventError); ShowDebugLogFlag("ActiveId", ImGuiDebugLogFlags_EventActiveId); ShowDebugLogFlag("Clipper", ImGuiDebugLogFlags_EventClipper); ShowDebugLogFlag("Docking", ImGuiDebugLogFlags_EventDocking); ShowDebugLogFlag("Focus", ImGuiDebugLogFlags_EventFocus); ShowDebugLogFlag("IO", ImGuiDebugLogFlags_EventIO); - //ShowDebugLogFlag("Font", ImGuiDebugLogFlags_EventFont); ShowDebugLogFlag("Nav", ImGuiDebugLogFlags_EventNav); ShowDebugLogFlag("Popup", ImGuiDebugLogFlags_EventPopup); ShowDebugLogFlag("Selection", ImGuiDebugLogFlags_EventSelection); @@ -22435,7 +21747,6 @@ void ImGui::ShowDebugLogWindow(bool* p_open) { g.DebugLogBuf.clear(); g.DebugLogIndex.clear(); - g.DebugLogSkippedErrors = 0; } SameLine(); if (SmallButton("Copy")) @@ -22456,7 +21767,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open) EndPopup(); } - BeginChild("##log", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); + BeginChild("##log", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Border, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); const ImGuiDebugLogFlags backup_log_flags = g.DebugLogFlags; g.DebugLogFlags &= ~ImGuiDebugLogFlags_EventClipper; @@ -22478,14 +21789,14 @@ void ImGui::ShowDebugLogWindow(bool* p_open) void ImGui::DebugTextUnformattedWithLocateItem(const char* line_begin, const char* line_end) { TextUnformatted(line_begin, line_end); - if (!IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + if (!IsItemHovered()) return; ImGuiContext& g = *GImGui; ImRect text_rect = g.LastItemData.Rect; for (const char* p = line_begin; p <= line_end - 10; p++) { ImGuiID id = 0; - if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1 || ImCharIsXdigitA(p[10])) + if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1) continue; ImVec2 p0 = CalcTextSize(line_begin, p); ImVec2 p1 = CalcTextSize(p, p + 10); @@ -22728,7 +22039,7 @@ static int StackToolFormatLevelInfo(ImGuiIDStackTool* tool, int n, bool format_f void ImGui::ShowIDStackToolWindow(bool* p_open) { ImGuiContext& g = *GImGui; - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0) + if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)) SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 8.0f), ImGuiCond_FirstUseEver); if (!Begin("Dear ImGui ID Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1) { diff --git a/3rdparty/imgui/imgui.h b/3rdparty/imgui/imgui.h index 21603e4..b3374c2 100644 --- a/3rdparty/imgui/imgui.h +++ b/3rdparty/imgui/imgui.h @@ -1,17 +1,16 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.0 WIP // (headers) // Help: // - See links below. // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that. // - Read top of imgui.cpp for more details, links and comments. -// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4. // Resources: // - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md) // - Homepage ................... https://github.com/ocornut/imgui // - Releases & changelog ....... https://github.com/ocornut/imgui/releases -// - Gallery .................... https://github.com/ocornut/imgui/issues?q=label%3Agallery (please post your screenshots/video there!) +// - Gallery .................... https://github.com/ocornut/imgui/issues/7503 (please post your screenshots/video there!) // - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there) // - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code) // - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more) @@ -28,11 +27,12 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.8" -#define IMGUI_VERSION_NUM 19180 +#define IMGUI_VERSION "1.91.0 WIP" +#define IMGUI_VERSION_NUM 19097 #define IMGUI_HAS_TABLE #define IMGUI_HAS_VIEWPORT // Viewport WIP branch #define IMGUI_HAS_DOCK // Docking WIP branch +#define IMGUI_HAS_STACK_LAYOUT 1 // Stack-Layout PR #846 /* @@ -51,7 +51,7 @@ Index of this file: // [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) -// [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformMonitor, ImGuiPlatformImeData) +// [SECTION] Platform Dependent Interfaces (ImGuiPlatformIO, ImGuiPlatformMonitor, ImGuiPlatformImeData) // [SECTION] Obsolete functions and types */ @@ -132,17 +132,15 @@ Index of this file: #pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' #endif #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' -#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast +#pragma clang diagnostic ignored "-Wold-style-cast" #pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" #pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access -#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif //----------------------------------------------------------------------------- @@ -160,7 +158,7 @@ typedef unsigned int ImU32; // 32-bit unsigned integer (often used to st typedef signed long long ImS64; // 64-bit signed integer typedef unsigned long long ImU64; // 64-bit unsigned integer -// Forward declarations: ImDrawList, ImFontAtlas layer +// Forward declarations struct ImDrawChannel; // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit() struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback) struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix. @@ -175,19 +173,17 @@ struct ImFontConfig; // Configuration data when adding a font or struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using) - -// Forward declarations: ImGui layer struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) -struct ImGuiIO; // Main configuration and I/O between your application and ImGui (also see: ImGuiPlatformIO) +struct ImGuiIO; // Main configuration and I/O between your application and ImGui struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) struct ImGuiKeyData; // Storage for ImGuiIO and IsKeyDown(), IsKeyPressed() etc functions. struct ImGuiListClipper; // Helper to manually clip large list of items struct ImGuiMultiSelectIO; // Structure to interact with a BeginMultiSelect()/EndMultiSelect() block struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame struct ImGuiPayload; // User data payload for drag and drop operations -struct ImGuiPlatformIO; // Interface between platform/renderer backends and ImGui (e.g. Clipboard, IME, Multi-Viewport support). Extends ImGuiIO. -struct ImGuiPlatformImeData; // Platform IME data for io.PlatformSetImeDataFn() function. +struct ImGuiPlatformIO; // Multi-viewport support: interface for Platform/Renderer backends + viewports to render struct ImGuiPlatformMonitor; // Multi-viewport support: user-provided bounds for each connected monitor/display. Used when positioning popups and tooltips to avoid them straddling monitors +struct ImGuiPlatformImeData; // Platform IME data for io.PlatformSetImeDataFn() function. struct ImGuiSelectionBasicStorage; // Optional helper to store multi-selection state + apply multi-selection requests. struct ImGuiSelectionExternalStorage;//Optional helper to apply multi-selection requests to existing randomly accessible storage. struct ImGuiSelectionRequest; // A selection request (stored in ImGuiMultiSelectIO) @@ -258,10 +254,8 @@ typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: f // ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type] // - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file. // - This can be whatever to you want it to be! read the FAQ about ImTextureID for details. -// - You can make this a structure with various constructors if you need. You will have to implement ==/!= operators. -// - (note: before v1.91.4 (2024/10/08) the default type for ImTextureID was void*. Use intermediary intptr_t cast and read FAQ if you have casting warnings) #ifndef ImTextureID -typedef ImU64 ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that) +typedef void* ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that) #endif // ImDrawIdx: vertex index. [Compile-time configurable type] @@ -293,8 +287,8 @@ typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data); typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions() // ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type] -// - This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type. -// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4. +// This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type. +// Add '#define IMGUI_DEFINE_MATH_OPERATORS' in your imconfig.h file to benefit from courtesy maths operators for those types. IM_MSVC_RUNTIME_CHECKS_OFF struct ImVec2 { @@ -337,8 +331,7 @@ namespace ImGui IMGUI_API void SetCurrentContext(ImGuiContext* ctx); // Main - IMGUI_API ImGuiIO& GetIO(); // access the ImGuiIO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags) - IMGUI_API ImGuiPlatformIO& GetPlatformIO(); // access the ImGuiPlatformIO structure (mostly hooks/functions to connect to platform/renderer and OS Clipboard, IME etc.) + IMGUI_API ImGuiIO& GetIO(); // access the IO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags) IMGUI_API ImGuiStyle& GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleColor(), PushStyleVar() to modify style mid-frame! IMGUI_API void NewFrame(); // start a new Dear ImGui frame, you can submit any command from this point until Render()/EndFrame(). IMGUI_API void EndFrame(); // ends the Dear ImGui frame. automatically called by Render(). If you don't need to render data (skipping rendering) you may call EndFrame() without Render()... but you'll have wasted CPU already! If you don't need to render, better to not create any windows and not call NewFrame() at all! @@ -380,10 +373,10 @@ namespace ImGui // Child Windows // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child. // - Before 1.90 (November 2023), the "ImGuiChildFlags child_flags = 0" parameter was "bool border = false". - // This API is backward compatible with old code, as we guarantee that ImGuiChildFlags_Borders == true. + // This API is backward compatible with old code, as we guarantee that ImGuiChildFlags_Border == true. // Consider updating your old code: // BeginChild("Name", size, false) -> Begin("Name", size, 0); or Begin("Name", size, ImGuiChildFlags_None); - // BeginChild("Name", size, true) -> Begin("Name", size, ImGuiChildFlags_Borders); + // BeginChild("Name", size, true) -> Begin("Name", size, ImGuiChildFlags_Border); // - Manual sizing (each axis can use a different setting e.g. ImVec2(0.0f, 400.0f)): // == 0.0f: use remaining parent window size for this axis. // > 0.0f: use specified size for this axis. @@ -407,10 +400,10 @@ namespace ImGui IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered and hoverable (e.g. not blocked by a popup/modal)? See ImGuiHoveredFlags_ for options. IMPORTANT: If you are trying to check whether your mouse should be dispatched to Dear ImGui or to your underlying app, you should not use this function! Use the 'io.WantCaptureMouse' boolean for that! Refer to FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" for details. IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives IMGUI_API float GetWindowDpiScale(); // get DPI scale currently associated to the current window's viewport. - IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider always using GetCursorScreenPos() and GetContentRegionAvail() instead) - IMGUI_API ImVec2 GetWindowSize(); // get current window size (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider always using GetCursorScreenPos() and GetContentRegionAvail() instead) - IMGUI_API float GetWindowWidth(); // get current window width (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for GetWindowSize().x. - IMGUI_API float GetWindowHeight(); // get current window height (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for GetWindowSize().y. + IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (note: it is unlikely you need to use this. Consider using current layout pos instead, GetCursorScreenPos()) + IMGUI_API ImVec2 GetWindowSize(); // get current window size (note: it is unlikely you need to use this. Consider using GetCursorScreenPos() and e.g. GetContentRegionAvail() instead) + IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x) + IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y) IMGUI_API ImGuiViewport*GetWindowViewport(); // get viewport currently associated to the current window. // Window manipulation @@ -434,6 +427,14 @@ namespace ImGui IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / top-most. use NULL to remove focus. + // Content region + // - Retrieve available space from a given point. GetContentRegionAvail() is frequently useful. + // - Those functions are bound to be redesigned (they are confusing, incomplete and the Min/Max return values are in local window coordinates which increases confusion) + IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos() + IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates + IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min for the full window (roughly (0,0)-Scroll), in window coordinates + IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max for the full window (roughly (0,0)+Size-Scroll) where Size can be overridden with SetNextWindowContentSize(), in window coordinates + // Windows Scrolling // - Any change of Scroll will be applied at the beginning of next frame in the first call to Begin(). // - You may instead use SetNextWindowScroll() prior to calling Begin() to avoid this delay, as an alternative to using SetScrollX()/SetScrollY(). @@ -454,10 +455,8 @@ namespace ImGui IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); // modify a style color. always use this if you modify the style after NewFrame(). IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); IMGUI_API void PopStyleColor(int count = 1); - IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); // modify a style float variable. always use this if you modify the style after NewFrame()! - IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); // modify a style ImVec2 variable. " - IMGUI_API void PushStyleVarX(ImGuiStyleVar idx, float val_x); // modify X component of a style ImVec2 variable. " - IMGUI_API void PushStyleVarY(ImGuiStyleVar idx, float val_y); // modify Y component of a style ImVec2 variable. " + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); // modify a style float variable. always use this if you modify the style after NewFrame(). + IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); // modify a style ImVec2 variable. always use this if you modify the style after NewFrame(). IMGUI_API void PopStyleVar(int count = 1); IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); // modify specified shared item flag, e.g. PushItemFlag(ImGuiItemFlags_NoTabStop, true) IMGUI_API void PopItemFlag(); @@ -474,7 +473,7 @@ namespace ImGui // - Use the ShowStyleEditor() function to interactively see/edit the colors. IMGUI_API ImFont* GetFont(); // get current font IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied - IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a white pixel, useful to draw custom shapes via the ImDrawList API + IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier, packed as a 32-bit value suitable for ImDrawList IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList IMGUI_API ImU32 GetColorU32(ImU32 col, float alpha_mul = 1.0f); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList @@ -484,22 +483,19 @@ namespace ImGui // - By "cursor" we mean the current output position. // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down. // - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceding widget. - // - YOU CAN DO 99% OF WHAT YOU NEED WITH ONLY GetCursorScreenPos() and GetContentRegionAvail(). // - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API: // - Absolute coordinate: GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions. -> this is the preferred way forward. - // - Window-local coordinates: SameLine(offset), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), PushTextWrapPos() - // - Window-local coordinates: GetContentRegionMax(), GetWindowContentRegionMin(), GetWindowContentRegionMax() --> all obsoleted. YOU DON'T NEED THEM. - // - GetCursorScreenPos() = GetCursorPos() + GetWindowPos(). GetWindowPos() is almost only ever useful to convert from window-local to absolute coordinates. Try not to use it. - IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position, absolute coordinates. THIS IS YOUR BEST FRIEND (prefer using this rather than GetCursorPos(), also more useful to work with ImDrawList API). - IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position, absolute coordinates. THIS IS YOUR BEST FRIEND. - IMGUI_API ImVec2 GetContentRegionAvail(); // available space from current position. THIS IS YOUR BEST FRIEND. - IMGUI_API ImVec2 GetCursorPos(); // [window-local] cursor position in window-local coordinates. This is not your best friend. + // - Window-local coordinates: SameLine(), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), GetContentRegionMax(), GetWindowContentRegion*(), PushTextWrapPos() + // - GetCursorScreenPos() = GetCursorPos() + GetWindowPos(). GetWindowPos() is almost only ever useful to convert from window-local to absolute coordinates. + IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute coordinates (prefer using this, also more useful to work with ImDrawList API). + IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute coordinates + IMGUI_API ImVec2 GetCursorPos(); // [window-local] cursor position in window coordinates (relative to window position) IMGUI_API float GetCursorPosX(); // [window-local] " IMGUI_API float GetCursorPosY(); // [window-local] " IMGUI_API void SetCursorPos(const ImVec2& local_pos); // [window-local] " IMGUI_API void SetCursorPosX(float local_x); // [window-local] " IMGUI_API void SetCursorPosY(float local_y); // [window-local] " - IMGUI_API ImVec2 GetCursorStartPos(); // [window-local] initial cursor position, in window-local coordinates. Call GetCursorScreenPos() after Begin() to get the absolute coordinates version. + IMGUI_API ImVec2 GetCursorStartPos(); // [window-local] initial cursor position, in window coordinates // Other layout functions IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator. @@ -536,7 +532,6 @@ namespace ImGui IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end); IMGUI_API ImGuiID GetID(const void* ptr_id); - IMGUI_API ImGuiID GetID(int int_id); // Widgets: Text IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text. @@ -575,7 +570,6 @@ namespace ImGui // - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples // - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above. // - Note that Image() may add +2.0f to provided size if a border is visible, ImageButton() adds style.FramePadding*2.0f to provided size. - // - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImVec4& border_col = ImVec4(0, 0, 0, 0)); IMGUI_API bool ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); @@ -594,7 +588,7 @@ namespace ImGui // the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. // - Format string may also be set to NULL or use the default format ("%f" or "%d"). - // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For keyboard/gamepad navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). + // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). // - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits if ImGuiSliderFlags_AlwaysClamp is not used. // - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum. // - We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. @@ -681,7 +675,6 @@ namespace ImGui IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop(). IMGUI_API bool CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags = 0); // when 'p_visible != NULL': if '*p_visible==true' display an additional small close button on upper right of the header which will set the bool to false when clicked, if '*p_visible==false' don't display the header. IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state. - IMGUI_API void SetNextItemStorageID(ImGuiID storage_id); // set id to use for open/close storage (default to same as item id). // Widgets: Selectables // - A selectable highlights when hovered, and can display another color when selected. @@ -689,12 +682,12 @@ namespace ImGui IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. - // Multi-selection system for Selectable(), Checkbox(), TreeNode() functions [BETA] + // Multi-selection system for Selectable(), Checkbox() functions* // - This enables standard multi-selection/range-selection idioms (CTRL+Mouse/Keyboard, SHIFT+Mouse/Keyboard, etc.) in a way that also allow a clipper to be used. // - ImGuiSelectionUserData is often used to store your item index within the current view (but may store something else). // - Read comments near ImGuiMultiSelectIO for instructions/details and see 'Demo->Widgets->Selection State & Multi-Select' for demo. - // - TreeNode() is technically supported but... using this correctly is more complicated. You need some sort of linear/random access to your tree, - // which is suited to advanced trees setups already implementing filters and clipper. We will work simplifying the current demo. + // - (*) TreeNode() is technically supported but... using this correctly is more complicate: you need some sort of linear/random access to your tree, + // which is suited to advanced trees setups already implementing filters and clipper. We will work toward simplifying and demoing this. // - 'selection_size' and 'items_count' parameters are optional and used by a few features. If they are costly for you to compute, you may avoid them. IMGUI_API ImGuiMultiSelectIO* BeginMultiSelect(ImGuiMultiSelectFlags flags, int selection_size = -1, int items_count = -1); IMGUI_API ImGuiMultiSelectIO* EndMultiSelect(); @@ -703,7 +696,6 @@ namespace ImGui // Widgets: List Boxes // - This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. - // - If you don't need a label you can probably simply use BeginChild() with the ImGuiChildFlags_FrameStyle flag for the same result. // - You can submit contents and manage your selection state however you want it, by creating e.g. Selectable() or any other items. // - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analoguous to how Combos are created. // - Choose frame width: size.x > 0.0f: custom / size.x < 0.0f or -FLT_MIN: right-align / size.x = 0.0f (default): use current ItemWidth @@ -859,7 +851,7 @@ namespace ImGui // Legacy Columns API (prefer using Tables!) // - You can also use SameLine(pos_x) to mimic simplified columns. - IMGUI_API void Columns(int count = 1, const char* id = NULL, bool borders = true); + IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true); IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished IMGUI_API int GetColumnIndex(); // get current column index IMGUI_API float GetColumnWidth(int column_index = -1); // get column width (in pixels). pass -1 to use current column @@ -924,7 +916,7 @@ namespace ImGui // - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors) // - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled) // - Tooltips windows by exception are opted out of disabling. - // - BeginDisabled(false)/EndDisabled() essentially does nothing but is provided to facilitate use of boolean expressions (as a micro-optimization: if you have tens of thousands of BeginDisabled(false)/EndDisabled() pairs, you might want to reformulate your code to avoid making those calls) + // - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it. IMGUI_API void BeginDisabled(bool disabled = true); IMGUI_API void EndDisabled(); @@ -934,12 +926,10 @@ namespace ImGui IMGUI_API void PopClipRect(); // Focus, Activation - IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of of a newly appearing window. + // - Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item" + IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a window. IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. - // Keyboard/Gamepad Navigation - IMGUI_API void SetNavCursorVisible(bool visible); // alter visibility of keyboard/gamepad cursor. by default: show when using an arrow key, hide when clicking with mouse. - // Overlapping mode IMGUI_API void SetNextItemAllowOverlap(); // allow next item to be overlapped by a subsequent item. Useful with invisible buttons, selectable, treenode covering an area where subsequent items may need to be added. Note that both Selectable() and TreeNode() have dedicated flags doing this. @@ -995,8 +985,9 @@ namespace ImGui // Inputs Utilities: Keyboard/Mouse/Gamepad // - the ImGuiKey enum contains all possible keyboard, mouse and gamepad inputs (e.g. ImGuiKey_A, ImGuiKey_MouseLeft, ImGuiKey_GamepadDpadUp...). - // - (legacy: before v1.87, we used ImGuiKey to carry native/user indices as defined by each backends. This was obsoleted in 1.87 (2022-02) and completely removed in 1.91.5 (2024-11). See https://github.com/ocornut/imgui/issues/4921) - // - (legacy: any use of ImGuiKey will assert when key < 512 to detect passing legacy native/user indices) + // - before v1.87, we used ImGuiKey to carry native/user indices as defined by each backends. About use of those legacy ImGuiKey values: + // - without IMGUI_DISABLE_OBSOLETE_KEYIO (legacy support): you can still use your legacy native/user indices (< 512) according to how your backend/engine stored them in io.KeysDown[], but need to cast them to ImGuiKey. + // - with IMGUI_DISABLE_OBSOLETE_KEYIO (this is the way forward): any use of ImGuiKey will assert with key < 512. GetKeyIndex() is pass-through and therefore deprecated (gone if IMGUI_DISABLE_OBSOLETE_KEYIO is defined). IMGUI_API bool IsKeyDown(ImGuiKey key); // is key being held. IMGUI_API bool IsKeyPressed(ImGuiKey key, bool repeat = true); // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate IMGUI_API bool IsKeyReleased(ImGuiKey key); // was key released (went from Down to !Down)? @@ -1031,7 +1022,7 @@ namespace ImGui // - Many related features are still in imgui_internal.h. For instance, most IsKeyXXX()/IsMouseXXX() functions have an owner-id-aware version. IMGUI_API void SetItemKeyOwner(ImGuiKey key); // Set key owner to last item ID if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'. - // Inputs Utilities: Mouse + // Inputs Utilities: Mouse specific // - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right. // - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle. // - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking position (see 'lock_threshold' and 'io.MouseDraggingThreshold') @@ -1039,7 +1030,6 @@ namespace ImGui IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat = false); // did mouse button clicked? (went from !Down to Down). Same as GetMouseClickedCount() == 1. IMGUI_API bool IsMouseReleased(ImGuiMouseButton button); // did mouse button released? (went from Down to !Down) IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button); // did mouse button double-clicked? Same as GetMouseClickedCount() == 2. (note that a double-click will also report IsMouseClicked() == true) - IMGUI_API bool IsMouseReleasedWithDelay(ImGuiMouseButton button, float delay); // delayed mouse release (use very sparingly!). Generally used with 'delay >= io.MouseDoubleClickTime' + combined with a 'io.MouseClickedLastCount==1' test. This is a very rarely used UI idiom, but some apps use this: e.g. MS Explorer single click on an icon to rename. IMGUI_API int GetMouseClickedCount(ImGuiMouseButton button); // return the number of successive mouse-clicks at the time where a click happen (otherwise 0). IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available @@ -1090,6 +1080,7 @@ namespace ImGui // (Optional) Platform/OS interface for multi-viewport support // Read comments around the ImGuiPlatformIO structure for more details. // Note: You may use GetWindowViewport() to get the current viewport of the current window. + IMGUI_API ImGuiPlatformIO& GetPlatformIO(); // platform/renderer functions, for backend to setup + viewports list. IMGUI_API void UpdatePlatformWindows(); // call in main loop. will call CreateWindow/ResizeWindow/etc. platform functions for each secondary viewport, and DestroyWindow for each inactive viewport. IMGUI_API void RenderPlatformWindowsDefault(void* platform_render_arg = NULL, void* renderer_render_arg = NULL); // call in main loop. will call RenderWindow/SwapBuffers platform functions for each secondary viewport which doesn't have the ImGuiViewportFlags_Minimized flag set. May be reimplemented by user for custom rendering needs. IMGUI_API void DestroyPlatformWindows(); // call DestroyWindow platform functions for all viewports. call from backend Shutdown() if you need to close platform windows before imgui shutdown. otherwise will be called by DestroyContext(). @@ -1123,8 +1114,8 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13, // Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus) ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14, // Always show vertical scrollbar (even if ContentSize.y < Size.y) ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15, // Always show horizontal scrollbar (even if ContentSize.x < Size.x) - ImGuiWindowFlags_NoNavInputs = 1 << 16, // No keyboard/gamepad navigation within the window - ImGuiWindowFlags_NoNavFocus = 1 << 17, // No focusing toward this window with keyboard/gamepad navigation (e.g. skipped by CTRL+TAB) + ImGuiWindowFlags_NoNavInputs = 1 << 16, // No gamepad/keyboard navigation within the window + ImGuiWindowFlags_NoNavFocus = 1 << 17, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB) ImGuiWindowFlags_UnsavedDocument = 1 << 18, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. ImGuiWindowFlags_NoDocking = 1 << 19, // Disable docking of this window ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, @@ -1132,22 +1123,22 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, // [Internal] - ImGuiWindowFlags_DockNodeHost = 1 << 23, // Don't use! For internal use by Begin()/NewFrame() ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild() ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip() ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal() ImGuiWindowFlags_ChildMenu = 1 << 28, // Don't use! For internal use by BeginMenu() + ImGuiWindowFlags_DockNodeHost = 1 << 29, // Don't use! For internal use by Begin()/NewFrame() // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiWindowFlags_NavFlattened = 1 << 29, // Obsoleted in 1.90.9: Use ImGuiChildFlags_NavFlattened in BeginChild() call. - ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 30, // Obsoleted in 1.90.0: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call. + ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 30, // Obsoleted in 1.90: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call. + ImGuiWindowFlags_NavFlattened = 1 << 31, // Obsoleted in 1.90.9: Use ImGuiChildFlags_NavFlattened in BeginChild() call. #endif }; // Flags for ImGui::BeginChild() -// (Legacy: bit 0 must always correspond to ImGuiChildFlags_Borders to be backward compatible with old API using 'bool border = false'. +// (Legacy: bit 0 must always correspond to ImGuiChildFlags_Border to be backward compatible with old API using 'bool border = false'. // About using AutoResizeX/AutoResizeY flags: // - May be combined with SetNextWindowSizeConstraints() to set a min/max size for each axis (see "Demo->Child->Auto-resize with Constraints"). // - Size measurement for a given axis is only performed when the child window is within visible boundaries, or is just appearing. @@ -1158,7 +1149,7 @@ enum ImGuiWindowFlags_ enum ImGuiChildFlags_ { ImGuiChildFlags_None = 0, - ImGuiChildFlags_Borders = 1 << 0, // Show an outer border and enable WindowPadding. (IMPORTANT: this is always == 1 == true for legacy reason) + ImGuiChildFlags_Border = 1 << 0, // Show an outer border and enable WindowPadding. (IMPORTANT: this is always == 1 == true for legacy reason) ImGuiChildFlags_AlwaysUseWindowPadding = 1 << 1, // Pad with style.WindowPadding even if no border are drawn (no padding by default for non-bordered child windows because it makes more sense) ImGuiChildFlags_ResizeX = 1 << 2, // Allow resize from right border (layout direction). Enable .ini saving (unless ImGuiWindowFlags_NoSavedSettings passed to window flags) ImGuiChildFlags_ResizeY = 1 << 3, // Allow resize from bottom border (layout direction). " @@ -1166,12 +1157,7 @@ enum ImGuiChildFlags_ ImGuiChildFlags_AutoResizeY = 1 << 5, // Enable auto-resizing height. Read "IMPORTANT: Size measurement" details above. ImGuiChildFlags_AlwaysAutoResize = 1 << 6, // Combined with AutoResizeX/AutoResizeY. Always measure size even when child is hidden, always return true, always disable clipping optimization! NOT RECOMMENDED. ImGuiChildFlags_FrameStyle = 1 << 7, // Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding. - ImGuiChildFlags_NavFlattened = 1 << 8, // [BETA] Share focus scope, allow keyboard/gamepad navigation to cross over parent border to this child or between sibling child windows. - - // Obsolete names -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiChildFlags_Border = ImGuiChildFlags_Borders, // Renamed in 1.91.1 (August 2024) for consistency. -#endif + ImGuiChildFlags_NavFlattened = 1 << 8, // Share focus scope, allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows. }; // Flags for ImGui::PushItemFlag() @@ -1184,7 +1170,6 @@ enum ImGuiItemFlags_ ImGuiItemFlags_NoNavDefaultFocus = 1 << 2, // false // Disable item being a candidate for default focus (e.g. used by title bar items). ImGuiItemFlags_ButtonRepeat = 1 << 3, // false // Any button-like behavior will have repeat mode enabled (based on io.KeyRepeatDelay and io.KeyRepeatRate values). Note that you can also call IsItemActive() after any button to tell if it is being held. ImGuiItemFlags_AutoClosePopups = 1 << 4, // true // MenuItem()/Selectable() automatically close their parent popup window. - ImGuiItemFlags_AllowDuplicateId = 1 << 5, // false // Allow submitting an item with the same identifier as an item already submitted this frame without triggering a warning tooltip if io.ConfigDebugHighlightIdConflicts is set. }; // Flags for ImGui::InputText() @@ -1201,7 +1186,7 @@ enum ImGuiInputTextFlags_ // Inputs ImGuiInputTextFlags_AllowTabInput = 1 << 5, // Pressing TAB input a '\t' character into the text field - ImGuiInputTextFlags_EnterReturnsTrue = 1 << 6, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider using IsItemDeactivatedAfterEdit() instead! + ImGuiInputTextFlags_EnterReturnsTrue = 1 << 6, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider looking at the IsItemDeactivatedAfterEdit() function. ImGuiInputTextFlags_EscapeClearsAll = 1 << 7, // Escape key clears content if not empty, and deactivate otherwise (contrast to default behavior of Escape to revert) ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 8, // In multi-line mode, validate with Enter, add new line with Ctrl+Enter (default is opposite: validate with Ctrl+Enter, add line with Enter). @@ -1215,16 +1200,13 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_NoHorizontalScroll = 1 << 15, // Disable following the cursor horizontally ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). - // Elide display / Alignment - ImGuiInputTextFlags_ElideLeft = 1 << 17, // When text doesn't fit, elide left side to ensure right side stays visible. Useful for path/filenames. Single-line only! - // Callback features - ImGuiInputTextFlags_CallbackCompletion = 1 << 18, // Callback on pressing TAB (for completion handling) - ImGuiInputTextFlags_CallbackHistory = 1 << 19, // Callback on pressing Up/Down arrows (for history handling) - ImGuiInputTextFlags_CallbackAlways = 1 << 20, // Callback on each iteration. User code may query cursor position, modify text buffer. - ImGuiInputTextFlags_CallbackCharFilter = 1 << 21, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. - ImGuiInputTextFlags_CallbackResize = 1 << 22, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) - ImGuiInputTextFlags_CallbackEdit = 1 << 23, // Callback on any edit. Note that InputText() already returns true on edit + you can always use IsItemEdited(). The callback is useful to manipulate the underlying buffer while focus is active. + ImGuiInputTextFlags_CallbackCompletion = 1 << 17, // Callback on pressing TAB (for completion handling) + ImGuiInputTextFlags_CallbackHistory = 1 << 18, // Callback on pressing Up/Down arrows (for history handling) + ImGuiInputTextFlags_CallbackAlways = 1 << 19, // Callback on each iteration. User code may query cursor position, modify text buffer. + ImGuiInputTextFlags_CallbackCharFilter = 1 << 20, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. + ImGuiInputTextFlags_CallbackResize = 1 << 21, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) + ImGuiInputTextFlags_CallbackEdit = 1 << 22, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) // Obsolete names //ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not matching behavior @@ -1240,23 +1222,21 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes) ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open - ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Open on double-click instead of simple click (default for multi-select unless any _OpenOnXXX behavior is set explicitly). Both behaviors may be combined. - ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Open when clicking on the arrow part (default for multi-select unless any _OpenOnXXX behavior is set explicitly). Both behaviors may be combined. + ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node + ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow. IMPORTANT: node can still be marked open/close if you don't set the _Leaf flag! ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding() before the node. ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line without using AllowOverlap mode. ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (cover the indent area). - ImGuiTreeNodeFlags_SpanLabelWidth = 1 << 13, // Narrow hit box + narrow hovering highlight, will only cover the label text. - ImGuiTreeNodeFlags_SpanAllColumns = 1 << 14, // Frame will span all columns of its container table (label will still fit in current column) - ImGuiTreeNodeFlags_LabelSpanAllColumns = 1 << 15, // Label will span all columns of its container table + ImGuiTreeNodeFlags_SpanTextWidth = 1 << 13, // Narrow hit box + narrow hovering highlight, will only cover the label text. + ImGuiTreeNodeFlags_SpanAllColumns = 1 << 14, // Frame will span all columns of its container table (text will still fit in current column) + ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 15, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 16, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible - ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 17, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog, #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7 - ImGuiTreeNodeFlags_SpanTextWidth = ImGuiTreeNodeFlags_SpanLabelWidth,// Renamed in 1.90.7 #endif }; @@ -1294,7 +1274,6 @@ enum ImGuiSelectableFlags_ ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one - ImGuiSelectableFlags_Highlight = 1 << 5, // Make the item be displayed as if it is hovered #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGuiSelectableFlags_DontClosePopups = ImGuiSelectableFlags_NoAutoClosePopups, // Renamed in 1.91.0 @@ -1378,7 +1357,7 @@ enum ImGuiHoveredFlags_ ImGuiHoveredFlags_AllowWhenOverlappedByItem = 1 << 8, // IsItemHovered() only: Return true even if the item uses AllowOverlap mode and is overlapped by another hoverable item. ImGuiHoveredFlags_AllowWhenOverlappedByWindow = 1 << 9, // IsItemHovered() only: Return true even if the position is obstructed or overlapped by another window. ImGuiHoveredFlags_AllowWhenDisabled = 1 << 10, // IsItemHovered() only: Return true even if the item is disabled - ImGuiHoveredFlags_NoNavOverride = 1 << 11, // IsItemHovered() only: Disable using keyboard/gamepad navigation state when active, always query mouse + ImGuiHoveredFlags_NoNavOverride = 1 << 11, // IsItemHovered() only: Disable using gamepad/keyboard navigation state when active, always query mouse ImGuiHoveredFlags_AllowWhenOverlapped = ImGuiHoveredFlags_AllowWhenOverlappedByItem | ImGuiHoveredFlags_AllowWhenOverlappedByWindow, ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows, @@ -1464,7 +1443,6 @@ enum ImGuiDataType_ ImGuiDataType_Float, // float ImGuiDataType_Double, // double ImGuiDataType_Bool, // bool (provided for user convenience, not supported by scalar widgets) - ImGuiDataType_String, // char* (provided for user convenience, not supported by scalar widgets) ImGuiDataType_COUNT }; @@ -1487,18 +1465,21 @@ enum ImGuiSortDirection : ImU8 ImGuiSortDirection_Descending = 2 // Descending = 9->0, Z->A etc. }; +// Since 1.90, defining IMGUI_DISABLE_OBSOLETE_FUNCTIONS automatically defines IMGUI_DISABLE_OBSOLETE_KEYIO as well. +#if defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && !defined(IMGUI_DISABLE_OBSOLETE_KEYIO) +#define IMGUI_DISABLE_OBSOLETE_KEYIO +#endif + // A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value): can represent Keyboard, Mouse and Gamepad values. -// All our named keys are >= 512. Keys value 0 to 511 are left unused and were legacy native/opaque key values (< 1.87). -// Support for legacy keys was completely removed in 1.91.5. -// Read details about the 1.87+ transition : https://github.com/ocornut/imgui/issues/4921 +// All our named keys are >= 512. Keys value 0 to 511 are left unused as legacy native/opaque key values (< 1.87). +// Since >= 1.89 we increased typing (went from int to enum), some legacy code may need a cast to ImGuiKey. +// Read details about the 1.87 and 1.89 transition : https://github.com/ocornut/imgui/issues/4921 // Note that "Keys" related to physical keys and are not the same concept as input "Characters", the later are submitted via io.AddInputCharacter(). // The keyboard key enum values are named after the keys on a standard US keyboard, and on other keyboard types the keys reported may not match the keycaps. enum ImGuiKey : int { // Keyboard ImGuiKey_None = 0, - ImGuiKey_NamedKey_BEGIN = 512, // First valid key value (other than 0) - ImGuiKey_Tab = 512, // == ImGuiKey_NamedKey_BEGIN ImGuiKey_LeftArrow, ImGuiKey_RightArrow, @@ -1586,7 +1567,7 @@ enum ImGuiKey : int // [Internal] Reserved for mod storage ImGuiKey_ReservedForModCtrl, ImGuiKey_ReservedForModShift, ImGuiKey_ReservedForModAlt, ImGuiKey_ReservedForModSuper, - ImGuiKey_NamedKey_END, + ImGuiKey_COUNT, // Keyboard Modifiers (explicitly submitted by backend via AddKeyEvent() calls) // - This is mirroring the data also written to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper, in a format allowing @@ -1604,13 +1585,21 @@ enum ImGuiKey : int ImGuiMod_Super = 1 << 15, // Windows/Super (non-macOS), Ctrl (macOS) ImGuiMod_Mask_ = 0xF000, // 4-bits - // [Internal] If you need to iterate all keys (for e.g. an input mapper) you may use ImGuiKey_NamedKey_BEGIN..ImGuiKey_NamedKey_END. + // [Internal] Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index + the io.KeyMap[] array. + // We are ditching this method but keeping a legacy path for user code doing e.g. IsKeyPressed(MY_NATIVE_KEY_CODE) + // If you need to iterate all keys (for e.g. an input mapper) you may use ImGuiKey_NamedKey_BEGIN..ImGuiKey_NamedKey_END. + ImGuiKey_NamedKey_BEGIN = 512, + ImGuiKey_NamedKey_END = ImGuiKey_COUNT, ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN, - //ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys - //ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // Accesses to io.KeysData[] must use (key - ImGuiKey_NamedKey_BEGIN) index. +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys + ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET) index. +#else + ImGuiKey_KeysData_SIZE = ImGuiKey_COUNT, // Size of KeysData[]: hold legacy 0..512 keycodes + named keys + ImGuiKey_KeysData_OFFSET = 0, // Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET) index. +#endif #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiKey_COUNT = ImGuiKey_NamedKey_END, // Obsoleted in 1.91.5 because it was extremely misleading (since named keys don't start at 0 anymore) ImGuiMod_Shortcut = ImGuiMod_Ctrl, // Removed in 1.90.7, you can now simply use ImGuiMod_Ctrl ImGuiKey_ModCtrl = ImGuiMod_Ctrl, ImGuiKey_ModShift = ImGuiMod_Shift, ImGuiKey_ModAlt = ImGuiMod_Alt, ImGuiKey_ModSuper = ImGuiMod_Super, // Renamed in 1.89 //ImGuiKey_KeyPadEnter = ImGuiKey_KeypadEnter, // Renamed in 1.87 @@ -1642,12 +1631,26 @@ enum ImGuiInputFlags_ ImGuiInputFlags_Tooltip = 1 << 18, // Automatically display a tooltip when hovering item [BETA] Unsure of right api (opt-in/opt-out) }; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO +// OBSOLETED in 1.88 (from July 2022): ImGuiNavInput and io.NavInputs[]. +// Official backends between 1.60 and 1.86: will keep working and feed gamepad inputs as long as IMGUI_DISABLE_OBSOLETE_KEYIO is not set. +// Custom backends: feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. +enum ImGuiNavInput +{ + ImGuiNavInput_Activate, ImGuiNavInput_Cancel, ImGuiNavInput_Input, ImGuiNavInput_Menu, ImGuiNavInput_DpadLeft, ImGuiNavInput_DpadRight, ImGuiNavInput_DpadUp, ImGuiNavInput_DpadDown, + ImGuiNavInput_LStickLeft, ImGuiNavInput_LStickRight, ImGuiNavInput_LStickUp, ImGuiNavInput_LStickDown, ImGuiNavInput_FocusPrev, ImGuiNavInput_FocusNext, ImGuiNavInput_TweakSlow, ImGuiNavInput_TweakFast, + ImGuiNavInput_COUNT, +}; +#endif + // Configuration flags stored in io.ConfigFlags. Set by user/application. enum ImGuiConfigFlags_ { ImGuiConfigFlags_None = 0, ImGuiConfigFlags_NavEnableKeyboard = 1 << 0, // Master keyboard navigation enable flag. Enable full Tabbing + directional arrows + space/enter to activate. ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. Backend also needs to set ImGuiBackendFlags_HasGamepad. + ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your backend, otherwise ImGui will react as if the mouse is jumping around back and forth. + ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set. ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct dear imgui to disable mouse inputs and interactions. ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct backend to not alter mouse cursor shape and visibility. Use if the backend cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead. ImGuiConfigFlags_NoKeyboard = 1 << 6, // Instruct dear imgui to disable keyboard inputs and interactions. This is done by ignoring keyboard events and clearing existing states. @@ -1664,11 +1667,6 @@ enum ImGuiConfigFlags_ // User storage (to allow your backend/engine to communicate to code that may be shared between multiple projects. Those flags are NOT used by core Dear ImGui) ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware. ImGuiConfigFlags_IsTouchScreen = 1 << 21, // Application is using a touch screen instead of a mouse. - -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavMoveSetMousePos - ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavCaptureKeyboard -#endif }; // Backend capabilities flags stored in io.BackendFlags. Set by imgui_impl_xxx or custom backend. @@ -1677,7 +1675,7 @@ enum ImGuiBackendFlags_ ImGuiBackendFlags_None = 0, ImGuiBackendFlags_HasGamepad = 1 << 0, // Backend Platform supports gamepad and currently has one connected. ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Backend Platform supports honoring GetMouseCursor() value to change the OS cursor shape. - ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Backend Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if io.ConfigNavMoveSetMousePos is set). + ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Backend Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set). ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3, // Backend Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices. // [BETA] Viewports @@ -1743,7 +1741,7 @@ enum ImGuiCol_ ImGuiCol_TextLink, // Hyperlink color ImGuiCol_TextSelectedBg, ImGuiCol_DragDropTarget, // Rectangle highlighting a drop target - ImGuiCol_NavCursor, // Color of keyboard/gamepad navigation cursor/rectangle, when visible + ImGuiCol_NavHighlight, // Gamepad/keyboard: current highlighted item ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active @@ -1753,7 +1751,6 @@ enum ImGuiCol_ ImGuiCol_TabActive = ImGuiCol_TabSelected, // [renamed in 1.90.9] ImGuiCol_TabUnfocused = ImGuiCol_TabDimmed, // [renamed in 1.90.9] ImGuiCol_TabUnfocusedActive = ImGuiCol_TabDimmedSelected, // [renamed in 1.90.9] - ImGuiCol_NavHighlight = ImGuiCol_NavCursor, // [renamed in 1.91.4] #endif }; @@ -1790,10 +1787,10 @@ enum ImGuiStyleVar_ ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding ImGuiStyleVar_GrabMinSize, // float GrabMinSize ImGuiStyleVar_GrabRounding, // float GrabRounding + ImGuiStyleVar_LayoutAlign, // float LayoutAlign ImGuiStyleVar_TabRounding, // float TabRounding ImGuiStyleVar_TabBorderSize, // float TabBorderSize ImGuiStyleVar_TabBarBorderSize, // float TabBarBorderSize - ImGuiStyleVar_TabBarOverlineSize, // float TabBarOverlineSize ImGuiStyleVar_TableAngledHeadersAngle, // float TableAngledHeadersAngle ImGuiStyleVar_TableAngledHeadersTextAlign,// ImVec2 TableAngledHeadersTextAlign ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign @@ -1813,7 +1810,7 @@ enum ImGuiButtonFlags_ ImGuiButtonFlags_MouseButtonRight = 1 << 1, // React on right mouse button ImGuiButtonFlags_MouseButtonMiddle = 1 << 2, // React on center mouse button ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle, // [Internal] - ImGuiButtonFlags_EnableNav = 1 << 3, // InvisibleButton(): do not disable navigation/tabbing. Otherwise disabled by default. + //ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft, }; // Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton() @@ -1831,16 +1828,10 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source. ImGuiColorEditFlags_NoBorder = 1 << 10, // // ColorButton: disable border (which is enforced by default) - // Alpha preview - // - Prior to 1.91.8 (2025/01/21): alpha was made opaque in the preview by default using old name ImGuiColorEditFlags_AlphaPreview. - // - We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior. - // - The new flags may be combined better and allow finer controls. - ImGuiColorEditFlags_AlphaOpaque = 1 << 11, // // ColorEdit, ColorPicker, ColorButton: disable alpha in the preview,. Contrary to _NoAlpha it may still be edited when calling ColorEdit4()/ColorPicker4(). For ColorButton() this does the same as _NoAlpha. - ImGuiColorEditFlags_AlphaNoBg = 1 << 12, // // ColorEdit, ColorPicker, ColorButton: disable rendering a checkerboard background behind transparent color. - ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 13, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half transparent preview. - // User Options (right-click on widget to change some of them). ImGuiColorEditFlags_AlphaBar = 1 << 16, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker. + ImGuiColorEditFlags_AlphaPreview = 1 << 17, // // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque. + ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 18, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque. 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. ImGuiColorEditFlags_DisplayHSV = 1 << 21, // [Display] // " @@ -1857,34 +1848,30 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_DefaultOptions_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar, // [Internal] Masks - ImGuiColorEditFlags_AlphaMask_ = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaOpaque | ImGuiColorEditFlags_AlphaNoBg | ImGuiColorEditFlags_AlphaPreviewHalf, ImGuiColorEditFlags_DisplayMask_ = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex, ImGuiColorEditFlags_DataTypeMask_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float, ImGuiColorEditFlags_PickerMask_ = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar, ImGuiColorEditFlags_InputMask_ = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV, // 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] }; // Flags for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc. // We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them. -// (Those are per-item flags. There is shared behavior flag too: ImGuiIO: io.ConfigDragClickToInputText) +// (Those are per-item flags. There are shared flags in ImGuiIO: io.ConfigDragClickToInputText) enum ImGuiSliderFlags_ { - ImGuiSliderFlags_None = 0, - ImGuiSliderFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits. - ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits). - ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget. - ImGuiSliderFlags_WrapAround = 1 << 8, // Enable wrapping around from max to min and from min to max. Only supported by DragXXX() functions for now. - ImGuiSliderFlags_ClampOnInput = 1 << 9, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds. - ImGuiSliderFlags_ClampZeroRange = 1 << 10, // Clamp even if min==max==0.0f. Otherwise due to legacy reason DragXXX functions don't clamp with those values. When your clamping limits are dynamic you almost always want to use it. - ImGuiSliderFlags_NoSpeedTweaks = 1 << 11, // Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic. - ImGuiSliderFlags_AlwaysClamp = ImGuiSliderFlags_ClampOnInput | ImGuiSliderFlags_ClampZeroRange, - ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed. + ImGuiSliderFlags_None = 0, + ImGuiSliderFlags_AlwaysClamp = 1 << 4, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds. + ImGuiSliderFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits. + ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits). + ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget. + ImGuiSliderFlags_WrapAround = 1 << 8, // Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions for now. + ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed. + + // Obsolete names + //ImGuiSliderFlags_ClampOnInput = ImGuiSliderFlags_AlwaysClamp, // [renamed in 1.79] }; // Identify a mouse button. @@ -2033,7 +2020,7 @@ enum ImGuiTableColumnFlags_ ImGuiTableColumnFlags_NoSort = 1 << 9, // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table). ImGuiTableColumnFlags_NoSortAscending = 1 << 10, // Disable ability to sort in the ascending direction. ImGuiTableColumnFlags_NoSortDescending = 1 << 11, // Disable ability to sort in the descending direction. - ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, // TableHeadersRow() will submit an empty label for this column. Convenient for some small columns. Name will still appear in context menu or in angled headers. You may append into this cell by calling TableSetColumnIndex() right after the TableHeadersRow() call. + ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, // TableHeadersRow() will not submit horizontal label for this column. Convenient for some small columns. Name will still appear in context menu or in angled headers. ImGuiTableColumnFlags_NoHeaderWidth = 1 << 13, // Disable header text width contribution to automatic column width. ImGuiTableColumnFlags_PreferSortAscending = 1 << 14, // Make the initial sort direction Ascending when first sorting on this column (default). ImGuiTableColumnFlags_PreferSortDescending = 1 << 15, // Make the initial sort direction Descending when first sorting on this column. @@ -2243,18 +2230,18 @@ struct ImGuiStyle float ScrollbarRounding; // Radius of grab corners for scrollbar. float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. + float LayoutAlign; // Element alignment inside horizontal and vertical layouts (0.0f - left/top, 1.0f - right/bottom, 0.5f - center). float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. float TabBorderSize; // Thickness of border around tabs. float TabMinWidthForCloseButton; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. - float TabBarOverlineSize; // Thickness of tab-bar overline, which highlights the selected tab-bar. float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees). ImVec2 TableAngledHeadersTextAlign;// Alignment of angled headers within the cell 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; // Thickness of border in SeparatorText() + 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; // Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen. @@ -2289,8 +2276,6 @@ struct ImGuiStyle // - initialization: backends and user code writes to ImGuiIO. // - main loop: backends writes to ImGuiIO, user code and imgui code reads from ImGuiIO. //----------------------------------------------------------------------------- -// Also see ImGui::GetPlatformIO() and ImGuiPlatformIO struct for OS/platform related functions: clipboard, IME etc. -//----------------------------------------------------------------------------- // [Internal] Storage used by IsKeyDown(), IsKeyPressed() etc functions. // If prior to 1.87 you used io.KeysDownDuration[] (which was marked as internal), you should use GetKeyData(key)->DownDuration and *NOT* io.KeysData[key]->DownDuration. @@ -2308,7 +2293,7 @@ struct ImGuiIO // Configuration // Default value //------------------------------------------------------------------ - ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Keyboard/Gamepad navigation options, etc. + ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc. ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by backend (imgui_impl_xxx files or custom backend) to communicate features supported by the backend. ImVec2 DisplaySize; // // Main display size, in pixels (generally == GetMainViewport()->Size). May change every frame. float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. May change every frame. @@ -2317,22 +2302,12 @@ struct ImGuiIO const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified). void* UserData; // = NULL // Store your own data. - // Font system ImFontAtlas*Fonts; // // Font atlas: load, rasterize and pack one or more fonts into a single texture. float FontGlobalScale; // = 1.0f // Global scale all fonts - bool FontAllowUserScaling; // = false // [OBSOLETE] Allow user scaling text of individual window with CTRL+Wheel. + bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. ImVec2 DisplayFramebufferScale; // = (1, 1) // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale. - // Keyboard/Gamepad Navigation options - bool ConfigNavSwapGamepadButtons; // = false // Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout. - bool ConfigNavMoveSetMousePos; // = false // Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult. Will update io.MousePos and set io.WantSetMousePos=true. - bool ConfigNavCaptureKeyboard; // = true // Sets io.WantCaptureKeyboard when io.NavActive is set. - bool ConfigNavEscapeClearFocusItem; // = true // Pressing Escape can clear focused item + navigation id/highlight. Set to false if you want to always keep highlight on. - bool ConfigNavEscapeClearFocusWindow;// = false // Pressing Escape can clear focused window as well (super set of io.ConfigNavEscapeClearFocusItem). - bool ConfigNavCursorVisibleAuto; // = true // Using directional navigation key makes the cursor visible. Mouse click hides the cursor. - bool ConfigNavCursorVisibleAlways; // = false // Navigation cursor is always visible. - // Docking options (when ImGuiConfigFlags_DockingEnable is set) bool ConfigDockingNoSplit; // = false // Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars. bool ConfigDockingWithShift; // = false // Enable docking with holding Shift key (reduce visual noise, allows dropping in wider space) @@ -2346,17 +2321,14 @@ struct ImGuiIO bool ConfigViewportsNoDefaultParent; // = false // Disable default OS parenting to main viewport for secondary viewports. By default, viewports are marked with ParentViewportId = , expecting the platform backend to setup a parent/child relationship between the OS windows (some backend may ignore this). Set to true if you want the default to be 0, then all viewports will be top-level OS windows. // 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 keep item active and select contents (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. + bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs 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. float ConfigMemoryCompactTimer; // = 60.0f // Timer (in seconds) to free transient windows/tables memory buffers when unused. Set to -1.0f to disable. // Inputs Behaviors @@ -2371,37 +2343,12 @@ struct ImGuiIO // Debug options //------------------------------------------------------------------ - // Options to configure Error Handling and how we handle recoverable errors [EXPERIMENTAL] - // - Error recovery is provided as a way to facilitate: - // - Recovery after a programming error (native code or scripting language - the later tends to facilitate iterating on code while running). - // - Recovery after running an exception handler or any error processing which may skip code after an error has been detected. - // - Error recovery is not perfect nor guaranteed! It is a feature to ease development. - // You not are not supposed to rely on it in the course of a normal application run. - // - Functions that support error recovery are using IM_ASSERT_USER_ERROR() instead of IM_ASSERT(). - // - By design, we do NOT allow error recovery to be 100% silent. One of the three options needs to be checked! - // - Always ensure that on programmers seats you have at minimum Asserts or Tooltips enabled when making direct imgui API calls! - // Otherwise it would severely hinder your ability to catch and correct mistakes! - // Read https://github.com/ocornut/imgui/wiki/Error-Handling for details. - // - Programmer seats: keep asserts (default), or disable asserts and keep error tooltips (new and nice!) - // - Non-programmer seats: maybe disable asserts, but make sure errors are resurfaced (tooltips, visible log entries, use callback etc.) - // - Recovery after error/exception: record stack sizes with ErrorRecoveryStoreState(), disable assert, set log callback (to e.g. trigger high-level breakpoint), recover with ErrorRecoveryTryToRecoverState(), restore settings. - bool ConfigErrorRecovery; // = true // Enable error recovery support. Some errors won't be detected and lead to direct crashes if recovery is disabled. - bool ConfigErrorRecoveryEnableAssert; // = true // Enable asserts on recoverable error. By default call IM_ASSERT() when returning from a failing IM_ASSERT_USER_ERROR() - bool ConfigErrorRecoveryEnableDebugLog; // = true // Enable debug log output on recoverable errors. - bool ConfigErrorRecoveryEnableTooltip; // = true // Enable tooltip on recoverable errors. The tooltip include a way to enable asserts if they were disabled. - // Option to enable various debug tools showing buttons that will call the IM_DEBUG_BREAK() macro. // - The Item Picker tool will be available regardless of this being enabled, in order to maximize its discoverability. // - Requires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application. // e.g. io.ConfigDebugIsDebuggerPresent = ::IsDebuggerPresent() on Win32, or refer to ImOsIsDebuggerPresent() imgui_test_engine/imgui_te_utils.cpp for a Unix compatible version). bool ConfigDebugIsDebuggerPresent; // = false // Enable various tools calling IM_DEBUG_BREAK(). - // Tools to detect code submitting items with conflicting/duplicate IDs - // - Code should use PushID()/PopID() in loops, or append "##xx" to same-label identifiers. - // - Empty label e.g. Button("") == same ID as parent widget/node. Use Button("##xx") instead! - // - See FAQ https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-about-the-id-stack-system - bool ConfigDebugHighlightIdConflicts;// = true // Highlight and show an error message when multiple items have conflicting identifiers. - // Tools to test correct Begin/End and BeginChild/EndChild behaviors. // - Presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX() // - This is inconsistent with other BeginXXX functions and create confusion for many users. @@ -2418,11 +2365,10 @@ struct ImGuiIO bool ConfigDebugIniSettings; // = false // Save .ini data with extra comments (particularly helpful for Docking, but makes saving slower) //------------------------------------------------------------------ - // Platform Identifiers + // Platform Functions // (the imgui_impl_xxxx backend files are setting those up for you) //------------------------------------------------------------------ - // Nowadays those would be stored in ImGuiPlatformIO but we are leaving them here for legacy reasons. // Optional: Platform/Renderer backend name (informational only! will be displayed in About Window) + User data for backend/wrappers to store their own stuff. const char* BackendPlatformName; // = NULL const char* BackendRendererName; // = NULL @@ -2430,6 +2376,25 @@ struct ImGuiIO void* BackendRendererUserData; // = NULL // User data for renderer backend void* BackendLanguageUserData; // = NULL // User data for non C++ programming language backend + // Optional: Access OS clipboard + // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) + const char* (*GetClipboardTextFn)(void* user_data); + void (*SetClipboardTextFn)(void* user_data, const char* text); + void* ClipboardUserData; + + // Optional: Open link/folder/file in OS Shell + // (default to use ShellExecuteA() on Windows, system() on Linux/Mac) + bool (*PlatformOpenInShellFn)(ImGuiContext* ctx, const char* path); + void* PlatformOpenInShellUserData; + + // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) + // (default to use native imm32 api on Windows) + void (*PlatformSetImeDataFn)(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); + //void (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data); // [Renamed to io.PlatformSetImeDataFn in 1.91.0] + + // Optional: Platform locale + ImWchar PlatformLocaleDecimalPoint; // '.' // [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point + //------------------------------------------------------------------ // Input - Call before calling NewFrame() //------------------------------------------------------------------ @@ -2465,10 +2430,10 @@ struct ImGuiIO bool WantCaptureMouse; // Set when Dear ImGui will use mouse inputs, in this case do not dispatch them to your main game/application (either way, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.). bool WantCaptureKeyboard; // Set when Dear ImGui will use keyboard inputs, in this case do not dispatch them to your main game/application (either way, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.). bool WantTextInput; // Mobile/console: when set, you may display an on-screen keyboard. This is set by Dear ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active). - bool WantSetMousePos; // MousePos has been altered, backend should reposition mouse on next frame. Rarely used! Set only when io.ConfigNavMoveSetMousePos is enabled. + bool WantSetMousePos; // MousePos has been altered, backend should reposition mouse on next frame. Rarely used! Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled. bool WantSaveIniSettings; // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving! bool NavActive; // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag. - bool NavVisible; // Keyboard/Gamepad navigation highlight is visible and allowed (will handle ImGuiKey_NavXXX events). + bool NavVisible; // Keyboard/Gamepad navigation is visible and allowed (will handle ImGuiKey_NavXXX events). float Framerate; // Estimate of application framerate (rolling average over 60 frames, based on io.DeltaTime), in frame per second. Solely for convenience. Slow applications may not want to use a moving average or may want to reset underlying buffers occasionally. int MetricsRenderVertices; // Vertices output during last call to Render() int MetricsRenderIndices; // Indices output during last call to Render() = number of triangles * 3 @@ -2498,7 +2463,7 @@ struct ImGuiIO // Other state maintained from data above + IO function calls ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags. Read-only, updated by NewFrame() - ImGuiKeyData KeysData[ImGuiKey_NamedKey_COUNT];// Key state for all known keys. Use IsKeyXXX() functions to access this. + ImGuiKeyData KeysData[ImGuiKey_KeysData_SIZE]; // Key state for all known keys. Use IsKeyXXX() functions to access this. bool WantCaptureMouseUnlessPopupClose; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup. ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) ImVec2 MouseClickedPos[5]; // Position at time of clicking @@ -2508,7 +2473,6 @@ struct ImGuiIO ImU16 MouseClickedCount[5]; // == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down ImU16 MouseClickedLastCount[5]; // Count successive number of clicks. Stays valid after mouse release. Reset after another click is done. bool MouseReleased[5]; // Mouse button went from Down to !Down - double MouseReleasedTime[5]; // Time of last released (rarely used! but useful to handle delayed single-click when trying to disambiguate them from double-click). bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds. bool MouseDownOwnedUnlessPopupClose[5]; // Track if button was clicked inside a dear imgui window. bool MouseWheelRequestAxisSwap; // On a non-Mac system, holding SHIFT requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system. @@ -2520,25 +2484,19 @@ struct ImGuiIO float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui. bool AppFocusLost; // Only modify via AddFocusEvent() bool AppAcceptingEvents; // Only modify via SetAppAcceptingEvents() + ImS8 BackendUsingLegacyKeyArrays; // -1: unknown, 0: using AddKeyEvent(), 1: using legacy io.KeysDown[] + bool BackendUsingLegacyNavInputArray; // 0: using AddKeyAnalogEvent(), 1: writing to legacy io.NavInputs[] directly ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16() ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform backend). Fill using AddInputCharacter() helper. // Legacy: before 1.87, we required backend to fill io.KeyMap[] (imgui->native map) during initialization and io.KeysDown[] (native indices) every frame. // This is still temporarily supported as a legacy feature. However the new preferred scheme is for backend to call io.AddKeyEvent(). // Old (<1.87): ImGui::IsKeyPressed(ImGui::GetIO().KeyMap[ImGuiKey_Space]) --> New (1.87+) ImGui::IsKeyPressed(ImGuiKey_Space) - // Old (<1.87): ImGui::IsKeyPressed(MYPLATFORM_KEY_SPACE) --> New (1.87+) ImGui::IsKeyPressed(ImGuiKey_Space) - // Read https://github.com/ocornut/imgui/issues/4921 for details. - //int KeyMap[ImGuiKey_COUNT]; // [LEGACY] Input: map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. The first 512 are now unused and should be kept zero. Legacy backend will write into KeyMap[] using ImGuiKey_ indices which are always >512. - //bool KeysDown[ImGuiKey_COUNT]; // [LEGACY] Input: Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). This used to be [512] sized. It is now ImGuiKey_COUNT to allow legacy io.KeysDown[GetKeyIndex(...)] to work without an overflow. - //float NavInputs[ImGuiNavInput_COUNT]; // [LEGACY] Since 1.88, NavInputs[] was removed. Backends from 1.60 to 1.86 won't build. Feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + int KeyMap[ImGuiKey_COUNT]; // [LEGACY] Input: map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. The first 512 are now unused and should be kept zero. Legacy backend will write into KeyMap[] using ImGuiKey_ indices which are always >512. + bool KeysDown[ImGuiKey_COUNT]; // [LEGACY] Input: Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). This used to be [512] sized. It is now ImGuiKey_COUNT to allow legacy io.KeysDown[GetKeyIndex(...)] to work without an overflow. + float NavInputs[ImGuiNavInput_COUNT]; // [LEGACY] Since 1.88, NavInputs[] was removed. Backends from 1.60 to 1.86 won't build. Feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. //void* ImeWindowHandle; // [Obsoleted in 1.87] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning. - - // Legacy: before 1.91.1, clipboard functions were stored in ImGuiIO instead of ImGuiPlatformIO. - // As this is will affect all users of custom engines/backends, we are providing proper legacy redirection (will obsolete). -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - const char* (*GetClipboardTextFn)(void* user_data); - void (*SetClipboardTextFn)(void* user_data, const char* text); - void* ClipboardUserData; #endif IMGUI_API ImGuiIO(); @@ -2551,7 +2509,7 @@ struct ImGuiIO // Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used. // The callback function should return 0 by default. // Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details) -// - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit. Note that InputText() already returns true on edit + you can always use IsItemEdited(). The callback is useful to manipulate the underlying buffer while focus is active. +// - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) // - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration // - ImGuiInputTextFlags_CallbackCompletion: Callback on pressing TAB // - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows @@ -2825,8 +2783,7 @@ struct ImGuiListClipper // Helpers: ImVec2/ImVec4 operators // - It is important that we are keeping those disabled by default so they don't leak in user space. // - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h) -// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4. -// - We intentionally provide ImVec2*float but not float*ImVec2: this is rare enough and we want to reduce the surface for possible user mistake. +// - You can use '#define IMGUI_DEFINE_MATH_OPERATORS' to import our operators, provided as a courtesy. #ifdef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED IM_MSVC_RUNTIME_CHECKS_OFF @@ -2854,8 +2811,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE #endif // Helpers macros to generate 32-bit encoded colors -// - User can declare their own format by #defining the 5 _SHIFT/_MASK macros in their imconfig file. -// - Any setting other than the default will need custom backend support. The only standard backend that supports anything else than the default is DirectX9. +// User can declare their own format by #defining the 5 _SHIFT/_MASK macros in their imconfig file. #ifndef IM_COL32_R_SHIFT #ifdef IMGUI_USE_BGRA_PACKED_COLOR #define IM_COL32_R_SHIFT 16 @@ -2944,10 +2900,10 @@ enum ImGuiMultiSelectFlags_ ImGuiMultiSelectFlags_SingleSelect = 1 << 0, // Disable selecting more than one item. This is available to allow single-selection code to share same code/logic if desired. It essentially disables the main purpose of BeginMultiSelect() tho! ImGuiMultiSelectFlags_NoSelectAll = 1 << 1, // Disable CTRL+A shortcut to select all. ImGuiMultiSelectFlags_NoRangeSelect = 1 << 2, // Disable Shift+selection mouse/keyboard support (useful for unordered 2D selection). With BoxSelect is also ensure contiguous SetRange requests are not combined into one. This allows not handling interpolation in SetRange requests. - ImGuiMultiSelectFlags_NoAutoSelect = 1 << 3, // Disable selecting items when navigating (useful for e.g. supporting range-select in a list of checkboxes). - ImGuiMultiSelectFlags_NoAutoClear = 1 << 4, // Disable clearing selection when navigating or selecting another one (generally used with ImGuiMultiSelectFlags_NoAutoSelect. useful for e.g. supporting range-select in a list of checkboxes). - ImGuiMultiSelectFlags_NoAutoClearOnReselect = 1 << 5, // Disable clearing selection when clicking/selecting an already selected item. - ImGuiMultiSelectFlags_BoxSelect1d = 1 << 6, // Enable box-selection with same width and same x pos items (e.g. full row Selectable()). Box-selection works better with little bit of spacing between items hit-box in order to be able to aim at empty space. + ImGuiMultiSelectFlags_NoAutoSelect = 1 << 3, // Disable selecting items when navigating (useful for e.g. supporting range-select in a list of checkboxes) + ImGuiMultiSelectFlags_NoAutoClear = 1 << 4, // Disable clearing selection when navigating or selecting another one (generally used with ImGuiMultiSelectFlags_NoAutoSelect. useful for e.g. supporting range-select in a list of checkboxes) + ImGuiMultiSelectFlags_NoAutoClearOnReselect = 1 << 5, // Disable clearing selection when clicking/selecting an already selected item + ImGuiMultiSelectFlags_BoxSelect1d = 1 << 6, // Enable box-selection with same width and same x pos items (e.g. only full row Selectable()). Box-selection works better with little bit of spacing between items hit-box in order to be able to aim at empty space. ImGuiMultiSelectFlags_BoxSelect2d = 1 << 7, // Enable box-selection with varying width or varying x pos items support (e.g. different width labels, or 2D layout/grid). This is slower: alters clipping logic so that e.g. horizontal movements will update selection of normally clipped items. ImGuiMultiSelectFlags_BoxSelectNoScroll = 1 << 8, // Disable scrolling when box-selecting near edges of scope. ImGuiMultiSelectFlags_ClearOnEscape = 1 << 9, // Clear selection when pressing Escape while scope is focused. @@ -3022,13 +2978,13 @@ struct ImGuiSelectionBasicStorage ImGuiStorage _Storage; // [Internal] Selection set. Think of this as similar to e.g. std::set. Prefer not accessing directly: iterate with GetNextSelectedItem(). // Methods - IMGUI_API ImGuiSelectionBasicStorage(); + ImGuiSelectionBasicStorage(); IMGUI_API void ApplyRequests(ImGuiMultiSelectIO* ms_io); // Apply selection requests coming from BeginMultiSelect() and EndMultiSelect() functions. It uses 'items_count' passed to BeginMultiSelect() IMGUI_API bool Contains(ImGuiID id) const; // Query if an item id is in selection. IMGUI_API void Clear(); // Clear selection IMGUI_API void Swap(ImGuiSelectionBasicStorage& r); // Swap two selections IMGUI_API void SetItemSelected(ImGuiID id, bool selected); // Add/remove an item from selection (generally done by ApplyRequests() function) - IMGUI_API bool GetNextSelectedItem(void** opaque_it, ImGuiID* out_id); // Iterate selection with 'void* it = NULL; ImGuiID id; while (selection.GetNextSelectedItem(&it, &id)) { ... }' + IMGUI_API bool GetNextSelectedItem(void** opaque_it, ImGuiID* out_id); // Iterate selection with 'void* it = NULL; ImGuiId id; while (selection.GetNextSelectedItem(&it, &id)) { ... }' inline ImGuiID GetStorageIdFromIndex(int idx) { return AdapterIndexToStorageId(this, idx); } // Convert index to item id based on provided adapter. }; @@ -3052,7 +3008,7 @@ struct ImGuiSelectionExternalStorage // The maximum line width to bake anti-aliased textures for. Build atlas with ImFontAtlasFlags_NoBakedLines to disable baking. #ifndef IM_DRAWLIST_TEX_LINES_WIDTH_MAX -#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (32) +#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (63) #endif // ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h] @@ -3085,11 +3041,9 @@ struct ImDrawCmd unsigned int IdxOffset; // 4 // Start offset in index buffer. unsigned int ElemCount; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. ImDrawCallback UserCallback; // 4-8 // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. - void* UserCallbackData; // 4-8 // Callback user data (when UserCallback != NULL). If called AddCallback() with size == 0, this is a copy of the AddCallback() argument. If called AddCallback() with size > 0, this is pointing to a buffer where data is stored. - int UserCallbackDataSize; // 4 // Size of callback user data when using storage, otherwise 0. - int UserCallbackDataOffset;// 4 // [Internal] Offset of callback user data when using storage, otherwise -1. + void* UserCallbackData; // 4-8 // The draw callback code can access this. - ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed + ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed // Since 1.83: returns ImTextureID associated with this draw call. Warning: DO NOT assume this is always same as 'TextureId' (we will change this function for an upcoming feature) inline ImTextureID GetTexID() const { return TextureId; } @@ -3126,6 +3080,7 @@ struct ImDrawChannel ImVector _IdxBuffer; }; + // Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order. // This is used by the Columns/Tables API, so items of each column can be batched together in a same draw call. struct ImDrawListSplitter @@ -3181,7 +3136,7 @@ enum ImDrawListFlags_ // access the current window draw list and draw custom primitives. // You can interleave normal ImGui:: calls and adding primitives to the current draw list. // In single viewport mode, top-left is == GetMainViewport()->Pos (generally 0,0), bottom-right is == GetMainViewport()->Pos+Size (generally io.DisplaySize). -// You are totally free to apply whatever transformation matrix you want to the data (depending on the use of the transformation you may want to apply it to ClipRect as well!) +// You are totally free to apply whatever transformation matrix to want to the data (depending on the use of the transformation you may want to apply it to ClipRect as well!) // Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects. struct ImDrawList { @@ -3201,15 +3156,13 @@ struct ImDrawList ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!) ImVector _ClipRectStack; // [Internal] ImVector _TextureIdStack; // [Internal] - ImVector _CallbacksDataBuf; // [Internal] float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content const char* _OwnerName; // Pointer to owner window's name for debugging - // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData(). - // (advanced: you may create and use your own ImDrawListSharedData so you can use ImDrawList without ImGui, but that's more involved) - IMGUI_API ImDrawList(ImDrawListSharedData* shared_data); - IMGUI_API ~ImDrawList(); + // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui) + ImDrawList(ImDrawListSharedData* shared_data) { memset(this, 0, sizeof(*this)); _Data = shared_data; } + ~ImDrawList() { _ClearFreeMemory(); } IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) IMGUI_API void PushClipRectFullScreen(); IMGUI_API void PopClipRect(); @@ -3240,7 +3193,7 @@ struct ImDrawList IMGUI_API void AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f); IMGUI_API void AddEllipseFilled(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot = 0.0f, int num_segments = 0); IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL); - IMGUI_API void AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); + IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); IMGUI_API void AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0); // Cubic Bezier (4 control points) IMGUI_API void AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments = 0); // Quadratic Bezier (3 control points) @@ -3275,18 +3228,8 @@ struct ImDrawList IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); // Quadratic Bezier (3 control points) IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawFlags flags = 0); - // Advanced: Draw Callbacks - // - May be used to alter render state (change sampler, blending, current shader). May be used to emit custom rendering commands (difficult to do correctly, but possible). - // - Use special ImDrawCallback_ResetRenderState callback to instruct backend to reset its render state to the default. - // - Your rendering loop must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. All standard backends are honoring this. - // - For some backends, the callback may access selected render-states exposed by the backend in a ImGui_ImplXXXX_RenderState structure pointed to by platform_io.Renderer_RenderState. - // - IMPORTANT: please be mindful of the different level of indirection between using size==0 (copying argument) and using size>0 (copying pointed data into a buffer). - // - If userdata_size == 0: we copy/store the 'userdata' argument as-is. It will be available unmodified in ImDrawCmd::UserCallbackData during render. - // - If userdata_size > 0, we copy/store 'userdata_size' bytes pointed to by 'userdata'. We store them in a buffer stored inside the drawlist. ImDrawCmd::UserCallbackData will point inside that buffer so you have to retrieve data from there. Your callback may need to use ImDrawCmd::UserCallbackDataSize if you expect dynamically-sized data. - // - Support for userdata_size > 0 was added in v1.91.4, October 2024. So earlier code always only allowed to copy/store a simple void*. - IMGUI_API void AddCallback(ImDrawCallback callback, void* userdata, size_t userdata_size = 0); - - // Advanced: Miscellaneous + // Advanced + IMGUI_API void AddCallback(ImDrawCallback callback, void* callback_data); // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles. IMGUI_API void AddDrawCmd(); // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible IMGUI_API ImDrawList* CloneOutput() const; // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer. @@ -3316,8 +3259,8 @@ struct ImDrawList //inline void AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f) { AddEllipse(center, ImVec2(radius_x, radius_y), col, rot, num_segments, thickness); } // OBSOLETED in 1.90.5 (Mar 2024) //inline void AddEllipseFilled(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0) { AddEllipseFilled(center, ImVec2(radius_x, radius_y), col, rot, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024) //inline void PathEllipticalArcTo(const ImVec2& center, float radius_x, float radius_y, float rot, float a_min, float a_max, int num_segments = 0) { PathEllipticalArcTo(center, ImVec2(radius_x, radius_y), rot, a_min, a_max, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024) - //inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } // OBSOLETED in 1.80 (Jan 2021) - //inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021) + //inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } // OBSOLETED in 1.80 (Jan 2021) + //inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021) // [Internal helpers] IMGUI_API void _ResetForNewFrame(); @@ -3327,7 +3270,6 @@ struct ImDrawList IMGUI_API void _OnChangedClipRect(); IMGUI_API void _OnChangedTextureID(); IMGUI_API void _OnChangedVtxOffset(); - IMGUI_API void _SetTextureID(ImTextureID texture_id); IMGUI_API int _CalcCircleAutoSegmentCount(float radius) const; IMGUI_API void _PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step); IMGUI_API void _PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments); @@ -3360,27 +3302,26 @@ struct ImDrawData // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont) //----------------------------------------------------------------------------- -// A font input/source (we may rename this to ImFontSource in the future) struct ImFontConfig { void* FontData; // // TTF/OTF data int FontDataSize; // // TTF/OTF data size bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). - bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. - bool PixelSnapH; // false // Align every glyph AdvanceX to pixel boundaries. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. int FontNo; // 0 // Index of font within TTF/OTF file - int OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. - int OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis. float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). - ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. + int OversampleH; // 2 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis. + bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. + ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs + bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. float RasterizerDensity; // 1.0f // DPI scale for rasterization, not altering other font metrics: make it easy to swap between e.g. a 100% and a 400% fonts for a zooming display. IMPORTANT: If you increase this it is expected that you increase font scale accordingly, otherwise quality may look lowered. - ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. + ImWchar EllipsisChar; // -1 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. // [Internal] char Name[40]; // Name (strictly to ease debugging) @@ -3420,16 +3361,13 @@ struct ImFontGlyphRangesBuilder // See ImFontAtlas::AddCustomRectXXX functions. struct ImFontAtlasCustomRect { - unsigned short X, Y; // Output // Packed position in Atlas - - // [Internal] unsigned short Width, Height; // Input // Desired rectangle dimension - unsigned int GlyphID : 31; // Input // For custom font glyphs only (ID < 0x110000) - unsigned int GlyphColored : 1; // Input // For custom font glyphs only: glyph is colored, removed tinting. + unsigned short X, Y; // Output // Packed position in Atlas + unsigned int GlyphID; // Input // For custom font glyphs only (ID < 0x110000) float GlyphAdvanceX; // Input // For custom font glyphs only: glyph xadvance ImVec2 GlyphOffset; // Input // For custom font glyphs only: glyph display offset ImFont* Font; // Input // For custom font glyphs only: target font - ImFontAtlasCustomRect() { X = Y = 0xFFFF; Width = Height = 0; GlyphID = 0; GlyphColored = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } + ImFontAtlasCustomRect() { Width = Height = 0; X = Y = 0xFFFF; GlyphID = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } bool IsPacked() const { return X != 0xFFFF; } }; @@ -3470,8 +3408,8 @@ struct ImFontAtlas IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_data_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. IMGUI_API void ClearInputData(); // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. - IMGUI_API void ClearFonts(); // Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates). IMGUI_API void ClearTexData(); // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. + IMGUI_API void ClearFonts(); // Clear output font data (glyphs storage, UV coordinates). IMGUI_API void Clear(); // Clear all input and output. // Build atlas, retrieve pixel data. @@ -3504,7 +3442,7 @@ struct ImFontAtlas IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietnamese characters //------------------------------------------- - // [ALPHA] Custom Rectangles/Glyphs API + // [BETA] Custom Rectangles/Glyphs API //------------------------------------------- // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. @@ -3529,12 +3467,12 @@ struct ImFontAtlas ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. - int TexGlyphPadding; // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). + int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). + bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). // [Internal] // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. - bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. bool TexReady; // Set when texture was built matching current font input bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format. unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight @@ -3565,47 +3503,46 @@ struct ImFontAtlas // ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32(). struct ImFont { - // [Internal] Members: Hot ~20/24 bytes (for CalcTextSize) - ImVector IndexAdvanceX; // 12-16 // out // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI). + // Members: Hot ~20/24 bytes (for CalcTextSize) + ImVector IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI). float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX - float FontSize; // 4 // in // Height of characters/line, set during loading (don't change after loading) + float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading) - // [Internal] Members: Hot ~28/40 bytes (for RenderText loop) - ImVector IndexLookup; // 12-16 // out // Sparse. Index glyphs by Unicode code-point. - ImVector Glyphs; // 12-16 // out // All glyphs. + // Members: Hot ~28/40 bytes (for CalcTextSize + render loop) + ImVector IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point. + ImVector Glyphs; // 12-16 // out // // All glyphs. const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) - // [Internal] Members: Cold ~32/40 bytes - // Conceptually ConfigData[] is the list of font sources merged to create this font. - ImFontAtlas* ContainerAtlas; // 4-8 // out // What we has been loaded into - const ImFontConfig* ConfigData; // 4-8 // in // Pointer within ContainerAtlas->ConfigData to ConfigDataCount instances - short ConfigDataCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont. + // Members: Cold ~32/40 bytes + ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into + const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData + short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. + ImWchar FallbackChar; // 2 // out // = FFFD/'?' // Character used if a glyph isn't found. + ImWchar EllipsisChar; // 2 // out // = '...'/'.'// Character used for ellipsis rendering. short EllipsisCharCount; // 1 // out // 1 or 3 - ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). - ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') - float EllipsisWidth; // 4 // out // Total ellipsis Width - float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 - float Scale; // 4 // in // Base font scale (1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() - float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) - int MetricsTotalSurface;// 4 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) + float EllipsisWidth; // 4 // out // Width + float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 bool DirtyLookupTables; // 1 // out // - ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. + float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() + float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) + int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) + ImU8 Used4kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/4096/8]; // 2 bytes if ImWchar=ImWchar16, 34 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. // Methods IMGUI_API ImFont(); IMGUI_API ~ImFont(); - IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c); - IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c); - float GetCharAdvance(ImWchar c) { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } - bool IsLoaded() const { return ContainerAtlas != NULL; } - const char* GetDebugName() const { return ConfigData ? ConfigData->Name : ""; } + IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const; + IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c) const; + float GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } + bool IsLoaded() const { return ContainerAtlas != NULL; } + const char* GetDebugName() const { return ConfigData ? ConfigData->Name : ""; } // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. - IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL); // utf8 - IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width); - IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c); - IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false); + IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8 + IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; + IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) const; + IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; // [Internal] Don't use! IMGUI_API void BuildLookupTable(); @@ -3627,7 +3564,7 @@ enum ImGuiViewportFlags_ ImGuiViewportFlags_None = 0, ImGuiViewportFlags_IsPlatformWindow = 1 << 0, // Represent a Platform Window ImGuiViewportFlags_IsPlatformMonitor = 1 << 1, // Represent a Platform Monitor (unused yet) - ImGuiViewportFlags_OwnedByApp = 1 << 2, // Platform Window: Is created/managed by the user application? (rather than our backend) + ImGuiViewportFlags_OwnedByApp = 1 << 2, // Platform Window: Was created/managed by the user application? (rather than our backend) ImGuiViewportFlags_NoDecoration = 1 << 3, // Platform Window: Disable platform decorations: title bar, borders, etc. (generally set all windows, but if ImGuiConfigFlags_ViewportsDecoration is set we only set this on popups/tooltips) ImGuiViewportFlags_NoTaskBarIcon = 1 << 4, // Platform Window: Disable platform task bar icon (generally set on popups/tooltips, or all windows if ImGuiConfigFlags_ViewportsNoTaskBarIcon is set) ImGuiViewportFlags_NoFocusOnAppearing = 1 << 5, // Platform Window: Don't take focus when created. @@ -3685,18 +3622,17 @@ struct ImGuiViewport }; //----------------------------------------------------------------------------- -// [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformMonitor, ImGuiPlatformImeData) +// [SECTION] Platform Dependent Interfaces (for e.g. multi-viewport support) //----------------------------------------------------------------------------- - -// [BETA] (Optional) Multi-Viewport Support! +// [BETA] (Optional) This is completely optional, for advanced users! // If you are new to Dear ImGui and trying to integrate it into your engine, you can probably ignore this for now. // // This feature allows you to seamlessly drag Dear ImGui windows outside of your application viewport. // This is achieved by creating new Platform/OS windows on the fly, and rendering into them. // Dear ImGui manages the viewport structures, and the backend create and maintain one Platform/OS window for each of those viewports. // -// See Recap: https://github.com/ocornut/imgui/wiki/Multi-Viewports // See Glossary https://github.com/ocornut/imgui/wiki/Glossary for details about some of the terminology. +// See Thread https://github.com/ocornut/imgui/issues/1542 for gifs, news and questions about this evolving feature. // // About the coordinates system: // - When multi-viewports are enabled, all Dear ImGui coordinates become absolute coordinates (same as OS coordinates!) @@ -3734,47 +3670,14 @@ struct ImGuiViewport // or you may decide to never setup those pointers and call your code directly. They are a convenience, not an obligatory interface. //----------------------------------------------------------------------------- -// Access via ImGui::GetPlatformIO() +// (Optional) Access via ImGui::GetPlatformIO() struct ImGuiPlatformIO { - IMGUI_API ImGuiPlatformIO(); - //------------------------------------------------------------------ - // Interface with OS and Platform backend (basic) - //------------------------------------------------------------------ - - // Optional: Access OS clipboard - // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures) - const char* (*Platform_GetClipboardTextFn)(ImGuiContext* ctx); - void (*Platform_SetClipboardTextFn)(ImGuiContext* ctx, const char* text); - void* Platform_ClipboardUserData; - - // Optional: Open link/folder/file in OS Shell - // (default to use ShellExecuteA() on Windows, system() on Linux/Mac) - bool (*Platform_OpenInShellFn)(ImGuiContext* ctx, const char* path); - void* Platform_OpenInShellUserData; - - // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows) - // (default to use native imm32 api on Windows) - void (*Platform_SetImeDataFn)(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data); - void* Platform_ImeUserData; - //void (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data); // [Renamed to platform_io.PlatformSetImeDataFn in 1.91.1] - - // Optional: Platform locale - // [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point - ImWchar Platform_LocaleDecimalPoint; // '.' - - //------------------------------------------------------------------ - // Interface with Renderer Backend - //------------------------------------------------------------------ - - // Written by some backends during ImGui_ImplXXXX_RenderDrawData() call to point backend_specific ImGui_ImplXXXX_RenderState* structure. - void* Renderer_RenderState; - - //------------------------------------------------------------------ - // Input - Interface with OS/backends (Multi-Viewport support!) + // Input - Backend interface/functions + Monitor List //------------------------------------------------------------------ + // (Optional) Platform functions (e.g. Win32, GLFW, SDL2) // For reference, the second column shows which function are generally calling the Platform Functions: // N = ImGui::NewFrame() ~ beginning of the dear imgui frame: read info from platform/OS windows (latest size/position) // F = ImGui::Begin(), ImGui::EndFrame() ~ during the dear imgui frame @@ -3782,12 +3685,12 @@ struct ImGuiPlatformIO // R = ImGui::RenderPlatformWindowsDefault() ~ render // D = ImGui::DestroyPlatformWindows() ~ shutdown // The general idea is that NewFrame() we will read the current Platform/OS state, and UpdatePlatformWindows() will write to it. + // + // The functions are designed so we can mix and match 2 imgui_impl_xxxx files, one for the Platform (~window/input handling), one for Renderer. + // Custom engine backends will often provide both Platform and Renderer interfaces and so may not need to use all functions. + // Platform functions are typically called before their Renderer counterpart, apart from Destroy which are called the other way. - // The handlers are designed so we can mix and match two imgui_impl_xxxx files, one Platform backend and one Renderer backend. - // Custom engine backends will often provide both Platform and Renderer interfaces together and so may not need to use all functions. - // Platform functions are typically called _before_ their Renderer counterpart, apart from Destroy which are called the other way. - - // Platform Backend functions (e.g. Win32, GLFW, SDL) ------------------- Called by ----- + // Platform function --------------------------------------------------- Called by ----- void (*Platform_CreateWindow)(ImGuiViewport* vp); // . . U . . // Create a new platform window for the given viewport void (*Platform_DestroyWindow)(ImGuiViewport* vp); // N . U . D // void (*Platform_ShowWindow)(ImGuiViewport* vp); // . . U . . // Newly created windows are initially hidden so SetWindowPos/Size/Title can be called on them before showing the window @@ -3805,10 +3708,9 @@ struct ImGuiPlatformIO void (*Platform_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Call Present/SwapBuffers (platform side! This is often unused!). 'render_arg' is the value passed to RenderPlatformWindowsDefault(). float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // N . . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI. void (*Platform_OnChangedViewport)(ImGuiViewport* vp); // . F . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Called during Begin() every time the viewport we are outputting into changes, so backend has a chance to swap fonts to adjust style. - ImVec4 (*Platform_GetWindowWorkAreaInsets)(ImGuiViewport* vp); // N . . . . // (Optional) [BETA] Get initial work area inset for the viewport (won't be covered by main menu bar, dockspace over viewport etc.). Default to (0,0),(0,0). 'safeAreaInsets' in iOS land, 'DisplayCutout' in Android land. int (*Platform_CreateVkSurface)(ImGuiViewport* vp, ImU64 vk_inst, const void* vk_allocators, ImU64* out_vk_surface); // (Optional) For a Vulkan Renderer to call into Platform code (since the surface creation needs to tie them both). - // Renderer Backend functions (e.g. DirectX, OpenGL, Vulkan) ------------ Called by ----- + // (Optional) Renderer functions (e.g. DirectX, OpenGL, Vulkan) void (*Renderer_CreateWindow)(ImGuiViewport* vp); // . . U . . // Create swap chain, frame buffers etc. (called after Platform_CreateWindow) void (*Renderer_DestroyWindow)(ImGuiViewport* vp); // N . U . D // Destroy swap chain, frame buffers etc. (called before Platform_DestroyWindow) void (*Renderer_SetWindowSize)(ImGuiViewport* vp, ImVec2 size); // . . U . . // Resize swap chain, frame buffers etc. (called after Platform_SetWindowSize) @@ -3827,6 +3729,7 @@ struct ImGuiPlatformIO // Viewports list (the list is updated by calling ImGui::EndFrame or ImGui::Render) // (in the future we will attempt to organize this feature to remove the need for a "main viewport") ImVector Viewports; // Main viewports, followed by all secondary viewports. + ImGuiPlatformIO() { memset(this, 0, sizeof(*this)); } // Zero clear }; // (Optional) This is required when enabling multi-viewport. Represent the bounds of each connected monitor/display and their DPI. @@ -3840,7 +3743,7 @@ struct ImGuiPlatformMonitor ImGuiPlatformMonitor() { MainPos = MainSize = WorkPos = WorkSize = ImVec2(0, 0); DpiScale = 1.0f; PlatformHandle = NULL; } }; -// (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. +// (Optional) Support for IME (Input Method Editor) via the io.PlatformSetImeDataFn() function. struct ImGuiPlatformImeData { bool WantVisible; // A widget wants the IME to be visible @@ -3864,14 +3767,11 @@ namespace ImGui static inline void PopButtonRepeat() { PopItemFlag(); } static inline void PushTabStop(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } static inline void PopTabStop() { PopItemFlag(); } - IMGUI_API ImVec2 GetContentRegionMax(); // Content boundaries max (e.g. window boundaries including scrolling, or current column boundaries). You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! - IMGUI_API ImVec2 GetWindowContentRegionMin(); // Content boundaries min for the window (roughly (0,0)-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! - IMGUI_API ImVec2 GetWindowContentRegionMax(); // Content boundaries max for the window (roughly (0,0)+Size-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()! // OBSOLETED in 1.90.0 (from September 2023) static inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags window_flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, window_flags); } static inline void EndChildFrame() { EndChild(); } - //static inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags){ return BeginChild(str_id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders - //static inline bool BeginChild(ImGuiID id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders + //static inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags window_flags){ return BeginChild(str_id, size_arg, border ? ImGuiChildFlags_Border : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Border + //static inline bool BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, border ? ImGuiChildFlags_Border : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Border static inline void ShowStackToolWindow(bool* p_open = NULL) { ShowIDStackToolWindow(p_open); } IMGUI_API bool Combo(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int popup_max_height_in_items = -1); IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1); @@ -3880,16 +3780,16 @@ namespace ImGui // OBSOLETED in 1.89.4 (from March 2023) static inline void PushAllowKeyboardFocus(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } static inline void PopAllowKeyboardFocus() { PopItemFlag(); } + // OBSOLETED in 1.89 (from August 2022) + IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // Use new ImageButton() signature (explicit item id, regular FramePadding) + // OBSOLETED in 1.87 (from February 2022 but more formally obsoleted April 2024) + IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key); // Map ImGuiKey_* values into legacy native key index. == io.KeyMap[key]. When using a 1.87+ backend using io.AddKeyEvent(), calling GetKeyIndex() with ANY ImGuiKey_XXXX values will return the same value! + //static inline ImGuiKey GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); return key; } // Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE) - //-- OBSOLETED in 1.89 (from August 2022) - //IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // --> Use new ImageButton() signature (explicit item id, regular FramePadding). Refer to code in 1.91 if you want to grab a copy of this version. //-- OBSOLETED in 1.88 (from May 2022) - //static inline void CaptureKeyboardFromApp(bool want_capture_keyboard = true) { SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value. - //static inline void CaptureMouseFromApp(bool want_capture_mouse = true) { SetNextFrameWantCaptureMouse(want_capture_mouse); } // Renamed as name was misleading + removed default value. - //-- OBSOLETED in 1.87 (from February 2022, more formally obsoleted April 2024) - //IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key); { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); const ImGuiKeyData* key_data = GetKeyData(key); return (ImGuiKey)(key_data - g.IO.KeysData); } // Map ImGuiKey_* values into legacy native key index. == io.KeyMap[key]. When using a 1.87+ backend using io.AddKeyEvent(), calling GetKeyIndex() with ANY ImGuiKey_XXXX values will return the same value! - //static inline ImGuiKey GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); return key; } + //static inline void CaptureKeyboardFromApp(bool want_capture_keyboard = true) { SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value. + //static inline void CaptureMouseFromApp(bool want_capture_mouse = true) { SetNextFrameWantCaptureMouse(want_capture_mouse); } // Renamed as name was misleading + removed default value. //-- OBSOLETED in 1.86 (from November 2021) //IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // Code removed, see 1.90 for last version of the code. Calculate range of visible items for large list of evenly sized items. Prefer using ImGuiListClipper. //-- OBSOLETED in 1.85 (from August 2021) @@ -3972,7 +3872,10 @@ namespace ImGui #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // RENAMED IMGUI_DISABLE_METRICS_WINDOW > IMGUI_DISABLE_DEBUG_TOOLS in 1.88 (from June 2022) -#ifdef IMGUI_DISABLE_METRICS_WINDOW +#if defined(IMGUI_DISABLE_METRICS_WINDOW) && !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && !defined(IMGUI_DISABLE_DEBUG_TOOLS) +#define IMGUI_DISABLE_DEBUG_TOOLS +#endif +#if defined(IMGUI_DISABLE_METRICS_WINDOW) && defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) #error IMGUI_DISABLE_METRICS_WINDOW was renamed to IMGUI_DISABLE_DEBUG_TOOLS, please use new name. #endif @@ -3988,6 +3891,10 @@ namespace ImGui #pragma warning (pop) #endif +#if IMGUI_HAS_STACK_LAYOUT +#include "imgui_stacklayout.h" +#endif + // Include imgui_user.h at the end of imgui.h // May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included. #ifdef IMGUI_INCLUDE_IMGUI_USER_H diff --git a/3rdparty/imgui/imgui_demo.cpp b/3rdparty/imgui/imgui_demo.cpp index 6400854..ab943c8 100644 --- a/3rdparty/imgui/imgui_demo.cpp +++ b/3rdparty/imgui/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.0 WIP // (demo code) // Help: @@ -117,9 +117,6 @@ Index of this file: #if !defined(_MSC_VER) || _MSC_VER >= 1800 #include // PRId64/PRIu64, not avail in some MinGW headers. #endif -#ifdef __EMSCRIPTEN__ -#include // __EMSCRIPTEN_major__ etc. -#endif // Visual Studio warnings #ifdef _MSC_VER @@ -146,16 +143,12 @@ Index of this file: #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access #elif defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe -#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size -#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' -#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure) -#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function -#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value -#pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. -#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 -#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure) +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. #endif // Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!) @@ -207,7 +200,6 @@ Index of this file: #if !defined(IMGUI_DISABLE_DEMO_WINDOWS) // Forward Declarations -struct ImGuiDemoWindowData; static void ShowExampleAppMainMenuBar(); static void ShowExampleAppAssetsBrowser(bool* p_open); static void ShowExampleAppConsole(bool* p_open); @@ -216,7 +208,7 @@ static void ShowExampleAppDockSpace(bool* p_open); static void ShowExampleAppDocuments(bool* p_open); static void ShowExampleAppLog(bool* p_open); static void ShowExampleAppLayout(bool* p_open); -static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data); +static void ShowExampleAppPropertyEditor(bool* p_open); static void ShowExampleAppSimpleOverlay(bool* p_open); static void ShowExampleAppAutoResize(bool* p_open); static void ShowExampleAppConstrainedResize(bool* p_open); @@ -227,9 +219,10 @@ static void ShowExampleMenuFile(); // We split the contents of the big ShowDemoWindow() function into smaller functions // (because the link time of very large functions tends to grow non-linearly) -static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data); -static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data); -static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data); +struct DemoWindowData; +static void ShowDemoWindowMenuBar(DemoWindowData* demo_data); +static void ShowDemoWindowWidgets(DemoWindowData* demo_data); +static void ShowDemoWindowMultiSelect(DemoWindowData* demo_data); static void ShowDemoWindowLayout(); static void ShowDemoWindowPopups(); static void ShowDemoWindowTables(); @@ -281,15 +274,14 @@ void* GImGuiDemoMarkerCallbackUserData = NULL; struct ExampleTreeNode { // Tree structure - char Name[28] = ""; + char Name[28]; int UID = 0; ExampleTreeNode* Parent = NULL; ImVector Childs; - unsigned short IndexInParent = 0; // Maintaining this allows us to implement linear traversal more easily // Leaf Data - bool HasData = false; // All leaves have data - bool DataMyBool = true; + bool HasData = false; // All leaves have data + bool DataMyBool = false; int DataMyInt = 128; ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f); }; @@ -307,7 +299,6 @@ struct ExampleMemberInfo // Metadata description of ExampleTreeNode struct. static const ExampleMemberInfo ExampleTreeNodeMemberInfos[] { - { "MyName", ImGuiDataType_String, 1, offsetof(ExampleTreeNode, Name) }, { "MyBool", ImGuiDataType_Bool, 1, offsetof(ExampleTreeNode, DataMyBool) }, { "MyInt", ImGuiDataType_S32, 1, offsetof(ExampleTreeNode, DataMyInt) }, { "MyVec2", ImGuiDataType_Float, 2, offsetof(ExampleTreeNode, DataMyVec2) }, @@ -319,42 +310,31 @@ static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, Exampl snprintf(node->Name, IM_ARRAYSIZE(node->Name), "%s", name); node->UID = uid; node->Parent = parent; - node->IndexInParent = parent ? (unsigned short)parent->Childs.Size : 0; if (parent) parent->Childs.push_back(node); return node; } -static void ExampleTree_DestroyNode(ExampleTreeNode* node) -{ - for (ExampleTreeNode* child_node : node->Childs) - ExampleTree_DestroyNode(child_node); - IM_DELETE(node); -} - // Create example tree data -// (this allocates _many_ more times than most other code in either Dear ImGui or others demo) static ExampleTreeNode* ExampleTree_CreateDemoTree() { - static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" }; - const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name); - char name_buf[NAME_MAX_LEN]; + static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; + char name_buf[32]; int uid = 0; ExampleTreeNode* node_L0 = ExampleTree_CreateNode("", ++uid, NULL); - const int root_items_multiplier = 2; - for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * root_items_multiplier; idx_L0++) + for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * 2; idx_L0++) { - snprintf(name_buf, IM_ARRAYSIZE(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier); + snprintf(name_buf, 32, "%s %d", root_names[idx_L0 / 2], idx_L0 % 2); ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0); const int number_of_childs = (int)strlen(node_L1->Name); for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++) { - snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Child %d", idx_L1); + snprintf(name_buf, 32, "Child %d", idx_L1); ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1); node_L2->HasData = true; if (idx_L1 == 0) { - snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Sub-child %d", 0); + snprintf(name_buf, 32, "Sub-child %d", 0); ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2); node_L3->HasData = true; } @@ -367,8 +347,7 @@ static ExampleTreeNode* ExampleTree_CreateDemoTree() // [SECTION] Demo Window / ShowDemoWindow() //----------------------------------------------------------------------------- -// Data to be shared across different functions of the demo. -struct ImGuiDemoWindowData +struct DemoWindowData { // Examples Apps (accessible from the "Examples" menu) bool ShowMainMenuBar = false; @@ -393,11 +372,6 @@ struct ImGuiDemoWindowData bool ShowIDStackTool = false; bool ShowStyleEditor = false; bool ShowAbout = false; - - // Other data - ExampleTreeNode* DemoTree = NULL; - - ~ImGuiDemoWindowData() { if (DemoTree) ExampleTree_DestroyNode(DemoTree); } }; // Demonstrate most Dear ImGui features (this is big function!) @@ -413,33 +387,33 @@ void ImGui::ShowDemoWindow(bool* p_open) IMGUI_CHECKVERSION(); // Stored data - static ImGuiDemoWindowData demo_data; + static DemoWindowData demo; // Examples Apps (accessible from the "Examples" menu) - if (demo_data.ShowMainMenuBar) { ShowExampleAppMainMenuBar(); } - if (demo_data.ShowAppDockSpace) { ShowExampleAppDockSpace(&demo_data.ShowAppDockSpace); } // Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) - if (demo_data.ShowAppDocuments) { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); } // ...process the Document app next, as it may also use a DockSpace() - if (demo_data.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); } - if (demo_data.ShowAppConsole) { ShowExampleAppConsole(&demo_data.ShowAppConsole); } - if (demo_data.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); } - if (demo_data.ShowAppLog) { ShowExampleAppLog(&demo_data.ShowAppLog); } - if (demo_data.ShowAppLayout) { ShowExampleAppLayout(&demo_data.ShowAppLayout); } - if (demo_data.ShowAppPropertyEditor) { ShowExampleAppPropertyEditor(&demo_data.ShowAppPropertyEditor, &demo_data); } - if (demo_data.ShowAppSimpleOverlay) { ShowExampleAppSimpleOverlay(&demo_data.ShowAppSimpleOverlay); } - if (demo_data.ShowAppAutoResize) { ShowExampleAppAutoResize(&demo_data.ShowAppAutoResize); } - if (demo_data.ShowAppConstrainedResize) { ShowExampleAppConstrainedResize(&demo_data.ShowAppConstrainedResize); } - if (demo_data.ShowAppFullscreen) { ShowExampleAppFullscreen(&demo_data.ShowAppFullscreen); } - if (demo_data.ShowAppLongText) { ShowExampleAppLongText(&demo_data.ShowAppLongText); } - if (demo_data.ShowAppWindowTitles) { ShowExampleAppWindowTitles(&demo_data.ShowAppWindowTitles); } + if (demo.ShowMainMenuBar) { ShowExampleAppMainMenuBar(); } + if (demo.ShowAppDockSpace) { ShowExampleAppDockSpace(&demo.ShowAppDockSpace); } // Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) + if (demo.ShowAppDocuments) { ShowExampleAppDocuments(&demo.ShowAppDocuments); } // ...Process the Document app next, as it may also use a DockSpace() + if (demo.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo.ShowAppAssetsBrowser); } + if (demo.ShowAppConsole) { ShowExampleAppConsole(&demo.ShowAppConsole); } + if (demo.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo.ShowAppCustomRendering); } + if (demo.ShowAppLog) { ShowExampleAppLog(&demo.ShowAppLog); } + if (demo.ShowAppLayout) { ShowExampleAppLayout(&demo.ShowAppLayout); } + if (demo.ShowAppPropertyEditor) { ShowExampleAppPropertyEditor(&demo.ShowAppPropertyEditor); } + if (demo.ShowAppSimpleOverlay) { ShowExampleAppSimpleOverlay(&demo.ShowAppSimpleOverlay); } + if (demo.ShowAppAutoResize) { ShowExampleAppAutoResize(&demo.ShowAppAutoResize); } + if (demo.ShowAppConstrainedResize) { ShowExampleAppConstrainedResize(&demo.ShowAppConstrainedResize); } + if (demo.ShowAppFullscreen) { ShowExampleAppFullscreen(&demo.ShowAppFullscreen); } + if (demo.ShowAppLongText) { ShowExampleAppLongText(&demo.ShowAppLongText); } + if (demo.ShowAppWindowTitles) { ShowExampleAppWindowTitles(&demo.ShowAppWindowTitles); } // Dear ImGui Tools (accessible from the "Tools" menu) - if (demo_data.ShowMetrics) { ImGui::ShowMetricsWindow(&demo_data.ShowMetrics); } - if (demo_data.ShowDebugLog) { ImGui::ShowDebugLogWindow(&demo_data.ShowDebugLog); } - if (demo_data.ShowIDStackTool) { ImGui::ShowIDStackToolWindow(&demo_data.ShowIDStackTool); } - if (demo_data.ShowAbout) { ImGui::ShowAboutWindow(&demo_data.ShowAbout); } - if (demo_data.ShowStyleEditor) + if (demo.ShowMetrics) { ImGui::ShowMetricsWindow(&demo.ShowMetrics); } + if (demo.ShowDebugLog) { ImGui::ShowDebugLogWindow(&demo.ShowDebugLog); } + if (demo.ShowIDStackTool) { ImGui::ShowIDStackToolWindow(&demo.ShowIDStackTool); } + if (demo.ShowAbout) { ImGui::ShowAboutWindow(&demo.ShowAbout); } + if (demo.ShowStyleEditor) { - ImGui::Begin("Dear ImGui Style Editor", &demo_data.ShowStyleEditor); + ImGui::Begin("Dear ImGui Style Editor", &demo.ShowStyleEditor); ImGui::ShowStyleEditor(); ImGui::End(); } @@ -491,7 +465,7 @@ void ImGui::ShowDemoWindow(bool* p_open) //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f); // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align) // Menu Bar - ShowDemoWindowMenuBar(&demo_data); + ShowDemoWindowMenuBar(&demo); ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); ImGui::Spacing(); @@ -531,6 +505,8 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SameLine(); HelpMarker("Enable keyboard controls."); ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); ImGui::SameLine(); HelpMarker("Enable gamepad controls. Require backend to set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details."); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", &io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); + ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse); ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions."); @@ -557,20 +533,6 @@ void ImGui::ShowDemoWindow(bool* p_open) 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("Keyboard/Gamepad Navigation"); - ImGui::Checkbox("io.ConfigNavSwapGamepadButtons", &io.ConfigNavSwapGamepadButtons); - ImGui::Checkbox("io.ConfigNavMoveSetMousePos", &io.ConfigNavMoveSetMousePos); - ImGui::SameLine(); HelpMarker("Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult"); - ImGui::Checkbox("io.ConfigNavCaptureKeyboard", &io.ConfigNavCaptureKeyboard); - ImGui::Checkbox("io.ConfigNavEscapeClearFocusItem", &io.ConfigNavEscapeClearFocusItem); - ImGui::SameLine(); HelpMarker("Pressing Escape clears focused item."); - ImGui::Checkbox("io.ConfigNavEscapeClearFocusWindow", &io.ConfigNavEscapeClearFocusWindow); - ImGui::SameLine(); HelpMarker("Pressing Escape clears focused window."); - ImGui::Checkbox("io.ConfigNavCursorVisibleAuto", &io.ConfigNavCursorVisibleAuto); - ImGui::SameLine(); HelpMarker("Using directional navigation key makes the cursor visible. Mouse click hides the cursor."); - ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways); - ImGui::SameLine(); HelpMarker("Navigation cursor is always visible."); - ImGui::SeparatorText("Docking"); ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", &io.ConfigFlags, ImGuiConfigFlags_DockingEnable); ImGui::SameLine(); @@ -609,15 +571,6 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Unindent(); } - ImGui::SeparatorText("Windows"); - ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); - ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback."); - ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); - ImGui::Checkbox("io.ConfigWindowsCopyContentsWithCtrlC", &io.ConfigWindowsCopyContentsWithCtrlC); // [EXPERIMENTAL] - ImGui::SameLine(); HelpMarker("*EXPERIMENTAL* CTRL+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order."); - ImGui::Checkbox("io.ConfigScrollbarScrollByPage", &io.ConfigScrollbarScrollByPage); - ImGui::SameLine(); HelpMarker("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location."); - ImGui::SeparatorText("Widgets"); ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); @@ -625,35 +578,18 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only)."); ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText); ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); + ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); + 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::SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors."); ImGui::Text("Also see Style->Rendering for rendering options."); - // Also read: https://github.com/ocornut/imgui/wiki/Error-Handling - ImGui::SeparatorText("Error Handling"); - - ImGui::Checkbox("io.ConfigErrorRecovery", &io.ConfigErrorRecovery); - ImGui::SameLine(); HelpMarker( - "Options to configure how we handle recoverable errors.\n" - "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n" - "- You not are not supposed to rely on it in the course of a normal application run.\n" - "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n" - "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call!" - "Otherwise it would severely hinder your ability to catch and correct mistakes!"); - ImGui::Checkbox("io.ConfigErrorRecoveryEnableAssert", &io.ConfigErrorRecoveryEnableAssert); - ImGui::Checkbox("io.ConfigErrorRecoveryEnableDebugLog", &io.ConfigErrorRecoveryEnableDebugLog); - ImGui::Checkbox("io.ConfigErrorRecoveryEnableTooltip", &io.ConfigErrorRecoveryEnableTooltip); - if (!io.ConfigErrorRecoveryEnableAssert && !io.ConfigErrorRecoveryEnableDebugLog && !io.ConfigErrorRecoveryEnableTooltip) - io.ConfigErrorRecoveryEnableAssert = io.ConfigErrorRecoveryEnableDebugLog = io.ConfigErrorRecoveryEnableTooltip = true; - - // Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools ImGui::SeparatorText("Debug"); ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent); ImGui::SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application."); - ImGui::Checkbox("io.ConfigDebugHighlightIdConflicts", &io.ConfigDebugHighlightIdConflicts); - ImGui::SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers."); ImGui::BeginDisabled(); - ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce); + ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce); // . ImGui::EndDisabled(); ImGui::SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover."); ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop); @@ -685,7 +621,6 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset); ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports", &io.BackendFlags, ImGuiBackendFlags_RendererHasViewports); ImGui::EndDisabled(); - ImGui::TreePop(); ImGui::Spacing(); } @@ -693,7 +628,7 @@ void ImGui::ShowDemoWindow(bool* p_open) IMGUI_DEMO_MARKER("Configuration/Style"); if (ImGui::TreeNode("Style")) { - ImGui::Checkbox("Style Editor", &demo_data.ShowStyleEditor); + ImGui::Checkbox("Style Editor", &demo.ShowStyleEditor); ImGui::SameLine(); HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function."); ImGui::TreePop(); @@ -742,7 +677,7 @@ void ImGui::ShowDemoWindow(bool* p_open) } // All demo contents - ShowDemoWindowWidgets(&demo_data); + ShowDemoWindowWidgets(&demo); ShowDemoWindowLayout(); ShowDemoWindowPopups(); ShowDemoWindowTables(); @@ -757,7 +692,7 @@ void ImGui::ShowDemoWindow(bool* p_open) // [SECTION] ShowDemoWindowMenuBar() //----------------------------------------------------------------------------- -static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data) +static void ShowDemoWindowMenuBar(DemoWindowData* demo_data) { IMGUI_DEMO_MARKER("Menu"); if (ImGui::BeginMenuBar()) @@ -797,32 +732,22 @@ static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data) if (ImGui::BeginMenu("Tools")) { IMGUI_DEMO_MARKER("Menu/Tools"); - ImGuiIO& io = ImGui::GetIO(); #ifndef IMGUI_DISABLE_DEBUG_TOOLS const bool has_debug_tools = true; #else const bool has_debug_tools = false; #endif ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools); - if (ImGui::BeginMenu("Debug Options")) - { - ImGui::BeginDisabled(!has_debug_tools); - ImGui::Checkbox("Highlight ID Conflicts", &io.ConfigDebugHighlightIdConflicts); - ImGui::EndDisabled(); - ImGui::Checkbox("Assert on error recovery", &io.ConfigErrorRecoveryEnableAssert); - ImGui::TextDisabled("(see Demo->Configuration for details & more)"); - ImGui::EndMenu(); - } ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools); ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools); - bool is_debugger_present = io.ConfigDebugIsDebuggerPresent; - if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools))// && is_debugger_present)) + ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor); + bool is_debugger_present = ImGui::GetIO().ConfigDebugIsDebuggerPresent; + if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present)) ImGui::DebugStartItemPicker(); if (!is_debugger_present) - ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable some extra features to avoid casual users crashing the application."); - ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor); + ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable the menu option to avoid casual users crashing the application.\n\nYou can however always access the Item Picker in Metrics->Tools."); + ImGui::Separator(); ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout); - ImGui::EndMenu(); } ImGui::EndMenuBar(); @@ -833,7 +758,7 @@ static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data) // [SECTION] ShowDemoWindowWidgets() //----------------------------------------------------------------------------- -static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) +static void ShowDemoWindowWidgets(DemoWindowData* demo_data) { IMGUI_DEMO_MARKER("Widgets"); //ImGui::SetNextItemOpen(true, ImGuiCond_Once); @@ -1101,7 +1026,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) // The following examples are passed for documentation purpose but may not be useful to most users. // Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from - // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used. + // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or gamepad/keyboard is being used. // With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary. ImGui::Button("Manual", sz); if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) @@ -1182,7 +1107,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node."); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &base_flags, ImGuiTreeNodeFlags_SpanLabelWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin."); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &base_flags, ImGuiTreeNodeFlags_SpanTextWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin."); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only."); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)"); @@ -1219,9 +1144,9 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::Text("This is a drag and drop source"); ImGui::EndDragDropSource(); } - if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanLabelWidth)) + if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanTextWidth)) { - // Item 2 has an additional inline button to help demonstrate SpanLabelWidth. + // Item 2 has an additional inline button to help demonstrate SpanTextWidth. ImGui::SameLine(); if (ImGui::SmallButton("button")) {} } @@ -1491,18 +1416,18 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively // stored in the object itself, etc.) const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; - static int item_selected_idx = 0; // Here we store our selection data as an index. + static int item_current_idx = 0; // Here we store our selection data as an index. // Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[]) - const char* combo_preview_value = items[item_selected_idx]; + const char* combo_preview_value = items[item_current_idx]; if (ImGui::BeginCombo("combo 1", combo_preview_value, flags)) { for (int n = 0; n < IM_ARRAYSIZE(items); n++) { - const bool is_selected = (item_selected_idx == n); + const bool is_selected = (item_current_idx == n); if (ImGui::Selectable(items[n], is_selected)) - item_selected_idx = n; + item_current_idx = n; // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) if (is_selected) @@ -1544,22 +1469,14 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively // stored in the object itself, etc.) const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; - static int item_selected_idx = 0; // Here we store our selected data as an index. - - static bool item_highlight = false; - int item_highlighted_idx = -1; // Here we store our highlighted data as an index. - ImGui::Checkbox("Highlight hovered item in second listbox", &item_highlight); - + static int item_current_idx = 0; // Here we store our selection data as an index. if (ImGui::BeginListBox("listbox 1")) { for (int n = 0; n < IM_ARRAYSIZE(items); n++) { - const bool is_selected = (item_selected_idx == n); + const bool is_selected = (item_current_idx == n); if (ImGui::Selectable(items[n], is_selected)) - item_selected_idx = n; - - if (item_highlight && ImGui::IsItemHovered()) - item_highlighted_idx = n; + item_current_idx = n; // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) if (is_selected) @@ -1575,10 +1492,9 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) { for (int n = 0; n < IM_ARRAYSIZE(items); n++) { - bool is_selected = (item_selected_idx == n); - ImGuiSelectableFlags flags = (item_highlighted_idx == n) ? ImGuiSelectableFlags_Highlight : 0; - if (ImGui::Selectable(items[n], is_selected, flags)) - item_selected_idx = n; + const bool is_selected = (item_current_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_current_idx = n; // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) if (is_selected) @@ -1625,8 +1541,8 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables"); - if (ImGui::TreeNode("In Tables")) + IMGUI_DEMO_MARKER("Widgets/Selectables/In columns"); + if (ImGui::TreeNode("In columns")) { static bool selected[10] = {}; @@ -1902,16 +1818,6 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Widgets/Text Input/Eliding, Alignment"); - if (ImGui::TreeNode("Eliding, Alignment")) - { - static char buf1[128] = "/path/to/some/folder/with/long/filename.cpp"; - static ImGuiInputTextFlags flags = ImGuiInputTextFlags_ElideLeft; - ImGui::CheckboxFlags("ImGuiInputTextFlags_ElideLeft", &flags, ImGuiInputTextFlags_ElideLeft); - ImGui::InputText("Path", buf1, IM_ARRAYSIZE(buf1), flags); - ImGui::TreePop(); - } - IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous"); if (ImGui::TreeNode("Miscellaneous")) { @@ -2133,12 +2039,8 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::SameLine(); ImGui::SliderInt("Sample count", &display_count, 1, 400); float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; - ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); - ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); - ImGui::Separator(); - - ImGui::Text("Need better plotting and graphing? Consider using ImPlot:"); - ImGui::TextLinkOpenURL("https://github.com/epezent/implot"); + ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); + ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); ImGui::Separator(); ImGui::TreePop(); @@ -2177,16 +2079,19 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) if (ImGui::TreeNode("Color/Picker Widgets")) { static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f); - static ImGuiColorEditFlags base_flags = ImGuiColorEditFlags_None; + static bool alpha_preview = true; + static bool alpha_half_preview = false; + static bool drag_and_drop = true; + static bool options_menu = true; + static bool hdr = false; ImGui::SeparatorText("Options"); - ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &base_flags, ImGuiColorEditFlags_NoAlpha); - ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", &base_flags, ImGuiColorEditFlags_AlphaOpaque); - ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", &base_flags, ImGuiColorEditFlags_AlphaNoBg); - ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", &base_flags, ImGuiColorEditFlags_AlphaPreviewHalf); - ImGui::CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", &base_flags, ImGuiColorEditFlags_NoDragDrop); - ImGui::CheckboxFlags("ImGuiColorEditFlags_NoOptions", &base_flags, ImGuiColorEditFlags_NoOptions); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); - ImGui::CheckboxFlags("ImGuiColorEditFlags_HDR", &base_flags, ImGuiColorEditFlags_HDR); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); + 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); + ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); + ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); + 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"); @@ -2194,15 +2099,15 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::SameLine(); HelpMarker( "Click on the color square to open a color picker.\n" "CTRL+click on individual component to input value.\n"); - ImGui::ColorEdit3("MyColor##1", (float*)&color, base_flags); + ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)"); ImGui::Text("Color widget HSV with Alpha:"); - ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | base_flags); + ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)"); ImGui::Text("Color widget with Float Display:"); - ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | base_flags); + ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)"); ImGui::Text("Color button with Picker:"); @@ -2210,7 +2115,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " "be used for the tooltip and picker popup."); - ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | base_flags); + ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)"); ImGui::Text("Color button with Custom Picker Popup:"); @@ -2230,7 +2135,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) } static ImVec4 backup_color; - bool open_popup = ImGui::ColorButton("MyColor##3b", color, base_flags); + bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); open_popup |= ImGui::Button("Palette"); if (open_popup) @@ -2242,7 +2147,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) { ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); ImGui::Separator(); - ImGui::ColorPicker4("##picker", (float*)&color, base_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); + ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); ImGui::SameLine(); ImGui::BeginGroup(); // Lock X position @@ -2284,42 +2189,40 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::Text("Color button only:"); static bool no_border = false; ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border); - ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, base_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); + ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker"); ImGui::SeparatorText("Color picker"); - + static bool alpha = true; + static bool alpha_bar = true; + static bool side_preview = true; static bool ref_color = false; static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f); - static int picker_mode = 0; static int display_mode = 0; - static ImGuiColorEditFlags color_picker_flags = ImGuiColorEditFlags_AlphaBar; - - ImGui::PushID("Color picker"); - ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &color_picker_flags, ImGuiColorEditFlags_NoAlpha); - ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaBar", &color_picker_flags, ImGuiColorEditFlags_AlphaBar); - ImGui::CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", &color_picker_flags, ImGuiColorEditFlags_NoSidePreview); - if (color_picker_flags & ImGuiColorEditFlags_NoSidePreview) + static int picker_mode = 0; + ImGui::Checkbox("With Alpha", &alpha); + ImGui::Checkbox("With Alpha Bar", &alpha_bar); + ImGui::Checkbox("With Side Preview", &side_preview); + if (side_preview) { ImGui::SameLine(); ImGui::Checkbox("With Ref Color", &ref_color); if (ref_color) { ImGui::SameLine(); - ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | base_flags); + ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags); } } - - 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."); - - ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0"); + ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0"); 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()."); - - ImGuiColorEditFlags flags = base_flags | color_picker_flags; + ImGui::SameLine(); HelpMarker("When not specified explicitly (Auto/Current mode), user can right-click the picker to change mode."); + ImGuiColorEditFlags flags = misc_flags; + if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4() + if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar; + if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview; if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays @@ -2348,7 +2251,6 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::SameLine(); ImGui::SetNextItemWidth(w); ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha); - ImGui::PopID(); // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV! @@ -2372,18 +2274,13 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! static ImGuiSliderFlags flags = ImGuiSliderFlags_None; ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp); - ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", &flags, ImGuiSliderFlags_ClampOnInput); - ImGui::SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds."); - ImGui::CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", &flags, ImGuiSliderFlags_ClampZeroRange); - ImGui::SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp."); + ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click."); ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic); ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values)."); ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat); ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits)."); ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput); ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget."); - ImGui::CheckboxFlags("ImGuiSliderFlags_NoSpeedTweaks", &flags, ImGuiSliderFlags_NoSpeedTweaks); - ImGui::SameLine(); HelpMarker("Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic."); ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround); ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)"); @@ -2395,8 +2292,6 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags); ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags); ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags); - //ImGui::DragFloat("DragFloat (0 -> 0)", &drag_f, 0.005f, 0.0f, 0.0f, "%.3f", flags); // To test ClampZeroRange - //ImGui::DragFloat("DragFloat (100 -> 100)", &drag_f, 0.005f, 100.0f, 100.0f, "%.3f", flags); ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags); // Sliders @@ -2736,11 +2631,6 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)"); if (ImGui::TreeNode("Drag to reorder items (simple)")) { - // FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice. - // This code was always slightly faulty but in a way which was not easily noticeable. - // Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue. - ImGui::PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); - // Simple reordering HelpMarker( "We don't use the drag and drop api at all here! " @@ -2762,8 +2652,6 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) } } } - - ImGui::PopItemFlag(); ImGui::TreePop(); } @@ -2916,7 +2804,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) static bool embed_all_inside_a_child_window = false; ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window); if (embed_all_inside_a_child_window) - ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Borders); + ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Border); // Testing IsWindowFocused() function with its various flags. ImGui::BulletText( @@ -2976,7 +2864,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow), ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary)); - ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Borders); + ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Border); ImGui::Text("This is another child window for testing the _ChildWindows flag."); ImGui::EndChild(); if (embed_all_inside_a_child_window) @@ -3273,7 +3161,7 @@ struct ExampleDualListBox // Also read: https://github.com/ocornut/imgui/wiki/Multi-Select //----------------------------------------------------------------------------- -static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) +static void ShowDemoWindowMultiSelect(DemoWindowData* demo_data) { IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select"); if (ImGui::TreeNode("Selection State & Multi-Select")) @@ -3483,52 +3371,6 @@ static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) ImGui::TreePop(); } - // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect() - IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (in a table)"); - if (ImGui::TreeNode("Multi-Select (in a table)")) - { - static ImGuiSelectionBasicStorage selection; - - const int ITEMS_COUNT = 10000; - ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT); - if (ImGui::BeginTable("##Basket", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter)) - { - ImGui::TableSetupColumn("Object"); - ImGui::TableSetupColumn("Action"); - ImGui::TableSetupScrollFreeze(0, 1); - ImGui::TableHeadersRow(); - - ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d; - ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT); - selection.ApplyRequests(ms_io); - - ImGuiListClipper clipper; - clipper.Begin(ITEMS_COUNT); - if (ms_io->RangeSrcItem != -1) - clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped. - while (clipper.Step()) - { - for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++) - { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - char label[64]; - sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]); - bool item_is_selected = selection.Contains((ImGuiID)n); - ImGui::SetNextItemSelectionUserData(n); - ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap); - ImGui::TableNextColumn(); - ImGui::SmallButton("hello"); - } - } - - ms_io = ImGui::EndMultiSelect(); - selection.ApplyRequests(ms_io); - ImGui::EndTable(); - } - ImGui::TreePop(); - } - IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (checkboxes)"); if (ImGui::TreeNode("Multi-Select (checkboxes)")) { @@ -3544,7 +3386,7 @@ static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear); ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d); // Cannot use ImGuiMultiSelectFlags_BoxSelect1d as checkboxes are varying width. - if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) + if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY)) { ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, -1, IM_ARRAYSIZE(items)); ImGuiSelectionExternalStorage storage_wrapper; @@ -3619,162 +3461,6 @@ static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) ImGui::TreePop(); } - // Demonstrate supporting multiple-selection in a tree. - // - We don't use linear indices for selection user data, but our ExampleTreeNode* pointer directly! - // This showcase how SetNextItemSelectionUserData() never assume indices! - // - The difficulty here is to "interpolate" from RangeSrcItem to RangeDstItem in the SetAll/SetRange request. - // We want this interpolation to match what the user sees: in visible order, skipping closed nodes. - // This is implemented by our TreeGetNextNodeInVisibleOrder() user-space helper. - // - Important: In a real codebase aiming to implement full-featured selectable tree with custom filtering, you - // are more likely to build an array mapping sequential indices to visible tree nodes, since your - // filtering/search + clipping process will benefit from it. Having this will make this interpolation much easier. - // - Consider this a prototype: we are working toward simplifying some of it. - IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (trees)"); - if (ImGui::TreeNode("Multi-Select (trees)")) - { - HelpMarker( - "This is rather advanced and experimental. If you are getting started with multi-select," - "please don't start by looking at how to use it for a tree!\n\n" - "Future versions will try to simplify and formalize some of this."); - - struct ExampleTreeFuncs - { - static void DrawNode(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection) - { - ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; - tree_node_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Enable pressing left to jump to parent - if (node->Childs.Size == 0) - tree_node_flags |= ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_Leaf; - if (selection->Contains((ImGuiID)node->UID)) - tree_node_flags |= ImGuiTreeNodeFlags_Selected; - - // Using SetNextItemStorageID() to specify storage id, so we can easily peek into - // the storage holding open/close stage, using our TreeNodeGetOpen/TreeNodeSetOpen() functions. - ImGui::SetNextItemSelectionUserData((ImGuiSelectionUserData)(intptr_t)node); - ImGui::SetNextItemStorageID((ImGuiID)node->UID); - if (ImGui::TreeNodeEx(node->Name, tree_node_flags)) - { - for (ExampleTreeNode* child : node->Childs) - DrawNode(child, selection); - ImGui::TreePop(); - } - else if (ImGui::IsItemToggledOpen()) - { - TreeCloseAndUnselectChildNodes(node, selection); - } - } - - static bool TreeNodeGetOpen(ExampleTreeNode* node) - { - return ImGui::GetStateStorage()->GetBool((ImGuiID)node->UID); - } - - static void TreeNodeSetOpen(ExampleTreeNode* node, bool open) - { - ImGui::GetStateStorage()->SetBool((ImGuiID)node->UID, open); - } - - // When closing a node: 1) close and unselect all child nodes, 2) select parent if any child was selected. - // FIXME: This is currently handled by user logic but I'm hoping to eventually provide tree node - // features to do this automatically, e.g. a ImGuiTreeNodeFlags_AutoCloseChildNodes etc. - static int TreeCloseAndUnselectChildNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, int depth = 0) - { - // Recursive close (the test for depth == 0 is because we call this on a node that was just closed!) - int unselected_count = selection->Contains((ImGuiID)node->UID) ? 1 : 0; - if (depth == 0 || TreeNodeGetOpen(node)) - { - for (ExampleTreeNode* child : node->Childs) - unselected_count += TreeCloseAndUnselectChildNodes(child, selection, depth + 1); - TreeNodeSetOpen(node, false); - } - - // Select root node if any of its child was selected, otherwise unselect - selection->SetItemSelected((ImGuiID)node->UID, (depth == 0 && unselected_count > 0)); - return unselected_count; - } - - // Apply multi-selection requests - static void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, ExampleTreeNode* tree, ImGuiSelectionBasicStorage* selection) - { - for (ImGuiSelectionRequest& req : ms_io->Requests) - { - if (req.Type == ImGuiSelectionRequestType_SetAll) - { - if (req.Selected) - TreeSetAllInOpenNodes(tree, selection, req.Selected); - else - selection->Clear(); - } - else if (req.Type == ImGuiSelectionRequestType_SetRange) - { - ExampleTreeNode* first_node = (ExampleTreeNode*)(intptr_t)req.RangeFirstItem; - ExampleTreeNode* last_node = (ExampleTreeNode*)(intptr_t)req.RangeLastItem; - for (ExampleTreeNode* node = first_node; node != NULL; node = TreeGetNextNodeInVisibleOrder(node, last_node)) - selection->SetItemSelected((ImGuiID)node->UID, req.Selected); - } - } - } - - static void TreeSetAllInOpenNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, bool selected) - { - if (node->Parent != NULL) // Root node isn't visible nor selectable in our scheme - selection->SetItemSelected((ImGuiID)node->UID, selected); - if (node->Parent == NULL || TreeNodeGetOpen(node)) - for (ExampleTreeNode* child : node->Childs) - TreeSetAllInOpenNodes(child, selection, selected); - } - - // Interpolate in *user-visible order* AND only *over opened nodes*. - // If you have a sequential mapping tables (e.g. generated after a filter/search pass) this would be simpler. - // Here the tricks are that: - // - we store/maintain ExampleTreeNode::IndexInParent which allows implementing a linear iterator easily, without searches, without recursion. - // this could be replaced by a search in parent, aka 'int index_in_parent = curr_node->Parent->Childs.find_index(curr_node)' - // which would only be called when crossing from child to a parent, aka not too much. - // - we call SetNextItemStorageID() before our TreeNode() calls with an ID which doesn't relate to UI stack, - // making it easier to call TreeNodeGetOpen()/TreeNodeSetOpen() from any location. - static ExampleTreeNode* TreeGetNextNodeInVisibleOrder(ExampleTreeNode* curr_node, ExampleTreeNode* last_node) - { - // Reached last node - if (curr_node == last_node) - return NULL; - - // Recurse into childs. Query storage to tell if the node is open. - if (curr_node->Childs.Size > 0 && TreeNodeGetOpen(curr_node)) - return curr_node->Childs[0]; - - // Next sibling, then into our own parent - while (curr_node->Parent != NULL) - { - if (curr_node->IndexInParent + 1 < curr_node->Parent->Childs.Size) - return curr_node->Parent->Childs[curr_node->IndexInParent + 1]; - curr_node = curr_node->Parent; - } - return NULL; - } - - }; // ExampleTreeFuncs - - static ImGuiSelectionBasicStorage selection; - if (demo_data->DemoTree == NULL) - demo_data->DemoTree = ExampleTree_CreateDemoTree(); // Create tree once - ImGui::Text("Selection size: %d", selection.Size); - - if (ImGui::BeginChild("##Tree", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY)) - { - ExampleTreeNode* tree = demo_data->DemoTree; - ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d; - ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, selection.Size, -1); - ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection); - for (ExampleTreeNode* node : tree->Childs) - ExampleTreeFuncs::DrawNode(node, &selection); - ms_io = ImGui::EndMultiSelect(); - ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection); - } - ImGui::EndChild(); - - ImGui::TreePop(); - } - // Advanced demonstration of BeginMultiSelect() // - Showcase clipping. // - Showcase deletion. @@ -3791,7 +3477,7 @@ static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) static bool use_deletion = true; static bool use_drag_drop = true; static bool show_in_table = false; - static bool show_color_button = true; + static bool show_color_button = false; static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d; static WidgetType widget_type = WidgetType_Selectable; @@ -3846,7 +3532,7 @@ static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) { ImVec2 color_button_sz(ImGui::GetFontSize(), ImGui::GetFontSize()); if (widget_type == WidgetType_TreeNode) - ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(ImGui::GetStyle().ItemSpacing.x, 0.0f)); ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size); selection.ApplyRequests(ms_io); @@ -3862,7 +3548,7 @@ static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) ImGui::BeginTable("##Split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoPadOuterX); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.70f); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.30f); - //ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacingY, 0.0f); + //ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(ImGui::GetStyle().ItemSpacing.x, 0.0f)); } ImGuiListClipper clipper; @@ -4050,7 +3736,7 @@ static void ShowDemoWindowLayout() if (!disable_menu) window_flags |= ImGuiWindowFlags_MenuBar; ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); - ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Borders, window_flags); + ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Border, window_flags); if (!disable_menu && ImGui::BeginMenuBar()) { if (ImGui::BeginMenu("Menu")) @@ -4079,11 +3765,8 @@ static void ShowDemoWindowLayout() ImGui::SeparatorText("Manual-resize"); { HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents."); - //if (ImGui::Button("Set Height to 200")) - // ImGui::SetNextWindowSize(ImVec2(-FLT_MIN, 200.0f)); - ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg)); - if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) + if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY)) for (int n = 0; n < 10; n++) ImGui::Text("Line %04d", n); ImGui::PopStyleColor(); @@ -4101,7 +3784,7 @@ static void ShowDemoWindowLayout() ImGui::DragInt("Max Height (in Lines)", &max_height_in_lines, 0.2f); ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines)); - if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY)) + if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) for (int n = 0; n < draw_lines; n++) ImGui::Text("Line %04d", n); ImGui::EndChild(); @@ -4119,11 +3802,11 @@ static void ShowDemoWindowLayout() { static int offset_x = 0; static bool override_bg_color = true; - static ImGuiChildFlags child_flags = ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY; + static ImGuiChildFlags child_flags = ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY; ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000); ImGui::Checkbox("Override ChildBg color", &override_bg_color); - ImGui::CheckboxFlags("ImGuiChildFlags_Borders", &child_flags, ImGuiChildFlags_Borders); + ImGui::CheckboxFlags("ImGuiChildFlags_Border", &child_flags, ImGuiChildFlags_Border); ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding); ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX); ImGui::CheckboxFlags("ImGuiChildFlags_ResizeY", &child_flags, ImGuiChildFlags_ResizeY); @@ -4309,7 +3992,7 @@ static void ShowDemoWindowLayout() ImGui::Text("Manual wrapping:"); ImGuiStyle& style = ImGui::GetStyle(); int buttons_count = 20; - float window_visible_x2 = ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x; + float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x; for (int n = 0; n < buttons_count; n++) { ImGui::PushID(n); @@ -4390,7 +4073,7 @@ static void ShowDemoWindowLayout() // down by FramePadding.y ahead of time) ImGui::AlignTextToFramePadding(); ImGui::Text("OK Blahblah"); ImGui::SameLine(); - ImGui::Button("Some framed item##2"); ImGui::SameLine(); + ImGui::Button("Some framed item"); ImGui::SameLine(); HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y"); // SmallButton() uses the same vertical padding as Text @@ -4533,7 +4216,7 @@ static void ShowDemoWindowLayout() const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0; const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); - const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Borders, child_flags); + const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Border, child_flags); if (ImGui::BeginMenuBar()) { ImGui::TextUnformatted("abc"); @@ -4580,7 +4263,7 @@ static void ShowDemoWindowLayout() float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f; ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0); ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i); - bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Borders, child_flags); + bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Border, child_flags); if (scroll_to_off) ImGui::SetScrollX(scroll_to_off_px); if (scroll_to_pos) @@ -4622,7 +4305,7 @@ static void ShowDemoWindowLayout() ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f)); ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30); - ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar); + ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Border, ImGuiWindowFlags_HorizontalScrollbar); for (int line = 0; line < lines; line++) { // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine() @@ -4768,7 +4451,7 @@ static void ShowDemoWindowLayout() } if (show_child) { - ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Borders); + ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Border); ImGui::EndChild(); } ImGui::End(); @@ -4777,8 +4460,8 @@ static void ShowDemoWindowLayout() ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Layout/Text Clipping"); - if (ImGui::TreeNode("Text Clipping")) + IMGUI_DEMO_MARKER("Layout/Clipping"); + if (ImGui::TreeNode("Clipping")) { static ImVec2 size(100.0f, 100.0f); static ImVec2 offset(30.0f, 30.0f); @@ -4872,6 +4555,156 @@ static void ShowDemoWindowLayout() ImGui::TreePop(); } + +#if IMGUI_HAS_STACK_LAYOUT + IMGUI_DEMO_MARKER("Layout/Stack Layout"); + if (ImGui::TreeNode("Stack Layout")) + { + static bool widget_a = true, widget_b = true, widget_c = true; + static bool spring_a = true, spring_ab = true, spring_bc = true, spring_c = true; + static bool minimize_width = false, minimize_height = true; + static bool horizontal = true, draw_springs = true; + static ImVec2 item_spacing = ImGui::GetStyle().ItemSpacing; + static float a_c_spring_weight = 0.0f; + static float ab_spring_weight = 0.5f; + static float alignment = 0.5f; + + struct funcs + { + static void VisibleSpring(float spring_weight) + { + ImGui::Spring(spring_weight); + if (!draw_springs) + return; + + ImVec2 rect_min = ImGui::GetItemRectMin(); + ImVec2 rect_max = ImGui::GetItemRectMax(); + + ImVec2 rect_size = ImGui::GetItemRectSize(); + if (rect_size.x <= 0.0f && rect_size.y <= 0.0f) + return; + + // Draw zig-zag + float width = 0.0f, spacing = 0.0f; + ImVec2 direction, origin; + ImVec2 spacing_min, spring_max; + + if (horizontal) + { + spacing = floorf(item_spacing.x); + width = rect_size.x - spacing; + origin = ImVec2(floorf(rect_min.x), floorf(rect_min.y + (rect_max.y - rect_min.y) / 2)); + direction = ImVec2(1.0f, 0.0f); + spring_max = ImVec2(rect_min.x + width, rect_max.y); + spacing_min = ImVec2(rect_min.x + width, rect_min.y); + } + else + { + spacing = floorf(item_spacing.y); + width = rect_size.y - spacing; + origin = ImVec2(floorf(rect_min.x + (rect_max.x - rect_min.x) / 2), floorf(rect_min.y)); + direction = ImVec2(0.0f, 1.0f); + spring_max = ImVec2(rect_max.x, rect_min.y + width); + spacing_min = ImVec2(rect_min.x, rect_min.y + width); + } + + if (spring_weight <= 0.0f && spacing <= 0.0f) + return; + + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + + draw_list->PushClipRect(rect_min, rect_max, true); + + draw_list->AddRectFilled(rect_min, spring_max, ImColor(80, 20, 80)); + draw_list->AddRectFilled(spacing_min, rect_max, ImColor(80, 20, 20)); + + const float zig_zag_size = 3; + ImVec2 normal = ImVec2(-direction.y, direction.x); + + draw_list->PathClear(); + origin.x += 0.5f; + origin.y += 0.5f; + draw_list->PathLineTo(origin); + for (float x = zig_zag_size * 0.5f; x <= width; x += zig_zag_size) + { + ImVec2 p; + p.x = origin.x + direction.x * x + normal.x * zig_zag_size; + p.y = origin.y + direction.y * x + normal.y * zig_zag_size; + draw_list->PathLineTo(p); + normal = ImVec2(-normal.x, -normal.y); + } + draw_list->PathStroke(ImColor(255, 255, 255, 190), false, 1.0f); + + draw_list->PopClipRect(); + } + }; + + ImGui::Checkbox("Widget A", &widget_a); ImGui::SameLine(); + ImGui::Checkbox("Widget B", &widget_b); ImGui::SameLine(); + ImGui::Checkbox("Widget C", &widget_c); + ImGui::Checkbox("Spring A", &spring_a); ImGui::SameLine(); + ImGui::Checkbox("Spring AB", &spring_ab); ImGui::SameLine(); + ImGui::Checkbox("Spring BC", &spring_bc); ImGui::SameLine(); + ImGui::Checkbox("Spring C", &spring_c); + ImGui::Checkbox("Horizontal", &horizontal); ImGui::SameLine(); + ImGui::Checkbox("Minimize Width", &minimize_width); ImGui::SameLine(); + ImGui::Checkbox("Minimize Height", &minimize_height); + ImGui::Checkbox("Draw Springs", &draw_springs); ImGui::SameLine(); + ImGui::TextUnformatted(" "); ImGui::SameLine(); + ImGui::ColorButton("- Spring", ImColor(80, 20, 80), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoPicker); ImGui::SameLine(); + ImGui::TextUnformatted("Spring"); ImGui::SameLine(); + ImGui::TextUnformatted(" "); ImGui::SameLine(); + ImGui::ColorButton("- Spacing", ImColor(80, 20, 20), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoPicker); ImGui::SameLine(); + ImGui::TextUnformatted("Item Spacing"); + ImGui::DragFloat("Item Spacing", horizontal ? &item_spacing.x : &item_spacing.y, 0.1f, 0.0f, 50.0f); + ImGui::DragFloat("A & C Spring Weight", &a_c_spring_weight, 0.002f, 0.0f, 1.0f); + ImGui::DragFloat("AB Spring Weight", &ab_spring_weight, 0.002f, 0.0f, 1.0f); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("BC Spring Weight = 1 - AB Spring Weight"); + ImGui::DragFloat("Minor Axis Alignment", &alignment, 0.002f, 0.0f, 1.0f); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("This is vertical alignment for horizontal layouts and horizontal alignment for vertical layouts."); + ImGui::Text("Layout widgets:"); + ImGui::Text("| Spring A | Widget A | Spring AB | Widget B | Spring BC | Widget C | Spring C |"); + + ImGui::Spacing(); + + ImVec2 widget_size; + widget_size.x = floorf(ImGui::GetContentRegionAvail().x / 4); + widget_size.y = horizontal ? floorf(widget_size.x / 3) : widget_size.x; + + ImVec2 small_widget_size = widget_size; + if (horizontal) + small_widget_size.y = floorf(small_widget_size.y / 2); + else + small_widget_size.x = floorf(small_widget_size.x / 2); + + ImVec2 layout_size = ImVec2(widget_size.x * 4, widget_size.y * 4); + if (minimize_width) layout_size.x = 0.0f; + if (minimize_height) layout_size.y = 0.0f; + + // Minor axis alignment can be set by style or directly in BeginHorizontal/BeginVertical + // Example: + // ImGui::PushStyleVar(ImGuiStyleVar_LayoutAlign, alignment); + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(floorf(item_spacing.x), floorf(item_spacing.y))); + + if (horizontal) { ImGui::BeginHorizontal("h1", layout_size, alignment); } else { ImGui::BeginVertical("v1", layout_size, alignment); } + if (spring_a) { funcs::VisibleSpring(a_c_spring_weight); } + if (widget_a) { ImGui::Button("Widget A", widget_size); } + if (spring_ab) { funcs::VisibleSpring(ab_spring_weight); } + if (widget_b) { ImGui::Button("Widget B", small_widget_size); } + if (spring_bc) { funcs::VisibleSpring(1.0f - ab_spring_weight); } + if (widget_c) { ImGui::Button("Widget C", widget_size); } + if (spring_c) { funcs::VisibleSpring(a_c_spring_weight); } + if (horizontal) { ImGui::EndHorizontal(); } else { ImGui::EndVertical(); } + + ImGui::PopStyleVar(); + + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), ImGui::GetColorU32(ImGuiCol_Border)); + + ImGui::TreePop(); + } +#endif // IMGUI_HAS_STACK_LAYOUT } //----------------------------------------------------------------------------- @@ -5254,8 +5087,8 @@ const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL; static void PushStyleCompact() { ImGuiStyle& style = ImGui::GetStyle(); - ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, (float)(int)(style.FramePadding.y * 0.60f)); - ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, (float)(int)(style.ItemSpacing.y * 0.60f)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.60f))); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.60f))); } static void PopStyleCompact() @@ -6289,7 +6122,7 @@ static void ShowDemoWindowTables() for (int row = 0; row < 8; row++) { if ((row % 3) == 2) - ImGui::PushStyleVarY(ImGuiStyleVar_CellPadding, 20.0f); + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(style.CellPadding.x, 20.0f)); ImGui::TableNextRow(ImGuiTableRowFlags_None); ImGui::TableNextColumn(); ImGui::Text("CellPadding.y = %.2f", style.CellPadding.y); @@ -6432,17 +6265,15 @@ static void ShowDemoWindowTables() IMGUI_DEMO_MARKER("Tables/Tree view"); if (ImGui::TreeNode("Tree view")) { - static ImGuiTableFlags table_flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; + static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; - static ImGuiTreeNodeFlags tree_node_flags_base = ImGuiTreeNodeFlags_SpanAllColumns; - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanLabelWidth); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanAllColumns); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_LabelSpanAllColumns); - ImGui::SameLine(); HelpMarker("Useful if you know that you aren't displaying contents in other columns"); + static ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAllColumns; + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanTextWidth); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags, ImGuiTreeNodeFlags_SpanAllColumns); HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns."); - if (ImGui::BeginTable("3ways", 3, table_flags)) + if (ImGui::BeginTable("3ways", 3, flags)) { // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide); @@ -6463,21 +6294,13 @@ static void ShowDemoWindowTables() ImGui::TableNextRow(); ImGui::TableNextColumn(); const bool is_folder = (node->ChildCount > 0); - - ImGuiTreeNodeFlags node_flags = tree_node_flags_base; - if (node != &all_nodes[0]) - node_flags &= ~ImGuiTreeNodeFlags_LabelSpanAllColumns; // Only demonstrate this on the root node. - if (is_folder) { - bool open = ImGui::TreeNodeEx(node->Name, node_flags); - if ((node_flags & ImGuiTreeNodeFlags_LabelSpanAllColumns) == 0) - { - ImGui::TableNextColumn(); - ImGui::TextDisabled("--"); - ImGui::TableNextColumn(); - ImGui::TextUnformatted(node->Type); - } + bool open = ImGui::TreeNodeEx(node->Name, tree_node_flags); + ImGui::TableNextColumn(); + ImGui::TextDisabled("--"); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(node->Type); if (open) { for (int child_n = 0; child_n < node->ChildCount; child_n++) @@ -6487,7 +6310,7 @@ static void ShowDemoWindowTables() } else { - ImGui::TreeNodeEx(node->Name, node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen); + ImGui::TreeNodeEx(node->Name, tree_node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen); ImGui::TableNextColumn(); ImGui::Text("%d", node->Size); ImGui::TableNextColumn(); @@ -6497,7 +6320,7 @@ static void ShowDemoWindowTables() }; static const MyTreeNode nodes[] = { - { "Root with Long Name", "Folder", -1, 1, 3 }, // 0 + { "Root", "Folder", -1, 1, 3 }, // 0 { "Music", "Folder", -1, 4, 2 }, // 1 { "Textures", "Folder", -1, 6, 3 }, // 2 { "desktop.ini", "System file", 1024, -1,-1 }, // 3 @@ -6578,11 +6401,7 @@ static void ShowDemoWindowTables() // FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox. static bool column_selected[3] = {}; - // Instead of calling TableHeadersRow() we'll submit custom headers ourselves. - // (A different approach is also possible: - // - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call. - // - Call TableHeadersRow() normally. This will submit TableHeader() with no name. - // - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().) + // Instead of calling TableHeadersRow() we'll submit custom headers ourselves ImGui::TableNextRow(ImGuiTableRowFlags_Headers); for (int column = 0; column < COLUMNS_COUNT; column++) { @@ -6597,7 +6416,6 @@ static void ShowDemoWindowTables() ImGui::PopID(); } - // Submit table contents for (int row = 0; row < 5; row++) { ImGui::TableNextRow(); @@ -6632,7 +6450,6 @@ static void ShowDemoWindowTables() ImGui::CheckboxFlags("_ScrollX", &table_flags, ImGuiTableFlags_ScrollX); ImGui::CheckboxFlags("_ScrollY", &table_flags, ImGuiTableFlags_ScrollY); ImGui::CheckboxFlags("_Resizable", &table_flags, ImGuiTableFlags_Resizable); - ImGui::CheckboxFlags("_Sortable", &table_flags, ImGuiTableFlags_Sortable); ImGui::CheckboxFlags("_NoBordersInBody", &table_flags, ImGuiTableFlags_NoBordersInBody); ImGui::CheckboxFlags("_HighlightHoveredColumn", &table_flags, ImGuiTableFlags_HighlightHoveredColumn); ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); @@ -7323,14 +7140,12 @@ static void ShowDemoWindowColumns() { if (h_borders && ImGui::GetColumnIndex() == 0) ImGui::Separator(); - ImGui::PushID(i); ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i); ImGui::Text("Width %.2f", ImGui::GetColumnWidth()); ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x); ImGui::Text("Offset %.2f", ImGui::GetColumnOffset()); ImGui::Text("Long text that is likely to clip"); ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f)); - ImGui::PopID(); ImGui::NextColumn(); } ImGui::Columns(1); @@ -7483,15 +7298,18 @@ static void ShowDemoWindowInputs() ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); - ImGui::Text("Mouse clicked count:"); - for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseClickedCount[i] > 0) { ImGui::SameLine(); ImGui::Text("b%d: %d", i, io.MouseClickedCount[i]); } // We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows // displaying the data for old/new backends. // User code should never have to go through such hoops! // You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END. +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN; +#else + struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key >= 0 && key < 512 && ImGui::GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array + ImGuiKey start_key = (ImGuiKey)0; +#endif ImGui::Text("Keys down:"); for (ImGuiKey key = start_key; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); } ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. @@ -7650,8 +7468,7 @@ static void ShowDemoWindowInputs() IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); ImGuiMouseCursor current = ImGui::GetMouseCursor(); - const char* cursor_name = (current >= ImGuiMouseCursor_Arrow) && (current < ImGuiMouseCursor_COUNT) ? mouse_cursors_names[current] : "N/A"; - ImGui::Text("Current mouse cursor = %d: %s", current, cursor_name); + ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]); ImGui::BeginDisabled(true); ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors); ImGui::EndDisabled(); @@ -7787,8 +7604,7 @@ void ImGui::ShowAboutWindow(bool* p_open) ImGui::TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding"); ImGui::Separator(); - ImGui::Text("(c) 2014-2025 Omar Cornut"); - ImGui::Text("Developed by Omar Cornut and all Dear ImGui contributors."); + ImGui::Text("By Omar Cornut and all Dear ImGui contributors."); ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information."); ImGui::Text("If your company uses this, please consider funding the project."); @@ -7815,6 +7631,9 @@ void ImGui::ShowAboutWindow(bool* p_open) #ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS"); #endif +#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO + ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_KEYIO"); +#endif #ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS"); #endif @@ -7874,7 +7693,6 @@ void ImGui::ShowAboutWindow(bool* p_open) #endif #ifdef __EMSCRIPTEN__ ImGui::Text("define: __EMSCRIPTEN__"); - ImGui::Text("Emscripten: %d.%d.%d", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__); #endif #ifdef IMGUI_HAS_VIEWPORT ImGui::Text("define: IMGUI_HAS_VIEWPORT"); @@ -7888,9 +7706,10 @@ void ImGui::ShowAboutWindow(bool* p_open) ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags); if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) ImGui::Text(" NavEnableKeyboard"); if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) ImGui::Text(" NavEnableGamepad"); + if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) ImGui::Text(" NavEnableSetMousePos"); + if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard) ImGui::Text(" NavNoCaptureKeyboard"); if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse"); if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange"); - if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) ImGui::Text(" NoKeyboard"); if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) ImGui::Text(" DockingEnable"); if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui::Text(" ViewportsEnable"); if (io.ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports) ImGui::Text(" DpiEnableScaleViewports"); @@ -7905,8 +7724,6 @@ void ImGui::ShowAboutWindow(bool* p_open) if (io.ConfigDockingAlwaysTabBar) ImGui::Text("io.ConfigDockingAlwaysTabBar"); if (io.ConfigDockingTransparentPayload) ImGui::Text("io.ConfigDockingTransparentPayload"); if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors"); - if (io.ConfigNavMoveSetMousePos) ImGui::Text("io.ConfigNavMoveSetMousePos"); - if (io.ConfigNavCaptureKeyboard) ImGui::Text("io.ConfigNavCaptureKeyboard"); if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink"); if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges"); if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly"); @@ -7966,8 +7783,6 @@ void ImGui::ShowFontSelector(const char* label) ImGui::PushID((void*)font); if (ImGui::Selectable(font->GetDebugName(), font == font_current)) io.FontDefault = font; - if (font == font_current) - ImGui::SetItemDefaultFocus(); ImGui::PopID(); } ImGui::EndCombo(); @@ -8064,8 +7879,6 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f"); - ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 3.0f, "%.0f"); - ImGui::SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set."); ImGui::SeparatorText("Rounding"); ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); @@ -8147,16 +7960,16 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) filter.Draw("Filter colors", ImGui::GetFontSize() * 16); static ImGuiColorEditFlags alpha_flags = 0; - if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_AlphaOpaque)) { alpha_flags = ImGuiColorEditFlags_AlphaOpaque; } ImGui::SameLine(); - if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine(); - if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine(); + if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine(); + if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine(); + if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine(); HelpMarker( "In the color list:\n" "Left-click on color square to open color picker,\n" "Right-click to open edit options menu."); ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX)); - ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); + ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Border | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); ImGui::PushItemWidth(ImGui::GetFontSize() * -12); for (int i = 0; i < ImGuiCol_COUNT; i++) { @@ -8390,7 +8203,7 @@ static void ShowExampleMenuFile() { static bool enabled = true; ImGui::MenuItem("Enabled", "", &enabled); - ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Borders); + ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Border); for (int i = 0; i < 10; i++) ImGui::Text("Scrolling Text %d", i); ImGui::EndChild(); @@ -8987,7 +8800,7 @@ static void ShowExampleAppLayout(bool* p_open) // Left static int selected = 0; { - ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX); + ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX); for (int i = 0; i < 100; i++) { // FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav @@ -9034,137 +8847,109 @@ static void ShowExampleAppLayout(bool* p_open) // [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor() //----------------------------------------------------------------------------- // Some of the interactions are a bit lack-luster: +// - We would want the table scrolling window to use NavFlattened. // - We would want pressing validating or leaving the filter to somehow restore focus. // - We may want more advanced filtering (child nodes) and clipper support: both will need extra work. -// - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties. //----------------------------------------------------------------------------- struct ExampleAppPropertyEditor { ImGuiTextFilter Filter; - ExampleTreeNode* VisibleNode = NULL; void Draw(ExampleTreeNode* root_node) { - // Left side: draw tree - // - Currently using a table to benefit from RowBg feature - if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened)) + ImGui::SetNextItemWidth(-FLT_MIN); + ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip); + ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true); + if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_ARRAYSIZE(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll)) + Filter.Build(); + ImGui::PopItemFlag(); + + ImGuiTableFlags table_flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg; + if (ImGui::BeginTable("##split", 2, table_flags)) { - ImGui::SetNextItemWidth(-FLT_MIN); - ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip); - ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true); - if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_ARRAYSIZE(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll)) - Filter.Build(); - ImGui::PopItemFlag(); + ImGui::TableSetupColumn("Object", ImGuiTableColumnFlags_WidthStretch, 1.0f); + ImGui::TableSetupColumn("Contents", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger + //ImGui::TableSetupScrollFreeze(0, 1); + //ImGui::TableHeadersRow(); - if (ImGui::BeginTable("##bg", 1, ImGuiTableFlags_RowBg)) - { - for (ExampleTreeNode* node : root_node->Childs) - if (Filter.PassFilter(node->Name)) // Filter root node - DrawTreeNode(node); - ImGui::EndTable(); - } + for (ExampleTreeNode* node : root_node->Childs) + if (Filter.PassFilter(node->Name)) // Filter root node + DrawTreeNode(node); + ImGui::EndTable(); } - ImGui::EndChild(); - - // Right side: draw properties - ImGui::SameLine(); - - ImGui::BeginGroup(); // Lock X position - if (ExampleTreeNode* node = VisibleNode) - { - ImGui::Text("%s", node->Name); - ImGui::TextDisabled("UID: 0x%08X", node->UID); - ImGui::Separator(); - if (ImGui::BeginTable("##properties", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY)) - { - // Push object ID after we entered the table, so table is shared for all objects - ImGui::PushID((int)node->UID); - ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger - if (node->HasData) - { - // In a typical application, the structure description would be derived from a data-driven system. - // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array. - // - Limits and some details are hard-coded to simplify the demo. - for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos) - { - ImGui::TableNextRow(); - ImGui::PushID(field_desc.Name); - ImGui::TableNextColumn(); - ImGui::AlignTextToFramePadding(); - ImGui::TextUnformatted(field_desc.Name); - ImGui::TableNextColumn(); - void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset); - switch (field_desc.DataType) - { - case ImGuiDataType_Bool: - { - IM_ASSERT(field_desc.DataCount == 1); - ImGui::Checkbox("##Editor", (bool*)field_ptr); - break; - } - case ImGuiDataType_S32: - { - int v_min = INT_MIN, v_max = INT_MAX; - ImGui::SetNextItemWidth(-FLT_MIN); - ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max); - break; - } - case ImGuiDataType_Float: - { - float v_min = 0.0f, v_max = 1.0f; - ImGui::SetNextItemWidth(-FLT_MIN); - ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max); - break; - } - case ImGuiDataType_String: - { - ImGui::InputText("##Editor", reinterpret_cast(field_ptr), 28); - break; - } - } - ImGui::PopID(); - } - } - ImGui::PopID(); - ImGui::EndTable(); - } - } - ImGui::EndGroup(); } void DrawTreeNode(ExampleTreeNode* node) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); + // Object tree node ImGui::PushID(node->UID); + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::AlignTextToFramePadding(); ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None; + tree_flags |= ImGuiTreeNodeFlags_SpanAllColumns | ImGuiTreeNodeFlags_AllowOverlap; // Highlight whole row for visibility tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we are likely to want to add selection afterwards tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Left arrow support - if (node == VisibleNode) - tree_flags |= ImGuiTreeNodeFlags_Selected; - if (node->Childs.Size == 0) - tree_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet; - if (node->DataMyBool == false) - ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]); - bool node_open = ImGui::TreeNodeEx("", tree_flags, "%s", node->Name); - if (node->DataMyBool == false) - ImGui::PopStyleColor(); - if (ImGui::IsItemFocused()) - VisibleNode = node; + bool node_open = ImGui::TreeNodeEx("##Object", tree_flags, "%s", node->Name); + ImGui::TableSetColumnIndex(1); + ImGui::TextDisabled("UID: 0x%08X", node->UID); + + // Display child and data if (node_open) - { for (ExampleTreeNode* child : node->Childs) DrawTreeNode(child); - ImGui::TreePop(); + if (node_open && node->HasData) + { + // In a typical application, the structure description would be derived from a data-driven system. + // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array. + // - Limits and some details are hard-coded to simplify the demo. + // - Text and Selectable are less high than framed widgets, using AlignTextToFramePadding() we add vertical spacing to make the selectable lines equal high. + for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos) + { + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::AlignTextToFramePadding(); + ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop | ImGuiItemFlags_NoNav, true); + ImGui::Selectable(field_desc.Name, false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap); + ImGui::PopItemFlag(); + ImGui::TableSetColumnIndex(1); + ImGui::PushID(field_desc.Name); + void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset); + switch (field_desc.DataType) + { + case ImGuiDataType_Bool: + { + IM_ASSERT(field_desc.DataCount == 1); + ImGui::Checkbox("##Editor", (bool*)field_ptr); + break; + } + case ImGuiDataType_S32: + { + int v_min = INT_MIN, v_max = INT_MAX; + ImGui::SetNextItemWidth(-FLT_MIN); + ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max); + break; + } + case ImGuiDataType_Float: + { + float v_min = 0.0f, v_max = 1.0f; + ImGui::SetNextItemWidth(-FLT_MIN); + ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max); + break; + } + } + ImGui::PopID(); + } } + if (node_open) + ImGui::TreePop(); ImGui::PopID(); } }; // Demonstrate creating a simple property editor. -static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data) +static void ShowExampleAppPropertyEditor(bool* p_open) { ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); if (!ImGui::Begin("Example: Property editor", p_open)) @@ -9175,9 +8960,8 @@ static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo IMGUI_DEMO_MARKER("Examples/Property Editor"); static ExampleAppPropertyEditor property_editor; - if (demo_data->DemoTree == NULL) - demo_data->DemoTree = ExampleTree_CreateDemoTree(); - property_editor.Draw(demo_data->DemoTree); + static ExampleTreeNode* tree_data = ExampleTree_CreateDemoTree(); + property_editor.Draw(tree_data); ImGui::End(); } @@ -9673,7 +9457,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) // To use a child window instead we could use, e.g: // ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding // ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color - // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove); + // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Border, ImGuiWindowFlags_NoMove); // ImGui::PopStyleColor(); // ImGui::PopStyleVar(); // [...] @@ -10520,8 +10304,8 @@ struct ExampleAssetsBrowser } ImGuiIO& io = ImGui::GetIO(); - ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.y + LayoutItemSpacing))); - if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove)) + ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.x + LayoutItemSpacing))); + if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Border, ImGuiWindowFlags_NoMove)) { ImDrawList* draw_list = ImGui::GetWindowDrawList(); @@ -10570,7 +10354,7 @@ struct ExampleAssetsBrowser // Rendering parameters const ImU32 icon_type_overlay_colors[3] = { 0, IM_COL32(200, 70, 70, 255), IM_COL32(70, 170, 70, 255) }; - const ImU32 icon_bg_color = ImGui::GetColorU32(IM_COL32(35, 35, 35, 220)); + const ImU32 icon_bg_color = ImGui::GetColorU32(ImGuiCol_MenuBarBg); const ImVec2 icon_type_overlay_size = ImVec2(4.0f, 4.0f); const bool display_label = (LayoutItemSize.x >= ImGui::CalcTextSize("999").x); @@ -10732,8 +10516,6 @@ void ImGui::ShowAboutWindow(bool*) {} void ImGui::ShowDemoWindow(bool*) {} void ImGui::ShowUserGuide() {} void ImGui::ShowStyleEditor(ImGuiStyle*) {} -bool ImGui::ShowStyleSelector(const char* label) { return false; } -void ImGui::ShowFontSelector(const char* label) {} #endif diff --git a/3rdparty/imgui/imgui_draw.cpp b/3rdparty/imgui/imgui_draw.cpp index fda0282..79b70a3 100644 --- a/3rdparty/imgui/imgui_draw.cpp +++ b/3rdparty/imgui/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.0 WIP // (drawing and font code) /* @@ -14,7 +14,7 @@ Index of this file: // [SECTION] Helpers ShadeVertsXXX functions // [SECTION] ImFontConfig // [SECTION] ImFontAtlas -// [SECTION] ImFontAtlas: glyph ranges helpers +// [SECTION] ImFontAtlas glyph ranges helpers // [SECTION] ImFontGlyphRangesBuilder // [SECTION] ImFont // [SECTION] ImGui Internal Render Helpers @@ -66,18 +66,13 @@ Index of this file: #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access -#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type -#pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier #elif defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used -#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe -#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function -#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value -#pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer -#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead -#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif //------------------------------------------------------------------------- @@ -106,15 +101,16 @@ namespace IMGUI_STB_NAMESPACE #if defined(__clang__) #pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma clang diagnostic ignored "-Wunused-function" #pragma clang diagnostic ignored "-Wmissing-prototypes" #pragma clang diagnostic ignored "-Wimplicit-fallthrough" +#pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier #endif #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits] -#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" // warning: this statement may fall through +#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers #endif #ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) @@ -221,7 +217,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); - colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.50f, 0.50f, 0.50f, 0.00f); + colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_HeaderActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f); colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); @@ -236,7 +232,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); - colors[ImGuiCol_NavCursor] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); + colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); @@ -286,7 +282,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); - colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.53f, 0.53f, 0.87f, 0.00f); + colors[ImGuiCol_TabDimmedSelectedOverline] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f); colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); @@ -301,7 +297,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); - colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); @@ -352,7 +348,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); - colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.26f, 0.59f, 1.00f, 0.00f); + colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.26f, 0.59f, 1.00f, 1.00f); colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f); colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); @@ -367,7 +363,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); - colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered]; + colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f); colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); @@ -403,17 +399,6 @@ void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error) ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); } -ImDrawList::ImDrawList(ImDrawListSharedData* shared_data) -{ - memset(this, 0, sizeof(*this)); - _Data = shared_data; -} - -ImDrawList::~ImDrawList() -{ - _ClearFreeMemory(); -} - // Initialize before use in a new frame. We always have a command ready in the buffer. // In the majority of cases, you would want to call PushClipRect() and PushTextureID() after this. void ImDrawList::_ResetForNewFrame() @@ -435,7 +420,6 @@ void ImDrawList::_ResetForNewFrame() _IdxWritePtr = NULL; _ClipRectStack.resize(0); _TextureIdStack.resize(0); - _CallbacksDataBuf.resize(0); _Path.resize(0); _Splitter.Clear(); CmdBuffer.push_back(ImDrawCmd()); @@ -453,7 +437,6 @@ void ImDrawList::_ClearFreeMemory() _IdxWritePtr = NULL; _ClipRectStack.clear(); _TextureIdStack.clear(); - _CallbacksDataBuf.clear(); _Path.clear(); _Splitter.ClearFreeMemory(); } @@ -493,7 +476,7 @@ void ImDrawList::_PopUnusedDrawCmd() } } -void ImDrawList::AddCallback(ImDrawCallback callback, void* userdata, size_t userdata_size) +void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) { IM_ASSERT_PARANOID(CmdBuffer.Size > 0); ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; @@ -503,26 +486,8 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* userdata, size_t use AddDrawCmd(); curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; } - curr_cmd->UserCallback = callback; - if (userdata_size == 0) - { - // Store user data directly in command (no indirection) - curr_cmd->UserCallbackData = userdata; - curr_cmd->UserCallbackDataSize = 0; - curr_cmd->UserCallbackDataOffset = -1; - } - else - { - // Copy and store user data in a buffer - IM_ASSERT(userdata != NULL); - IM_ASSERT(userdata_size < (1u << 31)); - curr_cmd->UserCallbackData = NULL; // Will be resolved during Render() - curr_cmd->UserCallbackDataSize = (int)userdata_size; - curr_cmd->UserCallbackDataOffset = _CallbacksDataBuf.Size; - _CallbacksDataBuf.resize(_CallbacksDataBuf.Size + (int)userdata_size); - memcpy(_CallbacksDataBuf.Data + (size_t)curr_cmd->UserCallbackDataOffset, userdata, userdata_size); - } + curr_cmd->UserCallbackData = callback_data; AddDrawCmd(); // Force a new command after us (see comment below) } @@ -567,6 +532,7 @@ void ImDrawList::_OnChangedClipRect() CmdBuffer.pop_back(); return; } + curr_cmd->ClipRect = _CmdHeader.ClipRect; } @@ -589,6 +555,7 @@ void ImDrawList::_OnChangedTextureID() CmdBuffer.pop_back(); return; } + curr_cmd->TextureId = _CmdHeader.TextureId; } @@ -664,15 +631,6 @@ void ImDrawList::PopTextureID() _OnChangedTextureID(); } -// This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTextureID()/PopTextureID(). -void ImDrawList::_SetTextureID(ImTextureID texture_id) -{ - if (_CmdHeader.TextureId == texture_id) - return; - _CmdHeader.TextureId = texture_id; - _OnChangedTextureID(); -} - // Reserve space for a number of vertices and indices. // You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or // submit the intermediate results. PrimUnreserve() can be used to release unused allocations. @@ -1667,7 +1625,7 @@ void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const Im PathStroke(col, 0, thickness); } -void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) +void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) { if ((col & IM_COL32_A_MASK) == 0) return; @@ -1675,7 +1633,8 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 // Accept null ranges if (text_begin == text_end || text_begin[0] == 0) return; - // No need to strlen() here: font->RenderText() will do it and may early out. + if (text_end == NULL) + text_end = text_begin + strlen(text_begin); // Pull default font/size from the shared ImDrawListSharedData instance if (font == NULL) @@ -1698,7 +1657,7 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end) { - AddText(_Data->Font, _Data->FontSize, pos, col, text_begin, text_end); + AddText(NULL, 0.0f, pos, col, text_begin, text_end); } void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col) @@ -2262,12 +2221,6 @@ void ImGui::AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector if (sizeof(ImDrawIdx) == 2) IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above"); - // Resolve callback data pointers - if (draw_list->_CallbacksDataBuf.Size > 0) - for (ImDrawCmd& cmd : draw_list->CmdBuffer) - if (cmd.UserCallback != NULL && cmd.UserCallbackDataOffset != -1 && cmd.UserCallbackDataSize > 0) - cmd.UserCallbackData = draw_list->_CallbacksDataBuf.Data + cmd.UserCallbackDataOffset; - // Add to output list + records state in ImDrawData out_list->push_back(draw_list); draw_data->CmdListsCount++; @@ -2380,49 +2333,17 @@ ImFontConfig::ImFontConfig() { memset(this, 0, sizeof(*this)); FontDataOwnedByAtlas = true; - OversampleH = 0; // Auto == 1 or 2 depending on size - OversampleV = 0; // Auto == 1 + OversampleH = 2; + OversampleV = 1; GlyphMaxAdvanceX = FLT_MAX; RasterizerMultiply = 1.0f; RasterizerDensity = 1.0f; - EllipsisChar = 0; + EllipsisChar = (ImWchar)-1; } //----------------------------------------------------------------------------- // [SECTION] ImFontAtlas //----------------------------------------------------------------------------- -// - Default texture data encoded in ASCII -// - ImFontAtlas::ClearInputData() -// - ImFontAtlas::ClearTexData() -// - ImFontAtlas::ClearFonts() -// - ImFontAtlas::Clear() -// - ImFontAtlas::GetTexDataAsAlpha8() -// - ImFontAtlas::GetTexDataAsRGBA32() -// - ImFontAtlas::AddFont() -// - ImFontAtlas::AddFontDefault() -// - ImFontAtlas::AddFontFromFileTTF() -// - ImFontAtlas::AddFontFromMemoryTTF() -// - ImFontAtlas::AddFontFromMemoryCompressedTTF() -// - ImFontAtlas::AddFontFromMemoryCompressedBase85TTF() -// - ImFontAtlas::AddCustomRectRegular() -// - ImFontAtlas::AddCustomRectFontGlyph() -// - ImFontAtlas::CalcCustomRectUV() -// - ImFontAtlas::GetMouseCursorTexData() -// - ImFontAtlas::Build() -// - ImFontAtlasBuildMultiplyCalcLookupTable() -// - ImFontAtlasBuildMultiplyRectAlpha8() -// - ImFontAtlasBuildWithStbTruetype() -// - ImFontAtlasGetBuilderForStbTruetype() -// - ImFontAtlasUpdateConfigDataPointers() -// - ImFontAtlasBuildSetupFont() -// - ImFontAtlasBuildPackCustomRects() -// - ImFontAtlasBuildRender8bppRectFromString() -// - ImFontAtlasBuildRender32bppRectFromString() -// - ImFontAtlasBuildRenderDefaultTexData() -// - ImFontAtlasBuildRenderLinesTexData() -// - ImFontAtlasBuildInit() -// - ImFontAtlasBuildFinish() -//----------------------------------------------------------------------------- // A work of art lies ahead! (. = white layer, X = black layer, others are blank) // The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes. @@ -2526,7 +2447,6 @@ void ImFontAtlas::ClearTexData() void ImFontAtlas::ClearFonts() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); - ClearInputData(); Fonts.clear_delete(); TexReady = false; } @@ -2578,14 +2498,13 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0); - IM_ASSERT(font_cfg->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?"); - IM_ASSERT(font_cfg->RasterizerDensity > 0.0f && "Is ImFontConfig struct correctly initialized?"); + IM_ASSERT(font_cfg->SizePixels > 0.0f); // Create new font if (!font_cfg->MergeMode) Fonts.push_back(IM_NEW(ImFont)); else - IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. + IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. ConfigData.push_back(*font_cfg); ImFontConfig& new_font_cfg = ConfigData.back(); @@ -2598,13 +2517,9 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize); } - // Round font size - // - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet. - // - Note that using io.FontGlobalScale or SetWindowFontScale(), with are legacy-ish, partially supported features, can still lead to unrounded sizes. - // - We may support it better later and remove this rounding. - new_font_cfg.SizePixels = ImTrunc(new_font_cfg.SizePixels); + if (new_font_cfg.DstFont->EllipsisChar == (ImWchar)-1) + new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar; - // Pointers to ConfigData and BuilderData are otherwise dangling ImFontAtlasUpdateConfigDataPointers(this); // Invalidate texture @@ -2616,6 +2531,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) // Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder) static unsigned int stb_decompress_length(const unsigned char* input); static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length); +static const char* GetDefaultCompressedFontDataTTFBase85(); static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; } static void Decode85(const unsigned char* src, unsigned char* dst) { @@ -2627,14 +2543,10 @@ static void Decode85(const unsigned char* src, unsigned char* dst) dst += 4; } } -#ifndef IMGUI_DISABLE_DEFAULT_FONT -static const char* GetDefaultCompressedFontDataTTF(int* out_size); -#endif // Load embedded ProggyClean.ttf at size 13, disable oversampling ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) { -#ifndef IMGUI_DISABLE_DEFAULT_FONT ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); if (!font_cfg_template) { @@ -2648,16 +2560,10 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) font_cfg.EllipsisChar = (ImWchar)0x0085; font_cfg.GlyphOffset.y = 1.0f * IM_TRUNC(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units - int ttf_compressed_size = 0; - const char* ttf_compressed = GetDefaultCompressedFontDataTTF(&ttf_compressed_size); + const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); - ImFont* font = AddFontFromMemoryCompressedTTF(ttf_compressed, ttf_compressed_size, font_cfg.SizePixels, &font_cfg, glyph_ranges); + ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges); return font; -#else - IM_ASSERT(0 && "AddFontDefault() disabled in this build."); - IM_UNUSED(font_cfg_template); - return NULL; -#endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT } ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) @@ -2741,7 +2647,6 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int r.Width = (unsigned short)width; r.Height = (unsigned short)height; r.GlyphID = id; - r.GlyphColored = 0; // Set to 1 manually to mark glyph as colored // FIXME: No official API for that (#8133) r.GlyphAdvanceX = advance_x; r.GlyphOffset = offset; r.Font = font; @@ -2825,13 +2730,6 @@ void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsig *data = table[*data]; } -void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v) -{ - // Automatically disable horizontal oversampling over size 36 - *out_oversample_h = (cfg->OversampleH != 0) ? cfg->OversampleH : (cfg->SizePixels * cfg->RasterizerDensity > 36.0f || cfg->PixelSnapH) ? 1 : 2; - *out_oversample_v = (cfg->OversampleV != 0) ? cfg->OversampleV : 1; -} - #ifdef IMGUI_ENABLE_STB_TRUETYPE // Temporary data for one source font (multiple source fonts can be merged into one destination ImFont) // (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.) @@ -2923,9 +2821,8 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) { // Check for valid range. This may also help detect *some* dangling pointers, because a common - // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent, - // or to forget to zero-terminate the glyph range array. - IM_ASSERT(src_range[0] <= src_range[1] && "Invalid range: is your glyph range array persistent? it is zero-terminated?"); + // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent. + IM_ASSERT(src_range[0] <= src_range[1]); src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); } dst_tmp.SrcCount++; @@ -2985,7 +2882,6 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) int total_surface = 0; int buf_rects_out_n = 0; int buf_packedchars_out_n = 0; - const int pack_padding = atlas->TexGlyphPadding; for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) { ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; @@ -2997,35 +2893,30 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) buf_rects_out_n += src_tmp.GlyphsCount; buf_packedchars_out_n += src_tmp.GlyphsCount; - // Automatic selection of oversampling parameters - ImFontConfig& cfg = atlas->ConfigData[src_i]; - int oversample_h, oversample_v; - ImFontAtlasBuildGetOversampleFactors(&cfg, &oversample_h, &oversample_v); - // Convert our ranges in the format stb_truetype wants + ImFontConfig& cfg = atlas->ConfigData[src_i]; src_tmp.PackRange.font_size = cfg.SizePixels * cfg.RasterizerDensity; src_tmp.PackRange.first_unicode_codepoint_in_range = 0; src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data; src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size; src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars; - src_tmp.PackRange.h_oversample = (unsigned char)oversample_h; - src_tmp.PackRange.v_oversample = (unsigned char)oversample_v; + src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH; + src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV; // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects) const float scale = (cfg.SizePixels > 0.0f) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels * cfg.RasterizerDensity) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels * cfg.RasterizerDensity); + const int padding = atlas->TexGlyphPadding; for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) { int x0, y0, x1, y1; const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]); IM_ASSERT(glyph_index_in_font != 0); - stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * oversample_h, scale * oversample_v, 0, 0, &x0, &y0, &x1, &y1); - src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + pack_padding + oversample_h - 1); - src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + pack_padding + oversample_v - 1); + stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1); + src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1); + src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1); total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; } } - for (int i = 0; i < atlas->CustomRects.Size; i++) - total_surface += (atlas->CustomRects[i].Width + pack_padding) * (atlas->CustomRects[i].Height + pack_padding); // We need a width for the skyline algorithm, any width! // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. @@ -3041,8 +2932,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). const int TEX_HEIGHT_MAX = 1024 * 32; stbtt_pack_context spc = {}; - stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, 0, NULL); - spc.padding = atlas->TexGlyphPadding; // Because we mixup stbtt_PackXXX and stbrp_PackXXX there's a bit of a hack here, not passing the value to stbtt_PackBegin() allows us to still pack a TexWidth-1 wide item. (#8107) + stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL); ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info); // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point. @@ -3188,14 +3078,13 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opa if (user_rects.Size < 1) { __builtin_unreachable(); } // Workaround for GCC bug if IM_ASSERT() is defined to conditionally throw (see #5343) #endif - const int pack_padding = atlas->TexGlyphPadding; ImVector pack_rects; pack_rects.resize(user_rects.Size); memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes()); for (int i = 0; i < user_rects.Size; i++) { - pack_rects[i].w = user_rects[i].Width + pack_padding; - pack_rects[i].h = user_rects[i].Height + pack_padding; + pack_rects[i].w = user_rects[i].Width; + pack_rects[i].h = user_rects[i].Height; } stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size); for (int i = 0; i < pack_rects.Size; i++) @@ -3203,7 +3092,7 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opa { user_rects[i].X = (unsigned short)pack_rects[i].x; user_rects[i].Y = (unsigned short)pack_rects[i].y; - IM_ASSERT(pack_rects[i].w == user_rects[i].Width + pack_padding && pack_rects[i].h == user_rects[i].Height + pack_padding); + IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height); atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h); } } @@ -3234,23 +3123,9 @@ static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) IM_ASSERT(r->IsPacked()); const int w = atlas->TexWidth; - if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) + if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) { - // White pixels only - IM_ASSERT(r->Width == 2 && r->Height == 2); - const int offset = (int)r->X + (int)r->Y * w; - if (atlas->TexPixelsAlpha8 != NULL) - { - atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; - } - else - { - atlas->TexPixelsRGBA32[offset] = atlas->TexPixelsRGBA32[offset + 1] = atlas->TexPixelsRGBA32[offset + w] = atlas->TexPixelsRGBA32[offset + w + 1] = IM_COL32_WHITE; - } - } - else - { - // White pixels and mouse cursor + // Render/copy pixels IM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); const int x_for_white = r->X; const int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; @@ -3265,6 +3140,20 @@ static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', IM_COL32_WHITE); } } + else + { + // Render 4 white pixels + IM_ASSERT(r->Width == 2 && r->Height == 2); + const int offset = (int)r->X + (int)r->Y * w; + if (atlas->TexPixelsAlpha8 != NULL) + { + atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; + } + else + { + atlas->TexPixelsRGBA32[offset] = atlas->TexPixelsRGBA32[offset + 1] = atlas->TexPixelsRGBA32[offset + w] = atlas->TexPixelsRGBA32[offset + w + 1] = IM_COL32_WHITE; + } + } atlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y); } @@ -3276,38 +3165,38 @@ static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas) // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdLines); IM_ASSERT(r->IsPacked()); - for (int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row + for (unsigned int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row { // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle - int y = n; - int line_width = n; - int pad_left = (r->Width - line_width) / 2; - int pad_right = r->Width - (pad_left + line_width); + unsigned int y = n; + unsigned int line_width = n; + unsigned int pad_left = (r->Width - line_width) / 2; + unsigned int pad_right = r->Width - (pad_left + line_width); // Write each slice IM_ASSERT(pad_left + line_width + pad_right == r->Width && y < r->Height); // Make sure we're inside the texture bounds before we start writing pixels if (atlas->TexPixelsAlpha8 != NULL) { unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)]; - for (int i = 0; i < pad_left; i++) + for (unsigned int i = 0; i < pad_left; i++) *(write_ptr + i) = 0x00; - for (int i = 0; i < line_width; i++) + for (unsigned int i = 0; i < line_width; i++) *(write_ptr + pad_left + i) = 0xFF; - for (int i = 0; i < pad_right; i++) + for (unsigned int i = 0; i < pad_right; i++) *(write_ptr + pad_left + line_width + i) = 0x00; } else { unsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)]; - for (int i = 0; i < pad_left; i++) + for (unsigned int i = 0; i < pad_left; i++) *(write_ptr + i) = IM_COL32(255, 255, 255, 0); - for (int i = 0; i < line_width; i++) + for (unsigned int i = 0; i < line_width; i++) *(write_ptr + pad_left + i) = IM_COL32_WHITE; - for (int i = 0; i < pad_right; i++) + for (unsigned int i = 0; i < pad_right; i++) *(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0); } @@ -3322,6 +3211,13 @@ static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas) // Note: this is called / shared by both the stb_truetype and the FreeType builder void ImFontAtlasBuildInit(ImFontAtlas* atlas) { + // Round font size + // - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet. + // - Note that using io.FontGlobalScale or SetWindowFontScale(), with are legacy-ish, partially supported features, can still lead to unrounded sizes. + // - We may support it better later and remove this rounding. + for (ImFontConfig& cfg : atlas->ConfigData) + cfg.SizePixels = ImTrunc(cfg.SizePixels); + // Register texture region for mouse cursors or standard white pixels if (atlas->PackIdMouseCursors < 0) { @@ -3360,8 +3256,6 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas) ImVec2 uv0, uv1; atlas->CalcCustomRectUV(r, &uv0, &uv1); r->Font->AddGlyph(NULL, (ImWchar)r->GlyphID, r->GlyphOffset.x, r->GlyphOffset.y, r->GlyphOffset.x + r->Width, r->GlyphOffset.y + r->Height, uv0.x, uv0.y, uv1.x, uv1.y, r->GlyphAdvanceX); - if (r->GlyphColored) - r->Font->Glyphs.back().Colored = 1; } // Build all fonts lookup tables @@ -3372,20 +3266,6 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas) atlas->TexReady = true; } -//------------------------------------------------------------------------- -// [SECTION] ImFontAtlas: glyph ranges helpers -//------------------------------------------------------------------------- -// - GetGlyphRangesDefault() -// - GetGlyphRangesGreek() -// - GetGlyphRangesKorean() -// - GetGlyphRangesChineseFull() -// - GetGlyphRangesChineseSimplifiedCommon() -// - GetGlyphRangesJapanese() -// - GetGlyphRangesCyrillic() -// - GetGlyphRangesThai() -// - GetGlyphRangesVietnamese() -//----------------------------------------------------------------------------- - // Retrieve list of range (2 int per range, values are inclusive) const ImWchar* ImFontAtlas::GetGlyphRangesDefault() { @@ -3447,6 +3327,10 @@ static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* out_ranges[0] = 0; } +//------------------------------------------------------------------------- +// [SECTION] ImFontAtlas glyph ranges helpers +//------------------------------------------------------------------------- + const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() { // Store 2500 regularly used characters for Simplified Chinese. @@ -3693,8 +3577,8 @@ ImFont::ImFont() { FontSize = 0.0f; FallbackAdvanceX = 0.0f; - FallbackChar = 0; - EllipsisChar = 0; + FallbackChar = (ImWchar)-1; + EllipsisChar = (ImWchar)-1; EllipsisWidth = EllipsisCharStep = 0.0f; EllipsisCharCount = 0; FallbackGlyph = NULL; @@ -3705,7 +3589,7 @@ ImFont::ImFont() Scale = 1.0f; Ascent = Descent = 0.0f; MetricsTotalSurface = 0; - memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); + memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); } ImFont::~ImFont() @@ -3725,7 +3609,6 @@ void ImFont::ClearOutputData() DirtyLookupTables = true; Ascent = Descent = 0.0f; MetricsTotalSurface = 0; - memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); } static ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count) @@ -3733,7 +3616,7 @@ static ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_cha for (int n = 0; n < candidate_chars_count; n++) if (font->FindGlyphNoFallback(candidate_chars[n]) != NULL) return candidate_chars[n]; - return 0; + return (ImWchar)-1; } void ImFont::BuildLookupTable() @@ -3748,17 +3631,17 @@ void ImFont::BuildLookupTable() IndexAdvanceX.clear(); IndexLookup.clear(); DirtyLookupTables = false; - memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); + memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); GrowIndex(max_codepoint + 1); for (int i = 0; i < Glyphs.Size; i++) { int codepoint = (int)Glyphs[i].Codepoint; IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX; - IndexLookup[codepoint] = (ImU16)i; + IndexLookup[codepoint] = (ImWchar)i; // Mark 4K page as used - const int page_n = codepoint / 8192; - Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7); + const int page_n = codepoint / 4096; + Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7); } // Create a glyph to handle TAB @@ -3772,7 +3655,7 @@ void ImFont::BuildLookupTable() tab_glyph.Codepoint = '\t'; tab_glyph.AdvanceX *= IM_TABSIZE; IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX; - IndexLookup[(int)tab_glyph.Codepoint] = (ImU16)(Glyphs.Size - 1); + IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size - 1); } // Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons) @@ -3800,35 +3683,35 @@ void ImFont::BuildLookupTable() // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots. - const ImWchar ellipsis_chars[] = { ConfigData->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 }; + const ImWchar ellipsis_chars[] = { (ImWchar)0x2026, (ImWchar)0x0085 }; const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; - if (EllipsisChar == 0) + if (EllipsisChar == (ImWchar)-1) EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars)); const ImWchar dot_char = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars)); - if (EllipsisChar != 0) + if (EllipsisChar != (ImWchar)-1) { EllipsisCharCount = 1; EllipsisWidth = EllipsisCharStep = FindGlyph(EllipsisChar)->X1; } - else if (dot_char != 0) + else if (dot_char != (ImWchar)-1) { - const ImFontGlyph* dot_glyph = FindGlyph(dot_char); + const ImFontGlyph* glyph = FindGlyph(dot_char); EllipsisChar = dot_char; EllipsisCharCount = 3; - EllipsisCharStep = (float)(int)(dot_glyph->X1 - dot_glyph->X0) + 1.0f; - EllipsisWidth = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + EllipsisCharStep * 3.0f - 1.0f); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents. + EllipsisCharStep = (glyph->X1 - glyph->X0) + 1.0f; + EllipsisWidth = EllipsisCharStep * 3.0f - 1.0f; } } -// API is designed this way to avoid exposing the 8K page size +// API is designed this way to avoid exposing the 4K page size // e.g. use with IsGlyphRangeUnused(0, 255) bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last) { - unsigned int page_begin = (c_begin / 8192); - unsigned int page_last = (c_last / 8192); + unsigned int page_begin = (c_begin / 4096); + unsigned int page_last = (c_last / 4096); for (unsigned int page_n = page_begin; page_n <= page_last; page_n++) - if ((page_n >> 3) < sizeof(Used8kPagesMap)) - if (Used8kPagesMap[page_n >> 3] & (1 << (page_n & 7))) + if ((page_n >> 3) < sizeof(Used4kPagesMap)) + if (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7))) return false; return true; } @@ -3845,7 +3728,7 @@ void ImFont::GrowIndex(int new_size) if (new_size <= IndexLookup.Size) return; IndexAdvanceX.resize(new_size, -1.0f); - IndexLookup.resize(new_size, (ImU16)-1); + IndexLookup.resize(new_size, (ImWchar)-1); } // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. @@ -3873,9 +3756,8 @@ void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, floa advance_x += cfg->GlyphExtraSpacing.x; } - int glyph_idx = Glyphs.Size; Glyphs.resize(Glyphs.Size + 1); - ImFontGlyph& glyph = Glyphs[glyph_idx]; + ImFontGlyph& glyph = Glyphs.back(); glyph.Codepoint = (unsigned int)codepoint; glyph.Visible = (x0 != x1) && (y0 != y1); glyph.Colored = false; @@ -3888,7 +3770,6 @@ void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, floa glyph.U1 = u1; glyph.V1 = v1; glyph.AdvanceX = advance_x; - IM_ASSERT(Glyphs.Size < 0xFFFF); // IndexLookup[] hold 16-bit values and -1 is reserved. // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round) // We use (U1-U0)*TexWidth instead of X1-X0 to account for oversampling. @@ -3902,38 +3783,37 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. unsigned int index_size = (unsigned int)IndexLookup.Size; - if (dst < index_size && IndexLookup.Data[dst] == (ImU16)-1 && !overwrite_dst) // 'dst' already exists + if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists return; if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op return; GrowIndex(dst + 1); - IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImU16)-1; + IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImWchar)-1; IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f; } -// Find glyph, return fallback if missing -const ImFontGlyph* ImFont::FindGlyph(ImWchar c) +const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const { if (c >= (size_t)IndexLookup.Size) return FallbackGlyph; - const ImU16 i = IndexLookup.Data[c]; - if (i == (ImU16)-1) + const ImWchar i = IndexLookup.Data[c]; + if (i == (ImWchar)-1) return FallbackGlyph; return &Glyphs.Data[i]; } -const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) +const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const { if (c >= (size_t)IndexLookup.Size) return NULL; - const ImU16 i = IndexLookup.Data[c]; - if (i == (ImU16)-1) + const ImWchar i = IndexLookup.Data[c]; + if (i == (ImWchar)-1) return NULL; return &Glyphs.Data[i]; } -// Trim trailing space and find beginning of next line +// Wrapping skips upcoming blanks static inline const char* CalcWordWrapNextLineStartA(const char* text, const char* text_end) { while (text < text_end && ImCharIsBlankA(*text)) @@ -3943,12 +3823,10 @@ static inline const char* CalcWordWrapNextLineStartA(const char* text, const cha return text; } -#define ImFontGetCharAdvanceX(_FONT, _CH) ((int)(_CH) < (_FONT)->IndexAdvanceX.Size ? (_FONT)->IndexAdvanceX.Data[_CH] : (_FONT)->FallbackAdvanceX) - // Simple word-wrapping for English, not full-featured. Please submit failing cases! // This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end. // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) -const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) +const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const { // For references, possible wrap point marked with ^ // "aaa bbb, ccc,ddd. eee fff. ggg!" @@ -3997,7 +3875,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c } } - const float char_width = ImFontGetCharAdvanceX(this, c); + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX); if (ImCharIsBlankW(c)) { if (inside_word) @@ -4046,7 +3924,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c return s; } -ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) +ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const { if (!text_end) text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this. @@ -4102,7 +3980,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons continue; } - const float char_width = ImFontGetCharAdvanceX(this, c) * scale; + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale; if (line_width + char_width >= max_width) { s = prev_s; @@ -4125,7 +4003,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons } // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. -void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) +void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) const { const ImFontGlyph* glyph = FindGlyph(c); if (!glyph || !glyph->Visible) @@ -4140,20 +4018,20 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, Im } // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. -void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) +void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const { + if (!text_end) + text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. + // Align to be pixel perfect float x = IM_TRUNC(pos.x); float y = IM_TRUNC(pos.y); if (y > clip_rect.w) return; - if (!text_end) - text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. - + const float start_x = x; const float scale = size / FontSize; const float line_height = FontSize * scale; - const float origin_x = x; const bool word_wrap_enabled = (wrap_width > 0.0f); // Fast-forward to first visible line @@ -4212,11 +4090,11 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im { // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. if (!word_wrap_eol) - word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - origin_x)); + word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - start_x)); if (s >= word_wrap_eol) { - x = origin_x; + x = start_x; y += line_height; if (y > clip_rect.w) break; // break out of main loop @@ -4237,7 +4115,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im { if (c == '\n') { - x = origin_x; + x = start_x; y += line_height; if (y > clip_rect.w) break; // break out of main loop @@ -4680,187 +4558,101 @@ static unsigned int stb_decompress(unsigned char *output, const unsigned char *i // MIT license (see License.txt in http://www.proggyfonts.net/index.php?menu=download) // Download and more information at http://www.proggyfonts.net or http://upperboundsinteractive.com/fonts.php //----------------------------------------------------------------------------- - -#ifndef IMGUI_DISABLE_DEFAULT_FONT - // File: 'ProggyClean.ttf' (41208 bytes) -// Exported using binary_to_compressed_c.exe -u8 "ProggyClean.ttf" proggy_clean_ttf -static const unsigned int proggy_clean_ttf_compressed_size = 9583; -static const unsigned char proggy_clean_ttf_compressed_data[9583] = -{ - 87,188,0,0,0,0,0,0,0,0,160,248,0,4,0,0,55,0,1,0,0,0,12,0,128,0,3,0,64,79,83,47,50,136,235,116,144,0,0,1,72,130,21,44,78,99,109,97,112,2,18,35,117,0,0,3,160,130,19,36,82,99,118,116, - 32,130,23,130,2,33,4,252,130,4,56,2,103,108,121,102,18,175,137,86,0,0,7,4,0,0,146,128,104,101,97,100,215,145,102,211,130,27,32,204,130,3,33,54,104,130,16,39,8,66,1,195,0,0,1,4,130, - 15,59,36,104,109,116,120,138,0,126,128,0,0,1,152,0,0,2,6,108,111,99,97,140,115,176,216,0,0,5,130,30,41,2,4,109,97,120,112,1,174,0,218,130,31,32,40,130,16,44,32,110,97,109,101,37,89, - 187,150,0,0,153,132,130,19,44,158,112,111,115,116,166,172,131,239,0,0,155,36,130,51,44,210,112,114,101,112,105,2,1,18,0,0,4,244,130,47,32,8,132,203,46,1,0,0,60,85,233,213,95,15,60, - 245,0,3,8,0,131,0,34,183,103,119,130,63,43,0,0,189,146,166,215,0,0,254,128,3,128,131,111,130,241,33,2,0,133,0,32,1,130,65,38,192,254,64,0,0,3,128,131,16,130,5,32,1,131,7,138,3,33,2, - 0,130,17,36,1,1,0,144,0,130,121,130,23,38,2,0,8,0,64,0,10,130,9,32,118,130,9,130,6,32,0,130,59,33,1,144,131,200,35,2,188,2,138,130,16,32,143,133,7,37,1,197,0,50,2,0,131,0,33,4,9,131, - 5,145,3,43,65,108,116,115,0,64,0,0,32,172,8,0,131,0,35,5,0,1,128,131,77,131,3,33,3,128,191,1,33,1,128,130,184,35,0,0,128,0,130,3,131,11,32,1,130,7,33,0,128,131,1,32,1,136,9,32,0,132, - 15,135,5,32,1,131,13,135,27,144,35,32,1,149,25,131,21,32,0,130,0,32,128,132,103,130,35,132,39,32,0,136,45,136,97,133,17,130,5,33,0,0,136,19,34,0,128,1,133,13,133,5,32,128,130,15,132, - 131,32,3,130,5,32,3,132,27,144,71,32,0,133,27,130,29,130,31,136,29,131,63,131,3,65,63,5,132,5,132,205,130,9,33,0,0,131,9,137,119,32,3,132,19,138,243,130,55,32,1,132,35,135,19,131,201, - 136,11,132,143,137,13,130,41,32,0,131,3,144,35,33,128,0,135,1,131,223,131,3,141,17,134,13,136,63,134,15,136,53,143,15,130,96,33,0,3,131,4,130,3,34,28,0,1,130,5,34,0,0,76,130,17,131, - 9,36,28,0,4,0,48,130,17,46,8,0,8,0,2,0,0,0,127,0,255,32,172,255,255,130,9,34,0,0,129,132,9,130,102,33,223,213,134,53,132,22,33,1,6,132,6,64,4,215,32,129,165,216,39,177,0,1,141,184, - 1,255,133,134,45,33,198,0,193,1,8,190,244,1,28,1,158,2,20,2,136,2,252,3,20,3,88,3,156,3,222,4,20,4,50,4,80,4,98,4,162,5,22,5,102,5,188,6,18,6,116,6,214,7,56,7,126,7,236,8,78,8,108, - 8,150,8,208,9,16,9,74,9,136,10,22,10,128,11,4,11,86,11,200,12,46,12,130,12,234,13,94,13,164,13,234,14,80,14,150,15,40,15,176,16,18,16,116,16,224,17,82,17,182,18,4,18,110,18,196,19, - 76,19,172,19,246,20,88,20,174,20,234,21,64,21,128,21,166,21,184,22,18,22,126,22,198,23,52,23,142,23,224,24,86,24,186,24,238,25,54,25,150,25,212,26,72,26,156,26,240,27,92,27,200,28, - 4,28,76,28,150,28,234,29,42,29,146,29,210,30,64,30,142,30,224,31,36,31,118,31,166,31,166,32,16,130,1,52,46,32,138,32,178,32,200,33,20,33,116,33,152,33,238,34,98,34,134,35,12,130,1, - 33,128,35,131,1,60,152,35,176,35,216,36,0,36,74,36,104,36,144,36,174,37,6,37,96,37,130,37,248,37,248,38,88,38,170,130,1,8,190,216,39,64,39,154,40,10,40,104,40,168,41,14,41,32,41,184, - 41,248,42,54,42,96,42,96,43,2,43,42,43,94,43,172,43,230,44,32,44,52,44,154,45,40,45,92,45,120,45,170,45,232,46,38,46,166,47,38,47,182,47,244,48,94,48,200,49,62,49,180,50,30,50,158, - 51,30,51,130,51,238,52,92,52,206,53,58,53,134,53,212,54,38,54,114,54,230,55,118,55,216,56,58,56,166,57,18,57,116,57,174,58,46,58,154,59,6,59,124,59,232,60,58,60,150,61,34,61,134,61, - 236,62,86,62,198,63,42,63,154,64,18,64,106,64,208,65,54,65,162,66,8,66,64,66,122,66,184,66,240,67,98,67,204,68,42,68,138,68,238,69,88,69,182,69,226,70,84,70,180,71,20,71,122,71,218, - 72,84,72,198,73,64,0,36,70,21,8,8,77,3,0,7,0,11,0,15,0,19,0,23,0,27,0,31,0,35,0,39,0,43,0,47,0,51,0,55,0,59,0,63,0,67,0,71,0,75,0,79,0,83,0,87,0,91,0,95,0,99,0,103,0,107,0,111,0,115, - 0,119,0,123,0,127,0,131,0,135,0,139,0,143,0,0,17,53,51,21,49,150,3,32,5,130,23,32,33,130,3,211,7,151,115,32,128,133,0,37,252,128,128,2,128,128,190,5,133,74,32,4,133,6,206,5,42,0,7, - 1,128,0,0,2,0,4,0,0,65,139,13,37,0,1,53,51,21,7,146,3,32,3,130,19,32,1,141,133,32,3,141,14,131,13,38,255,0,128,128,0,6,1,130,84,35,2,128,4,128,140,91,132,89,32,51,65,143,6,139,7,33, - 1,0,130,57,32,254,130,3,32,128,132,4,32,4,131,14,138,89,35,0,0,24,0,130,0,33,3,128,144,171,66,55,33,148,115,65,187,19,32,5,130,151,143,155,163,39,32,1,136,182,32,253,134,178,132,7, - 132,200,145,17,32,3,65,48,17,165,17,39,0,0,21,0,128,255,128,3,65,175,17,65,3,27,132,253,131,217,139,201,155,233,155,27,131,67,131,31,130,241,33,255,0,131,181,137,232,132,15,132,4,138, - 247,34,255,0,128,179,238,32,0,130,0,32,20,65,239,48,33,0,19,67,235,10,32,51,65,203,14,65,215,11,32,7,154,27,135,39,32,33,130,35,33,128,128,130,231,32,253,132,231,32,128,132,232,34, - 128,128,254,133,13,136,8,32,253,65,186,5,130,36,130,42,176,234,133,231,34,128,0,0,66,215,44,33,0,1,68,235,6,68,211,19,32,49,68,239,14,139,207,139,47,66,13,7,32,51,130,47,33,1,0,130, - 207,35,128,128,1,0,131,222,131,5,130,212,130,6,131,212,32,0,130,10,133,220,130,233,130,226,32,254,133,255,178,233,39,3,1,128,3,0,2,0,4,68,15,7,68,99,12,130,89,130,104,33,128,4,133, - 93,130,10,38,0,0,11,1,0,255,0,68,63,16,70,39,9,66,215,8,32,7,68,77,6,68,175,14,32,29,68,195,6,132,7,35,2,0,128,255,131,91,132,4,65,178,5,141,111,67,129,23,165,135,140,107,142,135,33, - 21,5,69,71,6,131,7,33,1,0,140,104,132,142,130,4,137,247,140,30,68,255,12,39,11,0,128,0,128,3,0,3,69,171,15,67,251,7,65,15,8,66,249,11,65,229,7,67,211,7,66,13,7,35,1,128,128,254,133, - 93,32,254,131,145,132,4,132,18,32,2,151,128,130,23,34,0,0,9,154,131,65,207,8,68,107,15,68,51,7,32,7,70,59,7,135,121,130,82,32,128,151,111,41,0,0,4,0,128,255,0,1,128,1,137,239,33,0, - 37,70,145,10,65,77,10,65,212,14,37,0,0,0,5,0,128,66,109,5,70,123,10,33,0,19,72,33,18,133,237,70,209,11,33,0,2,130,113,137,119,136,115,33,1,0,133,43,130,5,34,0,0,10,69,135,6,70,219, - 13,66,155,7,65,9,12,66,157,11,66,9,11,32,7,130,141,132,252,66,151,9,137,9,66,15,30,36,0,20,0,128,0,130,218,71,11,42,68,51,8,65,141,7,73,19,15,69,47,23,143,39,66,81,7,32,1,66,55,6,34, - 1,128,128,68,25,5,69,32,6,137,6,136,25,32,254,131,42,32,3,66,88,26,148,26,32,0,130,0,32,14,164,231,70,225,12,66,233,7,67,133,19,71,203,15,130,161,32,255,130,155,32,254,139,127,134, - 12,164,174,33,0,15,164,159,33,59,0,65,125,20,66,25,7,32,5,68,191,6,66,29,7,144,165,65,105,9,35,128,128,255,0,137,2,133,182,164,169,33,128,128,197,171,130,155,68,235,7,32,21,70,77,19, - 66,21,10,68,97,8,66,30,5,66,4,43,34,0,17,0,71,19,41,65,253,20,71,25,23,65,91,15,65,115,7,34,2,128,128,66,9,8,130,169,33,1,0,66,212,13,132,28,72,201,43,35,0,0,0,18,66,27,38,76,231,5, - 68,157,20,135,157,32,7,68,185,13,65,129,28,66,20,5,32,253,66,210,11,65,128,49,133,61,32,0,65,135,6,74,111,37,72,149,12,66,203,19,65,147,19,68,93,7,68,85,8,76,4,5,33,255,0,133,129,34, - 254,0,128,68,69,8,181,197,34,0,0,12,65,135,32,65,123,20,69,183,27,133,156,66,50,5,72,87,10,67,137,32,33,0,19,160,139,78,251,13,68,55,20,67,119,19,65,91,36,69,177,15,32,254,143,16,65, - 98,53,32,128,130,0,32,0,66,43,54,70,141,23,66,23,15,131,39,69,47,11,131,15,70,129,19,74,161,9,36,128,255,0,128,254,130,153,65,148,32,67,41,9,34,0,0,4,79,15,5,73,99,10,71,203,8,32,3, - 72,123,6,72,43,8,32,2,133,56,131,99,130,9,34,0,0,6,72,175,5,73,159,14,144,63,135,197,132,189,133,66,33,255,0,73,6,7,70,137,12,35,0,0,0,10,130,3,73,243,25,67,113,12,65,73,7,69,161,7, - 138,7,37,21,2,0,128,128,254,134,3,73,116,27,33,128,128,130,111,39,12,0,128,1,0,3,128,2,72,219,21,35,43,0,47,0,67,47,20,130,111,33,21,1,68,167,13,81,147,8,133,230,32,128,77,73,6,32, - 128,131,142,134,18,130,6,32,255,75,18,12,131,243,37,128,0,128,3,128,3,74,231,21,135,123,32,29,134,107,135,7,32,21,74,117,7,135,7,134,96,135,246,74,103,23,132,242,33,0,10,67,151,28, - 67,133,20,66,141,11,131,11,32,3,77,71,6,32,128,130,113,32,1,81,4,6,134,218,66,130,24,131,31,34,0,26,0,130,0,77,255,44,83,15,11,148,155,68,13,7,32,49,78,231,18,79,7,11,73,243,11,32, - 33,65,187,10,130,63,65,87,8,73,239,19,35,0,128,1,0,131,226,32,252,65,100,6,32,128,139,8,33,1,0,130,21,32,253,72,155,44,73,255,20,32,128,71,67,8,81,243,39,67,15,20,74,191,23,68,121, - 27,32,1,66,150,6,32,254,79,19,11,131,214,32,128,130,215,37,2,0,128,253,0,128,136,5,65,220,24,147,212,130,210,33,0,24,72,219,42,84,255,13,67,119,16,69,245,19,72,225,19,65,3,15,69,93, - 19,131,55,132,178,71,115,14,81,228,6,142,245,33,253,0,132,43,172,252,65,16,11,75,219,8,65,219,31,66,223,24,75,223,10,33,29,1,80,243,10,66,175,8,131,110,134,203,133,172,130,16,70,30, - 7,164,183,130,163,32,20,65,171,48,65,163,36,65,143,23,65,151,19,65,147,13,65,134,17,133,17,130,216,67,114,5,164,217,65,137,12,72,147,48,79,71,19,74,169,22,80,251,8,65,173,7,66,157, - 15,74,173,15,32,254,65,170,8,71,186,45,72,131,6,77,143,40,187,195,152,179,65,123,38,68,215,57,68,179,15,65,85,7,69,187,14,32,21,66,95,15,67,19,25,32,1,83,223,6,32,2,76,240,7,77,166, - 43,65,8,5,130,206,32,0,67,39,54,143,167,66,255,19,82,193,11,151,47,85,171,5,67,27,17,132,160,69,172,11,69,184,56,66,95,6,33,12,1,130,237,32,2,68,179,27,68,175,16,80,135,15,72,55,7, - 71,87,12,73,3,12,132,12,66,75,32,76,215,5,169,139,147,135,148,139,81,12,12,81,185,36,75,251,7,65,23,27,76,215,9,87,165,12,65,209,15,72,157,7,65,245,31,32,128,71,128,6,32,1,82,125,5, - 34,0,128,254,131,169,32,254,131,187,71,180,9,132,27,32,2,88,129,44,32,0,78,47,40,65,79,23,79,171,14,32,21,71,87,8,72,15,14,65,224,33,130,139,74,27,62,93,23,7,68,31,7,75,27,7,139,15, - 74,3,7,74,23,27,65,165,11,65,177,15,67,123,5,32,1,130,221,32,252,71,96,5,74,12,12,133,244,130,25,34,1,0,128,130,2,139,8,93,26,8,65,9,32,65,57,14,140,14,32,0,73,79,67,68,119,11,135, - 11,32,51,90,75,14,139,247,65,43,7,131,19,139,11,69,159,11,65,247,6,36,1,128,128,253,0,90,71,9,33,1,0,132,14,32,128,89,93,14,69,133,6,130,44,131,30,131,6,65,20,56,33,0,16,72,179,40, - 75,47,12,65,215,19,74,95,19,65,43,11,131,168,67,110,5,75,23,17,69,106,6,75,65,5,71,204,43,32,0,80,75,47,71,203,15,159,181,68,91,11,67,197,7,73,101,13,68,85,6,33,128,128,130,214,130, - 25,32,254,74,236,48,130,194,37,0,18,0,128,255,128,77,215,40,65,139,64,32,51,80,159,10,65,147,39,130,219,84,212,43,130,46,75,19,97,74,33,11,65,201,23,65,173,31,33,1,0,79,133,6,66,150, - 5,67,75,48,85,187,6,70,207,37,32,71,87,221,13,73,163,14,80,167,15,132,15,83,193,19,82,209,8,78,99,9,72,190,11,77,110,49,89,63,5,80,91,35,99,63,32,70,235,23,81,99,10,69,148,10,65,110, - 36,32,0,65,99,47,95,219,11,68,171,51,66,87,7,72,57,7,74,45,17,143,17,65,114,50,33,14,0,65,111,40,159,195,98,135,15,35,7,53,51,21,100,78,9,95,146,16,32,254,82,114,6,32,128,67,208,37, - 130,166,99,79,58,32,17,96,99,14,72,31,19,72,87,31,82,155,7,67,47,14,32,21,131,75,134,231,72,51,17,72,78,8,133,8,80,133,6,33,253,128,88,37,9,66,124,36,72,65,12,134,12,71,55,43,66,139, - 27,85,135,10,91,33,12,65,35,11,66,131,11,71,32,8,90,127,6,130,244,71,76,11,168,207,33,0,12,66,123,32,32,0,65,183,15,68,135,11,66,111,7,67,235,11,66,111,15,32,254,97,66,12,160,154,67, - 227,52,80,33,15,87,249,15,93,45,31,75,111,12,93,45,11,77,99,9,160,184,81,31,12,32,15,98,135,30,104,175,7,77,249,36,69,73,15,78,5,12,32,254,66,151,19,34,128,128,4,87,32,12,149,35,133, - 21,96,151,31,32,19,72,35,5,98,173,15,143,15,32,21,143,99,158,129,33,0,0,65,35,52,65,11,15,147,15,98,75,11,33,1,0,143,151,132,15,32,254,99,200,37,132,43,130,4,39,0,10,0,128,1,128,3, - 0,104,151,14,97,187,20,69,131,15,67,195,11,87,227,7,33,128,128,132,128,33,254,0,68,131,9,65,46,26,42,0,0,0,7,0,0,255,128,3,128,0,88,223,15,33,0,21,89,61,22,66,209,12,65,2,12,37,0,2, - 1,0,3,128,101,83,8,36,0,1,53,51,29,130,3,34,21,1,0,66,53,8,32,0,68,215,6,100,55,25,107,111,9,66,193,11,72,167,8,73,143,31,139,31,33,1,0,131,158,32,254,132,5,33,253,128,65,16,9,133, - 17,89,130,25,141,212,33,0,0,93,39,8,90,131,25,93,39,14,66,217,6,106,179,8,159,181,71,125,15,139,47,138,141,87,11,14,76,23,14,65,231,26,140,209,66,122,8,81,179,5,101,195,26,32,47,74, - 75,13,69,159,11,83,235,11,67,21,16,136,167,131,106,130,165,130,15,32,128,101,90,24,134,142,32,0,65,103,51,108,23,11,101,231,15,75,173,23,74,237,23,66,15,6,66,46,17,66,58,17,65,105, - 49,66,247,55,71,179,12,70,139,15,86,229,7,84,167,15,32,1,95,72,12,89,49,6,33,128,128,65,136,38,66,30,9,32,0,100,239,7,66,247,29,70,105,20,65,141,19,69,81,15,130,144,32,128,83,41,5, - 32,255,131,177,68,185,5,133,126,65,97,37,32,0,130,0,33,21,0,130,55,66,195,28,67,155,13,34,79,0,83,66,213,13,73,241,19,66,59,19,65,125,11,135,201,66,249,16,32,128,66,44,11,66,56,17, - 68,143,8,68,124,38,67,183,12,96,211,9,65,143,29,112,171,5,32,0,68,131,63,34,33,53,51,71,121,11,32,254,98,251,16,32,253,74,231,10,65,175,37,133,206,37,0,0,8,1,0,0,107,123,11,113,115, - 9,33,0,1,130,117,131,3,73,103,7,66,51,18,66,44,5,133,75,70,88,5,32,254,65,39,12,68,80,9,34,12,0,128,107,179,28,68,223,6,155,111,86,147,15,32,2,131,82,141,110,33,254,0,130,15,32,4,103, - 184,15,141,35,87,176,5,83,11,5,71,235,23,114,107,11,65,189,16,70,33,15,86,153,31,135,126,86,145,30,65,183,41,32,0,130,0,32,10,65,183,24,34,35,0,39,67,85,9,65,179,15,143,15,33,1,0,65, - 28,17,157,136,130,123,32,20,130,3,32,0,97,135,24,115,167,19,80,71,12,32,51,110,163,14,78,35,19,131,19,155,23,77,229,8,78,9,17,151,17,67,231,46,94,135,8,73,31,31,93,215,56,82,171,25, - 72,77,8,162,179,169,167,99,131,11,69,85,19,66,215,15,76,129,13,68,115,22,72,79,35,67,113,5,34,0,0,19,70,31,46,65,89,52,73,223,15,85,199,33,95,33,8,132,203,73,29,32,67,48,16,177,215, - 101,13,15,65,141,43,69,141,15,75,89,5,70,0,11,70,235,21,178,215,36,10,0,128,0,0,71,207,24,33,0,19,100,67,6,80,215,11,66,67,7,80,43,12,71,106,7,80,192,5,65,63,5,66,217,26,33,0,13,156, - 119,68,95,5,72,233,12,134,129,85,81,11,76,165,20,65,43,8,73,136,8,75,10,31,38,128,128,0,0,0,13,1,130,4,32,3,106,235,29,114,179,12,66,131,23,32,7,77,133,6,67,89,12,131,139,116,60,9, - 89,15,37,32,0,74,15,7,103,11,22,65,35,5,33,55,0,93,81,28,67,239,23,78,85,5,107,93,14,66,84,17,65,193,26,74,183,10,66,67,34,143,135,79,91,15,32,7,117,111,8,75,56,9,84,212,9,154,134, - 32,0,130,0,32,18,130,3,70,171,41,83,7,16,70,131,19,84,191,15,84,175,19,84,167,30,84,158,12,154,193,68,107,15,33,0,0,65,79,42,65,71,7,73,55,7,118,191,16,83,180,9,32,255,76,166,9,154, - 141,32,0,130,0,69,195,52,65,225,15,151,15,75,215,31,80,56,10,68,240,17,100,32,9,70,147,39,65,93,12,71,71,41,92,85,15,84,135,23,78,35,15,110,27,10,84,125,8,107,115,29,136,160,38,0,0, - 14,0,128,255,0,82,155,24,67,239,8,119,255,11,69,131,11,77,29,6,112,31,8,134,27,105,203,8,32,2,75,51,11,75,195,12,74,13,29,136,161,37,128,0,0,0,11,1,130,163,82,115,8,125,191,17,69,35, - 12,74,137,15,143,15,32,1,65,157,12,136,12,161,142,65,43,40,65,199,6,65,19,24,102,185,11,76,123,11,99,6,12,135,12,32,254,130,8,161,155,101,23,9,39,8,0,0,1,128,3,128,2,78,63,17,72,245, - 12,67,41,11,90,167,9,32,128,97,49,9,32,128,109,51,14,132,97,81,191,8,130,97,125,99,12,121,35,9,127,75,15,71,79,12,81,151,23,87,97,7,70,223,15,80,245,16,105,97,15,32,254,113,17,6,32, - 128,130,8,105,105,8,76,122,18,65,243,21,74,63,7,38,4,1,0,255,0,2,0,119,247,28,133,65,32,255,141,91,35,0,0,0,16,67,63,36,34,59,0,63,77,59,9,119,147,11,143,241,66,173,15,66,31,11,67, - 75,8,81,74,16,32,128,131,255,87,181,42,127,43,5,34,255,128,2,120,235,11,37,19,0,23,0,0,37,109,191,14,118,219,7,127,43,14,65,79,14,35,0,0,0,3,73,91,5,130,5,38,3,0,7,0,11,0,0,70,205, - 11,88,221,12,32,0,73,135,7,87,15,22,73,135,10,79,153,15,97,71,19,65,49,11,32,1,131,104,121,235,11,80,65,11,142,179,144,14,81,123,46,32,1,88,217,5,112,5,8,65,201,15,83,29,15,122,147, - 11,135,179,142,175,143,185,67,247,39,66,199,7,35,5,0,128,3,69,203,15,123,163,12,67,127,7,130,119,71,153,10,141,102,70,175,8,32,128,121,235,30,136,89,100,191,11,116,195,11,111,235,15, - 72,39,7,32,2,97,43,5,132,5,94,67,8,131,8,125,253,10,32,3,65,158,16,146,16,130,170,40,0,21,0,128,0,0,3,128,5,88,219,15,24,64,159,32,135,141,65,167,15,68,163,10,97,73,49,32,255,82,58, - 7,93,80,8,97,81,16,24,67,87,52,34,0,0,5,130,231,33,128,2,80,51,13,65,129,8,113,61,6,132,175,65,219,5,130,136,77,152,17,32,0,95,131,61,70,215,6,33,21,51,90,53,10,78,97,23,105,77,31, - 65,117,7,139,75,24,68,195,9,24,64,22,9,33,0,128,130,11,33,128,128,66,25,5,121,38,5,134,5,134,45,66,40,36,66,59,18,34,128,0,0,66,59,81,135,245,123,103,19,120,159,19,77,175,12,33,255, - 0,87,29,10,94,70,21,66,59,54,39,3,1,128,3,0,2,128,4,24,65,7,15,66,47,7,72,98,12,37,0,0,0,3,1,0,24,65,55,21,131,195,32,1,67,178,6,33,4,0,77,141,8,32,6,131,47,74,67,16,24,69,3,20,24, - 65,251,7,133,234,130,229,94,108,17,35,0,0,6,0,141,175,86,59,5,162,79,85,166,8,70,112,13,32,13,24,64,67,26,24,71,255,7,123,211,12,80,121,11,69,215,15,66,217,11,69,71,10,131,113,132, - 126,119,90,9,66,117,19,132,19,32,0,130,0,24,64,47,59,33,7,0,73,227,5,68,243,15,85,13,12,76,37,22,74,254,15,130,138,33,0,4,65,111,6,137,79,65,107,16,32,1,77,200,6,34,128,128,3,75,154, - 12,37,0,16,0,0,2,0,104,115,36,140,157,68,67,19,68,51,15,106,243,15,134,120,70,37,10,68,27,10,140,152,65,121,24,32,128,94,155,7,67,11,8,24,74,11,25,65,3,12,83,89,18,82,21,37,67,200, - 5,130,144,24,64,172,12,33,4,0,134,162,74,80,14,145,184,32,0,130,0,69,251,20,32,19,81,243,5,82,143,8,33,5,53,89,203,5,133,112,79,109,15,33,0,21,130,71,80,175,41,36,75,0,79,0,83,121, - 117,9,87,89,27,66,103,11,70,13,15,75,191,11,135,67,87,97,20,109,203,5,69,246,8,108,171,5,78,195,38,65,51,13,107,203,11,77,3,17,24,75,239,17,65,229,28,79,129,39,130,175,32,128,123,253, - 7,132,142,24,65,51,15,65,239,41,36,128,128,0,0,13,65,171,5,66,163,28,136,183,118,137,11,80,255,15,67,65,7,74,111,8,32,0,130,157,32,253,24,76,35,10,103,212,5,81,175,9,69,141,7,66,150, - 29,131,158,24,75,199,28,124,185,7,76,205,15,68,124,14,32,3,123,139,16,130,16,33,128,128,108,199,6,33,0,3,65,191,35,107,11,6,73,197,11,24,70,121,15,83,247,15,24,70,173,23,69,205,14, - 32,253,131,140,32,254,136,4,94,198,9,32,3,78,4,13,66,127,13,143,13,32,0,130,0,33,16,0,24,69,59,39,109,147,12,76,253,19,24,69,207,15,69,229,15,130,195,71,90,10,139,10,130,152,73,43, - 40,91,139,10,65,131,37,35,75,0,79,0,84,227,12,143,151,68,25,15,80,9,23,95,169,11,34,128,2,128,112,186,5,130,6,83,161,19,76,50,6,130,37,65,145,44,110,83,5,32,16,67,99,6,71,67,15,76, - 55,17,140,215,67,97,23,76,69,15,77,237,11,104,211,23,77,238,11,65,154,43,33,0,10,83,15,28,83,13,20,67,145,19,67,141,14,97,149,21,68,9,15,86,251,5,66,207,5,66,27,37,82,1,23,127,71,12, - 94,235,10,110,175,24,98,243,15,132,154,132,4,24,66,69,10,32,4,67,156,43,130,198,35,2,1,0,4,75,27,9,69,85,9,95,240,7,32,128,130,35,32,28,66,43,40,24,82,63,23,83,123,12,72,231,15,127, - 59,23,116,23,19,117,71,7,24,77,99,15,67,111,15,71,101,8,36,2,128,128,252,128,127,60,11,32,1,132,16,130,18,141,24,67,107,9,32,3,68,194,15,175,15,38,0,11,0,128,1,128,2,80,63,25,32,0, - 24,65,73,11,69,185,15,83,243,16,32,0,24,81,165,8,130,86,77,35,6,155,163,88,203,5,24,66,195,30,70,19,19,24,80,133,15,32,1,75,211,8,32,254,108,133,8,79,87,20,65,32,9,41,0,0,7,0,128,0, - 0,2,128,2,68,87,15,66,1,16,92,201,16,24,76,24,17,133,17,34,128,0,30,66,127,64,34,115,0,119,73,205,9,66,43,11,109,143,15,24,79,203,11,90,143,15,131,15,155,31,65,185,15,86,87,11,35,128, - 128,253,0,69,7,6,130,213,33,1,0,119,178,15,142,17,66,141,74,83,28,6,36,7,0,0,4,128,82,39,18,76,149,12,67,69,21,32,128,79,118,15,32,0,130,0,32,8,131,206,32,2,79,83,9,100,223,14,102, - 113,23,115,115,7,24,65,231,12,130,162,32,4,68,182,19,130,102,93,143,8,69,107,29,24,77,255,12,143,197,72,51,7,76,195,15,132,139,85,49,15,130,152,131,18,71,81,23,70,14,11,36,0,10,0,128, - 2,69,59,9,89,151,15,66,241,11,76,165,12,71,43,15,75,49,13,65,12,23,132,37,32,0,179,115,130,231,95,181,16,132,77,32,254,67,224,8,65,126,20,79,171,8,32,2,89,81,5,75,143,6,80,41,8,34, - 2,0,128,24,81,72,9,32,0,130,0,35,17,0,0,255,77,99,39,95,65,36,67,109,15,24,69,93,11,77,239,5,95,77,23,35,128,1,0,128,24,86,7,8,132,167,32,2,69,198,41,130,202,33,0,26,120,75,44,24,89, - 51,15,71,243,12,70,239,11,24,84,3,11,66,7,11,71,255,10,32,21,69,155,35,88,151,12,32,128,74,38,10,65,210,8,74,251,5,65,226,5,75,201,13,32,3,65,9,41,146,41,40,0,0,0,9,1,0,1,0,2,91,99, - 19,32,35,106,119,13,70,219,15,83,239,12,137,154,32,2,67,252,19,36,128,0,0,4,1,130,196,32,2,130,8,91,107,8,32,0,135,81,24,73,211,8,132,161,73,164,13,36,0,8,0,128,2,105,123,26,139,67, - 76,99,15,34,1,0,128,135,76,83,156,20,92,104,8,67,251,30,24,86,47,27,123,207,12,24,86,7,15,71,227,8,32,4,65,20,20,131,127,32,0,130,123,32,0,71,223,26,32,19,90,195,22,71,223,15,84,200, - 6,32,128,133,241,24,84,149,9,67,41,25,36,0,0,0,22,0,88,111,49,32,87,66,21,5,77,3,27,123,75,7,71,143,19,135,183,71,183,19,130,171,74,252,5,131,5,89,87,17,32,1,132,18,130,232,68,11,10, - 33,1,128,70,208,16,66,230,18,147,18,130,254,223,255,75,27,23,65,59,15,135,39,155,255,34,128,128,254,104,92,8,33,0,128,65,32,11,65,1,58,33,26,0,130,0,72,71,18,78,55,17,76,11,19,86,101, - 12,75,223,11,89,15,11,24,76,87,15,75,235,15,131,15,72,95,7,85,71,11,72,115,11,73,64,6,34,1,128,128,66,215,9,34,128,254,128,134,14,33,128,255,67,102,5,32,0,130,16,70,38,11,66,26,57, - 88,11,8,24,76,215,34,78,139,7,95,245,7,32,7,24,73,75,23,32,128,131,167,130,170,101,158,9,82,49,22,118,139,6,32,18,67,155,44,116,187,9,108,55,14,80,155,23,66,131,15,93,77,10,131,168, - 32,128,73,211,12,24,75,187,22,32,4,96,71,20,67,108,19,132,19,120,207,8,32,5,76,79,15,66,111,21,66,95,8,32,3,190,211,111,3,8,211,212,32,20,65,167,44,34,75,0,79,97,59,13,32,33,112,63, - 10,65,147,19,69,39,19,143,39,24,66,71,9,130,224,65,185,43,94,176,12,65,183,24,71,38,8,24,72,167,7,65,191,38,136,235,24,96,167,12,65,203,62,115,131,13,65,208,42,175,235,67,127,6,32, - 4,76,171,29,114,187,5,32,71,65,211,5,65,203,68,72,51,8,164,219,32,0,172,214,71,239,58,78,3,27,66,143,15,77,19,15,147,31,35,33,53,51,21,66,183,10,173,245,66,170,30,150,30,34,0,0,23, - 80,123,54,76,1,16,73,125,15,82,245,11,167,253,24,76,85,12,70,184,5,32,254,131,185,37,254,0,128,1,0,128,133,16,117,158,18,92,27,38,65,3,17,130,251,35,17,0,128,254,24,69,83,39,140,243, - 121,73,19,109,167,7,81,41,15,24,95,175,12,102,227,15,121,96,11,24,95,189,7,32,3,145,171,154,17,24,77,47,9,33,0,5,70,71,37,68,135,7,32,29,117,171,11,69,87,15,24,79,97,19,24,79,149,23, - 131,59,32,1,75,235,5,72,115,11,72,143,7,132,188,71,27,46,131,51,32,0,69,95,6,175,215,32,21,131,167,81,15,19,151,191,151,23,131,215,71,43,5,32,254,24,79,164,24,74,109,8,77,166,13,65, - 176,26,88,162,5,98,159,6,171,219,120,247,6,79,29,8,99,169,10,103,59,19,65,209,35,131,35,91,25,19,112,94,15,83,36,8,173,229,33,20,0,88,75,43,71,31,12,65,191,71,33,1,0,130,203,32,254, - 131,4,68,66,7,67,130,6,104,61,13,173,215,38,13,1,0,0,0,2,128,67,111,28,74,129,16,104,35,19,79,161,16,87,14,7,138,143,132,10,67,62,36,114,115,5,162,151,67,33,16,108,181,15,143,151,67, - 5,5,24,100,242,15,170,153,34,0,0,14,65,51,34,32,55,79,75,9,32,51,74,7,10,65,57,38,132,142,32,254,72,0,14,139,163,32,128,80,254,8,67,158,21,65,63,7,32,4,72,227,27,95,155,12,67,119,19, - 124,91,24,149,154,72,177,34,97,223,8,155,151,24,108,227,15,88,147,16,72,117,19,68,35,11,92,253,15,70,199,15,24,87,209,17,32,2,87,233,7,32,1,24,88,195,10,119,24,8,32,3,81,227,24,65, - 125,21,35,128,128,0,25,76,59,48,24,90,187,9,97,235,12,66,61,11,91,105,19,24,79,141,11,24,79,117,15,24,79,129,27,90,53,13,130,13,32,253,131,228,24,79,133,40,69,70,8,66,137,31,65,33, - 19,96,107,8,68,119,29,66,7,5,68,125,16,65,253,19,65,241,27,24,90,179,13,24,79,143,18,33,128,128,130,246,32,254,130,168,68,154,36,77,51,9,97,47,5,167,195,32,21,131,183,78,239,27,155, - 195,78,231,14,201,196,77,11,6,32,5,73,111,37,97,247,12,77,19,31,155,207,78,215,19,162,212,69,17,14,66,91,19,80,143,57,78,203,39,159,215,32,128,93,134,8,24,80,109,24,66,113,15,169,215, - 66,115,6,32,4,69,63,33,32,0,101,113,7,86,227,35,143,211,36,49,53,51,21,1,77,185,14,65,159,28,69,251,34,67,56,8,33,9,0,24,107,175,25,90,111,12,110,251,11,119,189,24,119,187,34,87,15, - 9,32,4,66,231,37,90,39,7,66,239,8,84,219,15,69,105,23,24,85,27,27,87,31,11,33,1,128,76,94,6,32,1,85,241,7,33,128,128,106,48,10,33,128,128,69,136,11,133,13,24,79,116,49,84,236,8,24, - 91,87,9,32,5,165,255,69,115,12,66,27,15,159,15,24,72,247,12,74,178,5,24,80,64,15,33,0,128,143,17,77,89,51,130,214,24,81,43,7,170,215,74,49,8,159,199,143,31,139,215,69,143,5,32,254, - 24,81,50,35,181,217,84,123,70,143,195,159,15,65,187,16,66,123,7,65,175,15,65,193,29,68,207,39,79,27,5,70,131,6,32,4,68,211,33,33,67,0,83,143,14,159,207,143,31,140,223,33,0,128,24,80, - 82,14,24,93,16,23,32,253,65,195,5,68,227,40,133,214,107,31,7,32,5,67,115,27,87,9,8,107,31,43,66,125,6,32,0,103,177,23,131,127,72,203,36,32,0,110,103,8,155,163,73,135,6,32,19,24,112, - 99,10,65,71,11,73,143,19,143,31,126,195,5,24,85,21,9,24,76,47,14,32,254,24,93,77,36,68,207,11,39,25,0,0,255,128,3,128,4,66,51,37,95,247,13,82,255,24,76,39,19,147,221,66,85,27,24,118, - 7,8,24,74,249,12,76,74,8,91,234,8,67,80,17,131,222,33,253,0,121,30,44,73,0,16,69,15,6,32,0,65,23,38,69,231,12,65,179,6,98,131,16,86,31,27,24,108,157,14,80,160,8,24,65,46,17,33,4,0, - 96,2,18,144,191,65,226,8,68,19,5,171,199,80,9,15,180,199,67,89,5,32,255,24,79,173,28,174,201,24,79,179,50,32,1,24,122,5,10,82,61,10,180,209,83,19,8,32,128,24,80,129,27,111,248,43,131, - 71,24,115,103,8,67,127,41,78,213,24,100,247,19,66,115,39,75,107,5,32,254,165,219,78,170,40,24,112,163,49,32,1,97,203,6,65,173,64,32,0,83,54,7,133,217,88,37,12,32,254,131,28,33,128, - 3,67,71,44,84,183,6,32,5,69,223,33,96,7,7,123,137,16,192,211,24,112,14,9,32,255,67,88,29,68,14,10,84,197,38,33,0,22,116,47,50,32,87,106,99,9,116,49,15,89,225,15,97,231,23,70,41,19, - 82,85,8,93,167,6,32,253,132,236,108,190,7,89,251,5,116,49,58,33,128,128,131,234,32,15,24,74,67,38,70,227,24,24,83,45,23,89,219,12,70,187,12,89,216,19,32,2,69,185,24,141,24,70,143,66, - 24,82,119,56,78,24,10,32,253,133,149,132,6,24,106,233,7,69,198,48,178,203,81,243,12,68,211,15,106,255,23,66,91,15,69,193,7,100,39,10,24,83,72,16,176,204,33,19,0,88,207,45,68,21,12, - 68,17,10,65,157,53,68,17,6,32,254,92,67,10,65,161,25,69,182,43,24,118,91,47,69,183,18,181,209,111,253,12,89,159,8,66,112,12,69,184,45,35,0,0,0,9,24,80,227,26,73,185,16,118,195,15,131, - 15,33,1,0,65,59,15,66,39,27,160,111,66,205,12,148,111,143,110,33,128,128,156,112,24,81,199,8,75,199,23,66,117,20,155,121,32,254,68,126,12,72,213,29,134,239,149,123,89,27,16,148,117, - 65,245,8,24,71,159,14,141,134,134,28,73,51,55,109,77,15,105,131,11,68,67,11,76,169,27,107,209,12,102,174,8,32,128,72,100,18,116,163,56,79,203,11,75,183,44,85,119,19,71,119,23,151,227, - 32,1,93,27,8,65,122,5,77,102,8,110,120,20,66,23,8,66,175,17,66,63,12,133,12,79,35,8,74,235,33,67,149,16,69,243,15,78,57,15,69,235,16,67,177,7,151,192,130,23,67,84,29,141,192,174,187, - 77,67,15,69,11,12,159,187,77,59,10,199,189,24,70,235,50,96,83,19,66,53,23,105,65,19,77,47,12,163,199,66,67,37,78,207,50,67,23,23,174,205,67,228,6,71,107,13,67,22,14,66,85,11,83,187, - 38,124,47,49,95,7,19,66,83,23,67,23,19,24,96,78,17,80,101,16,71,98,40,33,0,7,88,131,22,24,89,245,12,84,45,12,102,213,5,123,12,9,32,2,126,21,14,43,255,0,128,128,0,0,20,0,128,255,128, - 3,126,19,39,32,75,106,51,7,113,129,15,24,110,135,19,126,47,15,115,117,11,69,47,11,32,2,109,76,9,102,109,9,32,128,75,2,10,130,21,32,254,69,47,6,32,3,94,217,47,32,0,65,247,10,69,15,46, - 65,235,31,65,243,15,101,139,10,66,174,14,65,247,16,72,102,28,69,17,14,84,243,9,165,191,88,47,48,66,53,12,32,128,71,108,6,203,193,32,17,75,187,42,73,65,16,65,133,52,114,123,9,167,199, - 69,21,37,86,127,44,75,171,11,180,197,78,213,12,148,200,81,97,46,24,95,243,9,32,4,66,75,33,113,103,9,87,243,36,143,225,24,84,27,31,90,145,8,148,216,67,49,5,24,84,34,14,75,155,27,67, - 52,13,140,13,36,0,20,0,128,255,24,135,99,46,88,59,43,155,249,80,165,7,136,144,71,161,23,32,253,132,33,32,254,88,87,44,136,84,35,128,0,0,21,81,103,5,94,47,44,76,51,12,143,197,151,15, - 65,215,31,24,64,77,13,65,220,20,65,214,14,71,4,40,65,213,13,32,0,130,0,35,21,1,2,0,135,0,34,36,0,72,134,10,36,1,0,26,0,130,134,11,36,2,0,14,0,108,134,11,32,3,138,23,32,4,138,11,34, - 5,0,20,134,33,34,0,0,6,132,23,32,1,134,15,32,18,130,25,133,11,37,1,0,13,0,49,0,133,11,36,2,0,7,0,38,134,11,36,3,0,17,0,45,134,11,32,4,138,35,36,5,0,10,0,62,134,23,32,6,132,23,36,3, - 0,1,4,9,130,87,131,167,133,11,133,167,133,11,133,167,133,11,37,3,0,34,0,122,0,133,11,133,167,133,11,133,167,133,11,133,167,34,50,0,48,130,1,34,52,0,47,134,5,8,49,49,0,53,98,121,32, - 84,114,105,115,116,97,110,32,71,114,105,109,109,101,114,82,101,103,117,108,97,114,84,84,88,32,80,114,111,103,103,121,67,108,101,97,110,84,84,50,48,48,52,47,130,2,53,49,53,0,98,0,121, - 0,32,0,84,0,114,0,105,0,115,0,116,0,97,0,110,130,15,32,71,132,15,36,109,0,109,0,101,130,9,32,82,130,5,36,103,0,117,0,108,130,29,32,114,130,43,34,84,0,88,130,35,32,80,130,25,34,111, - 0,103,130,1,34,121,0,67,130,27,32,101,132,59,32,84,130,31,33,0,0,65,155,9,34,20,0,0,65,11,6,130,8,135,2,33,1,1,130,9,8,120,1,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,1,11,1,12,1,13,1,14, - 1,15,1,16,1,17,1,18,1,19,1,20,1,21,1,22,1,23,1,24,1,25,1,26,1,27,1,28,1,29,1,30,1,31,1,32,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,16,0,17,0,18,0,19,0,20,0,21,0, - 22,0,23,0,24,0,25,0,26,0,27,0,28,0,29,0,30,0,31,130,187,8,66,33,0,34,0,35,0,36,0,37,0,38,0,39,0,40,0,41,0,42,0,43,0,44,0,45,0,46,0,47,0,48,0,49,0,50,0,51,0,52,0,53,0,54,0,55,0,56,0, - 57,0,58,0,59,0,60,0,61,0,62,0,63,0,64,0,65,0,66,130,243,9,75,68,0,69,0,70,0,71,0,72,0,73,0,74,0,75,0,76,0,77,0,78,0,79,0,80,0,81,0,82,0,83,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,91,0, - 92,0,93,0,94,0,95,0,96,0,97,1,33,1,34,1,35,1,36,1,37,1,38,1,39,1,40,1,41,1,42,1,43,1,44,1,45,1,46,1,47,1,48,1,49,1,50,1,51,1,52,1,53,1,54,1,55,1,56,1,57,1,58,1,59,1,60,1,61,1,62,1, - 63,1,64,1,65,0,172,0,163,0,132,0,133,0,189,0,150,0,232,0,134,0,142,0,139,0,157,0,169,0,164,0,239,0,138,0,218,0,131,0,147,0,242,0,243,0,141,0,151,0,136,0,195,0,222,0,241,0,158,0,170, - 0,245,0,244,0,246,0,162,0,173,0,201,0,199,0,174,0,98,0,99,0,144,0,100,0,203,0,101,0,200,0,202,0,207,0,204,0,205,0,206,0,233,0,102,0,211,0,208,0,209,0,175,0,103,0,240,0,145,0,214,0, - 212,0,213,0,104,0,235,0,237,0,137,0,106,0,105,0,107,0,109,0,108,0,110,0,160,0,111,0,113,0,112,0,114,0,115,0,117,0,116,0,118,0,119,0,234,0,120,0,122,0,121,0,123,0,125,0,124,0,184,0, - 161,0,127,0,126,0,128,0,129,0,236,0,238,0,186,14,117,110,105,99,111,100,101,35,48,120,48,48,48,49,141,14,32,50,141,14,32,51,141,14,32,52,141,14,32,53,141,14,32,54,141,14,32,55,141, - 14,32,56,141,14,32,57,141,14,32,97,141,14,32,98,141,14,32,99,141,14,32,100,141,14,32,101,141,14,32,102,140,14,33,49,48,141,14,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49, - 141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,45,49,102,6,100,101,108,101,116,101,4,69,117,114, - 111,140,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236, - 32,56,141,236,32,56,141,236,32,56,65,220,13,32,57,65,220,13,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141, - 239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,35,57,102,0,0,5,250,72,249,98,247, -}; +// Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding). +// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. +//----------------------------------------------------------------------------- +static const char proggy_clean_ttf_compressed_data_base85[11980 + 1] = + "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/" + "2*>]b(MC;$jPfY.;h^`IWM9Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1=Ke$$'5F%)]0^#0X@U.a$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;--VsM.M0rJfLH2eTM`*oJMHRC`N" + "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`�j@'DbG&#^$PG.Ll+DNa&VZ>1i%h1S9u5o@YaaW$e+bROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc." + "x]Ip.PH^'/aqUO/$1WxLoW0[iLAw=4h(9.`G" + "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?Ggv:[7MI2k).'2($5FNP&EQ(,)" + "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#" + "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM" + "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu" + "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/" + "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[Ket`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO" + "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%" + "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$MhLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]" + "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et" + "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:" + "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VBpqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<-+k?'(^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M" + "D?@f&1'BW-)Ju#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(" + "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs" + "bIu)'Z,*[>br5fX^:FPAWr-m2KgLQ_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q" + "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aege0jT6'N#(q%.O=?2S]u*(m<-" + "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i" + "sZ88+dKQ)W6>J%CL`.d*(B`-n8D9oK-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P r+$%CE=68>K8r0=dSC%%(@p7" + ".m7jilQ02'0-VWAgTlGW'b)Tq7VT9q^*^$$.:&N@@" + "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*" + "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u" + "@-W$U%VEQ/,,>>#)D#%8cY#YZ?=,`Wdxu/ae&#" + "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$so8lKN%5/$(vdfq7+ebA#" + "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoFDoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8" + "6e%B/:=>)N4xeW.*wft-;$'58-ESqr#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#" + "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjLV#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#SfD07&6D@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5" + "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%" + "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;" + "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmLq9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:" + "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3$U4O]GKx'm9)b@p7YsvK3w^YR-" + "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*" + "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdFTi1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IXSsDiWP,##P`%/L-" + "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdFl*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj" + "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#$(>.Z-I&J(Q0Hd5Q%7Co-b`-cP)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8WlA2);Sa" + ">gXm8YB`1d@K#n]76-a$U,mF%Ul:#/'xoFM9QX-$.QN'>" + "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I" + "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-uW%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)" + "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo" + "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P" + "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*'IAO" + "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#" + ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T" + "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4" + "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#" + "/QHC#3^ZC#7jmC#;v)D#?,)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP" + "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp" + "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#"; -static const char* GetDefaultCompressedFontDataTTF(int* out_size) +static const char* GetDefaultCompressedFontDataTTFBase85() { - *out_size = proggy_clean_ttf_compressed_size; - return (const char*)proggy_clean_ttf_compressed_data; + return proggy_clean_ttf_compressed_data_base85; } -#endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT #endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/imgui_internal.h b/3rdparty/imgui/imgui_internal.h index dceaf60..0dcf20c 100644 --- a/3rdparty/imgui/imgui_internal.h +++ b/3rdparty/imgui/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.0 WIP // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. @@ -11,6 +11,7 @@ Index of this file: // [SECTION] Forward declarations // [SECTION] Context pointer // [SECTION] STB libraries includes +// [SECTION] Stack Layout includes // [SECTION] Macros // [SECTION] Generic helpers // [SECTION] ImDrawList support @@ -28,7 +29,6 @@ Index of this file: // [SECTION] Viewport support // [SECTION] Settings support // [SECTION] Localization support -// [SECTION] Error handling, State recovery support // [SECTION] Metrics, Debug tools // [SECTION] Generic context hooks // [SECTION] ImGuiContext (main imgui context) @@ -61,14 +61,6 @@ Index of this file: #if (defined __SSE__ || defined __x86_64__ || defined _M_X64 || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1))) && !defined(IMGUI_DISABLE_SSE) #define IMGUI_ENABLE_SSE #include -#if (defined __AVX__ || defined __SSE4_2__) -#define IMGUI_ENABLE_SSE4_2 -#include -#endif -#endif -// Emscripten has partial SSE 4.2 support where _mm_crc32_u32 is not available. See https://emscripten.org/docs/porting/simd.html#id11 and #8213 -#if defined(IMGUI_ENABLE_SSE4_2) && !defined(IMGUI_USE_LEGACY_CRC32_ADLER) && !defined(__EMSCRIPTEN__) -#define IMGUI_ENABLE_SSE4_2_CRC #endif // Visual Studio warnings @@ -90,18 +82,18 @@ Index of this file: #endif #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' #pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok, for ImFloor() -#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant -#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#pragma clang diagnostic ignored "-Wdouble-promotion" #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wmissing-noreturn" // warning: function 'xxx' could be declared with attribute 'noreturn' #pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access -#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #endif @@ -130,29 +122,20 @@ Index of this file: // [SECTION] Forward declarations //----------------------------------------------------------------------------- -// Utilities -// (other types which are not forwarded declared are: ImBitArray<>, ImSpan<>, ImSpanAllocator<>, ImPool<>, ImChunkStream<>) struct ImBitVector; // Store 1-bit per value struct ImRect; // An axis-aligned rectangle (2 points) -struct ImGuiTextIndex; // Maintain a line index for a text buffer. - -// ImDrawList/ImFontAtlas struct ImDrawDataBuilder; // Helper to build a ImDrawData instance struct ImDrawListSharedData; // Data shared between all ImDrawList instances - -// ImGui struct ImGuiBoxSelectState; // Box-selection state (currently used by multi-selection, could potentially be used by others) struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it struct ImGuiContext; // Main Dear ImGui context struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine struct ImGuiDataVarInfo; // Variable information (e.g. to access style variables from an enum) struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum -struct ImGuiDeactivatedItemData; // Data for IsItemDeactivated()/IsItemDeactivatedAfterEdit() function. struct ImGuiDockContext; // Docking system context struct ImGuiDockRequest; // Docking system dock/undock queued request struct ImGuiDockNode; // Docking system node (hold a list of Windows OR two child dock nodes) struct ImGuiDockNodeSettings; // Storage for a dock node in .ini file (we preserve those even if the associated dock node isn't active during the session) -struct ImGuiErrorRecoveryState; // Storage of stack sizes for error handling and recovery struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup() struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box struct ImGuiInputTextDeactivateData;// Short term storage to backup text of a deactivating InputText() while another is stealing active id @@ -161,7 +144,7 @@ struct ImGuiLocEntry; // A localization entry. struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only struct ImGuiMultiSelectState; // Multi-selection persistent state (for focused selection). struct ImGuiMultiSelectTempData; // Multi-selection temporary state (while traversing). -struct ImGuiNavItemData; // Result of a keyboard/gamepad directional navigation move query result +struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions struct ImGuiNextWindowData; // Storage for SetNextWindow** functions struct ImGuiNextItemData; // Storage for SetNextItem** functions @@ -169,6 +152,7 @@ struct ImGuiOldColumnData; // Storage data for a single column for lega struct ImGuiOldColumns; // Storage data for a columns set for legacy Columns() api struct ImGuiPopupData; // Storage for current popup stack struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file +struct ImGuiStackSizes; // Storage of stack sizes for debugging/asserting struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it struct ImGuiTabBar; // Storage for a tab bar struct ImGuiTabItem; // Storage for a tab item (within a tab bar) @@ -196,11 +180,10 @@ typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // E // Flags typedef int ImGuiActivateFlags; // -> enum ImGuiActivateFlags_ // Flags: for navigation/focus function (will be for ActivateItem() later) typedef int ImGuiDebugLogFlags; // -> enum ImGuiDebugLogFlags_ // Flags: for ShowDebugLogWindow(), g.DebugLogFlags -typedef int ImGuiFocusRequestFlags; // -> enum ImGuiFocusRequestFlags_ // Flags: for FocusWindow() +typedef int ImGuiFocusRequestFlags; // -> enum ImGuiFocusRequestFlags_ // Flags: for FocusWindow(); typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for g.LastItemData.StatusFlags typedef int ImGuiOldColumnFlags; // -> enum ImGuiOldColumnFlags_ // Flags: for BeginColumns() -typedef int ImGuiLogFlags; // -> enum ImGuiLogFlags_ // Flags: for LogBegin() text capturing function -typedef int ImGuiNavRenderCursorFlags; // -> enum ImGuiNavRenderCursorFlags_//Flags: for RenderNavCursor() +typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight() typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests typedef int ImGuiNextItemDataFlags; // -> enum ImGuiNextItemDataFlags_ // Flags: for SetNextItemXXX() functions typedef int ImGuiNextWindowDataFlags; // -> enum ImGuiNextWindowDataFlags_// Flags: for SetNextWindowXXX() functions @@ -211,6 +194,8 @@ typedef int ImGuiTooltipFlags; // -> enum ImGuiTooltipFlags_ // F typedef int ImGuiTypingSelectFlags; // -> enum ImGuiTypingSelectFlags_ // Flags: for GetTypingSelectRequest() typedef int ImGuiWindowRefreshFlags; // -> enum ImGuiWindowRefreshFlags_ // Flags: for SetNextWindowRefreshPolicy() +typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...); + //----------------------------------------------------------------------------- // [SECTION] Context pointer // See implementation of this variable in imgui.cpp for comments and details. @@ -220,6 +205,32 @@ typedef int ImGuiWindowRefreshFlags; // -> enum ImGuiWindowRefreshFlags_ // F extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #endif +//------------------------------------------------------------------------- +// [SECTION] STB libraries includes +//------------------------------------------------------------------------- + +namespace ImStb +{ + +#undef IMSTB_TEXTEDIT_STRING +#undef IMSTB_TEXTEDIT_CHARTYPE +#define IMSTB_TEXTEDIT_STRING ImGuiInputTextState +#define IMSTB_TEXTEDIT_CHARTYPE ImWchar +#define IMSTB_TEXTEDIT_GETWIDTH_NEWLINE (-1.0f) +#define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99 +#define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999 +#include "imstb_textedit.h" + +} // namespace ImStb + +//------------------------------------------------------------------------- +// [SECTION] Stack Layout includes +//------------------------------------------------------------------------- + +#if IMGUI_HAS_STACK_LAYOUT +# include "imgui_stacklayout_internal.h" +#endif + //----------------------------------------------------------------------------- // [SECTION] Macros //----------------------------------------------------------------------------- @@ -238,7 +249,11 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #endif // Debug Logging for ShowDebugLogWindow(). This is designed for relatively rare events so please don't spam. -#define IMGUI_DEBUG_LOG_ERROR(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventError) IMGUI_DEBUG_LOG(__VA_ARGS__); else g.DebugLogSkippedErrors++; } while (0) +#ifndef IMGUI_DISABLE_DEBUG_TOOLS +#define IMGUI_DEBUG_LOG(...) ImGui::DebugLog(__VA_ARGS__) +#else +#define IMGUI_DEBUG_LOG(...) ((void)0) +#endif #define IMGUI_DEBUG_LOG_ACTIVEID(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventActiveId) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_FOCUS(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFocus) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_POPUP(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) @@ -246,7 +261,6 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #define IMGUI_DEBUG_LOG_SELECTION(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_CLIPPER(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventClipper) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_IO(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) -#define IMGUI_DEBUG_LOG_FONT(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFont) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_INPUTROUTING(...) do{if (g.DebugLogFlags & ImGuiDebugLogFlags_EventInputRouting)IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_DOCKING(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventDocking) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_VIEWPORT(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventViewport) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) @@ -263,6 +277,12 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #define IM_ASSERT_PARANOID(_EXPR) #endif +// Error handling +// Down the line in some frameworks/languages we would like to have a way to redirect those to the programmer and recover from more faults. +#ifndef IM_ASSERT_USER_ERROR +#define IM_ASSERT_USER_ERROR(_EXP,_MSG) IM_ASSERT((_EXP) && _MSG) // Recoverable User Error +#endif + // Misc Macros #define IM_PI 3.14159265358979323846f #ifdef _WIN32 @@ -284,15 +304,6 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #define IM_FLOOR IM_TRUNC #endif -// Hint for branch prediction -#if (defined(__cplusplus) && (__cplusplus >= 202002L)) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 202002L)) -#define IM_LIKELY [[likely]] -#define IM_UNLIKELY [[unlikely]] -#else -#define IM_LIKELY -#define IM_UNLIKELY -#endif - // Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall #ifdef _MSC_VER #define IMGUI_CDECL __cdecl @@ -393,12 +404,11 @@ IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end IMGUI_API void ImStrTrimBlanks(char* str); // Remove leading and trailing blanks from a buffer. IMGUI_API const char* ImStrSkipBlank(const char* str); // Find first non-blank character. IMGUI_API int ImStrlenW(const ImWchar* str); // Computer string length (ImWchar string) -IMGUI_API const char* ImStrbol(const char* buf_mid_line, const char* buf_begin); // Find beginning-of-line +IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line (ImWchar string) IM_MSVC_RUNTIME_CHECKS_OFF static inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; } static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } -static inline bool ImCharIsXdigitA(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); } IM_MSVC_RUNTIME_CHECKS_RESTORE // Helpers: Formatting @@ -754,7 +764,6 @@ struct ImGuiTextIndex // Helper: ImGuiStorage IMGUI_API ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStoragePair* in_end, ImGuiID key); - //----------------------------------------------------------------------------- // [SECTION] ImDrawList support //----------------------------------------------------------------------------- @@ -785,13 +794,10 @@ IMGUI_API ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStorag #define IM_DRAWLIST_ARCFAST_SAMPLE_MAX IM_DRAWLIST_ARCFAST_TABLE_SIZE // Sample index _PathArcToFastEx() for 360 angle. // Data shared between all ImDrawList instances -// Conceptually this could have been called e.g. ImDrawListSharedContext -// Typically one ImGui context would create and maintain one of this. -// You may want to create your own instance of you try to ImDrawList completely without ImGui. In that case, watch out for future changes to this structure. +// You may want to create your own instance of this if you want to use ImDrawList completely without ImGui. In that case, watch out for future changes to this structure. struct IMGUI_API ImDrawListSharedData { ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas - const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas ImFont* Font; // Current/default font (optional, for simplified AddText overload) float FontSize; // Current/default font size (optional, for simplified AddText overload) float FontScale; // Current/default font scale (== FontSize / Font->FontSize) @@ -799,12 +805,15 @@ struct IMGUI_API ImDrawListSharedData float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) - ImVector TempBuffer; // Temporary write buffer - // Lookup tables + // [Internal] Temp write buffer + ImVector TempBuffer; + + // [Internal] Lookup tables ImVec2 ArcFastVtx[IM_DRAWLIST_ARCFAST_TABLE_SIZE]; // Sample points on the quarter of the circle. float ArcFastRadiusCutoff; // Cutoff radius after which arc drawing will fallback to slower PathArcTo() ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius before we calculate it dynamically (to avoid calculation overhead) + const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas ImDrawListSharedData(); void SetCircleTessellationMaxError(float max_error); @@ -847,7 +856,8 @@ struct ImGuiDataTypeInfo // Extend ImGuiDataType_ enum ImGuiDataTypePrivate_ { - ImGuiDataType_Pointer = ImGuiDataType_COUNT + 1, + ImGuiDataType_String = ImGuiDataType_COUNT + 1, + ImGuiDataType_Pointer, ImGuiDataType_ID, }; @@ -856,18 +866,16 @@ enum ImGuiDataTypePrivate_ //----------------------------------------------------------------------------- // Extend ImGuiItemFlags -// - input: PushItemFlag() manipulates g.CurrentItemFlags, g.NextItemData.ItemFlags, ItemAdd() calls may add extra flags too. -// - output: stored in g.LastItemData.ItemFlags +// - input: PushItemFlag() manipulates g.CurrentItemFlags, ItemAdd() calls may add extra flags. +// - output: stored in g.LastItemData.InFlags enum ImGuiItemFlagsPrivate_ { // Controlled by user - ImGuiItemFlags_Disabled = 1 << 10, // false // Disable interactions (DOES NOT affect visuals. DO NOT mix direct use of this with BeginDisabled(). See BeginDisabled()/EndDisabled() for full disable feature, and github #211). + ImGuiItemFlags_Disabled = 1 << 10, // false // Disable interactions (DOES NOT affect visuals, see BeginDisabled()/EndDisabled() for full disable feature, and github #211). ImGuiItemFlags_ReadOnly = 1 << 11, // false // [ALPHA] Allow hovering interactions but underlying value is not changed. ImGuiItemFlags_MixedValue = 1 << 12, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) ImGuiItemFlags_NoWindowHoverableCheck = 1 << 13, // false // Disable hoverable check in ItemHoverable() ImGuiItemFlags_AllowOverlap = 1 << 14, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame. - ImGuiItemFlags_NoNavDisableMouseHover = 1 << 15, // false // Nav keyboard/gamepad mode doesn't disable hover highlight (behave as if NavHighlightItemUnderNav==false). - ImGuiItemFlags_NoMarkEdited = 1 << 16, // false // Skip calling MarkItemEdited() // Controlled by widget code ImGuiItemFlags_Inputable = 1 << 20, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature. @@ -920,8 +928,9 @@ enum ImGuiInputTextFlagsPrivate_ { // [Internal] ImGuiInputTextFlags_Multiline = 1 << 26, // For internal use by InputTextMultiline() - ImGuiInputTextFlags_MergedItem = 1 << 27, // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match. - ImGuiInputTextFlags_LocalizeDecimalPoint= 1 << 28, // For internal use by InputScalar() and TempInputScalar() + ImGuiInputTextFlags_NoMarkEdited = 1 << 27, // For internal use by functions using InputText() before reformatting data + ImGuiInputTextFlags_MergedItem = 1 << 28, // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match. + ImGuiInputTextFlags_LocalizeDecimalPoint= 1 << 29, // For internal use by InputScalar() and TempInputScalar() }; // Extend ImGuiButtonFlags_ @@ -933,15 +942,15 @@ enum ImGuiButtonFlagsPrivate_ ImGuiButtonFlags_PressedOnRelease = 1 << 7, // return true on release (default requires click+release) ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8, // return true on double-click (default requires click+release) ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) - //ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat -> use ImGuiItemFlags_ButtonRepeat instead. + ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat ImGuiButtonFlags_FlattenChildren = 1 << 11, // allow interactions even if a child window is overlapping ImGuiButtonFlags_AllowOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable. - //ImGuiButtonFlags_DontClosePopups = 1 << 13, // disable automatically closing parent popup on press + ImGuiButtonFlags_DontClosePopups = 1 << 13, // disable automatically closing parent popup on press // [UNUSED] //ImGuiButtonFlags_Disabled = 1 << 14, // disable interactions -> use BeginDisabled() or ImGuiItemFlags_Disabled ImGuiButtonFlags_AlignTextBaseLine = 1 << 15, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine - ImGuiButtonFlags_NoKeyModsAllowed = 1 << 16, // disable mouse interaction if a key modifier is held + ImGuiButtonFlags_NoKeyModifiers = 1 << 16, // disable mouse interaction if a key modifier is held ImGuiButtonFlags_NoHoldingActiveId = 1 << 17, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) - ImGuiButtonFlags_NoNavFocus = 1 << 18, // don't override navigation focus when activated (FIXME: this is essentially used every time an item uses ImGuiItemFlags_NoNav, but because legacy specs don't requires LastItemData to be set ButtonBehavior(), we can't poll g.LastItemData.ItemFlags) + ImGuiButtonFlags_NoNavFocus = 1 << 18, // don't override navigation focus when activated (FIXME: this is essentially used every time an item uses ImGuiItemFlags_NoNav, but because legacy specs don't requires LastItemData to be set ButtonBehavior(), we can't poll g.LastItemData.InFlags) ImGuiButtonFlags_NoHoveredOnFocus = 1 << 19, // don't report as hovered when nav focus is on this item ImGuiButtonFlags_NoSetKeyOwner = 1 << 20, // don't set key/input owner on the initial click (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) ImGuiButtonFlags_NoTestKeyOwner = 1 << 21, // don't test key/input owner when polling the key (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) @@ -980,8 +989,7 @@ enum ImGuiSelectableFlagsPrivate_ enum ImGuiTreeNodeFlagsPrivate_ { ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 28,// FIXME-WIP: Hard-coded for CollapsingHeader() - ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 29,// FIXME-WIP: Turn Down arrow into an Up arrow, for reversed trees (#6517) - ImGuiTreeNodeFlags_OpenOnMask_ = ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_OpenOnArrow, + ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 29,// FIXME-WIP: Turn Down arrow into an Up arrow, but reversed trees (#6517) }; enum ImGuiSeparatorFlags_ @@ -1022,16 +1030,13 @@ enum ImGuiLayoutType_ ImGuiLayoutType_Vertical = 1 }; -// Flags for LogBegin() text capturing function -enum ImGuiLogFlags_ +enum ImGuiLogType { - ImGuiLogFlags_None = 0, - - ImGuiLogFlags_OutputTTY = 1 << 0, - ImGuiLogFlags_OutputFile = 1 << 1, - ImGuiLogFlags_OutputBuffer = 1 << 2, - ImGuiLogFlags_OutputClipboard = 1 << 3, - ImGuiLogFlags_OutputMask_ = ImGuiLogFlags_OutputTTY | ImGuiLogFlags_OutputFile | ImGuiLogFlags_OutputBuffer | ImGuiLogFlags_OutputClipboard, + ImGuiLogType_None = 0, + ImGuiLogType_TTY, + ImGuiLogType_File, + ImGuiLogType_Buffer, + ImGuiLogType_Clipboard, }; // X/Y enums are fixed to 0/1 so they may be used to index ImVec2 @@ -1090,7 +1095,7 @@ struct IMGUI_API ImGuiGroupData ImVec2 BackupCurrLineSize; float BackupCurrLineTextBaseOffset; ImGuiID BackupActiveIdIsAlive; - bool BackupDeactivatedIdIsAlive; + bool BackupActiveIdPreviousFrameIsAlive; bool BackupHoveredIdIsAlive; bool BackupIsSameLine; bool EmitItem; @@ -1123,66 +1128,55 @@ struct IMGUI_API ImGuiInputTextDeactivatedState ImGuiInputTextDeactivatedState() { memset(this, 0, sizeof(*this)); } void ClearFreeMemory() { ID = 0; TextA.clear(); } }; - -// Forward declare imstb_textedit.h structure + make its main configuration define accessible -#undef IMSTB_TEXTEDIT_STRING -#undef IMSTB_TEXTEDIT_CHARTYPE -#define IMSTB_TEXTEDIT_STRING ImGuiInputTextState -#define IMSTB_TEXTEDIT_CHARTYPE char -#define IMSTB_TEXTEDIT_GETWIDTH_NEWLINE (-1.0f) -#define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99 -#define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999 -namespace ImStb { struct STB_TexteditState; } -typedef ImStb::STB_TexteditState ImStbTexteditState; - // Internal state of the currently focused/edited text input box // For a given item ID, access with ImGui::GetInputTextState() struct IMGUI_API ImGuiInputTextState { ImGuiContext* Ctx; // parent UI context (needs to be set explicitly by parent). - ImStbTexteditState* Stb; // State for stb_textedit.h - ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set. ImGuiID ID; // widget id owning the text state - int TextLen; // UTF-8 length of the string in TextA (in bytes) - const char* TextSrc; // == TextA.Data unless read-only, in which case == buf passed to InputText(). Field only set and valid _inside_ the call InputText() call. - ImVector TextA; // main UTF8 buffer. TextA.Size is a buffer size! Should always be >= buf_size passed by user (and of course >= CurLenA + 1). - ImVector TextToRevertTo; // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered) - ImVector CallbackTextBackup; // temporary storage for callback to support automatic reconcile of undo-stack - int BufCapacity; // end-user buffer capacity (include zero terminator) - ImVec2 Scroll; // horizontal offset (managed manually) + vertical scrolling (pulled from child window's own Scroll.y) + int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not. + ImVector TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. + ImVector TextA; // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity. + ImVector InitialTextA; // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered) + bool TextAIsValid; // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument) + int BufCapacityA; // end-user buffer capacity + float ScrollX; // horizontal scrolling/offset + ImStb::STB_TexteditState Stb; // state for stb_textedit.h float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection bool Edited; // edited this frame - bool WantReloadUserBuf; // force a reload of user buf so it may be modified externally. may be automatic in future version. - int ReloadSelectionStart; + ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set. + bool ReloadUserBuf; // force a reload of user buf so it may be modified externally. may be automatic in future version. + int ReloadSelectionStart; // POSITIONS ARE IN IMWCHAR units *NOT* UTF-8 this is why this is not exposed yet. int ReloadSelectionEnd; - ImGuiInputTextState(); - ~ImGuiInputTextState(); - void ClearText() { TextLen = 0; TextA[0] = 0; CursorClamp(); } - void ClearFreeMemory() { TextA.clear(); TextToRevertTo.clear(); } + ImGuiInputTextState() { memset(this, 0, sizeof(*this)); } + void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); } + void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); } + int GetUndoAvailCount() const { return Stb.undostate.undo_point; } + int GetRedoAvailCount() const { return IMSTB_TEXTEDIT_UNDOSTATECOUNT - Stb.undostate.redo_point; } void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation - void OnCharPressed(unsigned int c); // Cursor & Selection - void CursorAnimReset(); - void CursorClamp(); - bool HasSelection() const; - void ClearSelection(); - int GetCursorPos() const; - int GetSelectionStart() const; - int GetSelectionEnd() const; - void SelectAll(); + void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking + void CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); } + bool HasSelection() const { return Stb.select_start != Stb.select_end; } + void ClearSelection() { Stb.select_start = Stb.select_end = Stb.cursor; } + int GetCursorPos() const { return Stb.cursor; } + int GetSelectionStart() const { return Stb.select_start; } + int GetSelectionEnd() const { return Stb.select_end; } + void SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; } // Reload user buf (WIP #2890) // If you modify underlying user-passed const char* while active you need to call this (InputText V2 may lift this) // strcpy(my_buf, "hello"); // if (ImGuiInputTextState* state = ImGui::GetInputTextState(id)) // id may be ImGui::GetItemID() is last item // state->ReloadUserBufAndSelectAll(); - void ReloadUserBufAndSelectAll(); - void ReloadUserBufAndKeepSelection(); - void ReloadUserBufAndMoveToEnd(); + void ReloadUserBufAndSelectAll() { ReloadUserBuf = true; ReloadSelectionStart = 0; ReloadSelectionEnd = INT_MAX; } + void ReloadUserBufAndKeepSelection() { ReloadUserBuf = true; ReloadSelectionStart = Stb.select_start; ReloadSelectionEnd = Stb.select_end; } + void ReloadUserBufAndMoveToEnd() { ReloadUserBuf = true; ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; } + }; enum ImGuiWindowRefreshFlags_ @@ -1249,12 +1243,11 @@ enum ImGuiNextItemDataFlags_ ImGuiNextItemDataFlags_HasOpen = 1 << 1, ImGuiNextItemDataFlags_HasShortcut = 1 << 2, ImGuiNextItemDataFlags_HasRefVal = 1 << 3, - ImGuiNextItemDataFlags_HasStorageID = 1 << 4, }; struct ImGuiNextItemData { - ImGuiNextItemDataFlags HasFlags; // Called HasFlags instead of Flags to avoid mistaking this + ImGuiNextItemDataFlags Flags; ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap and ImGuiItemFlags_HasSelectionUserData. // Non-flags members are NOT cleared by ItemAdd() meaning they are still valid during NavProcessItem() ImGuiID FocusScopeId; // Set by SetNextItemSelectionUserData() @@ -1265,21 +1258,20 @@ struct ImGuiNextItemData bool OpenVal; // Set by SetNextItemOpen() ImU8 OpenCond; // Set by SetNextItemOpen() ImGuiDataTypeStorage RefVal; // Not exposed yet, for ImGuiInputTextFlags_ParseEmptyAsRefVal - ImGuiID StorageId; // Set by SetNextItemStorageID() ImGuiNextItemData() { memset(this, 0, sizeof(*this)); SelectionUserData = -1; } - inline void ClearFlags() { HasFlags = ImGuiNextItemDataFlags_None; ItemFlags = ImGuiItemFlags_None; } // Also cleared manually by ItemAdd()! + inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; ItemFlags = ImGuiItemFlags_None; } // Also cleared manually by ItemAdd()! }; // Status storage for the last submitted item struct ImGuiLastItemData { ImGuiID ID; - ImGuiItemFlags ItemFlags; // See ImGuiItemFlags_ (called 'InFlags' before v1.91.4). + ImGuiItemFlags InFlags; // See ImGuiItemFlags_ ImGuiItemStatusFlags StatusFlags; // See ImGuiItemStatusFlags_ ImRect Rect; // Full rectangle ImRect NavRect; // Navigation scoring rectangle (not displayed) - // Rarely used fields are not explicitly cleared, only valid when the corresponding ImGuiItemStatusFlags are set. + // Rarely used fields are not explicitly cleared, only valid when the corresponding ImGuiItemStatusFlags ar set. ImRect DisplayRect; // Display rectangle. ONLY VALID IF (StatusFlags & ImGuiItemStatusFlags_HasDisplayRect) is set. ImRect ClipRect; // Clip rectangle at the time of submitting item. ONLY VALID IF (StatusFlags & ImGuiItemStatusFlags_HasClipRect) is set.. ImGuiKeyChord Shortcut; // Shortcut at the time of submitting item. ONLY VALID IF (StatusFlags & ImGuiItemStatusFlags_HasShortcut) is set.. @@ -1295,16 +1287,13 @@ struct ImGuiTreeNodeStackData { ImGuiID ID; ImGuiTreeNodeFlags TreeFlags; - ImGuiItemFlags ItemFlags; // Used for nav landing + ImGuiItemFlags InFlags; // Used for nav landing ImRect NavRect; // Used for nav landing }; -// sizeof() = 20 -struct IMGUI_API ImGuiErrorRecoveryState +struct IMGUI_API ImGuiStackSizes { - short SizeOfWindowStack; short SizeOfIDStack; - short SizeOfTreeStack; short SizeOfColorStack; short SizeOfStyleVarStack; short SizeOfFontStack; @@ -1314,16 +1303,18 @@ struct IMGUI_API ImGuiErrorRecoveryState short SizeOfBeginPopupStack; short SizeOfDisabledStack; - ImGuiErrorRecoveryState() { memset(this, 0, sizeof(*this)); } + ImGuiStackSizes() { memset(this, 0, sizeof(*this)); } + void SetToContextState(ImGuiContext* ctx); + void CompareWithContextState(ImGuiContext* ctx); }; // Data saved for each window pushed into the stack struct ImGuiWindowStackData { - ImGuiWindow* Window; - ImGuiLastItemData ParentLastItemDataBackup; - ImGuiErrorRecoveryState StackSizesInBegin; // Store size of various stacks for asserting - bool DisabledOverrideReenable; // Non-child window override disabled flag + ImGuiWindow* Window; + ImGuiLastItemData ParentLastItemDataBackup; + ImGuiStackSizes StackSizesOnBegin; // Store size of various stacks for asserting + bool DisabledOverrideReenable; // Non-child window override disabled flag }; struct ImGuiShrinkWidthItem @@ -1342,15 +1333,6 @@ struct ImGuiPtrOrIndex ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; } }; -// Data used by IsItemDeactivated()/IsItemDeactivatedAfterEdit() functions -struct ImGuiDeactivatedItemData -{ - ImGuiID ID; - int ElapseFrame; - bool HasBeenEditedBefore; - bool IsAlive; -}; - //----------------------------------------------------------------------------- // [SECTION] Popup support //----------------------------------------------------------------------------- @@ -1401,8 +1383,8 @@ typedef ImBitArray ImBitAr #define ImGuiKey_NavKeyboardTweakFast ImGuiMod_Shift #define ImGuiKey_NavGamepadTweakSlow ImGuiKey_GamepadL1 #define ImGuiKey_NavGamepadTweakFast ImGuiKey_GamepadR1 -#define ImGuiKey_NavGamepadActivate (g.IO.ConfigNavSwapGamepadButtons ? ImGuiKey_GamepadFaceRight : ImGuiKey_GamepadFaceDown) -#define ImGuiKey_NavGamepadCancel (g.IO.ConfigNavSwapGamepadButtons ? ImGuiKey_GamepadFaceDown : ImGuiKey_GamepadFaceRight) +#define ImGuiKey_NavGamepadActivate ImGuiKey_GamepadFaceDown +#define ImGuiKey_NavGamepadCancel ImGuiKey_GamepadFaceRight #define ImGuiKey_NavGamepadMenu ImGuiKey_GamepadFaceLeft #define ImGuiKey_NavGamepadInput ImGuiKey_GamepadFaceUp @@ -1603,18 +1585,12 @@ enum ImGuiScrollFlags_ ImGuiScrollFlags_MaskY_ = ImGuiScrollFlags_KeepVisibleEdgeY | ImGuiScrollFlags_KeepVisibleCenterY | ImGuiScrollFlags_AlwaysCenterY, }; -enum ImGuiNavRenderCursorFlags_ +enum ImGuiNavHighlightFlags_ { - ImGuiNavRenderCursorFlags_None = 0, - ImGuiNavRenderCursorFlags_Compact = 1 << 1, // Compact highlight, no padding/distance from focused item - ImGuiNavRenderCursorFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) even when g.NavCursorVisible == false, aka even when using the mouse. - ImGuiNavRenderCursorFlags_NoRounding = 1 << 3, -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiNavHighlightFlags_None = ImGuiNavRenderCursorFlags_None, // Renamed in 1.91.4 - ImGuiNavHighlightFlags_Compact = ImGuiNavRenderCursorFlags_Compact, // Renamed in 1.91.4 - ImGuiNavHighlightFlags_AlwaysDraw = ImGuiNavRenderCursorFlags_AlwaysDraw, // Renamed in 1.91.4 - ImGuiNavHighlightFlags_NoRounding = ImGuiNavRenderCursorFlags_NoRounding, // Renamed in 1.91.4 -#endif + ImGuiNavHighlightFlags_None = 0, + ImGuiNavHighlightFlags_Compact = 1 << 1, // Compact highlight, no padding + ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse. + ImGuiNavHighlightFlags_NoRounding = 1 << 3, }; enum ImGuiNavMoveFlags_ @@ -1635,7 +1611,7 @@ enum ImGuiNavMoveFlags_ ImGuiNavMoveFlags_IsPageMove = 1 << 11, // Identify a PageDown/PageUp request. ImGuiNavMoveFlags_Activate = 1 << 12, // Activate/select target item. ImGuiNavMoveFlags_NoSelect = 1 << 13, // Don't trigger selection by not setting g.NavJustMovedTo - ImGuiNavMoveFlags_NoSetNavCursorVisible = 1 << 14, // Do not alter the nav cursor visible state + ImGuiNavMoveFlags_NoSetNavHighlight = 1 << 14, // Do not alter the visible state of keyboard vs mouse nav highlight ImGuiNavMoveFlags_NoClearActiveId = 1 << 15, // (Experimental) Do not clear active id when applying move result }; @@ -1653,17 +1629,17 @@ struct ImGuiNavItemData ImGuiID ID; // Init,Move // Best candidate item ID ImGuiID FocusScopeId; // Init,Move // Best candidate focus scope ID ImRect RectRel; // Init,Move // Best candidate bounding box in window relative space - ImGuiItemFlags ItemFlags; // ????,Move // Best candidate item flags + ImGuiItemFlags InFlags; // ????,Move // Best candidate item flags float DistBox; // Move // Best candidate box distance to current NavId float DistCenter; // Move // Best candidate center distance to current NavId float DistAxial; // Move // Best candidate axial distance to current NavId - ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionUserData() value. Valid if (ItemFlags & ImGuiItemFlags_HasSelectionUserData) + ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionUserData() value. Valid if (InFlags & ImGuiItemFlags_HasSelectionUserData) ImGuiNavItemData() { Clear(); } - void Clear() { Window = NULL; ID = FocusScopeId = 0; ItemFlags = 0; SelectionUserData = -1; DistBox = DistCenter = DistAxial = FLT_MAX; } + void Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; SelectionUserData = -1; DistBox = DistCenter = DistAxial = FLT_MAX; } }; -// Storage for PushFocusScope(), g.FocusScopeStack[], g.NavFocusRoute[] +// Storage for PushFocusScope() struct ImGuiFocusScopeData { ImGuiID ID; @@ -1774,7 +1750,6 @@ struct ImGuiBoxSelectState bool IsActive; bool IsStarting; bool IsStartedFromVoid; // Starting click was not from an item. - bool IsStartedSetNavIdOnce; bool RequestClear; ImGuiKeyChord KeyMods : 16; // Latched key-mods for box-select logic. ImVec2 StartPosRel; // Start position in window-contents relative space (to support scrolling) @@ -1807,7 +1782,6 @@ struct IMGUI_API ImGuiMultiSelectTempData ImGuiMultiSelectFlags Flags; ImVec2 ScopeRectMin; ImVec2 BackupCursorMaxPos; - ImGuiSelectionUserData LastSubmittedItem; // Copy of last submitted item data, used to merge output ranges. ImGuiID BoxSelectId; ImGuiKeyChord KeyMods; ImS8 LoopRequestSetAll; // -1: no operation, 0: clear all, 1: select all. @@ -1817,6 +1791,7 @@ struct IMGUI_API ImGuiMultiSelectTempData bool NavIdPassedBy; bool RangeSrcPassedBy; // Set by the item that matches RangeSrcItem. bool RangeDstPassedBy; // Set by the item that matches NavJustMovedToId when IsSetRange is set. + ImGuiSelectionUserData BoxSelectLastitem; // Copy of last submitted item data, used to merge output ranges. ImGuiMultiSelectTempData() { Clear(); } void Clear() { size_t io_sz = sizeof(IO); ClearIO(); memset((void*)(&IO + 1), 0, sizeof(*this) - io_sz); } // Zero-clear except IO as we preserve IO.Requests[] buffer allocation. @@ -1860,7 +1835,6 @@ enum ImGuiDockNodeFlagsPrivate_ ImGuiDockNodeFlags_NoResizeX = 1 << 16, // // ImGuiDockNodeFlags_NoResizeY = 1 << 17, // // ImGuiDockNodeFlags_DockedWindowsInFocusRoute= 1 << 18, // // Any docked window will be automatically be focus-route chained (window->ParentWindowForFocusRoute set to this) so Shortcut() in this window can run when any docked window is focused. - // Disable docking/undocking actions in this dockspace or individual node (existing docked nodes will be preserved) // Those are not exposed in public because the desirable sharing/inheriting/copy-flag-on-split behaviors are quite difficult to design and understand. // The two public flags ImGuiDockNodeFlags_NoDockingOverCentralNode/ImGuiDockNodeFlags_NoDockingSplit don't have those issues. @@ -1869,13 +1843,11 @@ enum ImGuiDockNodeFlagsPrivate_ ImGuiDockNodeFlags_NoDockingOverOther = 1 << 21, // // Disable this node from being docked over another window or non-empty node. ImGuiDockNodeFlags_NoDockingOverEmpty = 1 << 22, // // Disable this node from being docked over an empty node (e.g. DockSpace with no other windows) ImGuiDockNodeFlags_NoDocking = ImGuiDockNodeFlags_NoDockingOverMe | ImGuiDockNodeFlags_NoDockingOverOther | ImGuiDockNodeFlags_NoDockingOverEmpty | ImGuiDockNodeFlags_NoDockingSplit | ImGuiDockNodeFlags_NoDockingSplitOther, - // Masks ImGuiDockNodeFlags_SharedFlagsInheritMask_ = ~0, - ImGuiDockNodeFlags_NoResizeFlagsMask_ = (int)ImGuiDockNodeFlags_NoResize | ImGuiDockNodeFlags_NoResizeX | ImGuiDockNodeFlags_NoResizeY, - + ImGuiDockNodeFlags_NoResizeFlagsMask_ = ImGuiDockNodeFlags_NoResize | ImGuiDockNodeFlags_NoResizeX | ImGuiDockNodeFlags_NoResizeY, // When splitting, those local flags are moved to the inheriting child, never duplicated - ImGuiDockNodeFlags_LocalFlagsTransferMask_ = (int)ImGuiDockNodeFlags_NoDockingSplit | ImGuiDockNodeFlags_NoResizeFlagsMask_ | (int)ImGuiDockNodeFlags_AutoHideTabBar | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar | ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_NoCloseButton, + ImGuiDockNodeFlags_LocalFlagsTransferMask_ = ImGuiDockNodeFlags_NoDockingSplit | ImGuiDockNodeFlags_NoResizeFlagsMask_ | ImGuiDockNodeFlags_AutoHideTabBar | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar | ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_NoCloseButton, ImGuiDockNodeFlags_SavedFlagsMask_ = ImGuiDockNodeFlags_NoResizeFlagsMask_ | ImGuiDockNodeFlags_DockSpace | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar | ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_NoCloseButton, }; @@ -2007,7 +1979,6 @@ struct ImGuiViewportP : public ImGuiViewport int LastFocusedStampCount; // Last stamp number from when a window hosted by this viewport was focused (by comparing this value between two viewport we have an implicit viewport z-order we use as fallback) ImGuiID LastNameHash; ImVec2 LastPos; - ImVec2 LastSize; float Alpha; // Window opacity (when dragging dockable windows/viewports we make them transparent) float LastAlpha; bool LastFocusedHadNavWindow;// Instead of maintaining a LastFocusedWindow (which may harder to correctly maintain), we merely store weither NavWindow != NULL last time the viewport was focused. @@ -2019,29 +1990,24 @@ struct ImGuiViewportP : public ImGuiViewport ImVec2 LastPlatformPos; ImVec2 LastPlatformSize; ImVec2 LastRendererSize; - - // Per-viewport work area - // - Insets are >= 0.0f values, distance from viewport corners to work area. - // - BeginMainMenuBar() and DockspaceOverViewport() tend to use work area to avoid stepping over existing contents. - // - Generally 'safeAreaInsets' in iOS land, 'DisplayCutout' in Android land. - ImVec2 WorkInsetMin; // Work Area inset locked for the frame. GetWorkRect() always fits within GetMainRect(). - ImVec2 WorkInsetMax; // " - ImVec2 BuildWorkInsetMin; // Work Area inset accumulator for current frame, to become next frame's WorkInset - ImVec2 BuildWorkInsetMax; // " + ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!) + ImVec2 WorkOffsetMax; // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height). + ImVec2 BuildWorkOffsetMin; // Work Area: Offset being built during current frame. Generally >= 0.0f. + ImVec2 BuildWorkOffsetMax; // Work Area: Offset being built during current frame. Generally <= 0.0f. ImGuiViewportP() { Window = NULL; Idx = -1; LastFrameActive = BgFgDrawListsLastFrame[0] = BgFgDrawListsLastFrame[1] = LastFocusedStampCount = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; LastFocusedHadNavWindow = false; PlatformMonitor = -1; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; LastPlatformPos = LastPlatformSize = LastRendererSize = ImVec2(FLT_MAX, FLT_MAX); } ~ImGuiViewportP() { if (BgFgDrawLists[0]) IM_DELETE(BgFgDrawLists[0]); if (BgFgDrawLists[1]) IM_DELETE(BgFgDrawLists[1]); } void ClearRequestFlags() { PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; } // Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect) - ImVec2 CalcWorkRectPos(const ImVec2& inset_min) const { return ImVec2(Pos.x + inset_min.x, Pos.y + inset_min.y); } - ImVec2 CalcWorkRectSize(const ImVec2& inset_min, const ImVec2& inset_max) const { return ImVec2(ImMax(0.0f, Size.x - inset_min.x - inset_max.x), ImMax(0.0f, Size.y - inset_min.y - inset_max.y)); } - void UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkInsetMin); WorkSize = CalcWorkRectSize(WorkInsetMin, WorkInsetMax); } // Update public fields + ImVec2 CalcWorkRectPos(const ImVec2& off_min) const { return ImVec2(Pos.x + off_min.x, Pos.y + off_min.y); } + ImVec2 CalcWorkRectSize(const ImVec2& off_min, const ImVec2& off_max) const { return ImVec2(ImMax(0.0f, Size.x - off_min.x + off_max.x), ImMax(0.0f, Size.y - off_min.y + off_max.y)); } + void UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkOffsetMin); WorkSize = CalcWorkRectSize(WorkOffsetMin, WorkOffsetMax); } // Update public fields // Helpers to retrieve ImRect (we don't need to store BuildWorkRect as every access tend to change it, hence the code asymmetry) ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } ImRect GetWorkRect() const { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); } - ImRect GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkInsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkInsetMin, BuildWorkInsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); } + ImRect GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkOffsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkOffsetMin, BuildWorkOffsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); } }; //----------------------------------------------------------------------------- @@ -2100,7 +2066,6 @@ enum ImGuiLocKey : int ImGuiLocKey_WindowingMainMenuBar, ImGuiLocKey_WindowingPopup, ImGuiLocKey_WindowingUntitled, - ImGuiLocKey_OpenLink_s, ImGuiLocKey_CopyLink, ImGuiLocKey_DockingHideTabBar, ImGuiLocKey_DockingHoldShiftToDock, @@ -2114,45 +2079,27 @@ struct ImGuiLocEntry const char* Text; }; -//----------------------------------------------------------------------------- -// [SECTION] Error handling, State recovery support -//----------------------------------------------------------------------------- - -// Macros used by Recoverable Error handling -// - Only dispatch error if _EXPR: evaluate as assert (similar to an assert macro). -// - The message will always be a string literal, in order to increase likelihood of being display by an assert handler. -// - See 'Demo->Configuration->Error Handling' and ImGuiIO definitions for details on error handling. -// - Read https://github.com/ocornut/imgui/wiki/Error-Handling for details on error handling. -#ifndef IM_ASSERT_USER_ERROR -#define IM_ASSERT_USER_ERROR(_EXPR,_MSG) do { if (!(_EXPR) && ImGui::ErrorLog(_MSG)) { IM_ASSERT((_EXPR) && _MSG); } } while (0) // Recoverable User Error -#endif - -// The error callback is currently not public, as it is expected that only advanced users will rely on it. -typedef void (*ImGuiErrorCallback)(ImGuiContext* ctx, void* user_data, const char* msg); // Function signature for g.ErrorCallback //----------------------------------------------------------------------------- // [SECTION] Metrics, Debug Tools //----------------------------------------------------------------------------- -// See IMGUI_DEBUG_LOG() and IMGUI_DEBUG_LOG_XXX() macros. enum ImGuiDebugLogFlags_ { // Event types ImGuiDebugLogFlags_None = 0, - ImGuiDebugLogFlags_EventError = 1 << 0, // Error submitted by IM_ASSERT_USER_ERROR() - ImGuiDebugLogFlags_EventActiveId = 1 << 1, - ImGuiDebugLogFlags_EventFocus = 1 << 2, - ImGuiDebugLogFlags_EventPopup = 1 << 3, - ImGuiDebugLogFlags_EventNav = 1 << 4, - ImGuiDebugLogFlags_EventClipper = 1 << 5, - ImGuiDebugLogFlags_EventSelection = 1 << 6, - ImGuiDebugLogFlags_EventIO = 1 << 7, - ImGuiDebugLogFlags_EventFont = 1 << 8, - ImGuiDebugLogFlags_EventInputRouting = 1 << 9, - ImGuiDebugLogFlags_EventDocking = 1 << 10, - ImGuiDebugLogFlags_EventViewport = 1 << 11, + ImGuiDebugLogFlags_EventActiveId = 1 << 0, + ImGuiDebugLogFlags_EventFocus = 1 << 1, + ImGuiDebugLogFlags_EventPopup = 1 << 2, + ImGuiDebugLogFlags_EventNav = 1 << 3, + ImGuiDebugLogFlags_EventClipper = 1 << 4, + ImGuiDebugLogFlags_EventSelection = 1 << 5, + ImGuiDebugLogFlags_EventIO = 1 << 6, + ImGuiDebugLogFlags_EventInputRouting = 1 << 7, + ImGuiDebugLogFlags_EventDocking = 1 << 8, + ImGuiDebugLogFlags_EventViewport = 1 << 9, - ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventIO | ImGuiDebugLogFlags_EventFont | ImGuiDebugLogFlags_EventInputRouting | ImGuiDebugLogFlags_EventDocking | ImGuiDebugLogFlags_EventViewport, + ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventIO | ImGuiDebugLogFlags_EventInputRouting | ImGuiDebugLogFlags_EventDocking | ImGuiDebugLogFlags_EventViewport, ImGuiDebugLogFlags_OutputToTTY = 1 << 20, // Also send output to TTY ImGuiDebugLogFlags_OutputToTestEngine = 1 << 21, // Also send output to Test Engine }; @@ -2258,9 +2205,9 @@ struct ImGuiContext int FrameCountEnded; int FrameCountPlatformEnded; int FrameCountRendered; - ImGuiID WithinEndChildID; // Set within EndChild() bool WithinFrameScope; // Set by NewFrame(), cleared by EndFrame() bool WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed + bool WithinEndChild; // Set within EndChild() bool GcCompactAll; // Request full GC bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log() void* TestEngine; // Test engine user data @@ -2295,11 +2242,9 @@ struct ImGuiContext ImVec2 WheelingAxisAvg; // Item/widgets state and tracking information - ImGuiID DebugDrawIdConflicts; // Set when we detect multiple items with the same identifier ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by ID Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line] ImGuiID HoveredId; // Hovered widget, filled during the frame ImGuiID HoveredIdPreviousFrame; - int HoveredIdPreviousFrameItemCount; // Count numbers of items using the same ID as last frame's hovered id float HoveredIdTimer; // Measure contiguous hovering time float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active bool HoveredIdAllowOverlap; @@ -2320,8 +2265,9 @@ struct ImGuiContext ImGuiWindow* ActiveIdWindow; ImGuiInputSource ActiveIdSource; // Activating source: ImGuiInputSource_Mouse OR ImGuiInputSource_Keyboard OR ImGuiInputSource_Gamepad ImGuiID ActiveIdPreviousFrame; - ImGuiDeactivatedItemData DeactivatedItemData; - ImGuiDataTypeStorage ActiveIdValueOnActivation; // Backup of initial value at the time of activation. ONLY SET BY SPECIFIC WIDGETS: DragXXX and SliderXXX. + bool ActiveIdPreviousFrameIsAlive; + bool ActiveIdPreviousFrameHasBeenEditedBefore; + ImGuiWindow* ActiveIdPreviousFrameWindow; ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. @@ -2338,7 +2284,9 @@ struct ImGuiContext ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it) bool ActiveIdUsingAllKeyboardKeys; // Active widget will want to read all keyboard keys inputs. (this is a shortcut for not taking ownership of 100+ keys, frequently used by drag operations) ImGuiKeyChord DebugBreakInShortcutRouting; // Set to break in SetShortcutRouting()/Shortcut() calls. - //ImU32 ActiveIdUsingNavInputMask; // [OBSOLETE] Since (IMGUI_VERSION_NUM >= 18804) : 'g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);' becomes --> 'SetKeyOwner(ImGuiKey_Escape, g.ActiveId) and/or SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId);' +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + ImU32 ActiveIdUsingNavInputMask; // If you used this. Since (IMGUI_VERSION_NUM >= 18804) : 'g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);' becomes 'SetKeyOwner(ImGuiKey_Escape, g.ActiveId) and/or SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId);' +#endif // Next window/item data ImGuiID CurrentFocusScopeId; // Value for currently appending items == g.FocusScopeStack.back(). Not to be mistaken with g.NavFocusScopeId. @@ -2373,15 +2321,9 @@ struct ImGuiContext int PlatformWindowsCreatedCount; // Unique sequential creation counter (mostly for testing/debugging) int ViewportFocusedStampCount; // Every time the front-most window changes, we stamp its viewport with an incrementing counter - // Keyboard/Gamepad Navigation - bool NavCursorVisible; // Nav focus cursor/rectangle is visible? We hide it after a mouse click. We show it after a nav move. - bool NavHighlightItemUnderNav; // Disable mouse hovering highlight. Highlight navigation focused item instead of mouse hovered item. - //bool NavDisableHighlight; // Old name for !g.NavCursorVisible before 1.91.4 (2024/10/18). OPPOSITE VALUE (g.NavDisableHighlight == !g.NavCursorVisible) - //bool NavDisableMouseHover; // Old name for g.NavHighlightItemUnderNav before 1.91.1 (2024/10/18) this was called When user starts using keyboard/gamepad, we hide mouse hovering highlight until mouse is touched again. - bool NavMousePosDirty; // When set we will update mouse position if io.ConfigNavMoveSetMousePos is set (not enabled by default) - bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid - ImGuiID NavId; // Focused item for navigation + // Gamepad/keyboard Navigation ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow' + ImGuiID NavId; // Focused item for navigation ImGuiID NavFocusScopeId; // Focused focus scope (e.g. selection code often wants to "clear other items" when landing on an item of the same scope) ImGuiNavLayer NavLayer; // Focused layer (main scrolling layer, or menu/title bar layer) ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem() @@ -2395,7 +2337,10 @@ struct ImGuiContext ImGuiActivateFlags NavNextActivateFlags; ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse ImGuiSelectionUserData NavLastValidSelectionUserData; // Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data. - ImS8 NavCursorHideFrames; + bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid + bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default) + bool NavDisableHighlight; // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover) + bool NavDisableMouseHover; // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again. // Navigation: Init & Move Requests bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd() @@ -2427,7 +2372,7 @@ struct ImGuiContext ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest). ImGuiKeyChord NavJustMovedToKeyMods; bool NavJustMovedToIsTabbing; // Copy of ImGuiNavMoveFlags_IsTabbing. Maybe we should store whole flags. - bool NavJustMovedToHasSelectionData; // Copy of move result's ItemFlags & ImGuiItemFlags_HasSelectionUserData). Maybe we should just store ImGuiNavItemData. + bool NavJustMovedToHasSelectionData; // Copy of move result's InFlags & ImGuiItemFlags_HasSelectionUserData). Maybe we should just store ImGuiNavItemData. // Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize) ImGuiKeyChord ConfigNavWindowingKeyNext; // = ImGuiMod_Ctrl | ImGuiKey_Tab (or ImGuiMod_Super | ImGuiKey_Tab on OS X). For reconfiguration (see #4828) @@ -2522,8 +2467,8 @@ struct ImGuiContext ImGuiComboPreviewData ComboPreviewData; ImRect WindowResizeBorderExpectedRect; // Expected border rect, switch to relative edit if moving bool WindowResizeRelativeMode; - short ScrollbarSeekMode; // 0: scroll to clicked location, -1/+1: prev/next page. - float ScrollbarClickDeltaToGrabCenter; // When scrolling to mouse location: distance between mouse and center of grab box, normalized in parent space. + short ScrollbarSeekMode; // 0: relative, -1/+1: prev/next page. + float ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? float SliderGrabClickOffset; float SliderCurrentAccum; // Accumulated slider delta when using navigation controls. bool SliderCurrentAccumDirty; // Has the accumulated slider delta changed since last time we tried to apply it? @@ -2532,15 +2477,15 @@ struct ImGuiContext float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio float DisabledAlphaBackup; // Backup for style.Alpha for BeginDisabled() short DisabledStackSize; + short LockMarkEdited; short TooltipOverrideCount; - ImGuiWindow* TooltipPreviousWindow; // Window of last tooltip submitted during the frame ImVector ClipboardHandlerData; // If no custom clipboard handler is defined ImVector MenusIdSubmittedThisFrame; // A list of menu IDs that were rendered at least once ImGuiTypingSelectState TypingSelectState; // State for GetTypingSelectRequest() // Platform support ImGuiPlatformImeData PlatformImeData; // Data updated by current frame - ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data. When changed we call the platform_io.Platform_SetImeDataFn() handler. + ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data. When changed we call the io.PlatformSetImeDataFn() handler. ImGuiID PlatformImeViewport; // Extensions @@ -2563,8 +2508,7 @@ struct ImGuiContext // Capture/Logging bool LogEnabled; // Currently capturing - ImGuiLogFlags LogFlags; // Capture flags/type - ImGuiWindow* LogWindow; + ImGuiLogType LogType; // Capture target ImFileHandle LogFile; // If != NULL log to stdout/ file ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. const char* LogNextPrefix; @@ -2575,22 +2519,11 @@ struct ImGuiContext int LogDepthToExpand; int LogDepthToExpandDefault; // Default/stored value for LogDepthMaxExpand if not specified in the LogXXX function call. - // Error Handling - ImGuiErrorCallback ErrorCallback; // = NULL. May be exposed in public API eventually. - void* ErrorCallbackUserData; // = NULL - ImVec2 ErrorTooltipLockedPos; - bool ErrorFirst; - int ErrorCountCurrentFrame; // [Internal] Number of errors submitted this frame. - ImGuiErrorRecoveryState StackSizesInNewFrame; // [Internal] - ImGuiErrorRecoveryState*StackSizesInBeginForCurrentWindow; // [Internal] - // Debug Tools // (some of the highly frequently used data are interleaved in other structures above: DebugBreakXXX fields, DebugHookIdInfo, DebugLocateId etc.) - int DebugDrawIdConflictsCount; // Locked count (preserved when holding CTRL) ImGuiDebugLogFlags DebugLogFlags; ImGuiTextBuffer DebugLogBuf; ImGuiTextIndex DebugLogIndex; - int DebugLogSkippedErrors; ImGuiDebugLogFlags DebugLogAutoDisableFlags; ImU8 DebugLogAutoDisableFrames; ImU8 DebugLocateFrames; // For DebugLocateItemOnHover(). This is used together with DebugLocateId which is in a hot/cached spot above. @@ -2618,7 +2551,222 @@ struct ImGuiContext ImVector TempBuffer; // Temporary text buffer char TempKeychordName[64]; - ImGuiContext(ImFontAtlas* shared_font_atlas); + ImGuiContext(ImFontAtlas* shared_font_atlas) + { + IO.Ctx = this; + InputTextState.Ctx = this; + + Initialized = false; + ConfigFlagsCurrFrame = ConfigFlagsLastFrame = ImGuiConfigFlags_None; + FontAtlasOwnedByContext = shared_font_atlas ? false : true; + Font = NULL; + FontSize = FontBaseSize = FontScale = CurrentDpiScale = 0.0f; + IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); + Time = 0.0f; + FrameCount = 0; + FrameCountEnded = FrameCountPlatformEnded = FrameCountRendered = -1; + WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false; + GcCompactAll = false; + TestEngineHookItems = false; + TestEngine = NULL; + memset(ContextName, 0, sizeof(ContextName)); + + InputEventsNextMouseSource = ImGuiMouseSource_Mouse; + InputEventsNextEventId = 1; + + WindowsActiveCount = 0; + CurrentWindow = NULL; + HoveredWindow = NULL; + HoveredWindowUnderMovingWindow = NULL; + HoveredWindowBeforeClear = NULL; + MovingWindow = NULL; + WheelingWindow = NULL; + WheelingWindowStartFrame = WheelingWindowScrolledFrame = -1; + WheelingWindowReleaseTimer = 0.0f; + + DebugHookIdInfo = 0; + HoveredId = HoveredIdPreviousFrame = 0; + HoveredIdAllowOverlap = false; + HoveredIdIsDisabled = false; + HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f; + ItemUnclipByLog = false; + ActiveId = 0; + ActiveIdIsAlive = 0; + ActiveIdTimer = 0.0f; + ActiveIdIsJustActivated = false; + ActiveIdAllowOverlap = false; + ActiveIdNoClearOnFocusLoss = false; + ActiveIdHasBeenPressedBefore = false; + ActiveIdHasBeenEditedBefore = false; + ActiveIdHasBeenEditedThisFrame = false; + ActiveIdFromShortcut = false; + ActiveIdClickOffset = ImVec2(-1, -1); + ActiveIdWindow = NULL; + ActiveIdSource = ImGuiInputSource_None; + ActiveIdMouseButton = -1; + ActiveIdPreviousFrame = 0; + ActiveIdPreviousFrameIsAlive = false; + ActiveIdPreviousFrameHasBeenEditedBefore = false; + ActiveIdPreviousFrameWindow = NULL; + LastActiveId = 0; + LastActiveIdTimer = 0.0f; + + LastKeyboardKeyPressTime = LastKeyModsChangeTime = LastKeyModsChangeFromNoneTime = -1.0; + + ActiveIdUsingNavDirMask = 0x00; + ActiveIdUsingAllKeyboardKeys = false; +#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO + ActiveIdUsingNavInputMask = 0x00; +#endif + + CurrentFocusScopeId = 0; + CurrentItemFlags = ImGuiItemFlags_None; + DebugShowGroupRects = false; + + CurrentViewport = NULL; + MouseViewport = MouseLastHoveredViewport = NULL; + PlatformLastFocusedViewportId = 0; + ViewportCreatedCount = PlatformWindowsCreatedCount = 0; + ViewportFocusedStampCount = 0; + + NavWindow = NULL; + NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0; + NavLayer = ImGuiNavLayer_Main; + NavNextActivateId = 0; + NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None; + NavHighlightActivatedId = 0; + NavHighlightActivatedTimer = 0.0f; + NavInputSource = ImGuiInputSource_Keyboard; + NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid; + NavIdIsAlive = false; + NavMousePosDirty = false; + NavDisableHighlight = true; + NavDisableMouseHover = false; + + NavAnyRequest = false; + NavInitRequest = false; + NavInitRequestFromMove = false; + NavMoveSubmitted = false; + NavMoveScoringItems = false; + NavMoveForwardToNextFrame = false; + NavMoveFlags = ImGuiNavMoveFlags_None; + NavMoveScrollFlags = ImGuiScrollFlags_None; + NavMoveKeyMods = ImGuiMod_None; + NavMoveDir = NavMoveDirForDebug = NavMoveClipDir = ImGuiDir_None; + NavScoringDebugCount = 0; + NavTabbingDir = 0; + NavTabbingCounter = 0; + + NavJustMovedFromFocusScopeId = NavJustMovedToId = NavJustMovedToFocusScopeId = 0; + NavJustMovedToKeyMods = ImGuiMod_None; + NavJustMovedToIsTabbing = false; + NavJustMovedToHasSelectionData = false; + + // All platforms use Ctrl+Tab but Ctrl<>Super are swapped on Mac... + // FIXME: Because this value is stored, it annoyingly interfere with toggling io.ConfigMacOSXBehaviors updating this.. + ConfigNavWindowingKeyNext = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiKey_Tab); + ConfigNavWindowingKeyPrev = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiMod_Shift | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab); + NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL; + NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; + NavWindowingToggleLayer = false; + NavWindowingToggleKey = ImGuiKey_None; + + DimBgRatio = 0.0f; + + DragDropActive = DragDropWithinSource = DragDropWithinTarget = false; + DragDropSourceFlags = ImGuiDragDropFlags_None; + DragDropSourceFrameCount = -1; + DragDropMouseButton = -1; + DragDropTargetId = 0; + DragDropAcceptFlags = ImGuiDragDropFlags_None; + DragDropAcceptIdCurrRectSurface = 0.0f; + DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0; + DragDropAcceptFrameCount = -1; + DragDropHoldJustPressedId = 0; + memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal)); + + ClipperTempDataStacked = 0; + + CurrentTable = NULL; + TablesTempDataStacked = 0; + CurrentTabBar = NULL; + CurrentMultiSelect = NULL; + MultiSelectTempDataStacked = 0; + + HoverItemDelayId = HoverItemDelayIdPreviousFrame = HoverItemUnlockedStationaryId = HoverWindowUnlockedStationaryId = 0; + HoverItemDelayTimer = HoverItemDelayClearTimer = 0.0f; + + MouseCursor = ImGuiMouseCursor_Arrow; + MouseStationaryTimer = 0.0f; + + TempInputId = 0; + memset(&DataTypeZeroValue, 0, sizeof(DataTypeZeroValue)); + BeginMenuDepth = BeginComboDepth = 0; + ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_; + ColorEditCurrentID = ColorEditSavedID = 0; + ColorEditSavedHue = ColorEditSavedSat = 0.0f; + ColorEditSavedColor = 0; + WindowResizeRelativeMode = false; + ScrollbarSeekMode = 0; + ScrollbarClickDeltaToGrabCenter = 0.0f; + SliderGrabClickOffset = 0.0f; + SliderCurrentAccum = 0.0f; + SliderCurrentAccumDirty = false; + DragCurrentAccumDirty = false; + DragCurrentAccum = 0.0f; + DragSpeedDefaultRatio = 1.0f / 100.0f; + DisabledAlphaBackup = 0.0f; + DisabledStackSize = 0; + LockMarkEdited = 0; + TooltipOverrideCount = 0; + + PlatformImeData.InputPos = ImVec2(0.0f, 0.0f); + PlatformImeDataPrev.InputPos = ImVec2(-1.0f, -1.0f); // Different to ensure initial submission + PlatformImeViewport = 0; + + DockNodeWindowMenuHandler = NULL; + + SettingsLoaded = false; + SettingsDirtyTimer = 0.0f; + HookIdNext = 0; + + memset(LocalizationTable, 0, sizeof(LocalizationTable)); + + LogEnabled = false; + LogType = ImGuiLogType_None; + LogNextPrefix = LogNextSuffix = NULL; + LogFile = NULL; + LogLinePosY = FLT_MAX; + LogLineFirstItem = false; + LogDepthRef = 0; + LogDepthToExpand = LogDepthToExpandDefault = 2; + + DebugLogFlags = ImGuiDebugLogFlags_OutputToTTY; + DebugLocateId = 0; + DebugLogAutoDisableFlags = ImGuiDebugLogFlags_None; + DebugLogAutoDisableFrames = 0; + DebugLocateFrames = 0; + DebugBeginReturnValueCullDepth = -1; + DebugItemPickerActive = false; + DebugItemPickerMouseButton = ImGuiMouseButton_Left; + DebugItemPickerBreakId = 0; + DebugFlashStyleColorTime = 0.0f; + DebugFlashStyleColorIdx = ImGuiCol_COUNT; + DebugHoveredDockNode = NULL; + + // Same as DebugBreakClearData(). Those fields are scattered in their respective subsystem to stay in hot-data locations + DebugBreakInWindow = 0; + DebugBreakInTable = 0; + DebugBreakInLocateId = false; + DebugBreakKeyChord = ImGuiKey_Pause; + DebugBreakInShortcutRouting = ImGuiKey_None; + + memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); + FramerateSecPerFrameIdx = FramerateSecPerFrameCount = 0; + FramerateSecPerFrameAccum = 0.0f; + WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1; + memset(TempKeychordName, 0, sizeof(TempKeychordName)); + } }; //----------------------------------------------------------------------------- @@ -2669,12 +2817,6 @@ struct IMGUI_API ImGuiWindowTempData ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin() ImU32 ModalDimBgColor; - // Status flags - ImGuiItemStatusFlags WindowItemStatusFlags; - ImGuiItemStatusFlags ChildItemStatusFlags; - ImGuiItemStatusFlags DockTabItemStatusFlags; - ImRect DockTabItemRect; - // Local parameters stacks // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. float ItemWidth; // Current item width (>0.0: width in pixels, <0.0: align xx pixels to the right of window). @@ -2777,9 +2919,7 @@ struct IMGUI_API ImGuiWindow ImGuiStorage StateStorage; ImVector ColumnsStorage; float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale() - float FontWindowScaleParents; float FontDpiScale; - float FontRefSize; // This is a copy of window->CalcFontSize() at the time of Begin(), trying to phase out CalcFontSize() especially as it may be called on non-current window. int SettingsOffset; // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back) ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) @@ -2813,6 +2953,8 @@ struct IMGUI_API ImGuiWindow ImGuiDockNode* DockNode; // Which node are we docked into. Important: Prefer testing DockIsActive in many cases as this will still be set when the dock node is hidden. ImGuiDockNode* DockNodeAsHost; // Which node are we owning (for parent windows) ImGuiID DockId; // Backup of last valid DockNode->ID, so single window remember their dock node id even when they are not bound any more + ImGuiItemStatusFlags DockTabItemStatusFlags; + ImRect DockTabItemRect; public: ImGuiWindow(ImGuiContext* context, const char* name); @@ -2821,12 +2963,11 @@ public: ImGuiID GetID(const char* str, const char* str_end = NULL); ImGuiID GetID(const void* ptr); ImGuiID GetID(int n); - ImGuiID GetIDFromPos(const ImVec2& p_abs); ImGuiID GetIDFromRectangle(const ImRect& r_abs); // We don't use g.FontSize because the window may be != g.CurrentWindow. ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } - float CalcFontSize() const { ImGuiContext& g = *Ctx; return g.FontBaseSize * FontWindowScale * FontDpiScale * FontWindowScaleParents; } + float CalcFontSize() const { ImGuiContext& g = *Ctx; float scale = g.FontBaseSize * FontWindowScale * FontDpiScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; } ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight)); } ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight; return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight); } }; @@ -2849,8 +2990,7 @@ enum ImGuiTabItemFlagsPrivate_ ImGuiTabItemFlags_SectionMask_ = ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing, ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout) ImGuiTabItemFlags_Button = 1 << 21, // Used by TabItemButton, change the tab item behavior to mimic a button - ImGuiTabItemFlags_Invisible = 1 << 22, // To reserve space e.g. with ImGuiTabItemFlags_Leading - ImGuiTabItemFlags_Unsorted = 1 << 23, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. + ImGuiTabItemFlags_Unsorted = 1 << 22, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. }; // Storage for one active tab item (sizeof() 48 bytes) @@ -2873,10 +3013,9 @@ struct ImGuiTabItem ImGuiTabItem() { memset(this, 0, sizeof(*this)); LastFrameVisible = LastFrameSelected = -1; RequestedWidth = -1.0f; NameOffset = -1; BeginOrder = IndexDuringLayout = -1; } }; -// Storage for a tab bar (sizeof() 160 bytes) +// Storage for a tab bar (sizeof() 152 bytes) struct IMGUI_API ImGuiTabBar { - ImGuiWindow* Window; ImVector Tabs; ImGuiTabBarFlags Flags; ImGuiID ID; // Zero for tab-bars used by docking @@ -2937,7 +3076,6 @@ struct ImGuiTableColumn float MaxX; float WidthRequest; // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from StretchWeight in TableUpdateLayout() float WidthAuto; // Automatic width - float WidthMax; // Maximum width (FIXME: overwritten by each instance) float StretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially. float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_). ImRect ClipRect; // Clipping rectangle for the column @@ -3115,7 +3253,6 @@ struct IMGUI_API ImGuiTable ImGuiTableDrawChannelIdx DummyDrawChannel; // Redirect non-visible columns here. ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; // For Selectable() and other widgets drawing across columns after the freezing line. Index within DrawSplitter.Channels[] ImGuiTableDrawChannelIdx Bg2DrawChannelUnfrozen; - ImS8 NavLayer; // ImGuiNavLayer at the time of BeginTable(). bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row. bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow(). bool IsInitializing; @@ -3218,8 +3355,6 @@ namespace ImGui // If this ever crashes because g.CurrentWindow is NULL, it means that either: // - ImGui::NewFrame() has never been called, which is illegal. // - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. - IMGUI_API ImGuiIO& GetIOEx(ImGuiContext* ctx); - IMGUI_API ImGuiPlatformIO& GetPlatformIOEx(ImGuiContext* ctx); inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id); @@ -3239,8 +3374,8 @@ namespace ImGui inline void SetWindowParentWindowForFocusRoute(ImGuiWindow* window, ImGuiWindow* parent_window) { window->ParentWindowForFocusRoute = parent_window; } // You may also use SetNextWindowClass()'s FocusRouteParentWindowId field. inline ImRect WindowRectAbsToRel(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y); } inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); } - inline ImVec2 WindowPosAbsToRel(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x - off.x, p.y - off.y); } inline ImVec2 WindowPosRelToAbs(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x + off.x, p.y + off.y); } + inline ImVec2 WindowPosAbsToRel(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x - off.x, p.y - off.y); } // Windows: Display Order and Focus Order IMGUI_API void FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags = 0); @@ -3258,7 +3393,6 @@ namespace ImGui // Fonts, drawing IMGUI_API void SetCurrentFont(ImFont* font); inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } - IMGUI_API void PushPasswordFont(); inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { return GetForegroundDrawList(window->Viewport); } IMGUI_API void AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector* out_list, ImDrawList* draw_list); @@ -3281,7 +3415,7 @@ namespace ImGui IMGUI_API void CallContextHooks(ImGuiContext* context, ImGuiContextHookType type); // Viewports - IMGUI_API void TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos, const ImVec2& old_size, const ImVec2& new_size); + IMGUI_API void TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos); IMGUI_API void ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale); IMGUI_API void DestroyPlatformWindow(ImGuiViewportP* viewport); IMGUI_API void SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport); @@ -3322,8 +3456,8 @@ namespace ImGui //#endif // Basic Accessors - inline ImGuiItemStatusFlags GetItemStatusFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.StatusFlags; } - inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.ItemFlags; } + inline ImGuiItemStatusFlags GetItemStatusFlags(){ ImGuiContext& g = *GImGui; return g.LastItemData.StatusFlags; } + inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.InFlags; } inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; } inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; } IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window); @@ -3344,10 +3478,11 @@ namespace ImGui IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags); IMGUI_API bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags = 0); IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id); - IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags item_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); + IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); IMGUI_API void PushMultiItemsWidths(int components, float width_full); + IMGUI_API ImVec2 GetContentRegionMaxAbs(); IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess); // Parameter stacks (shared) @@ -3356,7 +3491,7 @@ namespace ImGui IMGUI_API void EndDisabledOverrideReenable(); // Logging/Capture - IMGUI_API void LogBegin(ImGuiLogFlags flags, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. + IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. IMGUI_API void LogToBuffer(int auto_open_depth = -1); // Start logging/capturing to internal buffer IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); IMGUI_API void LogSetNextTextDecoration(const char* prefix, const char* suffix); @@ -3392,7 +3527,7 @@ namespace ImGui IMGUI_API bool BeginComboPreview(); IMGUI_API void EndComboPreview(); - // Keyboard/Gamepad Navigation + // Gamepad/Keyboard Navigation IMGUI_API void NavInitWindow(ImGuiWindow* window, bool force_reinit); IMGUI_API void NavInitRequestApplyResult(); IMGUI_API bool NavMoveRequestButNoResultYet(); @@ -3405,7 +3540,7 @@ namespace ImGui IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); IMGUI_API void NavHighlightActivated(ImGuiID id); IMGUI_API void NavClearPreferredPosForAxis(ImGuiAxis axis); - IMGUI_API void SetNavCursorVisibleAfterMove(); + IMGUI_API void NavRestoreHighlightAfterMove(); IMGUI_API void NavUpdateCurrentWindowIsScrollPushableX(); IMGUI_API void SetNavWindow(ImGuiWindow* window); IMGUI_API void SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel); @@ -3426,7 +3561,7 @@ namespace ImGui inline bool IsGamepadKey(ImGuiKey key) { return key >= ImGuiKey_Gamepad_BEGIN && key < ImGuiKey_Gamepad_END; } inline bool IsMouseKey(ImGuiKey key) { return key >= ImGuiKey_Mouse_BEGIN && key < ImGuiKey_Mouse_END; } inline bool IsAliasKey(ImGuiKey key) { return key >= ImGuiKey_Aliases_BEGIN && key < ImGuiKey_Aliases_END; } - inline bool IsLRModKey(ImGuiKey key) { return key >= ImGuiKey_LeftCtrl && key <= ImGuiKey_RightSuper; } + inline bool IsModKey(ImGuiKey key) { return key >= ImGuiKey_LeftCtrl && key <= ImGuiKey_RightSuper; } ImGuiKeyChord FixupKeyChord(ImGuiKeyChord key_chord); inline ImGuiKey ConvertSingleModFlagToKey(ImGuiKey key) { @@ -3577,22 +3712,18 @@ namespace ImGui IMGUI_API void RenderDragDropTargetRect(const ImRect& bb, const ImRect& item_clip_rect); // Typing-Select API - // (provide Windows Explorer style "select items by typing partial name" + "cycle through items by typing same letter" feature) - // (this is currently not documented nor used by main library, but should work. See "widgets_typingselect" in imgui_test_suite for usage code. Please let us know if you use this!) IMGUI_API ImGuiTypingSelectRequest* GetTypingSelectRequest(ImGuiTypingSelectFlags flags = ImGuiTypingSelectFlags_None); IMGUI_API int TypingSelectFindMatch(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data, int nav_item_idx); IMGUI_API int TypingSelectFindNextSingleCharMatch(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data, int nav_item_idx); IMGUI_API int TypingSelectFindBestLeadingMatch(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data); // Box-Select API - IMGUI_API bool BeginBoxSelect(const ImRect& scope_rect, ImGuiWindow* window, ImGuiID box_select_id, ImGuiMultiSelectFlags ms_flags); + IMGUI_API bool BeginBoxSelect(ImGuiWindow* window, ImGuiID box_select_id, ImGuiMultiSelectFlags ms_flags); IMGUI_API void EndBoxSelect(const ImRect& scope_rect, ImGuiMultiSelectFlags ms_flags); // Multi-Select API IMGUI_API void MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags* p_button_flags); IMGUI_API void MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed); - IMGUI_API void MultiSelectAddSetAll(ImGuiMultiSelectTempData* ms, bool selected); - IMGUI_API void MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, int range_dir, ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item); inline ImGuiBoxSelectState* GetBoxSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.BoxSelectState.ID == id && g.BoxSelectState.IsActive) ? &g.BoxSelectState : NULL; } inline ImGuiMultiSelectState* GetMultiSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return g.MultiSelectStorage.GetByKey(id); } @@ -3647,7 +3778,7 @@ namespace ImGui IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n); IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n); IMGUI_API ImGuiID TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no = 0); - IMGUI_API float TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n); + IMGUI_API float TableGetMaxColumnWidth(const ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); IMGUI_API void TableRemove(ImGuiTable* table); @@ -3677,12 +3808,10 @@ namespace ImGui IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); IMGUI_API void TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); - IMGUI_API void TabBarQueueFocus(ImGuiTabBar* tab_bar, const char* tab_name); IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset); IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImVec2 mouse_pos); IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar); IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window); - IMGUI_API void TabItemSpacing(const char* str_id, ImGuiTabItemFlags flags, float width); IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker); IMGUI_API ImVec2 TabItemCalcSize(ImGuiWindow* window); IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col); @@ -3696,13 +3825,10 @@ namespace ImGui IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known); - IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders = true, float rounding = 0.0f); + IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f); IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0); - IMGUI_API void RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None); // Navigation highlight -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - inline void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None) { RenderNavCursor(bb, id, flags); } // Renamed in 1.91.4 -#endif + IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_None); // Navigation highlight IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. IMGUI_API void RenderMouseCursor(ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow); @@ -3720,7 +3846,7 @@ namespace ImGui IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); - IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0); + IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0); IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags, float thickness = 1.0f); 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); @@ -3730,7 +3856,7 @@ namespace ImGui IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos); IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_node); IMGUI_API void Scrollbar(ImGuiAxis axis); - IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 avail_v, ImS64 contents_v, ImDrawFlags draw_rounding_flags = 0); + IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 avail_v, ImS64 contents_v, ImDrawFlags flags); IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis); IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis); IMGUI_API ImGuiID GetWindowResizeCornerID(ImGuiWindow* window, int n); // 0..3: corners @@ -3743,7 +3869,7 @@ namespace ImGui IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f, ImU32 bg_col = 0); // Widgets: Tree Nodes - IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); + IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); IMGUI_API void TreePushOverrideID(ImGuiID id); IMGUI_API bool TreeNodeGetOpen(ImGuiID storage_id); IMGUI_API void TreeNodeSetOpen(ImGuiID storage_id, bool open); @@ -3766,7 +3892,6 @@ namespace ImGui IMGUI_API bool DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void* p_data, const char* format, void* p_data_when_empty = NULL); IMGUI_API int DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2); IMGUI_API bool DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max); - IMGUI_API bool DataTypeIsZero(ImGuiDataType data_type, const void* p_data); // InputText IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); @@ -3795,18 +3920,11 @@ namespace ImGui IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow* window); IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow* window); - // Error handling, State Recovery - IMGUI_API bool ErrorLog(const char* msg); - IMGUI_API void ErrorRecoveryStoreState(ImGuiErrorRecoveryState* state_out); - IMGUI_API void ErrorRecoveryTryToRecoverState(const ImGuiErrorRecoveryState* state_in); - IMGUI_API void ErrorRecoveryTryToRecoverWindowState(const ImGuiErrorRecoveryState* state_in); - IMGUI_API void ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); - IMGUI_API void ErrorCheckEndFrameFinalizeErrorTooltip(); - IMGUI_API bool BeginErrorTooltip(); - IMGUI_API void EndErrorTooltip(); - // Debug Tools IMGUI_API void DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr, size_t size); // size >= 0 : alloc, size = -1 : free + IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); + IMGUI_API void ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); + IMGUI_API void ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); IMGUI_API void DebugDrawCursorPos(ImU32 col = IM_COL32(255, 0, 0, 255)); IMGUI_API void DebugDrawLineExtents(ImU32 col = IM_COL32(255, 0, 0, 255)); IMGUI_API void DebugDrawItemRect(ImU32 col = IM_COL32(255, 0, 0, 255)); @@ -3837,14 +3955,14 @@ namespace ImGui IMGUI_API void DebugNodeWindowsList(ImVector* windows, const char* label); IMGUI_API void DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack); IMGUI_API void DebugNodeViewport(ImGuiViewportP* viewport); - IMGUI_API void DebugNodePlatformMonitor(ImGuiPlatformMonitor* monitor, const char* label, int idx); IMGUI_API void DebugRenderKeyboardPreview(ImDrawList* draw_list); IMGUI_API void DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb); // Obsolete functions #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - //inline void SetItemUsingMouseWheel() { SetItemKeyOwner(ImGuiKey_MouseWheelY); } // Changed in 1.89 - //inline bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0) { return TreeNodeUpdateNextOpen(id, flags); } // Renamed in 1.89 + inline void SetItemUsingMouseWheel() { SetItemKeyOwner(ImGuiKey_MouseWheelY); } // Changed in 1.89 + inline bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0) { return TreeNodeUpdateNextOpen(id, flags); } // Renamed in 1.89 + //inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { IM_ASSERT(IsNamedKey(key)); return IsKeyPressed(key, repeat); } // Removed in 1.87: Mapping from named key is always identity! // Refactored focus/nav/tabbing system in 1.82 and 1.84. If you have old/custom copy-and-pasted widgets which used FocusableItemRegister(): @@ -3862,8 +3980,7 @@ namespace ImGui // [SECTION] ImFontAtlas internal API //----------------------------------------------------------------------------- -// This structure is likely to evolve as we add support for incremental atlas updates. -// Conceptually this could be in ImGuiPlatformIO, but we are far from ready to make this public. +// This structure is likely to evolve as we add support for incremental atlas updates struct ImFontBuilderIO { bool (*FontBuilder_Build)(ImFontAtlas* atlas); @@ -3882,7 +3999,6 @@ IMGUI_API void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, IMGUI_API void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value); IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); -IMGUI_API void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v); //----------------------------------------------------------------------------- // [SECTION] Test Engine specific hooks (imgui_test_engine) @@ -3897,7 +4013,7 @@ extern const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext* ctx, ImGuiI // In IMGUI_VERSION_NUM >= 18934: changed IMGUI_TEST_ENGINE_ITEM_ADD(bb,id) to IMGUI_TEST_ENGINE_ITEM_ADD(id,bb,item_data); #define IMGUI_TEST_ENGINE_ITEM_ADD(_ID,_BB,_ITEM_DATA) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _ID, _BB, _ITEM_DATA) // Register item bounding box #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional) -#define IMGUI_TEST_ENGINE_LOG(_FMT,...) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log +#define IMGUI_TEST_ENGINE_LOG(_FMT,...) if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log #else #define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) ((void)0) #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) ((void)g) diff --git a/3rdparty/imgui/imgui_stacklayout.cpp b/3rdparty/imgui/imgui_stacklayout.cpp new file mode 100644 index 0000000..474bac2 --- /dev/null +++ b/3rdparty/imgui/imgui_stacklayout.cpp @@ -0,0 +1,1206 @@ +// dear imgui, v1.86 WIP +// (stack layout code) + +/* + +Index of this file: + +// [SECTION] Commentary +// [SECTION] Header mess +// [SECTION] Stack layout: Forward declarations +// [SECTION] Stack layout: flags, enums, data structures +// [SECTION] Stack Layout: Context forward declarations +// [SECTION] Stack Layout: Internal code forward declarations +// [SECTION] Stack Layout: Context +// [SECTION] Stack Layout: Internal code +// [SECTION] Stack Layout: Internal API +// [SECTION] Stack Layout: Public API + +*/ + +// Navigating this file: +// - In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. + +//----------------------------------------------------------------------------- +// [SECTION] Commentary +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Typical call flow: (root level is generally public API): +//----------------------------------------------------------------------------- +// +// - BeginHorizontal/BeginVertical() user begin into a layout +// - [...] user emit contents +// - | Spring() - separate widget groups in layout +// - | SuspendLayout() - stop any layout operations +// - | ResumeLayout() - resume layout operations +//----------------------------------------------------------------------------- +// - EndHorizontal/EndVertical() user ends the layout +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +// [SECTION] Header mess +//----------------------------------------------------------------------------- + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif + +#include "imgui.h" +#ifndef IMGUI_DISABLE +#include "imgui_internal.h" + +#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier +#include // intptr_t +#else +#include // intptr_t +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Stack layout: Forward declarations +//----------------------------------------------------------------------------- + +// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. +typedef int ImGuiLayoutItemType; // -> enum ImGuiLayoutItemType_ // Enum: Item or Spring + + +//----------------------------------------------------------------------------- +// [SECTION] Stack layout: flags, enums, data structures +//----------------------------------------------------------------------------- + +enum ImGuiLayoutItemType_ +{ + ImGuiLayoutItemType_Item, + ImGuiLayoutItemType_Spring +}; + +// sizeof() == 48 +struct ImGuiLayoutItem +{ + ImGuiLayoutItemType Type; // Type of an item + ImRect MeasuredBounds; + + float SpringWeight; // Weight of a spring + float SpringSpacing; // Spring spacing + float SpringSize; // Calculated spring size + + float CurrentAlign; + float CurrentAlignOffset; + + unsigned int VertexIndexBegin; + unsigned int VertexIndexEnd; + + ImGuiLayoutItem(ImGuiLayoutItemType type) + { + Type = type; + MeasuredBounds = ImRect(0, 0, 0, 0); // FIXME: @thedmd are you sure the default ImRect value FLT_MAX,FLT_MAX,-FLT_MAX,-FLT_MAX aren't enough here? + SpringWeight = 1.0f; + SpringSpacing = -1.0f; + SpringSize = 0.0f; + CurrentAlign = 0.0f; + CurrentAlignOffset = 0.0f; + VertexIndexBegin = VertexIndexEnd = (ImDrawIdx)0; + } +}; + +struct ImGuiLayout +{ + ImGuiID Id; + ImGuiLayoutType Type; + bool Live; + ImVec2 Size; // Size passed to BeginLayout + ImVec2 CurrentSize; // Bounds of layout known at the beginning the frame. + ImVec2 MinimumSize; // Minimum possible size when springs are collapsed. + ImVec2 MeasuredSize; // Measured size with springs expanded. + + ImVector Items; + int CurrentItemIndex; + int ParentItemIndex; + ImGuiLayout* Parent; + ImGuiLayout* FirstChild; + ImGuiLayout* NextSibling; + float Align; // Current item alignment. + float Indent; // Indent used to align items in vertical layout. + ImVec2 StartPos; // Initial cursor position when BeginLayout is called. + ImVec2 StartCursorMaxPos; // Maximum cursor position when BeginLayout is called. + + ImDrawListSplitter Splitter; + + ImGuiLayout(ImGuiID id, ImGuiLayoutType type) + { + Id = id; + Type = type; + Live = false; + Size = CurrentSize = MinimumSize = MeasuredSize = ImVec2(0, 0); + CurrentItemIndex = 0; + ParentItemIndex = 0; + Parent = FirstChild = NextSibling = NULL; + Align = -1.0f; + Indent = 0.0f; + StartPos = ImVec2(0, 0); + StartCursorMaxPos = ImVec2(0, 0); + } +}; + +struct ImGuiLayoutWindowState +{ + ImGuiWindow* Window; + ImGuiLayout* CurrentLayout; + ImGuiLayoutItem* CurrentLayoutItem; + ImVector LayoutStack; + ImGuiStorage Layouts; + + ImGuiLayoutWindowState() + { + Window = NULL; + CurrentLayout = NULL; + CurrentLayoutItem = NULL; + } +}; + +struct ImGuiLayoutState +{ + ImGuiStorage LayoutWindowStates; + + ImGuiContext* Context; + ImGuiID ContextID; + ImGuiID NewFramePreID; + ImGuiID EndFramePreID; + ImGuiID ShutdownHookID; + + ImGuiLayoutState() + { + Context = NULL; + ContextID = 0; + NewFramePreID = 0; + EndFramePreID = 0; + ShutdownHookID = 0; + } +}; + + +//----------------------------------------------------------------------------- +// [SECTION] Stack Layout: Context forward declarations +//----------------------------------------------------------------------------- + +static ImGuiStorage GStackLayoutStates; + +// Context management/hooks +static ImGuiID GetContextID(ImGuiContext* context); // FIXME: ImGuiContext probably should have their own ID assigned +static ImGuiLayoutState* GetCurrentLayoutState(); +static ImGuiLayoutState* GetLayoutState(ImGuiContext* context); +static ImGuiLayoutState* CreateLayoutState(ImGuiID context_id, ImGuiContext* context); +static void StackLayout_NewFramePreCallback(ImGuiContext* ctx, ImGuiContextHook* hook); +static void StackLayout_EndFramePreCallback(ImGuiContext* ctx, ImGuiContextHook* hook); +static void StackLayout_ShutdownCallback(ImGuiContext* ctx, ImGuiContextHook* hook); + +static ImGuiLayoutWindowState* GetWindowLayoutState(ImGuiID window_id, ImGuiWindow* window = NULL); +static ImGuiLayoutWindowState* GetCurrentWindowLayoutState(); +static void WindowLayoutState_OnNewFrame(ImGuiLayoutWindowState* state); +static void WindowLayoutState_OnEndFrame(ImGuiLayoutWindowState* state); +static void WindowLayoutState_OnShutdown(ImGuiLayoutWindowState* state); + + +//----------------------------------------------------------------------------- +// [SECTION] Stack Layout: Internal code forward declarations +//----------------------------------------------------------------------------- + +namespace ImGui +{ +// Stack Layout +static ImGuiLayout* FindLayout(ImGuiID id, ImGuiLayoutType type); +static ImGuiLayout* CreateNewLayout(ImGuiID id, ImGuiLayoutType type, ImVec2 size); +static void BeginLayout(ImGuiID id, ImGuiLayoutType type, ImVec2 size, float align); +static void EndLayout(ImGuiLayoutType type); +static ImVec2 CalculateLayoutSize(ImGuiLayout& layout, bool collapse_springs); +static void PushLayout(ImGuiLayout* layout); +static void PopLayout(ImGuiLayout* layout); +static void BalanceLayoutSprings(ImGuiLayout& layout); +static ImVec2 BalanceLayoutItemAlignment(ImGuiLayout& layout, ImGuiLayoutItem& item); +static void BalanceLayoutItemsAlignment(ImGuiLayout& layout); +static bool HasAnyNonZeroSpring(ImGuiLayout& layout); +static void BalanceChildLayouts(ImGuiLayout& layout); +static void BeginLayoutClipRect(ImGuiLayout& layout); +static void EndLayoutClipRect(ImGuiLayout& layout); +static void ApplyLayoutClipRect(ImGuiLayout& layout); +static void MergeLayoutSplitters(ImGuiLayout& layout); +static ImGuiLayoutItem* GenerateLayoutItem(ImGuiLayout& layout, ImGuiLayoutItemType type); +static float CalculateLayoutItemAlignmentOffset(ImGuiLayout& layout, ImGuiLayoutItem& item); +static void TranslateLayoutItem(ImGuiLayoutItem& item, const ImVec2& offset); +static void SignedIndent(float indent); +static void BeginLayoutItem(ImGuiLayout& layout); +static void EndLayoutItem(ImGuiLayout& layout); +static void AddLayoutSpring(ImGuiLayout& layout, float weight, float spacing); +} + + +//----------------------------------------------------------------------------- +// [SECTION] Stack Layout: Context +//----------------------------------------------------------------------------- + +static ImGuiID GetContextID(ImGuiContext* context) +{ + // Hash pointer to ImGuiContext which is unique + return ImHashData(&context, sizeof(context)); +} + +static ImGuiLayoutState* GetCurrentLayoutState() +{ + return GetLayoutState(ImGui::GetCurrentContext()); +} + +static ImGuiLayoutState* GetLayoutState(ImGuiContext* context) +{ + if (context == NULL) + return NULL; + + ImGuiID context_id = GetContextID(context); + + ImGuiLayoutState* state = (ImGuiLayoutState*)GStackLayoutStates.GetVoidPtr(context_id); + if (state == NULL) + state = CreateLayoutState(context_id, context); + + return state; +} + +static ImGuiLayoutState* CreateLayoutState(ImGuiID context_id, ImGuiContext* context) +{ + ImGuiLayoutState* state = IM_NEW(ImGuiLayoutState); + state->Context = context; + state->ContextID = context_id; + + ImGuiContextHook new_frame_pre_hook; + new_frame_pre_hook.Type = ImGuiContextHookType_NewFramePre; + new_frame_pre_hook.UserData = state; + new_frame_pre_hook.Callback = StackLayout_NewFramePreCallback; + state->NewFramePreID = ImGui::AddContextHook(context, &new_frame_pre_hook); + + ImGuiContextHook end_frame_pre_hook; + end_frame_pre_hook.Type = ImGuiContextHookType_EndFramePre; + end_frame_pre_hook.UserData = state; + end_frame_pre_hook.Callback = StackLayout_EndFramePreCallback; + state->EndFramePreID = ImGui::AddContextHook(context, &end_frame_pre_hook); + + ImGuiContextHook shutdown_hook; + shutdown_hook.Type = ImGuiContextHookType_Shutdown; + shutdown_hook.UserData = state; + shutdown_hook.Callback = StackLayout_ShutdownCallback; + state->ShutdownHookID = ImGui::AddContextHook(context, &shutdown_hook); + + GStackLayoutStates.SetVoidPtr(context_id, state); + + return state; +} + +static void StackLayout_NewFramePreCallback(ImGuiContext* ctx, ImGuiContextHook* hook) +{ + ImGuiLayoutState* layout_state = (ImGuiLayoutState*)hook->UserData; + + for (int i = 0; i < layout_state->LayoutWindowStates.Data.Size; ++i) + { + ImGuiLayoutWindowState* layout_window_state = (ImGuiLayoutWindowState*)layout_state->LayoutWindowStates.Data[i].val_p; + + WindowLayoutState_OnNewFrame(layout_window_state); + } +} + +static void StackLayout_EndFramePreCallback(ImGuiContext* ctx, ImGuiContextHook* hook) +{ + ImGuiLayoutState* layout_state = (ImGuiLayoutState*)hook->UserData; + + for (int i = 0; i < layout_state->LayoutWindowStates.Data.Size; ++i) + { + ImGuiLayoutWindowState* layout_window_state = (ImGuiLayoutWindowState*)layout_state->LayoutWindowStates.Data[i].val_p; + + WindowLayoutState_OnEndFrame(layout_window_state); + } +} + +static void StackLayout_ShutdownCallback(ImGuiContext* ctx, ImGuiContextHook* hook) +{ + ImGuiLayoutState* layout_state = (ImGuiLayoutState*)hook->UserData; + + for (int i = 0; i < layout_state->LayoutWindowStates.Data.Size; ++i) + { + ImGuiLayoutWindowState* layout_window_state = (ImGuiLayoutWindowState*)layout_state->LayoutWindowStates.Data[i].val_p; + + WindowLayoutState_OnShutdown(layout_window_state); + + IM_DELETE(layout_window_state); + } + + GStackLayoutStates.SetVoidPtr(layout_state->ContextID, nullptr); + + IM_DELETE(layout_state); +} + + +static ImGuiLayoutWindowState* GetWindowLayoutState(ImGuiID window_id, ImGuiWindow* window) +{ + ImGuiLayoutState* layout_state = GetCurrentLayoutState(); + if (layout_state == NULL) + return NULL; + + ImGuiLayoutWindowState* window_layout_state = (ImGuiLayoutWindowState*)layout_state->LayoutWindowStates.GetVoidPtr(window_id); + if (window_layout_state == NULL) + { + if (window == NULL) + { + window = ImGui::FindWindowByID(window_id); + IM_ASSERT(window && "GetWindowLayoutState called with invalid Window ID."); + } + + window_layout_state = IM_NEW(ImGuiLayoutWindowState); + window_layout_state->Window = window; + layout_state->LayoutWindowStates.SetVoidPtr(window_id, window_layout_state); + } + + return window_layout_state; + +} + + +static ImGuiLayoutWindowState* GetCurrentWindowLayoutState() +{ + ImGuiWindow* current_window = ImGui::GetCurrentWindow(); + if (current_window == NULL) + return NULL; + + return GetWindowLayoutState(current_window->ID, current_window); +} + +static void WindowLayoutState_OnNewFrame(ImGuiLayoutWindowState* state) +{ + // Mark all layouts as dead. They may be revived in this frame. + for (int i = 0; i < state->Layouts.Data.Size; i++) + { + ImGuiLayout* layout = (ImGuiLayout*)state->Layouts.Data[i].val_p; + layout->Live = false; + } +} + +static void WindowLayoutState_OnEndFrame(ImGuiLayoutWindowState* state) +{ + // Check stacks (like ImGuiStackSizes::CompareWithCurrentState() does) + IM_ASSERT(0 == state->LayoutStack.Size && (!state->LayoutStack.Size || state->LayoutStack.back()->Type == ImGuiLayoutType_Horizontal) && "BeginHorizontal/EndHorizontal Mismatch!"); + IM_ASSERT(0 == state->LayoutStack.Size && (!state->LayoutStack.Size || state->LayoutStack.back()->Type == ImGuiLayoutType_Vertical) && "BeginVertical/EndVertical Mismatch!"); +} + +static void WindowLayoutState_OnShutdown(ImGuiLayoutWindowState* state) +{ + for (int i = 0; i < state->Layouts.Data.Size; i++) + { + ImGuiLayout* layout = (ImGuiLayout*)state->Layouts.Data[i].val_p; + IM_DELETE(layout); + } +} + + +//----------------------------------------------------------------------------- +// [SECTION] Stack Layout: Internal code +//----------------------------------------------------------------------------- + +static ImGuiLayout* ImGui::FindLayout(ImGuiID id, ImGuiLayoutType type) +{ + IM_ASSERT(type == ImGuiLayoutType_Horizontal || type == ImGuiLayoutType_Vertical); + + ImGuiLayoutWindowState* window_state = GetCurrentWindowLayoutState(); + ImGuiLayout* layout = (ImGuiLayout*)window_state->Layouts.GetVoidPtr(id); + if (!layout) + return NULL; + + if (layout->Type != type) + { + layout->Type = type; + layout->MinimumSize = ImVec2(0.0f, 0.0f); + layout->Items.clear(); + } + + return layout; +} + +static ImGuiLayout* ImGui::CreateNewLayout(ImGuiID id, ImGuiLayoutType type, ImVec2 size) +{ + IM_ASSERT(type == ImGuiLayoutType_Horizontal || type == ImGuiLayoutType_Vertical); + + ImGuiLayoutWindowState* window_state = GetCurrentWindowLayoutState(); + + ImGuiLayout* layout = IM_NEW(ImGuiLayout)(id, type); + layout->Size = size; + + window_state->Layouts.SetVoidPtr(id, layout); + + return layout; +} + +static void ImGui::BeginLayout(ImGuiID id, ImGuiLayoutType type, ImVec2 size, float align) +{ + ImGuiWindow* window = GetCurrentWindow(); + + PushID(id); + + // Find or create + ImGuiLayout* layout = FindLayout(id, type); + if (!layout) + layout = CreateNewLayout(id, type, size); + + IM_ASSERT(!layout->Live && "BeginHorizontal/BeginVertical with same ID is already live in this frame. Please use PushID() to make ID's unique or rename layout."); + + layout->Live = true; + + PushLayout(layout); + + if (layout->Size.x != size.x || layout->Size.y != size.y) + layout->Size = size; + + if (align < 0.0f) + layout->Align = -1.0f; + else + layout->Align = ImClamp(align, 0.0f, 1.0f); + + // Start capture + layout->CurrentItemIndex = 0; + + layout->CurrentSize.x = layout->Size.x > 0.0f ? layout->Size.x : layout->MinimumSize.x; + layout->CurrentSize.y = layout->Size.y > 0.0f ? layout->Size.y : layout->MinimumSize.y; + + layout->StartPos = window->DC.CursorPos; + layout->StartCursorMaxPos = window->DC.CursorMaxPos; + + BeginLayoutClipRect(*layout); + + if (type == ImGuiLayoutType_Vertical) + { + // Push empty item to recalculate cursor position. + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); + Dummy(ImVec2(0.0f, 0.0f)); + PopStyleVar(); + + // Indent horizontal position to match edge of the layout. + layout->Indent = layout->StartPos.x - window->DC.CursorPos.x; + SignedIndent(layout->Indent); + } + + BeginLayoutItem(*layout); +} + +static void ImGui::EndLayout(ImGuiLayoutType type) +{ + ImGuiLayoutWindowState* window_state = GetCurrentWindowLayoutState(); + IM_ASSERT(window_state->CurrentLayout); + IM_ASSERT(window_state->CurrentLayout->Type == type); + IM_UNUSED(type); + + ImGuiLayout* layout = window_state->CurrentLayout; + + EndLayoutItem(*layout); + + if (layout->CurrentItemIndex < layout->Items.Size) + layout->Items.resize(layout->CurrentItemIndex); + + if (layout->Type == ImGuiLayoutType_Vertical) + SignedIndent(-layout->Indent); + + PopLayout(layout); + + const bool auto_width = layout->Size.x <= 0.0f; + const bool auto_height = layout->Size.y <= 0.0f; + + ImVec2 new_size = layout->Size; + if (auto_width) + new_size.x = layout->CurrentSize.x; + if (auto_height) + new_size.y = layout->CurrentSize.y; + + ImVec2 new_minimum_size = CalculateLayoutSize(*layout, true); + + if (new_minimum_size.x != layout->MinimumSize.x || new_minimum_size.y != layout->MinimumSize.y) + { + layout->MinimumSize = new_minimum_size; + + // Shrink + if (auto_width) + new_size.x = new_minimum_size.x; + if (auto_height) + new_size.y = new_minimum_size.y; + } + + if (!auto_width) + new_size.x = layout->Size.x; + if (!auto_height) + new_size.y = layout->Size.y; + + layout->CurrentSize = new_size; + + ImVec2 measured_size = new_size; + if ((auto_width || auto_height) && layout->Parent) + { + if (layout->Type == ImGuiLayoutType_Horizontal && auto_width && layout->Parent->CurrentSize.x > 0) + layout->CurrentSize.x = layout->Parent->CurrentSize.x; + else if (layout->Type == ImGuiLayoutType_Vertical && auto_height && layout->Parent->CurrentSize.y > 0) + layout->CurrentSize.y = layout->Parent->CurrentSize.y; + + BalanceLayoutSprings(*layout); + + measured_size = layout->CurrentSize; + } + + layout->CurrentSize = new_size; + layout->MeasuredSize = measured_size; + + PopID(); + + ImVec2 current_layout_item_max = ImVec2(0.0f, 0.0f); + if (window_state->CurrentLayoutItem) + current_layout_item_max = ImMax(window_state->CurrentLayoutItem->MeasuredBounds.Max, layout->StartPos + new_size); + + window_state->Window->DC.CursorPos = layout->StartPos; + window_state->Window->DC.CursorMaxPos = layout->StartCursorMaxPos; + ItemSize(new_size); + ItemAdd(ImRect(layout->StartPos, layout->StartPos + measured_size), 0); + + if (window_state->CurrentLayoutItem) + window_state->CurrentLayoutItem->MeasuredBounds.Max = current_layout_item_max; + + if (layout->Parent == NULL) + BalanceChildLayouts(*layout); + + EndLayoutClipRect(*layout); + + //window->DrawList->AddRect(layout->StartPos, layout->StartPos + measured_size, IM_COL32(0,255,0,255)); // [DEBUG] + //window->DrawList->AddRect(window->DC.LastItemRect.Min, window->DC.LastItemRect.Max, IM_COL32(255,255,0,255)); // [DEBUG] +} + +static ImVec2 ImGui::CalculateLayoutSize(ImGuiLayout& layout, bool collapse_springs) +{ + ImVec2 bounds = ImVec2(0.0f, 0.0f); + + if (layout.Type == ImGuiLayoutType_Vertical) + { + for (int i = 0; i < layout.Items.Size; i++) + { + ImGuiLayoutItem& item = layout.Items[i]; + ImVec2 item_size = item.MeasuredBounds.GetSize(); + + if (item.Type == ImGuiLayoutItemType_Item) + { + bounds.x = ImMax(bounds.x, item_size.x); + bounds.y += item_size.y; + } + else + { + bounds.y += ImFloor(item.SpringSpacing); + + if (!collapse_springs) + bounds.y += item.SpringSize; + } + } + } + else + { + for (int i = 0; i < layout.Items.Size; i++) + { + ImGuiLayoutItem& item = layout.Items[i]; + ImVec2 item_size = item.MeasuredBounds.GetSize(); + + if (item.Type == ImGuiLayoutItemType_Item) + { + bounds.x += item_size.x; + bounds.y = ImMax(bounds.y, item_size.y); + } + else + { + bounds.x += ImFloor(item.SpringSpacing); + + if (!collapse_springs) + bounds.x += item.SpringSize; + } + } + } + + return bounds; +} + +static void ImGui::PushLayout(ImGuiLayout* layout) +{ + ImGuiLayoutWindowState* window_state = GetCurrentWindowLayoutState(); + + if (layout) + { + layout->Parent = window_state->CurrentLayout; + if (layout->Parent != NULL) + layout->ParentItemIndex = layout->Parent->CurrentItemIndex; + if (window_state->CurrentLayout) + { + layout->NextSibling = window_state->CurrentLayout->FirstChild; + layout->FirstChild = NULL; + window_state->CurrentLayout->FirstChild = layout; + } + else + { + layout->NextSibling = NULL; + layout->FirstChild = NULL; + } + } + + window_state->LayoutStack.push_back(layout); + window_state->CurrentLayout = layout; + window_state->CurrentLayoutItem = NULL; +} + +static void ImGui::PopLayout(ImGuiLayout* layout) +{ + ImGuiLayoutWindowState* window_state = GetCurrentWindowLayoutState(); + + IM_ASSERT(!window_state->LayoutStack.empty()); + IM_ASSERT(window_state->LayoutStack.back() == layout); + IM_UNUSED(layout); + + window_state->LayoutStack.pop_back(); + + if (!window_state->LayoutStack.empty()) + { + window_state->CurrentLayout = window_state->LayoutStack.back(); + window_state->CurrentLayoutItem = &window_state->CurrentLayout->Items[window_state->CurrentLayout->CurrentItemIndex]; + } + else + { + window_state->CurrentLayout = NULL; + window_state->CurrentLayoutItem = NULL; + } +} + +static void ImGui::BalanceLayoutSprings(ImGuiLayout& layout) +{ + // Accumulate amount of occupied space and springs weights + float total_spring_weight = 0.0f; + + int last_spring_item_index = -1; + for (int i = 0; i < layout.Items.Size; i++) + { + ImGuiLayoutItem& item = layout.Items[i]; + if (item.Type == ImGuiLayoutItemType_Spring) + { + total_spring_weight += item.SpringWeight; + last_spring_item_index = i; + } + } + + // Determine occupied space and available space depending on layout type + const bool is_horizontal = (layout.Type == ImGuiLayoutType_Horizontal); + const bool is_auto_sized = ((is_horizontal ? layout.Size.x : layout.Size.y) <= 0.0f) && (layout.Parent == NULL); + const float occupied_space = is_horizontal ? layout.MinimumSize.x : layout.MinimumSize.y; + const float available_space = is_auto_sized ? occupied_space : (is_horizontal ? layout.CurrentSize.x : layout.CurrentSize.y); + const float free_space = ImMax(available_space - occupied_space, 0.0f); + + float span_start = 0.0f; + float current_weight = 0.0f; + for (int i = 0; i < layout.Items.Size; i++) + { + ImGuiLayoutItem& item = layout.Items[i]; + if (item.Type != ImGuiLayoutItemType_Spring) + continue; + + float last_spring_size = item.SpringSize; + + if (free_space > 0.0f && total_spring_weight > 0.0f) + { + float next_weight = current_weight + item.SpringWeight; + float span_end = ImFloor((i == last_spring_item_index) ? free_space : (free_space * next_weight / total_spring_weight)); + float spring_size = span_end - span_start; + item.SpringSize = spring_size; + span_start = span_end; + current_weight = next_weight; + } + else + { + item.SpringSize = 0.0f; + } + + // If spring changed its size, fix positioning of following items to avoid one frame visual bugs. + if (last_spring_size != item.SpringSize) + { + float difference = item.SpringSize - last_spring_size; + + ImVec2 offset = is_horizontal ? ImVec2(difference, 0.0f) : ImVec2(0.0f, difference); + + item.MeasuredBounds.Max += offset; + + for (int j = i + 1; j < layout.Items.Size; j++) + { + ImGuiLayoutItem& translated_item = layout.Items[j]; + + TranslateLayoutItem(translated_item, offset); + + translated_item.MeasuredBounds.Min += offset; + translated_item.MeasuredBounds.Max += offset; + } + } + } +} + +static ImVec2 ImGui::BalanceLayoutItemAlignment(ImGuiLayout& layout, ImGuiLayoutItem& item) +{ + // Fixup item alignment if necessary. + ImVec2 position_correction = ImVec2(0.0f, 0.0f); + if (item.CurrentAlign > 0.0f) + { + float item_align_offset = CalculateLayoutItemAlignmentOffset(layout, item); + if (item.CurrentAlignOffset != item_align_offset) + { + float offset = item_align_offset - item.CurrentAlignOffset; + + if (layout.Type == ImGuiLayoutType_Horizontal) + position_correction.y = offset; + else + position_correction.x = offset; + + TranslateLayoutItem(item, position_correction); + + item.CurrentAlignOffset = item_align_offset; + } + } + + return position_correction; +} + +static void ImGui::BalanceLayoutItemsAlignment(ImGuiLayout& layout) +{ + for (int i = 0; i < layout.Items.Size; ++i) + { + ImGuiLayoutItem& item = layout.Items[i]; + BalanceLayoutItemAlignment(layout, item); + } +} + +static bool ImGui::HasAnyNonZeroSpring(ImGuiLayout& layout) +{ + for (int i = 0; i < layout.Items.Size; ++i) + { + ImGuiLayoutItem& item = layout.Items[i]; + if (item.Type != ImGuiLayoutItemType_Spring) + continue; + if (item.SpringWeight > 0) + return true; + } + return false; +} + +static void ImGui::BalanceChildLayouts(ImGuiLayout& layout) +{ + for (ImGuiLayout* child = layout.FirstChild; child != NULL; child = child->NextSibling) + { + //ImVec2 child_layout_size = child->CurrentSize; + + // Propagate layout size down to child layouts. + // + // TODO: Distribution assume inner layout is only + // element inside parent item and assigns + // all available space to it. + // + // Investigate how to split space between + // adjacent layouts. + // + // Investigate how to measure non-layout items + // to treat them as fixed size blocks. + // + if (child->Type == ImGuiLayoutType_Horizontal && child->Size.x <= 0.0f) + child->CurrentSize.x = layout.CurrentSize.x; + else if (child->Type == ImGuiLayoutType_Vertical && child->Size.y <= 0.0f) + child->CurrentSize.y = layout.CurrentSize.y; + + BalanceChildLayouts(*child); + + //child->CurrentSize = child_layout_size; + + if (HasAnyNonZeroSpring(*child)) + { + // Expand item measured bounds to make alignment correct. + ImGuiLayoutItem& item = layout.Items[child->ParentItemIndex]; + + if (child->Type == ImGuiLayoutType_Horizontal && child->Size.x <= 0.0f) + item.MeasuredBounds.Max.x = ImMax(item.MeasuredBounds.Max.x, item.MeasuredBounds.Min.x + layout.CurrentSize.x); + else if (child->Type == ImGuiLayoutType_Vertical && child->Size.y <= 0.0f) + item.MeasuredBounds.Max.y = ImMax(item.MeasuredBounds.Max.y, item.MeasuredBounds.Min.y + layout.CurrentSize.y); + } + } + + BalanceLayoutSprings(layout); + BalanceLayoutItemsAlignment(layout); +} + +static void ImGui::BeginLayoutClipRect(ImGuiLayout& layout) +{ + ImGuiWindow* window = GetCurrentWindow(); + + // Use splitter to collect draw commands in separate channel, + // so we can clip them to the layout bounds. + layout.Splitter.Split(window->DrawList, 2); + layout.Splitter.SetCurrentChannel(window->DrawList, 1); + + // Clip to layout bounds, unrestricted and not measured bounds span + // all the way to the edge of the window. + ImVec2 clip_rect_min = layout.StartPos; + ImVec2 clip_rect_max; + clip_rect_max.x = layout.Size.x > 0.0f ? layout.StartPos.x + layout.Size.x : FLT_MAX; + clip_rect_max.y = layout.Size.y > 0.0f ? layout.StartPos.y + layout.Size.y : FLT_MAX; + + PushClipRect(clip_rect_min, clip_rect_max, true); +} + +static void ImGui::EndLayoutClipRect(ImGuiLayout& layout) +{ + PopClipRect(); + + if (layout.Parent != NULL) + return; + + ApplyLayoutClipRect(layout); + + MergeLayoutSplitters(layout); +} + +static void ImGui::ApplyLayoutClipRect(ImGuiLayout& layout) +{ + for (ImGuiLayout* child = layout.FirstChild; child != NULL; child = child->NextSibling) + ApplyLayoutClipRect(*child); + + ImGuiWindow* window = GetCurrentWindow(); + + ImVec4 current_clip_rect; + current_clip_rect.x = layout.StartPos.x; + current_clip_rect.y = layout.StartPos.y; + current_clip_rect.z = layout.StartPos.x + layout.MeasuredSize.x; + current_clip_rect.w = layout.StartPos.y + layout.MeasuredSize.y; + + layout.Splitter.SetCurrentChannel(window->DrawList, 0); + for (ImDrawCmd& cmd : layout.Splitter._Channels[1]._CmdBuffer) + { + + if (cmd.ClipRect.x < current_clip_rect.x) cmd.ClipRect.x = current_clip_rect.x; + if (cmd.ClipRect.y < current_clip_rect.y) cmd.ClipRect.y = current_clip_rect.y; + if (cmd.ClipRect.z > current_clip_rect.z) cmd.ClipRect.z = current_clip_rect.z; + if (cmd.ClipRect.w > current_clip_rect.w) cmd.ClipRect.w = current_clip_rect.w; + } + + //GetForegroundDrawList()->AddRect(layout.StartPos, layout.StartPos + layout.MeasuredSize, IM_COL32(255,0,0,128)); // [DEBUG] +} + +static void ImGui::MergeLayoutSplitters(ImGuiLayout& layout) +{ + for (ImGuiLayout* child = layout.FirstChild; child != NULL; child = child->NextSibling) + MergeLayoutSplitters(*child); + + ImGuiWindow* window = GetCurrentWindow(); + + layout.Splitter.Merge(window->DrawList); +} + +static ImGuiLayoutItem* ImGui::GenerateLayoutItem(ImGuiLayout& layout, ImGuiLayoutItemType type) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(layout.CurrentItemIndex <= layout.Items.Size); + + if (layout.CurrentItemIndex < layout.Items.Size) + { + ImGuiLayoutItem& item = layout.Items[layout.CurrentItemIndex]; + if (item.Type != type) + item = ImGuiLayoutItem(type); + } + else + { + layout.Items.push_back(ImGuiLayoutItem(type)); + } + + ImGuiLayoutWindowState* window_state = GetCurrentWindowLayoutState(); + window_state->CurrentLayoutItem = &layout.Items[layout.CurrentItemIndex]; + + return &layout.Items[layout.CurrentItemIndex]; +} + +// Calculate how many pixels from top/left layout edge item need to be moved to match +// layout alignment. +static float ImGui::CalculateLayoutItemAlignmentOffset(ImGuiLayout& layout, ImGuiLayoutItem& item) +{ + if (item.CurrentAlign <= 0.0f) + return 0.0f; + + ImVec2 item_size = item.MeasuredBounds.GetSize(); + + float layout_extent = (layout.Type == ImGuiLayoutType_Horizontal) ? layout.CurrentSize.y : layout.CurrentSize.x; + float item_extent = (layout.Type == ImGuiLayoutType_Horizontal) ? item_size.y : item_size.x; + + if (item_extent <= 0/* || layout_extent <= item_extent*/) + return 0.0f; + + float align_offset = ImFloor(item.CurrentAlign * (layout_extent - item_extent)); + + return align_offset; +} + +static void ImGui::TranslateLayoutItem(ImGuiLayoutItem& item, const ImVec2& offset) +{ + if ((offset.x == 0.0f && offset.y == 0.0f) || (item.VertexIndexBegin == item.VertexIndexEnd)) + return; + + //IMGUI_DEBUG_LOG("TranslateLayoutItem by %f,%f\n", offset.x, offset.y); + ImDrawList* draw_list = GetWindowDrawList(); + + ImDrawVert* begin = draw_list->VtxBuffer.Data + item.VertexIndexBegin; + ImDrawVert* end = draw_list->VtxBuffer.Data + item.VertexIndexEnd; + + for (ImDrawVert* vtx = begin; vtx < end; ++vtx) + { + vtx->pos.x += offset.x; + vtx->pos.y += offset.y; + } +} + +static void ImGui::SignedIndent(float indent) +{ + if (indent > 0.0f) + Indent(indent); + else if (indent < 0.0f) + Unindent(-indent); +} + +static void ImGui::BeginLayoutItem(ImGuiLayout& layout) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiLayoutItem& item = *GenerateLayoutItem(layout, ImGuiLayoutItemType_Item); + + item.CurrentAlign = layout.Align; + if (item.CurrentAlign < 0.0f) + item.CurrentAlign = ImClamp(g.Style.LayoutAlign, 0.0f, 1.0f); + + // Align item according to data from previous frame. + // If layout changes in current frame alignment will + // be corrected in EndLayout() to it visualy coherent. + item.CurrentAlignOffset = CalculateLayoutItemAlignmentOffset(layout, item); + if (item.CurrentAlign > 0.0f) + { + if (layout.Type == ImGuiLayoutType_Horizontal) + { + window->DC.CursorPos.y += item.CurrentAlignOffset; + } + else + { + float new_position = window->DC.CursorPos.x + item.CurrentAlignOffset; + + // Make placement behave like in horizontal case when next + // widget is placed at very same Y position. This indent + // make sure for vertical layout placed widgets has same X position. + SignedIndent(item.CurrentAlignOffset); + + window->DC.CursorPos.x = new_position; + } + } + + item.MeasuredBounds.Min = item.MeasuredBounds.Max = window->DC.CursorPos; + item.VertexIndexBegin = item.VertexIndexEnd = window->DrawList->_VtxCurrentIdx; +} + +static void ImGui::EndLayoutItem(ImGuiLayout& layout) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + IM_ASSERT(layout.CurrentItemIndex < layout.Items.Size); + + ImGuiLayoutItem& item = layout.Items[layout.CurrentItemIndex]; + + ImDrawList* draw_list = window->DrawList; + item.VertexIndexEnd = draw_list->_VtxCurrentIdx; + + if (item.CurrentAlign > 0.0f && layout.Type == ImGuiLayoutType_Vertical) + SignedIndent(-item.CurrentAlignOffset); + + // Fixup item alignment in case item size changed in current frame. + ImVec2 position_correction = BalanceLayoutItemAlignment(layout, item); + + item.MeasuredBounds.Min += position_correction; + item.MeasuredBounds.Max += position_correction; + + if (layout.Type == ImGuiLayoutType_Horizontal) + window->DC.CursorPos.y = layout.StartPos.y; + else + window->DC.CursorPos.x = layout.StartPos.x; + + layout.CurrentItemIndex++; +} + +static void ImGui::AddLayoutSpring(ImGuiLayout& layout, float weight, float spacing) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiLayoutItem* previous_item = &layout.Items[layout.CurrentItemIndex]; + + // Undo item padding, spring should consume all space between items. + if (layout.Type == ImGuiLayoutType_Horizontal) + window->DC.CursorPos.x = previous_item->MeasuredBounds.Max.x; + else + window->DC.CursorPos.y = previous_item->MeasuredBounds.Max.y; + + previous_item = NULL; // may be invalid after call to GenerateLayoutItem() + + EndLayoutItem(layout); + + ImGuiLayoutItem* spring_item = GenerateLayoutItem(layout, ImGuiLayoutItemType_Spring); + + spring_item->MeasuredBounds.Min = spring_item->MeasuredBounds.Max = window->DC.CursorPos; + + if (weight < 0.0f) + weight = 0.0f; + + if (spring_item->SpringWeight != weight) + spring_item->SpringWeight = weight; + + if (spacing < 0.0f) + { + ImVec2 style_spacing = g.Style.ItemSpacing; + if (layout.Type == ImGuiLayoutType_Horizontal) + spacing = style_spacing.x; + else + spacing = style_spacing.y; + } + + if (spring_item->SpringSpacing != spacing) + spring_item->SpringSpacing = spacing; + + if (spring_item->SpringSize > 0.0f || spacing > 0.0f) + { + ImVec2 spring_size, spring_spacing; + if (layout.Type == ImGuiLayoutType_Horizontal) + { + spring_spacing = ImVec2(0.0f, g.Style.ItemSpacing.y); + spring_size = ImVec2(spacing + spring_item->SpringSize, layout.CurrentSize.y); + } + else + { + spring_spacing = ImVec2(g.Style.ItemSpacing.x, 0.0f); + spring_size = ImVec2(layout.CurrentSize.x, spacing + spring_item->SpringSize); + } + + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImFloor(spring_spacing)); + Dummy(ImFloor(spring_size)); + PopStyleVar(); + } + + layout.CurrentItemIndex++; + + BeginLayoutItem(layout); +} + + +//----------------------------------------------------------------------------- +// [SECTION] Stack Layout: Internal API +//----------------------------------------------------------------------------- + +ImGuiLayoutType ImGuiInternal::GetCurrentLayoutType(ImGuiID window_id) +{ + ImGuiLayoutWindowState* state = GetWindowLayoutState(window_id); + + ImGuiLayoutType layout_type = state->Window->DC.LayoutType; + if (state->CurrentLayout) + layout_type = state->CurrentLayout->Type; + + return layout_type; +} + +void ImGuiInternal::UpdateItemRect(ImGuiID window_id, const ImVec2& min, const ImVec2& max) +{ + ImGuiLayoutWindowState* state = GetWindowLayoutState(window_id); + + if (state->CurrentLayoutItem) + state->CurrentLayoutItem->MeasuredBounds.Max = ImMax(state->CurrentLayoutItem->MeasuredBounds.Max, max); + + IM_UNUSED(min); +} + + +//----------------------------------------------------------------------------- +// [SECTION] Stack Layout: Public API +//----------------------------------------------------------------------------- + +void ImGui::BeginHorizontal(const char* str_id, const ImVec2& size/* = ImVec2(0, 0)*/, float align/* = -1*/) +{ + ImGuiWindow* window = GetCurrentWindow(); + BeginLayout(window->GetID(str_id), ImGuiLayoutType_Horizontal, size, align); +} + +void ImGui::BeginHorizontal(const void* ptr_id, const ImVec2& size/* = ImVec2(0, 0)*/, float align/* = -1*/) +{ + ImGuiWindow* window = GetCurrentWindow(); + BeginLayout(window->GetID(ptr_id), ImGuiLayoutType_Horizontal, size, align); +} + +void ImGui::BeginHorizontal(int id, const ImVec2& size/* = ImVec2(0, 0)*/, float align/* = -1*/) +{ + ImGuiWindow* window = GetCurrentWindow(); + BeginLayout(window->GetID((void*)(intptr_t)id), ImGuiLayoutType_Horizontal, size, align); +} + +void ImGui::EndHorizontal() +{ + EndLayout(ImGuiLayoutType_Horizontal); +} + +void ImGui::BeginVertical(const char* str_id, const ImVec2& size/* = ImVec2(0, 0)*/, float align/* = -1*/) +{ + ImGuiWindow* window = GetCurrentWindow(); + BeginLayout(window->GetID(str_id), ImGuiLayoutType_Vertical, size, align); +} + +void ImGui::BeginVertical(const void* ptr_id, const ImVec2& size/* = ImVec2(0, 0)*/, float align/* = -1*/) +{ + ImGuiWindow* window = GetCurrentWindow(); + BeginLayout(window->GetID(ptr_id), ImGuiLayoutType_Vertical, size, align); +} + +void ImGui::BeginVertical(int id, const ImVec2& size/* = ImVec2(0, 0)*/, float align/* = -1*/) +{ + ImGuiWindow* window = GetCurrentWindow(); + BeginLayout(window->GetID((void*)(intptr_t)id), ImGuiLayoutType_Vertical, size, align); +} + +void ImGui::EndVertical() +{ + EndLayout(ImGuiLayoutType_Vertical); +} + +// Inserts spring separator in layout +// weight <= 0 : spring will always have zero size +// weight > 0 : power of current spring +// spacing < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 +// spacing >= 0 : enforce spacing amount +void ImGui::Spring(float weight/* = 1.0f*/, float spacing/* = -1.0f*/) +{ + ImGuiLayoutWindowState* window_state = GetCurrentWindowLayoutState(); + IM_ASSERT(window_state->CurrentLayout); + + AddLayoutSpring(*window_state->CurrentLayout, weight, spacing); +} + +void ImGui::SuspendLayout() +{ + PushLayout(NULL); +} + +void ImGui::ResumeLayout() +{ + ImGuiLayoutWindowState* window_state = GetCurrentWindowLayoutState(); + IM_ASSERT(!window_state->CurrentLayout); + IM_ASSERT(!window_state->LayoutStack.empty()); + IM_UNUSED(window_state); + PopLayout(NULL); +} + +//----------------------------------------------------------------------------- + +#endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/imgui_stacklayout.h b/3rdparty/imgui/imgui_stacklayout.h new file mode 100644 index 0000000..d9364df --- /dev/null +++ b/3rdparty/imgui/imgui_stacklayout.h @@ -0,0 +1,38 @@ +// dear imgui, v1.86 WIP +// (stack layout headers) + +/* + +Index of this file: +// [SECTION] Stack Layout API + +*/ + +#pragma once + +#include "imgui.h" + +#ifndef IMGUI_DISABLE + +//----------------------------------------------------------------------------- +// [SECTION] Stack Layout API +//----------------------------------------------------------------------------- + +namespace ImGui +{ + IMGUI_API void BeginHorizontal(const char* str_id, const ImVec2& size = ImVec2(0, 0), float align = -1.0f); + IMGUI_API void BeginHorizontal(const void* ptr_id, const ImVec2& size = ImVec2(0, 0), float align = -1.0f); + IMGUI_API void BeginHorizontal(int id, const ImVec2& size = ImVec2(0, 0), float align = -1); + IMGUI_API void EndHorizontal(); + IMGUI_API void BeginVertical(const char* str_id, const ImVec2& size = ImVec2(0, 0), float align = -1.0f); + IMGUI_API void BeginVertical(const void* ptr_id, const ImVec2& size = ImVec2(0, 0), float align = -1.0f); + IMGUI_API void BeginVertical(int id, const ImVec2& size = ImVec2(0, 0), float align = -1); + IMGUI_API void EndVertical(); + IMGUI_API void Spring(float weight = 1.0f, float spacing = -1.0f); + IMGUI_API void SuspendLayout(); + IMGUI_API void ResumeLayout(); + +} // namespace ImGui + + +#endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/imgui_stacklayout_internal.h b/3rdparty/imgui/imgui_stacklayout_internal.h new file mode 100644 index 0000000..4a5e9bd --- /dev/null +++ b/3rdparty/imgui/imgui_stacklayout_internal.h @@ -0,0 +1,30 @@ +// dear imgui, v1.86 WIP +// (stack layout headers) + +/* + +Index of this file: +// [SECTION] Stack Layout Internal API + +*/ + +#pragma once + +#include "imgui_internal.h" +#include "imgui_stacklayout.h" + +#ifndef IMGUI_DISABLE + +//----------------------------------------------------------------------------- +// [SECTION] Stack Layout Internal API +//----------------------------------------------------------------------------- + +namespace ImGuiInternal +{ + IMGUI_API ImGuiLayoutType GetCurrentLayoutType(ImGuiID window_id); + IMGUI_API void UpdateItemRect(ImGuiID window_id, const ImVec2& min, const ImVec2& max); + +} // namespace ImGuiInternal + + +#endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/imgui_tables.cpp b/3rdparty/imgui/imgui_tables.cpp index e7a3b8e..ce6fed1 100644 --- a/3rdparty/imgui/imgui_tables.cpp +++ b/3rdparty/imgui/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.0 WIP // (tables and columns code) /* @@ -229,14 +229,9 @@ Index of this file: #pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access -#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked -#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function -#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' -#pragma GCC diagnostic ignored "-Wstrict-overflow" #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif @@ -333,7 +328,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG // - always performing the GetOrAddByKey() O(log N) query in g.Tables.Map[]. const bool use_child_window = (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) != 0; const ImVec2 avail_size = GetContentRegionAvail(); - const ImVec2 actual_outer_size = ImTrunc(CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f)); + const ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f); const ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size); const bool outer_window_is_measuring_size = (outer_window->AutoFitFramesX > 0) || (outer_window->AutoFitFramesY > 0); // Doesn't apply to AlwaysAutoResize windows! if (use_child_window && IsClippedEx(outer_rect, 0) && !outer_window_is_measuring_size) @@ -374,7 +369,6 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->ColumnsCount = columns_count; table->IsLayoutLocked = false; table->InnerWidth = inner_width; - table->NavLayer = (ImS8)outer_window->DC.NavLayerCurrent; temp_data->UserOuterSize = outer_size; // Instance data (for instance 0, TableID == TableInstanceID) @@ -415,8 +409,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG // Reset scroll if we are reactivating it if ((previous_flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) == 0) - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll) == 0) - SetNextWindowScroll(ImVec2(0.0f, 0.0f)); + SetNextWindowScroll(ImVec2(0.0f, 0.0f)); // Create scrolling region (without border and zero window padding) ImGuiWindowFlags child_window_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None; @@ -467,27 +460,16 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG temp_data->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size; inner_window->DC.PrevLineSize = inner_window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); - // Make borders not overlap our contents by offsetting HostClipRect (#6765, #7428, #3752) + // Make left and top borders not overlap our contents by offsetting HostClipRect (#6765) // (we normally shouldn't alter HostClipRect as we rely on TableMergeDrawChannels() expanding non-clipped column toward the // limits of that rectangle, in order for ImDrawListSplitter::Merge() to merge the draw commands. However since the overlap // problem only affect scrolling tables in this case we can get away with doing it without extra cost). if (inner_window != outer_window) { - // FIXME: Because inner_window's Scrollbar doesn't know about border size, since it's not encoded in window->WindowBorderSize, - // it already overlaps it and doesn't need an extra offset. Ideally we should be able to pass custom border size with - // different x/y values to BeginChild(). if (flags & ImGuiTableFlags_BordersOuterV) - { table->HostClipRect.Min.x = ImMin(table->HostClipRect.Min.x + TABLE_BORDER_SIZE, table->HostClipRect.Max.x); - if (inner_window->DecoOuterSizeX2 == 0.0f) - table->HostClipRect.Max.x = ImMax(table->HostClipRect.Max.x - TABLE_BORDER_SIZE, table->HostClipRect.Min.x); - } if (flags & ImGuiTableFlags_BordersOuterH) - { table->HostClipRect.Min.y = ImMin(table->HostClipRect.Min.y + TABLE_BORDER_SIZE, table->HostClipRect.Max.y); - if (inner_window->DecoOuterSizeY2 == 0.0f) - table->HostClipRect.Max.y = ImMax(table->HostClipRect.Max.y - TABLE_BORDER_SIZE, table->HostClipRect.Min.y); - } } // Padding and Spacing @@ -515,7 +497,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->InnerClipRect = (inner_window == outer_window) ? table->WorkRect : inner_window->ClipRect; table->InnerClipRect.ClipWith(table->WorkRect); // We need this to honor inner_width table->InnerClipRect.ClipWithFull(table->HostClipRect); - table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : table->HostClipRect.Max.y; + table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : inner_window->ClipRect.Max.y; table->RowPosY1 = table->RowPosY2 = table->WorkRect.Min.y; // This is needed somehow table->RowTextBaseline = 0.0f; // This will be cleared again by TableBeginRow() @@ -873,7 +855,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping) // Combine width from regular rows + width from headers unless requested not to. - if (!column->IsPreserveWidthAuto && table->InstanceCurrent == 0) + if (!column->IsPreserveWidthAuto) column->WidthAuto = TableGetColumnWidthAuto(table, column); // Non-resizable columns keep their requested width (apply user value regardless of IsPreserveWidthAuto) @@ -1051,8 +1033,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) const int column_n = table->DisplayOrderToIndex[order_n]; ImGuiTableColumn* column = &table->Columns[column_n]; - // Initial nav layer: using FreezeRowsCount, NOT FreezeRowsRequest, so Header line changes layer when frozen - column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : (ImGuiNavLayer)table->NavLayer); + column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); // Use Count NOT request so Header line changes layer when frozen if (offset_x_frozen && table->FreezeColumnsCount == visible_n) { @@ -1078,12 +1059,16 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) continue; } + // Detect hovered column + if (is_hovering_table && mouse_skewed_x >= column->ClipRect.Min.x && mouse_skewed_x < column->ClipRect.Max.x) + table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n; + // Lock start position column->MinX = offset_x; // Lock width based on start position and minimum/maximum width for this position - column->WidthMax = TableCalcMaxColumnWidth(table, column_n); - column->WidthGiven = ImMin(column->WidthGiven, column->WidthMax); + float max_width = TableGetMaxColumnWidth(table, column_n); + column->WidthGiven = ImMin(column->WidthGiven, max_width); column->WidthGiven = ImMax(column->WidthGiven, ImMin(column->WidthRequest, table->MinColumnWidth)); column->MaxX = offset_x + column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f; @@ -1132,13 +1117,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) column->Flags |= ImGuiTableColumnFlags_IsVisible; if (column->SortOrder != -1) column->Flags |= ImGuiTableColumnFlags_IsSorted; - - // Detect hovered column - if (is_hovering_table && mouse_skewed_x >= column->ClipRect.Min.x && mouse_skewed_x < column->ClipRect.Max.x) - { + if (table->HoveredColumnBody == column_n) column->Flags |= ImGuiTableColumnFlags_IsHovered; - table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n; - } // Alignment // FIXME-TABLE: This align based on the whole column width, not per-cell, and therefore isn't useful in @@ -1168,7 +1148,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) } // Don't decrement auto-fit counters until container window got a chance to submit its items - if (table->HostSkipItems == false && table->InstanceCurrent == 0) + if (table->HostSkipItems == false) { column->AutoFitQueue >>= 1; column->CannotSkipItemsQueue >>= 1; @@ -1269,7 +1249,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) if (table->Flags & ImGuiTableFlags_NoClip) table->DrawSplitter->SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); else - inner_window->DrawList->PushClipRect(inner_window->InnerClipRect.Min, inner_window->InnerClipRect.Max, false); // FIXME: use table->InnerClipRect? + inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false); } // Process hit-testing on resizing borders. Actual size change will be applied in EndTable() @@ -1339,11 +1319,7 @@ void ImGui::EndTable() { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "EndTable() call should only be done while in BeginTable() scope!"); - return; - } + IM_ASSERT(table != NULL && "Only call EndTable() if BeginTable() returns true!"); // This assert would be very useful to catch a common error... unfortunately it would probably trigger in some // cases, and for consistency user may sometimes output empty tables (and still benefit from e.g. outer border) @@ -1495,10 +1471,8 @@ void ImGui::EndTable() if (inner_window != outer_window) { short backup_nav_layers_active_mask = inner_window->DC.NavLayersActiveMask; - inner_window->DC.NavLayersActiveMask |= 1 << table->NavLayer; // So empty table don't appear to navigate differently. - g.CurrentTable = NULL; // To avoid error recovery recursing + inner_window->DC.NavLayersActiveMask |= 1 << ImGuiNavLayer_Main; // So empty table don't appear to navigate differently. EndChild(); - g.CurrentTable = table; inner_window->DC.NavLayersActiveMask = backup_nav_layers_active_mask; } else @@ -1566,12 +1540,8 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); - return; - } - IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!"); + IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!"); + IM_ASSERT(table->IsLayoutLocked == false && "Need to call call TableSetupColumn() before first row!"); IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()"); if (table->DeclColumnsCount >= table->ColumnsCount) { @@ -1644,11 +1614,7 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows) { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); - return; - } + IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!"); IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!"); IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS); IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit @@ -1725,11 +1691,9 @@ void ImGui::TableSetColumnEnabled(int column_n, bool enabled) { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); + IM_ASSERT(table != NULL); + if (!table) return; - } IM_ASSERT(table->Flags & ImGuiTableFlags_Hideable); // See comments above if (column_n < 0) column_n = table->CurrentColumn; @@ -2032,37 +1996,34 @@ void ImGui::TableEndRow(ImGuiTable* table) // We need to do that in TableEndRow() instead of TableBeginRow() so the list clipper can mark end of row and // get the new cursor position. if (unfreeze_rows_request) - { for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - table->Columns[column_n].NavLayerCurrent = table->NavLayer; - const float y0 = ImMax(table->RowPosY2 + 1, table->InnerClipRect.Min.y); + table->Columns[column_n].NavLayerCurrent = ImGuiNavLayer_Main; + if (unfreeze_rows_actual) + { + IM_ASSERT(table->IsUnfrozenRows == false); + const float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y); + table->IsUnfrozenRows = true; table_instance->LastFrozenHeight = y0 - table->OuterRect.Min.y; - if (unfreeze_rows_actual) + // BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect + table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y); + table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = window->InnerClipRect.Max.y; + table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen; + IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y); + + float row_height = table->RowPosY2 - table->RowPosY1; + table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y; + table->RowPosY1 = table->RowPosY2 - row_height; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { - IM_ASSERT(table->IsUnfrozenRows == false); - table->IsUnfrozenRows = true; - - // BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect - table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, table->InnerClipRect.Max.y); - table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = table->InnerClipRect.Max.y; - table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen; - IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y); - - float row_height = table->RowPosY2 - table->RowPosY1; - table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y; - table->RowPosY1 = table->RowPosY2 - row_height; - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - { - ImGuiTableColumn* column = &table->Columns[column_n]; - column->DrawChannelCurrent = column->DrawChannelUnfrozen; - column->ClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y; - } - - // Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y - SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect); - table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent); + ImGuiTableColumn* column = &table->Columns[column_n]; + column->DrawChannelCurrent = column->DrawChannelUnfrozen; + column->ClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y; } + + // Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y + SetWindowClipRectBeforeSetChannel(window, table->Columns[0].ClipRect); + table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[0].DrawChannelCurrent); } if (!(table->RowFlags & ImGuiTableRowFlags_Headers)) @@ -2231,8 +2192,8 @@ void ImGui::TableEndCell(ImGuiTable* table) // Note that actual columns widths are computed in TableUpdateLayout(). //------------------------------------------------------------------------- -// Maximum column content width given current layout. Use column->MinX so this value differs on a per-column basis. -float ImGui::TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n) +// Maximum column content width given current layout. Use column->MinX so this value on a per-column basis. +float ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n) { const ImGuiTableColumn* column = &table->Columns[column_n]; float max_width = FLT_MAX; @@ -2294,7 +2255,7 @@ void ImGui::TableSetColumnWidth(int column_n, float width) // Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded) IM_ASSERT(table->MinColumnWidth > 0.0f); const float min_width = table->MinColumnWidth; - const float max_width = ImMax(min_width, column_0->WidthMax); // Don't use TableCalcMaxColumnWidth() here as it would rely on MinX from last instance (#7933) + const float max_width = ImMax(min_width, TableGetMaxColumnWidth(table, column_n)); column_0_width = ImClamp(column_0_width, min_width, max_width); if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width) return; @@ -2779,7 +2740,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) const ImU32 outer_col = table->BorderColorStrong; if ((table->Flags & ImGuiTableFlags_BordersOuter) == ImGuiTableFlags_BordersOuter) { - inner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, 0, border_size); + inner_drawlist->AddRect(outer_border.Min, outer_border.Max + ImVec2(1, 1), outer_col, 0.0f, 0, border_size); } else if (table->Flags & ImGuiTableFlags_BordersOuterV) { @@ -3043,21 +3004,15 @@ float ImGui::TableGetHeaderAngledMaxLabelWidth() // The intent is that advanced users willing to create customized headers would not need to use this helper // and can create their own! For example: TableHeader() may be preceded by Checkbox() or other custom widgets. // See 'Demo->Tables->Custom headers' for a demonstration of implementing a custom version of this. -// This code is intentionally written to not make much use of internal functions, to give you better direction -// if you need to write your own. +// This code is constructed to not make much use of internal functions, as it is intended to be a template to copy. // FIXME-TABLE: TableOpenContextMenu() and TableGetHeaderRowHeight() are not public. void ImGui::TableHeadersRow() { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); - return; - } + IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!"); - // Call layout if not already done. This is automatically done by TableNextRow: we do it here _only_ to make - // it easier to debug-step in TableUpdateLayout(). Your own version of this function doesn't need this. + // Layout if not already done (this is automatically done by TableNextRow, we do it here solely to facilitate stepping in debugger as it is frequent to step in TableUpdateLayout) if (!table->IsLayoutLocked) TableUpdateLayout(table); @@ -3074,7 +3029,8 @@ void ImGui::TableHeadersRow() if (!TableSetColumnIndex(column_n)) continue; - // Push an id to allow empty/unnamed headers. This is also idiomatic as it ensure there is a consistent ID path to access columns (for e.g. automation) + // Push an id to allow unnamed labels (generally accidental, but let's behave nicely with them) + // In your own code you may omit the PushID/PopID all-together, provided you know they won't collide. const char* name = (TableGetColumnFlags(column_n) & ImGuiTableColumnFlags_NoHeaderLabel) ? "" : TableGetColumnName(column_n); PushID(column_n); TableHeader(name); @@ -3099,12 +3055,7 @@ void ImGui::TableHeader(const char* label) return; ImGuiTable* table = g.CurrentTable; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); - return; - } - + IM_ASSERT(table != NULL && "Need to call TableHeader() after BeginTable()!"); IM_ASSERT(table->CurrentColumn != -1); const int column_n = table->CurrentColumn; ImGuiTableColumn* column = &table->Columns[column_n]; @@ -3170,7 +3121,7 @@ void ImGui::TableHeader(const char* label) if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0) TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn); } - RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding); + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact | ImGuiNavHighlightFlags_NoRounding); if (held) table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n; window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f; @@ -3279,11 +3230,7 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label ImGuiTable* table = g.CurrentTable; ImGuiWindow* window = g.CurrentWindow; ImDrawList* draw_list = window->DrawList; - if (table == NULL) - { - IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); - return; - } + IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!"); IM_ASSERT(table->CurrentRow == -1 && "Must be first row"); if (max_label_width == 0.0f) @@ -3328,7 +3275,7 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label const ImVec2 align = g.Style.TableAngledHeadersTextAlign; // Draw background and labels in first pass, then all borders. - float max_x = -FLT_MAX; + float max_x = 0.0f; for (int pass = 0; pass < 2; pass++) for (int order_n = 0; order_n < data_count; order_n++) { @@ -4446,7 +4393,7 @@ void ImGui::EndColumns() { ButtonBehavior(column_hit_rect, column_id, &hovered, &held); if (hovered || held) - SetMouseCursor(ImGuiMouseCursor_ResizeEW); + g.MouseCursor = ImGuiMouseCursor_ResizeEW; if (held && !(column->Flags & ImGuiOldColumnFlags_NoResize)) dragging_column = n; } @@ -4478,12 +4425,12 @@ void ImGui::EndColumns() NavUpdateCurrentWindowIsScrollPushableX(); } -void ImGui::Columns(int columns_count, const char* id, bool borders) +void ImGui::Columns(int columns_count, const char* id, bool border) { ImGuiWindow* window = GetCurrentWindow(); IM_ASSERT(columns_count >= 1); - ImGuiOldColumnFlags flags = (borders ? 0 : ImGuiOldColumnFlags_NoBorder); + ImGuiOldColumnFlags flags = (border ? 0 : ImGuiOldColumnFlags_NoBorder); //flags |= ImGuiOldColumnFlags_NoPreserveWidths; // NB: Legacy behavior ImGuiOldColumns* columns = window->DC.CurrentColumns; if (columns != NULL && columns->Count == columns_count && columns->Flags == flags) diff --git a/3rdparty/imgui/imgui_widgets.cpp b/3rdparty/imgui/imgui_widgets.cpp index 8f3f53b..d488b88 100644 --- a/3rdparty/imgui/imgui_widgets.cpp +++ b/3rdparty/imgui/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.0 WIP // (widgets code) /* @@ -79,17 +79,11 @@ Index of this file: #pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access -#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe -#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked -#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated -#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function -#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead -#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #endif //------------------------------------------------------------------------- @@ -134,7 +128,7 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1); // For InputTextEx() static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard = false); static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); -static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end, const char** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); +static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false); //------------------------------------------------------------------------- // [SECTION] Widgets: Text, etc. @@ -477,7 +471,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args) // - PressedOnDragDropHold can generally be associated with any flag. // - PressedOnDoubleClick can be associated by PressedOnClickRelease/PressedOnRelease, in which case the second release event won't be reported. //------------------------------------------------------------------------------------------------------------------------------------------------ -// The behavior of the return-value changes when ImGuiItemFlags_ButtonRepeat is set: +// The behavior of the return-value changes when ImGuiButtonFlags_Repeat is set: // Repeat+ Repeat+ Repeat+ Repeat+ // PressedOnClickRelease PressedOnClick PressedOnRelease PressedOnDoubleClick //------------------------------------------------------------------------------------------------------------------------------------------------- @@ -488,32 +482,29 @@ void ImGui::BulletTextV(const char* fmt, va_list args) // Frame N + RepeatDelay + RepeatRate*N true true - true //------------------------------------------------------------------------------------------------------------------------------------------------- -// - FIXME: For refactor we could output flags, incl mouse hovered vs nav keyboard vs nav triggered etc. -// And better standardize how widgets use 'GetColor32((held && hovered) ? ... : hovered ? ...)' vs 'GetColor32(held ? ... : hovered ? ...);' -// For mouse feedback we typically prefer the 'held && hovered' test, but for nav feedback not always. Outputting hovered=true on Activation may be misleading. -// - Since v1.91.2 (Sept 2024) we included io.ConfigDebugHighlightIdConflicts feature. -// One idiom which was previously valid which will now emit a warning is when using multiple overlayed ButtonBehavior() -// with same ID and different MouseButton (see #8030). You can fix it by: -// (1) switching to use a single ButtonBehavior() with multiple _MouseButton flags. -// or (2) surrounding those calls with PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); ... PopItemFlag() +// FIXME: For refactor we could output flags, incl mouse hovered vs nav keyboard vs nav triggered etc. +// And better standardize how widgets use 'GetColor32((held && hovered) ? ... : hovered ? ...)' vs 'GetColor32(held ? ... : hovered ? ...);' +// For mouse feedback we typically prefer the 'held && hovered' test, but for nav feedback not always. Outputting hovered=true on Activation may be misleading. bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - // Default behavior inherited from item flags - // Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check that. - ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.ItemFlags : g.CurrentItemFlags); - if (flags & ImGuiButtonFlags_AllowOverlap) - item_flags |= ImGuiItemFlags_AllowOverlap; - // Default only reacts to left mouse button if ((flags & ImGuiButtonFlags_MouseButtonMask_) == 0) flags |= ImGuiButtonFlags_MouseButtonLeft; // Default behavior requires click + release inside bounding box if ((flags & ImGuiButtonFlags_PressedOnMask_) == 0) - flags |= (item_flags & ImGuiItemFlags_ButtonRepeat) ? ImGuiButtonFlags_PressedOnClick : ImGuiButtonFlags_PressedOnDefault_; + flags |= ImGuiButtonFlags_PressedOnDefault_; + + // Default behavior inherited from item flags + // Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check that. + ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); + if (flags & ImGuiButtonFlags_AllowOverlap) + item_flags |= ImGuiItemFlags_AllowOverlap; + if (flags & ImGuiButtonFlags_Repeat) + item_flags |= ImGuiItemFlags_ButtonRepeat; ImGuiWindow* backup_hovered_window = g.HoveredWindow; const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindowDockTree == window->RootWindowDockTree; @@ -565,8 +556,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } // Process initial action - const bool mods_ok = !(flags & ImGuiButtonFlags_NoKeyModsAllowed) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt); - if (mods_ok) + if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt)) { if (mouse_button_clicked != -1 && g.ActiveId != id) { @@ -577,14 +567,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool SetActiveID(id, window); g.ActiveIdMouseButton = mouse_button_clicked; if (!(flags & ImGuiButtonFlags_NoNavFocus)) - { SetFocusID(id, window); - FocusWindow(window); - } - else - { - FocusWindow(window, ImGuiFocusRequestFlags_RestoreFocusedChild); // Still need to focus and bring to front, but try to avoid losing NavId when navigating a child - } + FocusWindow(window); } if ((flags & ImGuiButtonFlags_PressedOnClick) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseClickedCount[mouse_button_clicked] == 2)) { @@ -593,16 +577,10 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool ClearActiveID(); else SetActiveID(id, window); // Hold on ID - g.ActiveIdMouseButton = mouse_button_clicked; if (!(flags & ImGuiButtonFlags_NoNavFocus)) - { SetFocusID(id, window); - FocusWindow(window); - } - else - { - FocusWindow(window, ImGuiFocusRequestFlags_RestoreFocusedChild); // Still need to focus and bring to front, but try to avoid losing NavId when navigating a child - } + g.ActiveIdMouseButton = mouse_button_clicked; + FocusWindow(window); } } if (flags & ImGuiButtonFlags_PressedOnRelease) @@ -613,7 +591,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool if (!has_repeated_at_least_once) pressed = true; if (!(flags & ImGuiButtonFlags_NoNavFocus)) - SetFocusID(id, window); // FIXME: Lack of FocusWindow() call here is inconsistent with other paths. Research why. + SetFocusID(id, window); ClearActiveID(); } } @@ -625,13 +603,13 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool pressed = true; } - if (pressed && g.IO.ConfigNavCursorVisibleAuto) - g.NavCursorVisible = false; + if (pressed) + g.NavDisableHighlight = true; } - // Keyboard/Gamepad navigation handling + // Gamepad/Keyboard handling // We report navigated and navigation-activated items as hovered but we don't set g.HoveredId to not interfere with mouse. - if (g.NavId == id && g.NavCursorVisible && g.NavHighlightItemUnderNav) + if (g.NavId == id && !g.NavDisableHighlight && g.NavDisableMouseHover) if (!(flags & ImGuiButtonFlags_NoHoveredOnFocus)) hovered = true; if (g.NavActivateDownId == id) @@ -694,8 +672,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool } ClearActiveID(); } - if (!(flags & ImGuiButtonFlags_NoNavFocus) && g.IO.ConfigNavCursorVisibleAuto) - g.NavCursorVisible = false; + if (!(flags & ImGuiButtonFlags_NoNavFocus)) + g.NavDisableHighlight = true; } else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) { @@ -745,7 +723,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags // Render const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); - RenderNavCursor(bb, id); + RenderNavHighlight(bb, id); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); if (g.LogEnabled) @@ -792,12 +770,11 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg, ImGuiBut ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); ItemSize(size); - if (!ItemAdd(bb, id, NULL, (flags & ImGuiButtonFlags_EnableNav) ? ImGuiItemFlags_None : ImGuiItemFlags_NoNav)) + if (!ItemAdd(bb, id)) return false; bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); - RenderNavCursor(bb, id); IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags); return pressed; @@ -823,7 +800,7 @@ bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu // Render const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); const ImU32 text_col = GetColorU32(ImGuiCol_Text); - RenderNavCursor(bb, id); + RenderNavHighlight(bb, id); RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding); RenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), text_col, dir); @@ -864,7 +841,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) ImU32 bg_col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered); if (hovered) window->DrawList->AddRectFilled(bb.Min, bb.Max, bg_col); - RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact); + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact); ImU32 cross_col = GetColorU32(ImGuiCol_Text); ImVec2 cross_center = bb.GetCenter() - ImVec2(0.5f, 0.5f); float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f; @@ -893,7 +870,7 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_no ImU32 text_col = GetColorU32(ImGuiCol_Text); if (hovered || held) window->DrawList->AddRectFilled(bb.Min, bb.Max, bg_col); - RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact); + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_Compact); if (dock_node) RenderArrowDockMenu(window->DrawList, bb.Min, g.FontSize, text_col); @@ -915,17 +892,15 @@ ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis) // Return scrollbar rectangle, must only be called for corresponding axis if window->ScrollbarX/Y is set. ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis) { - ImGuiContext& g = *GImGui; const ImRect outer_rect = window->Rect(); const ImRect inner_rect = window->InnerRect; + const float border_size = window->WindowBorderSize; const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar) IM_ASSERT(scrollbar_size > 0.0f); - const float border_size = IM_ROUND(window->WindowBorderSize * 0.5f); - const float border_top = (window->Flags & ImGuiWindowFlags_MenuBar) ? IM_ROUND(g.Style.FrameBorderSize * 0.5f) : 0.0f; if (axis == ImGuiAxis_X) - return ImRect(inner_rect.Min.x + border_size, ImMax(outer_rect.Min.y + border_size, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size); + return ImRect(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size); else - return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y + border_top, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size); + return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size); } void ImGui::Scrollbar(ImGuiAxis axis) @@ -963,7 +938,7 @@ void ImGui::Scrollbar(ImGuiAxis axis) // - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar // - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal. // Still, the code should probably be made simpler.. -bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 size_visible_v, ImS64 size_contents_v, ImDrawFlags draw_rounding_flags) +bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 size_visible_v, ImS64 size_contents_v, ImDrawFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; @@ -1018,10 +993,9 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6 const int held_dir = (clicked_v_norm < grab_v_norm) ? -1 : (clicked_v_norm > grab_v_norm + grab_h_norm) ? +1 : 0; if (g.ActiveIdIsJustActivated) { - // On initial click when held_dir == 0 (clicked over grab): calculate the distance between mouse and the center of the grab - const bool scroll_to_clicked_location = (g.IO.ConfigScrollbarScrollByPage == false || g.IO.KeyShift || held_dir == 0); - g.ScrollbarSeekMode = scroll_to_clicked_location ? 0 : (short)held_dir; - g.ScrollbarClickDeltaToGrabCenter = (held_dir == 0 && !g.IO.KeyShift) ? clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f : 0.0f; + // On initial click calculate the distance between mouse and the center of the grab + g.ScrollbarSeekMode = (short)held_dir; + g.ScrollbarClickDeltaToGrabCenter = (g.ScrollbarSeekMode == 0.0f) ? clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f : 0.0f; } // Apply scroll (p_scroll_v will generally point on one member of window->Scroll) @@ -1054,7 +1028,7 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6 // Render const ImU32 bg_col = GetColorU32(ImGuiCol_ScrollbarBg); const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha); - window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window->WindowRounding, draw_rounding_flags); + window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window->WindowRounding, flags); ImRect grab_rect; if (axis == ImGuiAxis_X) grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y); @@ -1086,7 +1060,9 @@ void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const I window->DrawList->AddImage(user_texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); } -bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) +// ImageButton() is flawed as 'id' is always derived from 'texture_id' (see #2464 #1390) +// We provide this internal helper to write your own variant while we figure out how to redesign the public ImageButton() API. +bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -1104,17 +1080,16 @@ bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID user_texture_id, const ImVec2& // Render const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); - RenderNavCursor(bb, id); + RenderNavHighlight(bb, id); RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, g.Style.FrameRounding)); if (bg_col.w > 0.0f) window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col)); - window->DrawList->AddImage(user_texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); + window->DrawList->AddImage(texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); return pressed; } -// - ImageButton() adds style.FramePadding*2.0f to provided size. This is in order to facilitate fitting an image in a button. -// - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. (#8165) // FIXME: Maybe that's not the best design? +// Note that ImageButton() adds style.FramePadding*2.0f to provided size. This is in order to facilitate fitting an image in a button. bool ImGui::ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) { ImGuiContext& g = *GImGui; @@ -1127,24 +1102,28 @@ bool ImGui::ImageButton(const char* str_id, ImTextureID user_texture_id, const I #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Legacy API obsoleted in 1.89. Two differences with new ImageButton() -// - old ImageButton() used ImTextureID as item id (created issue with multiple buttons with same image, transient texture id values, opaque computation of ID) -// - new ImageButton() requires an explicit 'const char* str_id' -// - old ImageButton() had frame_padding' override argument. -// - new ImageButton() always use style.FramePadding. -/* +// - new ImageButton() requires an explicit 'const char* str_id' Old ImageButton() used opaque imTextureId (created issue with: multiple buttons with same image, transient texture id values, opaque computation of ID) +// - new ImageButton() always use style.FramePadding Old ImageButton() had an override argument. +// If you need to change padding with new ImageButton() you can use PushStyleVar(ImGuiStyleVar_FramePadding, value), consistent with other Button functions. bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) { + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return false; + // Default to using texture ID as ID. User can still push string/integer prefixes. - PushID((ImTextureID)(intptr_t)user_texture_id); + PushID((void*)(intptr_t)user_texture_id); + const ImGuiID id = window->GetID("#image"); + PopID(); + if (frame_padding >= 0) PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2((float)frame_padding, (float)frame_padding)); - bool ret = ImageButton("", user_texture_id, size, uv0, uv1, bg_col, tint_col); + bool ret = ImageButtonEx(id, user_texture_id, size, uv0, uv1, bg_col, tint_col); if (frame_padding >= 0) PopStyleVar(); - PopID(); return ret; } -*/ #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS bool ImGui::Checkbox(const char* label, bool* v) @@ -1163,7 +1142,7 @@ bool ImGui::Checkbox(const char* label, bool* v) const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); ItemSize(total_bb, style.FramePadding.y); const bool is_visible = ItemAdd(total_bb, id); - const bool is_multi_select = (g.LastItemData.ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0; + const bool is_multi_select = (g.LastItemData.InFlags & ImGuiItemFlags_IsMultiSelect) != 0; if (!is_visible) if (!is_multi_select || !g.BoxSelectState.UnclipMode || !g.BoxSelectState.UnclipRect.Overlaps(total_bb)) // Extra layer of "no logic clip" for box-select support { @@ -1193,10 +1172,10 @@ bool ImGui::Checkbox(const char* label, bool* v) } const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); - const bool mixed_value = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0; + const bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0; if (is_visible) { - RenderNavCursor(total_bb, id); + RenderNavHighlight(total_bb, id); RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); ImU32 check_col = GetColorU32(ImGuiCol_CheckMark); if (mixed_value) @@ -1298,7 +1277,7 @@ bool ImGui::RadioButton(const char* label, bool active) if (pressed) MarkItemEdited(id); - RenderNavCursor(total_bb, id); + RenderNavHighlight(total_bb, id); const int num_segment = window->DrawList->_CalcCircleAutoSegmentCount(radius); window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), num_segment); if (active) @@ -1438,10 +1417,7 @@ bool ImGui::TextLink(const char* label) bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held); - RenderNavCursor(bb, id); - - if (hovered) - SetMouseCursor(ImGuiMouseCursor_Hand); + RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_None); ImVec4 text_colf = g.Style.Colors[ImGuiCol_TextLink]; ImVec4 line_colf = text_colf; @@ -1477,9 +1453,9 @@ void ImGui::TextLinkOpenURL(const char* label, const char* url) if (url == NULL) url = label; if (TextLink(label)) - if (g.PlatformIO.Platform_OpenInShellFn != NULL) - g.PlatformIO.Platform_OpenInShellFn(&g, url); - SetItemTooltip(LocalizeGetMsg(ImGuiLocKey_OpenLink_s), url); // It is more reassuring for user to _always_ display URL when we same as label + if (g.IO.PlatformOpenInShellFn != NULL) + g.IO.PlatformOpenInShellFn(&g, url); + SetItemTooltip("%s", url); // It is more reassuring for user to _always_ display URL when we same as label if (BeginPopupContextItem()) { if (MenuItem(LocalizeGetMsg(ImGuiLocKey_CopyLink))) @@ -1869,7 +1845,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF // Render shape const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); const float value_x2 = ImMax(bb.Min.x, bb.Max.x - arrow_size); - RenderNavCursor(bb, id); + RenderNavHighlight(bb, id); if (!(flags & ImGuiComboFlags_NoPreview)) window->DrawList->AddRectFilled(bb.Min, ImVec2(value_x2, bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft); if (!(flags & ImGuiComboFlags_NoArrowButton)) @@ -1959,7 +1935,7 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags // We don't use BeginPopupEx() solely because we have a custom name string, which we could make an argument to BeginPopupEx() ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove; - PushStyleVarX(ImGuiStyleVar_WindowPadding, g.Style.FramePadding.x); // Horizontally align ourselves with the framed text + PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(g.Style.FramePadding.x, g.Style.WindowPadding.y)); // Horizontally align ourselves with the framed text bool ret = Begin(name, NULL, window_flags); PopStyleVar(); if (!ret) @@ -2179,7 +2155,6 @@ static const ImGuiDataTypeInfo GDataTypeInfo[] = { sizeof(float), "float", "%.3f","%f" }, // ImGuiDataType_Float (float are promoted to double in va_arg) { sizeof(double), "double","%f", "%lf" }, // ImGuiDataType_Double { sizeof(bool), "bool", "%d", "%d" }, // ImGuiDataType_Bool - { 0, "char*","%s", "%s" }, // ImGuiDataType_String }; IM_STATIC_ASSERT(IM_ARRAYSIZE(GDataTypeInfo) == ImGuiDataType_COUNT); @@ -2370,12 +2345,6 @@ bool ImGui::DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_m return false; } -bool ImGui::DataTypeIsZero(ImGuiDataType data_type, const void* p_data) -{ - ImGuiContext& g = *GImGui; - return DataTypeCompare(data_type, p_data, &g.DataTypeZeroValue) == 0; -} - static float GetMinimumStepAtDecimalPrecision(int decimal_precision) { static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f }; @@ -2434,7 +2403,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const { ImGuiContext& g = *GImGui; const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; - const bool is_bounded = (v_min < v_max) || ((v_min == v_max) && (v_min != 0.0f || (flags & ImGuiSliderFlags_ClampZeroRange))); + const bool is_bounded = (v_min < v_max); const bool is_wrapped = is_bounded && (flags & ImGuiSliderFlags_WrapAround); const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); @@ -2448,9 +2417,9 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) { adjust_delta = g.IO.MouseDelta[axis]; - if (g.IO.KeyAlt && !(flags & ImGuiSliderFlags_NoSpeedTweaks)) + if (g.IO.KeyAlt) adjust_delta *= 1.0f / 100.0f; - if (g.IO.KeyShift && !(flags & ImGuiSliderFlags_NoSpeedTweaks)) + if (g.IO.KeyShift) adjust_delta *= 10.0f; } else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) @@ -2458,7 +2427,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; const bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow); const bool tweak_fast = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast); - const float tweak_factor = (flags & ImGuiSliderFlags_NoSpeedTweaks) ? 1.0f : tweak_slow ? 1.0f / 10.0f : tweak_fast ? 10.0f : 1.0f; + const float tweak_factor = tweak_slow ? 1.0f / 10.0f : tweak_fast ? 10.0f : 1.0f; adjust_delta = GetNavTweakPressedAmount(axis) * tweak_factor; v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)); } @@ -2576,7 +2545,7 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v } if (g.ActiveId != id) return false; - if ((g.LastItemData.ItemFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) + if ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) return false; switch (data_type) @@ -2623,7 +2592,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { @@ -2646,10 +2615,6 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, temp_input_is_active = true; } - // Store initial value (not used by main lib but available as a convenience but some mods e.g. to revert) - if (make_active) - memcpy(&g.ActiveIdValueOnActivation, p_data, DataTypeGetInfo(data_type)->Size); - if (make_active && !temp_input_is_active) { SetActiveID(id, window); @@ -2661,22 +2626,14 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, if (temp_input_is_active) { - // Only clamp CTRL+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via ImGuiSliderFlags_AlwaysClamp) - bool clamp_enabled = false; - if ((flags & ImGuiSliderFlags_ClampOnInput) && (p_min != NULL || p_max != NULL)) - { - const int clamp_range_dir = (p_min != NULL && p_max != NULL) ? DataTypeCompare(data_type, p_min, p_max) : 0; // -1 when *p_min < *p_max, == 0 when *p_min == *p_max - if (p_min == NULL || p_max == NULL || clamp_range_dir < 0) - clamp_enabled = true; - else if (clamp_range_dir == 0) - clamp_enabled = DataTypeIsZero(data_type, p_min) ? ((flags & ImGuiSliderFlags_ClampZeroRange) != 0) : true; - } - return TempInputScalar(frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL, clamp_enabled ? p_max : NULL); + // Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set + const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0 && (p_min == NULL || p_max == NULL || DataTypeCompare(data_type, p_min, p_max) < 0); + return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL); } // Draw frame const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); - RenderNavCursor(frame_bb, id); + RenderNavHighlight(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); // Drag behavior @@ -3067,14 +3024,14 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; if (decimal_precision > 0) { - input_delta /= 100.0f; // Keyboard/Gamepad tweak speeds in % of slider bounds + input_delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds if (tweak_slow) input_delta /= 10.0f; } else { if ((v_range_f >= -100.0f && v_range_f <= 100.0f && v_range_f != 0.0f) || tweak_slow) - input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / v_range_f; // Keyboard/Gamepad tweak speeds in integer steps + input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / v_range_f; // Gamepad/keyboard tweak speeds in integer steps else input_delta /= 100.0f; } @@ -3122,7 +3079,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ } if (set_new_value) - if ((g.LastItemData.ItemFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) + if ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly)) set_new_value = false; if (set_new_value) @@ -3227,7 +3184,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { @@ -3240,10 +3197,6 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if ((clicked && g.IO.KeyCtrl) || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))) temp_input_is_active = true; - // Store initial value (not used by main lib but available as a convenience but some mods e.g. to revert) - if (make_active) - memcpy(&g.ActiveIdValueOnActivation, p_data, DataTypeGetInfo(data_type)->Size); - if (make_active && !temp_input_is_active) { SetActiveID(id, window); @@ -3255,14 +3208,14 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if (temp_input_is_active) { - // Only clamp CTRL+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via ImGuiSliderFlags_AlwaysClamp) - const bool clamp_enabled = (flags & ImGuiSliderFlags_ClampOnInput) != 0; - return TempInputScalar(frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL, clamp_enabled ? p_max : NULL); + // Only clamp CTRL+Click input when ImGuiSliderFlags_AlwaysClamp is set + const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0; + return TempInputScalar(frame_bb, id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL); } // Draw frame const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); - RenderNavCursor(frame_bb, id); + RenderNavHighlight(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); // Slider behavior @@ -3351,8 +3304,7 @@ bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, fl format = "%.0f deg"; float v_deg = (*v_rad) * 360.0f / (2 * IM_PI); bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, format, flags); - if (value_changed) - *v_rad = v_deg * (2 * IM_PI) / 360.0f; + *v_rad = v_deg * (2 * IM_PI) / 360.0f; return value_changed; } @@ -3398,7 +3350,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); const bool clicked = hovered && IsMouseClicked(0, ImGuiInputFlags_None, id); if (clicked || g.NavActivateId == id) { @@ -3412,7 +3364,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d // Draw frame const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); - RenderNavCursor(frame_bb, id); + RenderNavHighlight(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); // Slider behavior @@ -3594,8 +3546,6 @@ int ImParseFormatPrecision(const char* fmt, int default_precision) // Create text input in place of another active widget (e.g. used when doing a CTRL+Click on drag/slider widgets) // FIXME: Facilitate using this in variety of other situations. -// FIXME: Among other things, setting ImGuiItemFlags_AllowDuplicateId in LastItemData is currently correct but -// the expected relationship between TempInputXXX functions and LastItemData is a little fishy. bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags) { // On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id. @@ -3606,7 +3556,6 @@ bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* ClearActiveID(); g.CurrentWindow->DC.CursorPos = bb.Min; - g.LastItemData.ItemFlags |= ImGuiItemFlags_AllowDuplicateId; bool value_changed = InputTextEx(label, NULL, buf, buf_size, bb.GetSize(), flags | ImGuiInputTextFlags_MergedItem); if (init) { @@ -3624,7 +3573,6 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG { // FIXME: May need to clarify display behavior if format doesn't contain %. // "%d" -> "%d" / "There are %d items" -> "%d" / "items" -> "%d" (fallback). Also see #6405 - ImGuiContext& g = *GImGui; const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type); char fmt_buf[32]; char data_buf[32]; @@ -3634,8 +3582,8 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format); ImStrTrimBlanks(data_buf); - ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint; - g.LastItemData.ItemFlags |= ImGuiItemFlags_NoMarkEdited; // Because TempInputText() uses ImGuiInputTextFlags_MergedItem it doesn't submit a new item, so we poke LastItemData. + ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_NoMarkEdited | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint; + bool value_changed = false; if (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags)) { @@ -3654,7 +3602,6 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG } // Only mark as edited if new value is different - g.LastItemData.ItemFlags &= ~ImGuiItemFlags_NoMarkEdited; value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; if (value_changed) MarkItemEdited(id); @@ -3665,7 +3612,7 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG void ImGui::SetNextItemRefVal(ImGuiDataType data_type, void* p_data) { ImGuiContext& g = *GImGui; - g.NextItemData.HasFlags |= ImGuiNextItemDataFlags_HasRefVal; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasRefVal; memcpy(&g.NextItemData.RefVal, p_data, DataTypeGetInfo(data_type)->Size); } @@ -3679,12 +3626,11 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data ImGuiContext& g = *GImGui; ImGuiStyle& style = g.Style; - IM_ASSERT((flags & ImGuiInputTextFlags_EnterReturnsTrue) == 0); // Not supported by InputScalar(). Please open an issue if you this would be useful to you. Otherwise use IsItemDeactivatedAfterEdit()! if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - void* p_data_default = (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasRefVal) ? &g.NextItemData.RefVal : &g.DataTypeZeroValue; + void* p_data_default = (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasRefVal) ? &g.NextItemData.RefVal : &g.DataTypeZeroValue; char buf[64]; if ((flags & ImGuiInputTextFlags_DisplayEmptyRefVal) && DataTypeCompare(data_type, p_data, p_data_default) == 0) @@ -3692,10 +3638,8 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data else DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format); - // Disable the MarkItemEdited() call in InputText but keep ImGuiItemStatusFlags_Edited. - // We call MarkItemEdited() ourselves by comparing the actual data rather than the string. - g.NextItemData.ItemFlags |= ImGuiItemFlags_NoMarkEdited; - flags |= ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint; + flags |= ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string. + flags |= (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint; bool value_changed = false; if (p_step == NULL) @@ -3717,22 +3661,21 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data // Step buttons const ImVec2 backup_frame_padding = style.FramePadding; style.FramePadding.x = style.FramePadding.y; + ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups; if (flags & ImGuiInputTextFlags_ReadOnly) BeginDisabled(); - PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); SameLine(0, style.ItemInnerSpacing.x); - if (ButtonEx("-", ImVec2(button_size, button_size))) + if (ButtonEx("-", ImVec2(button_size, button_size), button_flags)) { DataTypeApplyOp(data_type, '-', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step); value_changed = true; } SameLine(0, style.ItemInnerSpacing.x); - if (ButtonEx("+", ImVec2(button_size, button_size))) + if (ButtonEx("+", ImVec2(button_size, button_size), button_flags)) { DataTypeApplyOp(data_type, '+', p_data, p_data, g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step); value_changed = true; } - PopItemFlag(); if (flags & ImGuiInputTextFlags_ReadOnly) EndDisabled(); @@ -3747,8 +3690,6 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data PopID(); EndGroup(); } - - g.LastItemData.ItemFlags &= ~ImGuiItemFlags_NoMarkEdited; if (value_changed) MarkItemEdited(g.LastItemData.ID); @@ -3840,7 +3781,6 @@ bool ImGui::InputDouble(const char* label, double* v, double step, double step_f //------------------------------------------------------------------------- // [SECTION] Widgets: InputText, InputTextMultiline, InputTextWithHint //------------------------------------------------------------------------- -// - imstb_textedit.h include // - InputText() // - InputTextWithHint() // - InputTextMultiline() @@ -3851,11 +3791,6 @@ bool ImGui::InputDouble(const char* label, double* v, double step, double step_f // - DebugNodeInputTextState() [Internal] //------------------------------------------------------------------------- -namespace ImStb -{ -#include "imstb_textedit.h" -} - bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) { IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() @@ -3873,28 +3808,21 @@ bool ImGui::InputTextWithHint(const char* label, const char* hint, char* buf, si return InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data); } -// This is only used in the path where the multiline widget is inactivate. static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end) { int line_count = 0; const char* s = text_begin; - while (true) - { - const char* s_eol = strchr(s, '\n'); + while (char c = *s++) // We are only matching for \n so we can ignore UTF-8 decoding + if (c == '\n') + line_count++; + s--; + if (s[0] != '\n' && s[0] != '\r') line_count++; - if (s_eol == NULL) - { - s = s + strlen(s); - break; - } - s = s_eol + 1; - } *out_text_end = s; return line_count; } -// FIXME: Ideally we'd share code with ImFont::CalcTextSizeA() -static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end, const char** remaining, ImVec2* out_offset, bool stop_on_new_line) +static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line) { ImGuiContext& g = *ctx; ImFont* font = g.Font; @@ -3904,15 +3832,10 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c ImVec2 text_size = ImVec2(0, 0); float line_width = 0.0f; - const char* s = text_begin; + const ImWchar* s = text_begin; while (s < text_end) { - unsigned int c = (unsigned int)*s; - if (c < 0x80) - s += 1; - else - s += ImTextCharFromUtf8(&c, s, text_end); - + unsigned int c = (unsigned int)(*s++); if (c == '\n') { text_size.x = ImMax(text_size.x, line_width); @@ -3925,7 +3848,7 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c if (c == '\r') continue; - const float char_width = ((int)c < font->IndexAdvanceX.Size ? font->IndexAdvanceX.Data[c] : font->FallbackAdvanceX) * scale; + const float char_width = font->GetCharAdvance((ImWchar)c) * scale; line_width += char_width; } @@ -3945,21 +3868,19 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c } // Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar) -// With our UTF-8 use of stb_textedit: -// - STB_TEXTEDIT_GETCHAR is nothing more than a a "GETBYTE". It's only used to compare to ascii or to copy blocks of text so we are fine. -// - One exception is the STB_TEXTEDIT_IS_SPACE feature which would expect a full char in order to handle full-width space such as 0x3000 (see ImCharIsBlankW). -// - ...but we don't use that feature. namespace ImStb { -static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->TextLen; } -static char STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { IM_ASSERT(idx <= obj->TextLen); return obj->TextSrc[idx]; } -static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { unsigned int c; ImTextCharFromUtf8(&c, obj->TextSrc + line_start_idx + char_idx, obj->TextSrc + obj->TextLen); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance((ImWchar)c) * g.FontScale; } -static char STB_TEXTEDIT_NEWLINE = '\n'; + +static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->CurLenW; } +static ImWchar STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { IM_ASSERT(idx <= obj->CurLenW); return obj->TextW[idx]; } +static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance(c) * g.FontScale; } +static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x200000 ? 0 : key; } +static ImWchar STB_TEXTEDIT_NEWLINE = '\n'; static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx) { - const char* text = obj->TextSrc; - const char* text_remaining = NULL; - const ImVec2 size = InputTextCalcTextSize(obj->Ctx, text + line_start_idx, text + obj->TextLen, &text_remaining, NULL, true); + const ImWchar* text = obj->TextW.Data; + const ImWchar* text_remaining = NULL; + const ImVec2 size = InputTextCalcTextSizeW(obj->Ctx, text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true); r->x0 = 0.0f; r->x1 = size.x; r->baseline_y_delta = size.y; @@ -3968,37 +3889,9 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* ob r->num_chars = (int)(text_remaining - (text + line_start_idx)); } -#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL -#define IMSTB_TEXTEDIT_GETPREVCHARINDEX IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL - -static int IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx) +static bool is_separator(unsigned int c) { - if (idx >= obj->TextLen) - return obj->TextLen + 1; - unsigned int c; - return idx + ImTextCharFromUtf8(&c, obj->TextSrc + idx, obj->TextSrc + obj->TextLen); -} - -static int IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx) -{ - if (idx <= 0) - return -1; - const char* p = ImTextFindPreviousUtf8Codepoint(obj->TextSrc, obj->TextSrc + idx); - return (int)(p - obj->TextSrc); -} - -static bool ImCharIsSeparatorW(unsigned int c) -{ - static const unsigned int separator_list[] = - { - ',', 0x3001, '.', 0x3002, ';', 0xFF1B, '(', 0xFF08, ')', 0xFF09, '{', 0xFF5B, '}', 0xFF5D, - '[', 0x300C, ']', 0x300D, '|', 0xFF5C, '!', 0xFF01, '\\', 0xFFE5, '/', 0x30FB, 0xFF0F, - '\n', '\r', - }; - for (unsigned int separator : separator_list) - if (c == separator) - return true; - return false; + return c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|' || c=='\n' || c=='\r' || c=='.' || c=='!'; } static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) @@ -4007,15 +3900,10 @@ static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0) return 0; - const char* curr_p = obj->TextSrc + idx; - const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextSrc, curr_p); - unsigned int curr_c; ImTextCharFromUtf8(&curr_c, curr_p, obj->TextSrc + obj->TextLen); - unsigned int prev_c; ImTextCharFromUtf8(&prev_c, prev_p, obj->TextSrc + obj->TextLen); - - bool prev_white = ImCharIsBlankW(prev_c); - bool prev_separ = ImCharIsSeparatorW(prev_c); - bool curr_white = ImCharIsBlankW(curr_c); - bool curr_separ = ImCharIsSeparatorW(curr_c); + bool prev_white = ImCharIsBlankW(obj->TextW[idx - 1]); + bool prev_separ = is_separator(obj->TextW[idx - 1]); + bool curr_white = ImCharIsBlankW(obj->TextW[idx]); + bool curr_separ = is_separator(obj->TextW[idx]); return ((prev_white || prev_separ) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ); } static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) @@ -4023,82 +3911,63 @@ static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0) return 0; - const char* curr_p = obj->TextSrc + idx; - const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextSrc, curr_p); - unsigned int prev_c; ImTextCharFromUtf8(&prev_c, curr_p, obj->TextSrc + obj->TextLen); - unsigned int curr_c; ImTextCharFromUtf8(&curr_c, prev_p, obj->TextSrc + obj->TextLen); - - bool prev_white = ImCharIsBlankW(prev_c); - bool prev_separ = ImCharIsSeparatorW(prev_c); - bool curr_white = ImCharIsBlankW(curr_c); - bool curr_separ = ImCharIsSeparatorW(curr_c); + bool prev_white = ImCharIsBlankW(obj->TextW[idx]); + bool prev_separ = is_separator(obj->TextW[idx]); + bool curr_white = ImCharIsBlankW(obj->TextW[idx - 1]); + bool curr_separ = is_separator(obj->TextW[idx - 1]); return ((prev_white) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ); } -static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) -{ - idx = IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx); - while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) - idx = IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx); - return idx < 0 ? 0 : idx; -} -static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) -{ - int len = obj->TextLen; - idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx); - while (idx < len && !is_word_boundary_from_left(obj, idx)) - idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx); - return idx > len ? len : idx; -} -static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) -{ - idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx); - int len = obj->TextLen; - while (idx < len && !is_word_boundary_from_right(obj, idx)) - idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx); - return idx > len ? len : idx; -} +static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; } +static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; } static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { ImGuiContext& g = *obj->Ctx; if (g.IO.ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); } -#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h -#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL +#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h +#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n) { - // Offset remaining text (+ copy zero terminator) - IM_ASSERT(obj->TextSrc == obj->TextA.Data); - char* dst = obj->TextA.Data + pos; - char* src = obj->TextA.Data + pos + n; - memmove(dst, src, obj->TextLen - n - pos + 1); + ImWchar* dst = obj->TextW.Data + pos; + + // We maintain our buffer length in both UTF-8 and wchar formats obj->Edited = true; - obj->TextLen -= n; + obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n); + obj->CurLenW -= n; + + // Offset remaining text (FIXME-OPT: Use memmove) + const ImWchar* src = obj->TextW.Data + pos + n; + while (ImWchar c = *src++) + *dst++ = c; + *dst = '\0'; } -static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const char* new_text, int new_text_len) +static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const ImWchar* new_text, int new_text_len) { const bool is_resizable = (obj->Flags & ImGuiInputTextFlags_CallbackResize) != 0; - const int text_len = obj->TextLen; + const int text_len = obj->CurLenW; IM_ASSERT(pos <= text_len); - if (!is_resizable && (new_text_len + obj->TextLen + 1 > obj->BufCapacity)) + const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len); + if (!is_resizable && (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufCapacityA)) return false; // Grow internal buffer if needed - IM_ASSERT(obj->TextSrc == obj->TextA.Data); - if (new_text_len + text_len + 1 > obj->TextA.Size) + if (new_text_len + text_len + 1 > obj->TextW.Size) { if (!is_resizable) return false; - obj->TextA.resize(text_len + ImClamp(new_text_len, 32, ImMax(256, new_text_len)) + 1); - obj->TextSrc = obj->TextA.Data; + IM_ASSERT(text_len < obj->TextW.Size); + obj->TextW.resize(text_len + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1); } - char* text = obj->TextA.Data; + ImWchar* text = obj->TextW.Data; if (pos != text_len) - memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos)); - memcpy(text + pos, new_text, (size_t)new_text_len); + memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar)); + memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar)); obj->Edited = true; - obj->TextLen += new_text_len; - obj->TextA[obj->TextLen] = '\0'; + obj->CurLenW += new_text_len; + obj->CurLenA += new_text_len_utf8; + obj->TextW[obj->CurLenW] = '\0'; return true; } @@ -4130,8 +3999,8 @@ static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const ch // the stb_textedit_paste() function creates two separate records, so we perform it manually. (FIXME: Report to nothings/stb?) static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len) { - stb_text_makeundo_replace(str, state, 0, str->TextLen, text_len); - ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->TextLen); + stb_text_makeundo_replace(str, state, 0, str->CurLenW, text_len); + ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->CurLenW); state->cursor = state->select_start = state->select_end = 0; if (text_len <= 0) return; @@ -4146,65 +4015,29 @@ static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* st } // namespace ImStb -// We added an extra indirection where 'Stb' is heap-allocated, in order facilitate the work of bindings generators. -ImGuiInputTextState::ImGuiInputTextState() -{ - memset(this, 0, sizeof(*this)); - Stb = IM_NEW(ImStbTexteditState); - memset(Stb, 0, sizeof(*Stb)); -} - -ImGuiInputTextState::~ImGuiInputTextState() -{ - IM_DELETE(Stb); -} - void ImGuiInputTextState::OnKeyPressed(int key) { - stb_textedit_key(this, Stb, key); + stb_textedit_key(this, &Stb, key); CursorFollow = true; CursorAnimReset(); } -void ImGuiInputTextState::OnCharPressed(unsigned int c) -{ - // Convert the key to a UTF8 byte sequence. - // The changes we had to make to stb_textedit_key made it very much UTF-8 specific which is not too great. - char utf8[5]; - ImTextCharToUtf8(utf8, c); - stb_textedit_text(this, Stb, utf8, (int)strlen(utf8)); - CursorFollow = true; - CursorAnimReset(); -} - -// Those functions are not inlined in imgui_internal.h, allowing us to hide ImStbTexteditState from that header. -void ImGuiInputTextState::CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking -void ImGuiInputTextState::CursorClamp() { Stb->cursor = ImMin(Stb->cursor, TextLen); Stb->select_start = ImMin(Stb->select_start, TextLen); Stb->select_end = ImMin(Stb->select_end, TextLen); } -bool ImGuiInputTextState::HasSelection() const { return Stb->select_start != Stb->select_end; } -void ImGuiInputTextState::ClearSelection() { Stb->select_start = Stb->select_end = Stb->cursor; } -int ImGuiInputTextState::GetCursorPos() const { return Stb->cursor; } -int ImGuiInputTextState::GetSelectionStart() const { return Stb->select_start; } -int ImGuiInputTextState::GetSelectionEnd() const { return Stb->select_end; } -void ImGuiInputTextState::SelectAll() { Stb->select_start = 0; Stb->cursor = Stb->select_end = TextLen; Stb->has_preferred_x = 0; } -void ImGuiInputTextState::ReloadUserBufAndSelectAll() { WantReloadUserBuf = true; ReloadSelectionStart = 0; ReloadSelectionEnd = INT_MAX; } -void ImGuiInputTextState::ReloadUserBufAndKeepSelection() { WantReloadUserBuf = true; ReloadSelectionStart = Stb->select_start; ReloadSelectionEnd = Stb->select_end; } -void ImGuiInputTextState::ReloadUserBufAndMoveToEnd() { WantReloadUserBuf = true; ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; } - ImGuiInputTextCallbackData::ImGuiInputTextCallbackData() { memset(this, 0, sizeof(*this)); } -// Public API to manipulate UTF-8 text from within a callback. +// Public API to manipulate UTF-8 text +// We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar) // FIXME: The existence of this rarely exercised code path is a bit of a nuisance. -// Historically they existed because STB_TEXTEDIT_INSERTCHARS() etc. worked on our ImWchar -// buffer, but nowadays they both work on UTF-8 data. Should aim to merge both. void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count) { IM_ASSERT(pos + bytes_count <= BufTextLen); char* dst = Buf + pos; const char* src = Buf + pos + bytes_count; - memmove(dst, src, BufTextLen - bytes_count - pos + 1); + while (char c = *src++) + *dst++ = c; + *dst = '\0'; if (CursorPos >= pos + bytes_count) CursorPos -= bytes_count; @@ -4221,7 +4054,6 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons if (new_text == new_text_end) return; - // Grow internal buffer if needed const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0; const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text); if (new_text_len + BufTextLen >= BufSize) @@ -4229,15 +4061,15 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons if (!is_resizable) return; + // Contrary to STB_TEXTEDIT_INSERTCHARS() this is working in the UTF8 buffer, hence the mildly similar code (until we remove the U16 buffer altogether!) ImGuiContext& g = *Ctx; ImGuiInputTextState* edit_state = &g.InputTextState; IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID); IM_ASSERT(Buf == edit_state->TextA.Data); int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1; - edit_state->TextA.resize(new_buf_size + 1); - edit_state->TextSrc = edit_state->TextA.Data; + edit_state->TextA.reserve(new_buf_size + 1); Buf = edit_state->TextA.Data; - BufSize = edit_state->BufCapacity = new_buf_size; + BufSize = edit_state->BufCapacityA = new_buf_size; } if (BufTextLen != pos) @@ -4252,23 +4084,6 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons BufTextLen += new_text_len; } -void ImGui::PushPasswordFont() -{ - ImGuiContext& g = *GImGui; - ImFont* in_font = g.Font; - ImFont* out_font = &g.InputTextPasswordFont; - const ImFontGlyph* glyph = in_font->FindGlyph('*'); - out_font->FontSize = in_font->FontSize; - out_font->Scale = in_font->Scale; - out_font->Ascent = in_font->Ascent; - out_font->Descent = in_font->Descent; - out_font->ContainerAtlas = in_font->ContainerAtlas; - out_font->FallbackGlyph = glyph; - out_font->FallbackAdvanceX = glyph->AdvanceX; - IM_ASSERT(out_font->Glyphs.Size == 0 && out_font->IndexAdvanceX.Size == 0 && out_font->IndexLookup.Size == 0); - PushFont(out_font); -} - // Return false to discard a character. static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard) { @@ -4308,10 +4123,10 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im // The standard mandate that programs starts in the "C" locale where the decimal point is '.'. // We don't really intend to provide widespread support for it, but out of empathy for people stuck with using odd API, we support the bare minimum aka overriding the decimal point. // Change the default decimal_point with: - // ImGui::GetPlatformIO()->Platform_LocaleDecimalPoint = *localeconv()->decimal_point; + // ImGui::GetIO()->PlatformLocaleDecimalPoint = *localeconv()->decimal_point; // Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions. ImGuiContext& g = *ctx; - const unsigned c_decimal_point = (unsigned int)g.PlatformIO.Platform_LocaleDecimalPoint; + const unsigned c_decimal_point = (unsigned int)g.IO.PlatformLocaleDecimalPoint; if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint)) if (c == '.' || c == ',') c = c_decimal_point; @@ -4370,11 +4185,19 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im return true; } -// Find the shortest single replacement we can make to get from old_buf to new_buf -// Note that this doesn't directly alter state->TextA, state->TextLen. They are expected to be made valid separately. +// Find the shortest single replacement we can make to get the new text from the old text. +// Important: needs to be run before TextW is rewritten with the new characters because calling STB_TEXTEDIT_GETCHAR() at the end. // FIXME: Ideally we should transition toward (1) making InsertChars()/DeleteChars() update undo-stack (2) discourage (and keep reconcile) or obsolete (and remove reconcile) accessing buffer directly. -static void InputTextReconcileUndoState(ImGuiInputTextState* state, const char* old_buf, int old_length, const char* new_buf, int new_length) +static void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* state, const char* new_buf_a, int new_length_a) { + ImGuiContext& g = *GImGui; + const ImWchar* old_buf = state->TextW.Data; + const int old_length = state->CurLenW; + const int new_length = ImTextCountCharsFromUtf8(new_buf_a, new_buf_a + new_length_a); + g.TempBuffer.reserve_discard((new_length + 1) * sizeof(ImWchar)); + ImWchar* new_buf = (ImWchar*)(void*)g.TempBuffer.Data; + ImTextStrFromUtf8(new_buf, new_length + 1, new_buf_a, new_buf_a + new_length_a); + const int shorter_length = ImMin(old_length, new_length); int first_diff; for (first_diff = 0; first_diff < shorter_length; first_diff++) @@ -4383,7 +4206,7 @@ static void InputTextReconcileUndoState(ImGuiInputTextState* state, const char* if (first_diff == old_length && first_diff == new_length) return; - int old_last_diff = old_length - 1; + int old_last_diff = old_length - 1; int new_last_diff = new_length - 1; for (; old_last_diff >= first_diff && new_last_diff >= first_diff; old_last_diff--, new_last_diff--) if (old_buf[old_last_diff] != new_buf[new_last_diff]) @@ -4392,9 +4215,9 @@ static void InputTextReconcileUndoState(ImGuiInputTextState* state, const char* const int insert_len = new_last_diff - first_diff + 1; const int delete_len = old_last_diff - first_diff + 1; if (insert_len > 0 || delete_len > 0) - if (IMSTB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->Stb->undostate, first_diff, delete_len, insert_len)) + if (IMSTB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->Stb.undostate, first_diff, delete_len, insert_len)) for (int i = 0; i < delete_len; i++) - p[i] = old_buf[first_diff + i]; + p[i] = ImStb::STB_TEXTEDIT_GETCHAR(state, first_diff + i); } // As InputText() retain textual data and we currently provide a path for user to not retain it (via local variables) @@ -4415,9 +4238,8 @@ void ImGui::InputTextDeactivateHook(ImGuiID id) else { IM_ASSERT(state->TextA.Data != 0); - IM_ASSERT(state->TextA[state->TextLen] == 0); - g.InputTextDeactivatedState.TextA.resize(state->TextLen + 1); - memcpy(g.InputTextDeactivatedState.TextA.Data, state->TextA.Data, state->TextLen + 1); + g.InputTextDeactivatedState.TextA.resize(state->CurLenA + 1); + memcpy(g.InputTextDeactivatedState.TextA.Data, state->TextA.Data, state->CurLenA + 1); } } @@ -4438,7 +4260,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ IM_ASSERT(buf != NULL && buf_size >= 0); IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) - IM_ASSERT(!((flags & ImGuiInputTextFlags_ElideLeft) && (flags & ImGuiInputTextFlags_Multiline))); // Multiline will not work with left-trimming ImGuiContext& g = *GImGui; ImGuiIO& io = g.IO; @@ -4486,7 +4307,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Ensure no clip rect so mouse hover can reach FramePadding edges - bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove); + bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), ImGuiChildFlags_Border, ImGuiWindowFlags_NoMove); g.NavActivateId = backup_activate_id; PopStyleVar(3); PopStyleColor(); @@ -4509,18 +4330,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable)) return false; } - - // Ensure mouse cursor is set even after switching to keyboard/gamepad mode. May generalize further? (#6417) - bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.ItemFlags | ImGuiItemFlags_NoNavDisableMouseHover); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); if (hovered) - SetMouseCursor(ImGuiMouseCursor_TextInput); - if (hovered && g.NavHighlightItemUnderNav) - hovered = false; + g.MouseCursor = ImGuiMouseCursor_TextInput; // We are only allowed to access the state if we are already the active widget. ImGuiInputTextState* state = GetInputTextState(id); - if (g.LastItemData.ItemFlags & ImGuiItemFlags_ReadOnly) + if (g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) flags |= ImGuiInputTextFlags_ReadOnly; const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0; const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; @@ -4539,67 +4356,63 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX; - const bool init_reload_from_user_buf = (state != NULL && state->WantReloadUserBuf); - const bool init_changed_specs = (state != NULL && state->Stb->single_line != !is_multiline); // state != NULL means its our state. + const bool init_reload_from_user_buf = (state != NULL && state->ReloadUserBuf); + const bool init_changed_specs = (state != NULL && state->Stb.single_line != !is_multiline); // state != NULL means its our state. const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav); const bool init_state = (init_make_active || user_scroll_active); - if (init_reload_from_user_buf) - { - int new_len = (int)strlen(buf); - IM_ASSERT(new_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?"); - state->WantReloadUserBuf = false; - InputTextReconcileUndoState(state, state->TextA.Data, state->TextLen, buf, new_len); - state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. - state->TextLen = new_len; - memcpy(state->TextA.Data, buf, state->TextLen + 1); - state->Stb->select_start = state->ReloadSelectionStart; - state->Stb->cursor = state->Stb->select_end = state->ReloadSelectionEnd; - state->CursorClamp(); - } - else if ((init_state && g.ActiveId != id) || init_changed_specs) + if ((init_state && g.ActiveId != id) || init_changed_specs || init_reload_from_user_buf) { // Access state even if we don't own it yet. state = &g.InputTextState; state->CursorAnimReset(); + state->ReloadUserBuf = false; // Backup state of deactivating item so they'll have a chance to do a write to output buffer on the same frame they report IsItemDeactivatedAfterEdit (#4714) InputTextDeactivateHook(state->ID); - // Take a copy of the initial buffer value. // From the moment we focused we are normally ignoring the content of 'buf' (unless we are in read-only mode) const int buf_len = (int)strlen(buf); - IM_ASSERT(buf_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?"); - state->TextToRevertTo.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. - memcpy(state->TextToRevertTo.Data, buf, buf_len + 1); + if (!init_reload_from_user_buf) + { + // Take a copy of the initial buffer value. + state->InitialTextA.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. + memcpy(state->InitialTextA.Data, buf, buf_len + 1); + } // Preserve cursor position and undo/redo stack if we come back to same widget // FIXME: Since we reworked this on 2022/06, may want to differentiate recycle_cursor vs recycle_undostate? - bool recycle_state = (state->ID == id && !init_changed_specs); - if (recycle_state && (state->TextLen != buf_len || (state->TextA.Data == NULL || strncmp(state->TextA.Data, buf, buf_len) != 0))) + bool recycle_state = (state->ID == id && !init_changed_specs && !init_reload_from_user_buf); + if (recycle_state && (state->CurLenA != buf_len || (state->TextAIsValid && strncmp(state->TextA.Data, buf, buf_len) != 0))) recycle_state = false; // Start edition + const char* buf_end = NULL; state->ID = id; - state->TextLen = buf_len; - if (!is_readonly) + state->TextW.resize(buf_size + 1); // wchar count <= UTF-8 count. we use +1 to make sure that .Data is always pointing to at least an empty string. + state->TextA.resize(0); + state->TextAIsValid = false; // TextA is not valid yet (we will display buf until then) + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end); + state->CurLenA = (int)(buf_end - buf); // We can't get the result from ImStrncpy() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8. + + if (recycle_state) { - state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. - memcpy(state->TextA.Data, buf, state->TextLen + 1); + // Recycle existing cursor/selection/undo stack but clamp position + // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler. + state->CursorClamp(); + } + else + { + state->ScrollX = 0.0f; + stb_textedit_initialize_state(&state->Stb, !is_multiline); } - // Find initial scroll position for right alignment - state->Scroll = ImVec2(0.0f, 0.0f); - if (flags & ImGuiInputTextFlags_ElideLeft) - state->Scroll.x += ImMax(0.0f, CalcTextSize(buf).x - frame_size.x + style.FramePadding.x * 2.0f); - - // Recycle existing cursor/selection/undo stack but clamp position - // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler. - if (recycle_state) + if (init_reload_from_user_buf) + { + state->Stb.select_start = state->ReloadSelectionStart; + state->Stb.cursor = state->Stb.select_end = state->ReloadSelectionEnd; state->CursorClamp(); - else - stb_textedit_initialize_state(state->Stb, !is_multiline); - - if (!is_multiline) + } + else if (!is_multiline) { if (flags & ImGuiInputTextFlags_AutoSelectAll) select_all = true; @@ -4610,7 +4423,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } if (flags & ImGuiInputTextFlags_AlwaysOverwrite) - state->Stb->insert_mode = 1; // stb field name is indeed incorrect (see #2863) + state->Stb.insert_mode = 1; // stb field name is indeed incorrect (see #2863) } const bool is_osx = io.ConfigMacOSXBehaviors; @@ -4624,19 +4437,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (g.ActiveId == id) { // Declare some inputs, the other are registered and polled via Shortcut() routing system. - // FIXME: The reason we don't use Shortcut() is we would need a routing flag to specify multiple mods, or to all mods combinaison into individual shortcuts. - const ImGuiKey always_owned_keys[] = { ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_Enter, ImGuiKey_KeypadEnter, ImGuiKey_Delete, ImGuiKey_Backspace, ImGuiKey_Home, ImGuiKey_End }; - for (ImGuiKey key : always_owned_keys) - SetKeyOwner(key, id); if (user_clicked) SetKeyOwner(ImGuiKey_MouseLeft, id); g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory)) - { g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down); - SetKeyOwner(ImGuiKey_UpArrow, id); - SetKeyOwner(ImGuiKey_DownArrow, id); - } + SetKeyOwner(ImGuiKey_Enter, id); + SetKeyOwner(ImGuiKey_KeypadEnter, id); + SetKeyOwner(ImGuiKey_Home, id); + SetKeyOwner(ImGuiKey_End, id); if (is_multiline) { SetKeyOwner(ImGuiKey_PageUp, id); @@ -4645,19 +4454,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // FIXME: May be a problem to always steal Alt on OSX, would ideally still allow an uninterrupted Alt down-up to toggle menu if (is_osx) SetKeyOwner(ImGuiMod_Alt, id); - - // Expose scroll in a manner that is agnostic to us using a child window - if (is_multiline && state != NULL) - state->Scroll.y = draw_window->Scroll.y; - - // Read-only mode always ever read from source buffer. Refresh TextLen when active. - if (is_readonly && state != NULL) - state->TextLen = (int)strlen(buf); - //if (is_readonly && state != NULL) - // state->TextA.clear(); // Uncomment to facilitate debugging, but we otherwise prefer to keep/amortize th allocation. } - if (state != NULL) - state->TextSrc = is_readonly ? buf : state->TextA.Data; // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function) if (g.ActiveId == id && state == NULL) @@ -4673,20 +4470,46 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ bool value_changed = false; bool validated = false; + // When read-only we always use the live data passed to the function + // FIXME-OPT: Because our selection/cursor code currently needs the wide text we need to convert it when active, which is not ideal :( + if (is_readonly && state != NULL && (render_cursor || render_selection)) + { + const char* buf_end = NULL; + state->TextW.resize(buf_size + 1); + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, buf, NULL, &buf_end); + state->CurLenA = (int)(buf_end - buf); + state->CursorClamp(); + render_selection &= state->HasSelection(); + } + // Select the buffer to render. - const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state; + const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state && state->TextAIsValid; const bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0); // Password pushes a temporary font with only a fallback glyph if (is_password && !is_displaying_hint) - PushPasswordFont(); + { + const ImFontGlyph* glyph = g.Font->FindGlyph('*'); + ImFont* password_font = &g.InputTextPasswordFont; + password_font->FontSize = g.Font->FontSize; + password_font->Scale = g.Font->Scale; + password_font->Ascent = g.Font->Ascent; + password_font->Descent = g.Font->Descent; + password_font->ContainerAtlas = g.Font->ContainerAtlas; + password_font->FallbackGlyph = glyph; + password_font->FallbackAdvanceX = glyph->AdvanceX; + IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty()); + PushFont(password_font); + } // Process mouse inputs and character inputs + int backup_current_text_length = 0; if (g.ActiveId == id) { IM_ASSERT(state != NULL); + backup_current_text_length = state->CurLenA; state->Edited = false; - state->BufCapacity = buf_size; + state->BufCapacityA = buf_size; state->Flags = flags; // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. @@ -4694,7 +4517,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ g.ActiveIdAllowOverlap = !io.MouseDown[0]; // Edit in progress - const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->Scroll.x; + const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX; const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f)); if (select_all) @@ -4704,34 +4527,34 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } else if (hovered && io.MouseClickedCount[0] >= 2 && !io.KeyShift) { - stb_textedit_click(state, state->Stb, mouse_x, mouse_y); + stb_textedit_click(state, &state->Stb, mouse_x, mouse_y); const int multiclick_count = (io.MouseClickedCount[0] - 2); if ((multiclick_count % 2) == 0) { // Double-click: Select word // We always use the "Mac" word advance for double-click select vs CTRL+Right which use the platform dependent variant: // FIXME: There are likely many ways to improve this behavior, but there's no "right" behavior (depends on use-case, software, OS) - const bool is_bol = (state->Stb->cursor == 0) || ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb->cursor - 1) == '\n'; - if (STB_TEXT_HAS_SELECTION(state->Stb) || !is_bol) + const bool is_bol = (state->Stb.cursor == 0) || ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor - 1) == '\n'; + if (STB_TEXT_HAS_SELECTION(&state->Stb) || !is_bol) state->OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT); //state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT); - if (!STB_TEXT_HAS_SELECTION(state->Stb)) - ImStb::stb_textedit_prep_selection_at_cursor(state->Stb); - state->Stb->cursor = ImStb::STB_TEXTEDIT_MOVEWORDRIGHT_MAC(state, state->Stb->cursor); - state->Stb->select_end = state->Stb->cursor; - ImStb::stb_textedit_clamp(state, state->Stb); + if (!STB_TEXT_HAS_SELECTION(&state->Stb)) + ImStb::stb_textedit_prep_selection_at_cursor(&state->Stb); + state->Stb.cursor = ImStb::STB_TEXTEDIT_MOVEWORDRIGHT_MAC(state, state->Stb.cursor); + state->Stb.select_end = state->Stb.cursor; + ImStb::stb_textedit_clamp(state, &state->Stb); } else { // Triple-click: Select line - const bool is_eol = ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb->cursor) == '\n'; + const bool is_eol = ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor) == '\n'; state->OnKeyPressed(STB_TEXTEDIT_K_LINESTART); state->OnKeyPressed(STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT); state->OnKeyPressed(STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT); if (!is_eol && is_multiline) { - ImSwap(state->Stb->select_start, state->Stb->select_end); - state->Stb->cursor = state->Stb->select_end; + ImSwap(state->Stb.select_start, state->Stb.select_end); + state->Stb.cursor = state->Stb.select_end; } state->CursorFollow = false; } @@ -4742,15 +4565,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (hovered) { if (io.KeyShift) - stb_textedit_drag(state, state->Stb, mouse_x, mouse_y); + stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y); else - stb_textedit_click(state, state->Stb, mouse_x, mouse_y); + stb_textedit_click(state, &state->Stb, mouse_x, mouse_y); state->CursorAnimReset(); } } else if (io.MouseDown[0] && !state->SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)) { - stb_textedit_drag(state, state->Stb, mouse_x, mouse_y); + stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y); state->CursorAnimReset(); state->CursorFollow = true; } @@ -4765,7 +4588,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { unsigned int c = '\t'; // Insert TAB if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data)) - state->OnCharPressed(c); + state->OnKeyPressed((int)c); } // FIXME: Implement Shift+Tab /* @@ -4788,7 +4611,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (c == '\t') // Skip Tab, see above. continue; if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data)) - state->OnCharPressed(c); + state->OnKeyPressed((int)c); } // Consume characters @@ -4803,7 +4626,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ IM_ASSERT(state != NULL); const int row_count_per_page = ImMax((int)((inner_size.y - style.FramePadding.y) / g.FontSize), 1); - state->Stb->row_count_per_page = row_count_per_page; + state->Stb.row_count_per_page = row_count_per_page; const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0); const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl @@ -4872,7 +4695,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { unsigned int c = '\n'; // Insert new line if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data)) - state->OnCharPressed(c); + state->OnKeyPressed((int)c); } } else if (is_cancel) @@ -4908,22 +4731,22 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ else if (is_cut || is_copy) { // Cut, Copy - if (g.PlatformIO.Platform_SetClipboardTextFn != NULL) + if (io.SetClipboardTextFn) { - // SetClipboardText() only takes null terminated strings + state->TextSrc may point to read-only user buffer, so we need to make a copy. - const int ib = state->HasSelection() ? ImMin(state->Stb->select_start, state->Stb->select_end) : 0; - const int ie = state->HasSelection() ? ImMax(state->Stb->select_start, state->Stb->select_end) : state->TextLen; - g.TempBuffer.reserve(ie - ib + 1); - memcpy(g.TempBuffer.Data, state->TextSrc + ib, ie - ib); - g.TempBuffer.Data[ie - ib] = 0; - SetClipboardText(g.TempBuffer.Data); + const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0; + const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW; + const int clipboard_data_len = ImTextCountUtf8BytesFromStr(state->TextW.Data + ib, state->TextW.Data + ie) + 1; + char* clipboard_data = (char*)IM_ALLOC(clipboard_data_len * sizeof(char)); + ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie); + SetClipboardText(clipboard_data); + MemFree(clipboard_data); } if (is_cut) { if (!state->HasSelection()) state->SelectAll(); state->CursorFollow = true; - stb_textedit_cut(state, state->Stb); + stb_textedit_cut(state, &state->Stb); } } else if (is_paste) @@ -4932,27 +4755,23 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // Filter pasted buffer const int clipboard_len = (int)strlen(clipboard); - ImVector clipboard_filtered; - clipboard_filtered.reserve(clipboard_len + 1); + ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len + 1) * sizeof(ImWchar)); + int clipboard_filtered_len = 0; for (const char* s = clipboard; *s != 0; ) { unsigned int c; - int in_len = ImTextCharFromUtf8(&c, s, NULL); - s += in_len; + s += ImTextCharFromUtf8(&c, s, NULL); if (!InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, true)) continue; - char c_utf8[5]; - ImTextCharToUtf8(c_utf8, c); - int out_len = (int)strlen(c_utf8); - clipboard_filtered.resize(clipboard_filtered.Size + out_len); - memcpy(clipboard_filtered.Data + clipboard_filtered.Size - out_len, c_utf8, out_len); + clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; } - if (clipboard_filtered.Size > 0) // If everything was filtered, ignore the pasting operation + clipboard_filtered[clipboard_filtered_len] = 0; + if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation { - clipboard_filtered.push_back(0); - stb_textedit_paste(state, state->Stb, clipboard_filtered.Data, clipboard_filtered.Size - 1); + stb_textedit_paste(state, &state->Stb, clipboard_filtered, clipboard_filtered_len); state->CursorFollow = true; } + MemFree(clipboard_filtered); } } @@ -4976,31 +4795,46 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ apply_new_text_length = 0; value_changed = true; IMSTB_TEXTEDIT_CHARTYPE empty_string; - stb_textedit_replace(state, state->Stb, &empty_string, 0); + stb_textedit_replace(state, &state->Stb, &empty_string, 0); } - else if (strcmp(buf, state->TextToRevertTo.Data) != 0) + else if (strcmp(buf, state->InitialTextA.Data) != 0) { - apply_new_text = state->TextToRevertTo.Data; - apply_new_text_length = state->TextToRevertTo.Size - 1; - // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents. // Push records into the undo stack so we can CTRL+Z the revert operation itself + apply_new_text = state->InitialTextA.Data; + apply_new_text_length = state->InitialTextA.Size - 1; value_changed = true; - stb_textedit_replace(state, state->Stb, state->TextToRevertTo.Data, state->TextToRevertTo.Size - 1); + ImVector w_text; + if (apply_new_text_length > 0) + { + w_text.resize(ImTextCountCharsFromUtf8(apply_new_text, apply_new_text + apply_new_text_length) + 1); + ImTextStrFromUtf8(w_text.Data, w_text.Size, apply_new_text, apply_new_text + apply_new_text_length); + } + stb_textedit_replace(state, &state->Stb, w_text.Data, (apply_new_text_length > 0) ? (w_text.Size - 1) : 0); } } - // FIXME-OPT: We always reapply the live buffer back to the input buffer before clearing ActiveId, - // even though strictly speaking it wasn't modified on this frame. Should mark dirty state from the stb_textedit callbacks. - // If we do that, need to ensure that as special case, 'validated == true' also writes back. - // This also allows the user to use InputText() without maintaining any user-side storage. + // Apply ASCII value + if (!is_readonly) + { + state->TextAIsValid = true; + state->TextA.resize(state->TextW.Size * 4 + 1); + ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->TextW.Data, NULL); + } + + // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer + // before clearing ActiveId, even though strictly speaking it wasn't modified on this frame. + // If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail. + // This also allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage // (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object // unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize). - const bool apply_edit_back_to_user_buffer = true;// !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); + const bool apply_edit_back_to_user_buffer = !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); if (apply_edit_back_to_user_buffer) { - // Apply current edited text immediately. + // Apply new value immediately - copy modified buffer back // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer + // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect. + // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks. // User callback if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0) @@ -5042,21 +4876,18 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ callback_data.Flags = flags; callback_data.UserData = callback_user_data; - // FIXME-OPT: Undo stack reconcile needs a backup of the data until we rework API, see #7925 char* callback_buf = is_readonly ? buf : state->TextA.Data; - IM_ASSERT(callback_buf == state->TextSrc); - state->CallbackTextBackup.resize(state->TextLen + 1); - memcpy(state->CallbackTextBackup.Data, callback_buf, state->TextLen + 1); - callback_data.EventKey = event_key; callback_data.Buf = callback_buf; - callback_data.BufTextLen = state->TextLen; - callback_data.BufSize = state->BufCapacity; + callback_data.BufTextLen = state->CurLenA; + callback_data.BufSize = state->BufCapacityA; callback_data.BufDirty = false; - const int utf8_cursor_pos = callback_data.CursorPos = state->Stb->cursor; - const int utf8_selection_start = callback_data.SelectionStart = state->Stb->select_start; - const int utf8_selection_end = callback_data.SelectionEnd = state->Stb->select_end; + // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188) + ImWchar* text = state->TextW.Data; + const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + state->Stb.cursor); + const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_start); + const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_end); // Call user code callback(&callback_data); @@ -5064,28 +4895,31 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Read back what user may have modified callback_buf = is_readonly ? buf : state->TextA.Data; // Pointer may have been invalidated by a resize callback IM_ASSERT(callback_data.Buf == callback_buf); // Invalid to modify those fields - IM_ASSERT(callback_data.BufSize == state->BufCapacity); + IM_ASSERT(callback_data.BufSize == state->BufCapacityA); IM_ASSERT(callback_data.Flags == flags); const bool buf_dirty = callback_data.BufDirty; - if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) { state->Stb->cursor = callback_data.CursorPos; state->CursorFollow = true; } - if (callback_data.SelectionStart != utf8_selection_start || buf_dirty) { state->Stb->select_start = (callback_data.SelectionStart == callback_data.CursorPos) ? state->Stb->cursor : callback_data.SelectionStart; } - if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb->select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb->select_start : callback_data.SelectionEnd; } + if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) { state->Stb.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow = true; } + if (callback_data.SelectionStart != utf8_selection_start || buf_dirty) { state->Stb.select_start = (callback_data.SelectionStart == callback_data.CursorPos) ? state->Stb.cursor : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); } + if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb.select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb.select_start : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); } if (buf_dirty) { - // Callback may update buffer and thus set buf_dirty even in read-only mode. + IM_ASSERT(!is_readonly); IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! - InputTextReconcileUndoState(state, state->CallbackTextBackup.Data, state->CallbackTextBackup.Size - 1, callback_data.Buf, callback_data.BufTextLen); - state->TextLen = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() + InputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen); // FIXME: Move the rest of this block inside function and rename to InputTextReconcileStateAfterUserCallback() ? + if (callback_data.BufTextLen > backup_current_text_length && is_resizable) + state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length)); // Worse case scenario resize + state->CurLenW = ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL); + state->CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() state->CursorAnimReset(); } } } // Will copy result string if modified - if (!is_readonly && strcmp(state->TextSrc, buf) != 0) + if (!is_readonly && strcmp(state->TextA.Data, buf) != 0) { - apply_new_text = state->TextSrc; - apply_new_text_length = state->TextLen; + apply_new_text = state->TextA.Data; + apply_new_text_length = state->CurLenA; value_changed = true; } } @@ -5107,9 +4941,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Copy result to user buffer. This can currently only happen when (g.ActiveId == id) if (apply_new_text != NULL) { - //// We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size - //// of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used - //// without any storage on user's side. + // We cannot test for 'backup_current_text_length != apply_new_text_length' here because we have no guarantee that the size + // of our owned buffer matches the size of the string object held by the user, and by design we allow InputText() to be used + // without any storage on user's side. IM_ASSERT(apply_new_text_length >= 0); if (is_resizable) { @@ -5143,7 +4977,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Render frame if (!is_multiline) { - RenderNavCursor(frame_bb, id); + RenderNavHighlight(frame_bb, id); RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); } @@ -5169,7 +5003,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { IM_ASSERT(state != NULL); if (!is_displaying_hint) - buf_display_end = buf_display + state->TextLen; + buf_display_end = buf_display + state->CurLenA; // Render text (with cursor and selection) // This is going to be messy. We need to: @@ -5178,40 +5012,52 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // - Measure text height (for scrollbar) // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort) // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8. - const char* text_begin = buf_display; - const char* text_end = text_begin + state->TextLen; + const ImWchar* text_begin = state->TextW.Data; ImVec2 cursor_offset, select_start_offset; { - // Find lines numbers straddling cursor and selection min position - int cursor_line_no = render_cursor ? -1 : -1000; - int selmin_line_no = render_selection ? -1 : -1000; - const char* cursor_ptr = render_cursor ? text_begin + state->Stb->cursor : NULL; - const char* selmin_ptr = render_selection ? text_begin + ImMin(state->Stb->select_start, state->Stb->select_end) : NULL; - - // Count lines and find line number for cursor and selection ends - int line_count = 1; - if (is_multiline) + // Find lines numbers straddling 'cursor' (slot 0) and 'select_start' (slot 1) positions. + const ImWchar* searches_input_ptr[2] = { NULL, NULL }; + int searches_result_line_no[2] = { -1000, -1000 }; + int searches_remaining = 0; + if (render_cursor) { - for (const char* s = text_begin; (s = (const char*)memchr(s, '\n', (size_t)(text_end - s))) != NULL; s++) - { - if (cursor_line_no == -1 && s >= cursor_ptr) { cursor_line_no = line_count; } - if (selmin_line_no == -1 && s >= selmin_ptr) { selmin_line_no = line_count; } - line_count++; - } + searches_input_ptr[0] = text_begin + state->Stb.cursor; + searches_result_line_no[0] = -1; + searches_remaining++; } - if (cursor_line_no == -1) - cursor_line_no = line_count; - if (selmin_line_no == -1) - selmin_line_no = line_count; + if (render_selection) + { + searches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); + searches_result_line_no[1] = -1; + searches_remaining++; + } + + // Iterate all lines to find our line numbers + // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter. + searches_remaining += is_multiline ? 1 : 0; + int line_count = 0; + //for (const ImWchar* s = text_begin; (s = (const ImWchar*)wcschr((const wchar_t*)s, (wchar_t)'\n')) != NULL; s++) // FIXME-OPT: Could use this when wchar_t are 16-bit + for (const ImWchar* s = text_begin; *s != 0; s++) + if (*s == '\n') + { + line_count++; + if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; } + if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; } + } + line_count++; + if (searches_result_line_no[0] == -1) + searches_result_line_no[0] = line_count; + if (searches_result_line_no[1] == -1) + searches_result_line_no[1] = line_count; // Calculate 2d position by finding the beginning of the line and measuring distance - cursor_offset.x = InputTextCalcTextSize(&g, ImStrbol(cursor_ptr, text_begin), cursor_ptr).x; - cursor_offset.y = cursor_line_no * g.FontSize; - if (selmin_line_no >= 0) + cursor_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; + cursor_offset.y = searches_result_line_no[0] * g.FontSize; + if (searches_result_line_no[1] >= 0) { - select_start_offset.x = InputTextCalcTextSize(&g, ImStrbol(selmin_ptr, text_begin), selmin_ptr).x; - select_start_offset.y = selmin_line_no * g.FontSize; + select_start_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; + select_start_offset.y = searches_result_line_no[1] * g.FontSize; } // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224) @@ -5227,14 +5073,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { const float scroll_increment_x = inner_size.x * 0.25f; const float visible_width = inner_size.x - style.FramePadding.x; - if (cursor_offset.x < state->Scroll.x) - state->Scroll.x = IM_TRUNC(ImMax(0.0f, cursor_offset.x - scroll_increment_x)); - else if (cursor_offset.x - visible_width >= state->Scroll.x) - state->Scroll.x = IM_TRUNC(cursor_offset.x - visible_width + scroll_increment_x); + if (cursor_offset.x < state->ScrollX) + state->ScrollX = IM_TRUNC(ImMax(0.0f, cursor_offset.x - scroll_increment_x)); + else if (cursor_offset.x - visible_width >= state->ScrollX) + state->ScrollX = IM_TRUNC(cursor_offset.x - visible_width + scroll_increment_x); } else { - state->Scroll.y = 0.0f; + state->ScrollX = 0.0f; } // Vertical scroll @@ -5255,41 +5101,43 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } // Draw selection - const ImVec2 draw_scroll = ImVec2(state->Scroll.x, 0.0f); + const ImVec2 draw_scroll = ImVec2(state->ScrollX, 0.0f); if (render_selection) { - const char* text_selected_begin = text_begin + ImMin(state->Stb->select_start, state->Stb->select_end); - const char* text_selected_end = text_begin + ImMax(state->Stb->select_start, state->Stb->select_end); + const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); + const ImWchar* text_selected_end = text_begin + ImMax(state->Stb.select_start, state->Stb.select_end); ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests. float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection. float bg_offy_dn = is_multiline ? 0.0f : 2.0f; ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll; - for (const char* p = text_selected_begin; p < text_selected_end; ) + for (const ImWchar* p = text_selected_begin; p < text_selected_end; ) { if (rect_pos.y > clip_rect.w + g.FontSize) break; if (rect_pos.y < clip_rect.y) { - p = (const char*)memchr((void*)p, '\n', text_selected_end - p); - p = p ? p + 1 : text_selected_end; + //p = (const ImWchar*)wmemchr((const wchar_t*)p, '\n', text_selected_end - p); // FIXME-OPT: Could use this when wchar_t are 16-bit + //p = p ? p + 1 : text_selected_end; + while (p < text_selected_end) + if (*p++ == '\n') + break; } else { - ImVec2 rect_size = InputTextCalcTextSize(&g, p, text_selected_end, &p, NULL, true); + ImVec2 rect_size = InputTextCalcTextSizeW(&g, p, text_selected_end, &p, NULL, true); if (rect_size.x <= 0.0f) rect_size.x = IM_TRUNC(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn)); rect.ClipWith(clip_rect); if (rect.Overlaps(clip_rect)) draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color); - rect_pos.x = draw_pos.x - draw_scroll.x; } + rect_pos.x = draw_pos.x - draw_scroll.x; rect_pos.y += g.FontSize; } } // We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash. - // FIXME-OPT: Multiline could submit a smaller amount of contents to AddText() since we already iterated through it. if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) { ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); @@ -5322,19 +5170,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_multiline) text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontSize); // We don't need width else if (!is_displaying_hint && g.ActiveId == id) - buf_display_end = buf_display + state->TextLen; + buf_display_end = buf_display + state->CurLenA; else if (!is_displaying_hint) buf_display_end = buf_display + strlen(buf_display); if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) { - // Find render position for right alignment - if (flags & ImGuiInputTextFlags_ElideLeft) - draw_pos.x = ImMin(draw_pos.x, frame_bb.Max.x - CalcTextSize(buf_display, NULL).x - style.FramePadding.x); - - const ImVec2 draw_scroll = /*state ? ImVec2(state->Scroll.x, 0.0f) :*/ ImVec2(0.0f, 0.0f); // Preserve scroll when inactive? ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); - draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); } } @@ -5343,24 +5186,22 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_multiline) { - // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (see #4761, #7870)... + // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (ref issue #4761)... Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); - g.NextItemData.ItemFlags |= (ImGuiItemFlags)ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; + g.NextItemData.ItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop; EndChild(); item_data_backup.StatusFlags |= (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredWindow); // ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active... // FIXME: This quite messy/tricky, should attempt to get rid of the child window. EndGroup(); - if (g.LastItemData.ID == 0 || g.LastItemData.ID != GetWindowScrollbarID(draw_window, ImGuiAxis_Y)) + if (g.LastItemData.ID == 0) { g.LastItemData.ID = id; - g.LastItemData.ItemFlags = item_data_backup.ItemFlags; + g.LastItemData.InFlags = item_data_backup.InFlags; g.LastItemData.StatusFlags = item_data_backup.StatusFlags; } } - if (state) - state->TextSrc = NULL; // Log as text if (g.LogEnabled && (!is_password || is_displaying_hint)) @@ -5372,7 +5213,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); - if (value_changed) + if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited)) MarkItemEdited(id); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable); @@ -5386,16 +5227,14 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) { #ifndef IMGUI_DISABLE_DEBUG_TOOLS ImGuiContext& g = *GImGui; - ImStb::STB_TexteditState* stb_state = state->Stb; + ImStb::STB_TexteditState* stb_state = &state->Stb; ImStb::StbUndoState* undo_state = &stb_state->undostate; Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId); DebugLocateItemOnHover(state->ID); - Text("CurLenA: %d, Cursor: %d, Selection: %d..%d", state->TextLen, stb_state->cursor, stb_state->select_start, stb_state->select_end); - Text("BufCapacityA: %d", state->BufCapacity); - Text("(Internal Buffer: TextA Size: %d, Capacity: %d)", state->TextA.Size, state->TextA.Capacity); + Text("CurLenW: %d, CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenW, state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end); Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x); Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point); - if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 10), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) // Visualize undo state + if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 10), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY)) // Visualize undo state { PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); for (int n = 0; n < IMSTB_TEXTEDIT_UNDOSTATECOUNT; n++) @@ -5404,10 +5243,11 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) const char undo_rec_type = (n < undo_state->undo_point) ? 'u' : (n >= undo_state->redo_point) ? 'r' : ' '; if (undo_rec_type == ' ') BeginDisabled(); - const int buf_preview_len = (undo_rec_type != ' ' && undo_rec->char_storage != -1) ? undo_rec->insert_length : 0; - const char* buf_preview_str = undo_state->undo_char + undo_rec->char_storage; - Text("%c [%02d] where %03d, insert %03d, delete %03d, char_storage %03d \"%.*s\"", - undo_rec_type, n, undo_rec->where, undo_rec->insert_length, undo_rec->delete_length, undo_rec->char_storage, buf_preview_len, buf_preview_str); + char buf[64] = ""; + if (undo_rec_type != ' ' && undo_rec->char_storage != -1) + ImTextStrToUtf8(buf, IM_ARRAYSIZE(buf), undo_state->undo_char + undo_rec->char_storage, undo_state->undo_char + undo_rec->char_storage + undo_rec->insert_length); + Text("%c [%02d] where %03d, insert %03d, delete %03d, char_storage %03d \"%s\"", + undo_rec_type, n, undo_rec->where, undo_rec->insert_length, undo_rec->delete_length, undo_rec->char_storage, buf); if (undo_rec_type == ' ') EndDisabled(); } @@ -5688,7 +5528,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag // Drag and Drop Target // NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test. - if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(g.LastItemData.ItemFlags & ImGuiItemFlags_ReadOnly) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget()) + if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget()) { bool accepted_drag_drop = false; if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) @@ -5916,7 +5756,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if ((flags & ImGuiColorEditFlags_NoLabel)) Text("Current"); - ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaMask_ | ImGuiColorEditFlags_NoTooltip; + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip; ColorButton("##current", col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2)); if (ref_col != NULL) { @@ -5956,7 +5796,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if ((flags & ImGuiColorEditFlags_NoInputs) == 0) { PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x); - ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaMask_ | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSmallPreview; + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf; ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker; if (flags & ImGuiColorEditFlags_DisplayRGB || (flags & ImGuiColorEditFlags_DisplayMask_) == 0) if (ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_DisplayRGB)) @@ -6132,8 +5972,8 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held); - if (flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaOpaque)) - flags &= ~(ImGuiColorEditFlags_AlphaNoBg | ImGuiColorEditFlags_AlphaPreviewHalf); + if (flags & ImGuiColorEditFlags_NoAlpha) + flags &= ~(ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf); ImVec4 col_rgb = col; if (flags & ImGuiColorEditFlags_InputHSV) @@ -6152,22 +5992,19 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f) { float mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f); - if ((flags & ImGuiColorEditFlags_AlphaNoBg) == 0) - RenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawFlags_RoundCornersRight); - else - window->DrawList->AddRectFilled(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), rounding, ImDrawFlags_RoundCornersRight); + RenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawFlags_RoundCornersRight); window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawFlags_RoundCornersLeft); } else { // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha - ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaOpaque) ? col_rgb_without_alpha : col_rgb; - if (col_source.w < 1.0f && (flags & ImGuiColorEditFlags_AlphaNoBg) == 0) + ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col_rgb : col_rgb_without_alpha; + if (col_source.w < 1.0f) RenderColorRectWithAlphaCheckerboard(window->DrawList, bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding); else window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding); } - RenderNavCursor(bb, id); + RenderNavHighlight(bb, id); if ((flags & ImGuiColorEditFlags_NoBorder) == 0) { if (g.Style.FrameBorderSize > 0.0f) @@ -6192,7 +6029,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl // Tooltip if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered && IsItemHovered(ImGuiHoveredFlags_ForTooltip)) - ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_AlphaMask_)); + ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); return pressed; } @@ -6233,8 +6070,7 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2); ImVec4 cf(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); - ImGuiColorEditFlags flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_AlphaMask_; - ColorButton("##preview", cf, (flags & flags_to_forward) | ImGuiColorEditFlags_NoTooltip, sz); + ColorButton("##preview", cf, (flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)) | ImGuiColorEditFlags_NoTooltip, sz); SameLine(); if ((flags & ImGuiColorEditFlags_InputRGB) || !(flags & ImGuiColorEditFlags_InputMask_)) { @@ -6259,9 +6095,8 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) bool allow_opt_datatype = !(flags & ImGuiColorEditFlags_DataTypeMask_); if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context")) return; - ImGuiContext& g = *GImGui; - PushItemFlag(ImGuiItemFlags_NoMarkEdited, true); + g.LockMarkEdited++; ImGuiColorEditFlags opts = g.ColorEditOptions; if (allow_opt_inputs) { @@ -6303,8 +6138,8 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags) } g.ColorEditOptions = opts; - PopItemFlag(); EndPopup(); + g.LockMarkEdited--; } void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags) @@ -6313,9 +6148,8 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar); if ((!allow_opt_picker && !allow_opt_alpha_bar) || !BeginPopup("context")) return; - ImGuiContext& g = *GImGui; - PushItemFlag(ImGuiItemFlags_NoMarkEdited, true); + g.LockMarkEdited++; if (allow_opt_picker) { ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function @@ -6344,8 +6178,8 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl if (allow_opt_picker) Separator(); CheckboxFlags("Alpha Bar", &g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); } - PopItemFlag(); EndPopup(); + g.LockMarkEdited--; } //------------------------------------------------------------------------- @@ -6387,7 +6221,7 @@ bool ImGui::TreeNode(const char* label) if (window->SkipItems) return false; ImGuiID id = window->GetID(label); - return TreeNodeBehavior(id, ImGuiTreeNodeFlags_None, label, NULL); + return TreeNodeBehavior(id, id, ImGuiTreeNodeFlags_None, label, NULL); } bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args) @@ -6406,7 +6240,7 @@ bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags) if (window->SkipItems) return false; ImGuiID id = window->GetID(label); - return TreeNodeBehavior(id, flags, label, NULL); + return TreeNodeBehavior(id, id, flags, label, NULL); } bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) @@ -6436,7 +6270,7 @@ bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char ImGuiID id = window->GetID(str_id); const char* label, *label_end; ImFormatStringToTempBufferV(&label, &label_end, fmt, args); - return TreeNodeBehavior(id, flags, label, label_end); + return TreeNodeBehavior(id, id, flags, label, label_end); } bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) @@ -6448,7 +6282,7 @@ bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char ImGuiID id = window->GetID(ptr_id); const char* label, *label_end; ImFormatStringToTempBufferV(&label, &label_end, fmt, args); - return TreeNodeBehavior(id, flags, label, label_end); + return TreeNodeBehavior(id, id, flags, label, label_end); } bool ImGui::TreeNodeGetOpen(ImGuiID storage_id) @@ -6476,7 +6310,7 @@ bool ImGui::TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags) ImGuiStorage* storage = window->DC.StateStorage; bool is_open; - if (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasOpen) + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasOpen) { if (g.NextItemData.OpenCond & ImGuiCond_Always) { @@ -6522,13 +6356,13 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags) ImGuiTreeNodeStackData* tree_node_data = &g.TreeNodeStack.back(); tree_node_data->ID = g.LastItemData.ID; tree_node_data->TreeFlags = flags; - tree_node_data->ItemFlags = g.LastItemData.ItemFlags; + tree_node_data->InFlags = g.LastItemData.InFlags; tree_node_data->NavRect = g.LastItemData.NavRect; window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth); } // When using public API, currently 'id == storage_id' is always true, but we separate the values to facilitate advanced user code doing storage queries outside of UI loop. -bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) +bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -6550,17 +6384,17 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // We vertically grow up to current line height up the typical widget height. const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2); const bool span_all_columns = (flags & ImGuiTreeNodeFlags_SpanAllColumns) != 0 && (g.CurrentTable != NULL); - const bool span_all_columns_label = (flags & ImGuiTreeNodeFlags_LabelSpanAllColumns) != 0 && (g.CurrentTable != NULL); ImRect frame_bb; frame_bb.Min.x = span_all_columns ? window->ParentWorkRect.Min.x : (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x; frame_bb.Min.y = window->DC.CursorPos.y; - frame_bb.Max.x = span_all_columns ? window->ParentWorkRect.Max.x : (flags & ImGuiTreeNodeFlags_SpanLabelWidth) ? window->DC.CursorPos.x + text_width + padding.x : window->WorkRect.Max.x; + frame_bb.Max.x = span_all_columns ? window->ParentWorkRect.Max.x : (flags & ImGuiTreeNodeFlags_SpanTextWidth) ? window->DC.CursorPos.x + text_width + padding.x : window->WorkRect.Max.x; frame_bb.Max.y = window->DC.CursorPos.y + frame_height; if (display_frame) { - const float outer_extend = IM_TRUNC(window->WindowPadding.x * 0.5f); // Framed header expand a little outside of current limits - frame_bb.Min.x -= outer_extend; - frame_bb.Max.x += outer_extend; + // Framed header expand a little outside the default padding, to the edge of InnerClipRect + // (FIXME: May remove this at some point and make InnerClipRect align with WindowPadding.x instead of WindowPadding.x*0.5f) + frame_bb.Min.x -= IM_TRUNC(window->WindowPadding.x * 0.5f - 1.0f); + frame_bb.Max.x += IM_TRUNC(window->WindowPadding.x * 0.5f); } ImVec2 text_pos(window->DC.CursorPos.x + text_offset_x, window->DC.CursorPos.y + text_offset_y); @@ -6568,31 +6402,29 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing ImRect interact_bb = frame_bb; - if ((flags & (ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanLabelWidth | ImGuiTreeNodeFlags_SpanAllColumns)) == 0) + if ((flags & (ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanTextWidth | ImGuiTreeNodeFlags_SpanAllColumns)) == 0) interact_bb.Max.x = frame_bb.Min.x + text_width + (label_size.x > 0.0f ? style.ItemSpacing.x * 2.0f : 0.0f); - // Compute open and multi-select states before ItemAdd() as it clear NextItem data. - ImGuiID storage_id = (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasStorageID) ? g.NextItemData.StorageId : id; - bool is_open = TreeNodeUpdateNextOpen(storage_id, flags); - - bool is_visible; - if (span_all_columns || span_all_columns_label) + // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable.. + const float backup_clip_rect_min_x = window->ClipRect.Min.x; + const float backup_clip_rect_max_x = window->ClipRect.Max.x; + if (span_all_columns) { - // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable.. - const float backup_clip_rect_min_x = window->ClipRect.Min.x; - const float backup_clip_rect_max_x = window->ClipRect.Max.x; window->ClipRect.Min.x = window->ParentWorkRect.Min.x; window->ClipRect.Max.x = window->ParentWorkRect.Max.x; - is_visible = ItemAdd(interact_bb, id); + } + + // Compute open and multi-select states before ItemAdd() as it clear NextItem data. + bool is_open = TreeNodeUpdateNextOpen(storage_id, flags); + bool item_add = ItemAdd(interact_bb, id); + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; + g.LastItemData.DisplayRect = frame_bb; + + if (span_all_columns) + { window->ClipRect.Min.x = backup_clip_rect_min_x; window->ClipRect.Max.x = backup_clip_rect_max_x; } - else - { - is_visible = ItemAdd(interact_bb, id); - } - g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; - g.LastItemData.DisplayRect = frame_bb; // If a NavLeft request is happening and ImGuiTreeNodeFlags_NavLeftJumpsBackHere enabled: // Store data for the current depth to allow returning to this node from any child item. @@ -6607,7 +6439,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l } const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; - if (!is_visible) + if (!item_add) { if (store_tree_node_stack_data && is_open) TreeNodeStoreStackData(flags); // Call before TreePushOverrideID() @@ -6617,7 +6449,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l return is_open; } - if (span_all_columns || span_all_columns_label) + if (span_all_columns) { TablePushBackgroundChannel(); g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasClipRect; @@ -6625,7 +6457,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l } ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None; - if ((flags & ImGuiTreeNodeFlags_AllowOverlap) || (g.LastItemData.ItemFlags & ImGuiItemFlags_AllowOverlap)) + if ((flags & ImGuiTreeNodeFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap)) button_flags |= ImGuiButtonFlags_AllowOverlap; if (!is_leaf) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; @@ -6637,10 +6469,6 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + style.TouchExtraPadding.x; const bool is_mouse_x_over_arrow = (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2); - const bool is_multi_select = (g.LastItemData.ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0; - if (is_multi_select) // We absolutely need to distinguish open vs select so _OpenOnArrow comes by default - flags |= (flags & ImGuiTreeNodeFlags_OpenOnMask_) == 0 ? ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick : ImGuiTreeNodeFlags_OpenOnArrow; - // Open behaviors can be altered with the _OpenOnArrow and _OnOnDoubleClick flags. // Some alteration have subtle effects (e.g. toggle on MouseUp vs MouseDown events) due to requirements for multi-selection and drag and drop support. // - Single-click on label = Toggle on MouseUp (default, when _OpenOnArrow=0) @@ -6661,17 +6489,21 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const bool was_selected = selected; // Multi-selection support (header) + const bool is_multi_select = (g.LastItemData.InFlags & ImGuiItemFlags_IsMultiSelect) != 0; if (is_multi_select) { // Handle multi-select + alter button flags for it MultiSelectItemHeader(id, &selected, &button_flags); if (is_mouse_x_over_arrow) button_flags = (button_flags | ImGuiButtonFlags_PressedOnClick) & ~ImGuiButtonFlags_PressedOnClickRelease; + + // We absolutely need to distinguish open vs select so comes by default + flags |= ImGuiTreeNodeFlags_OpenOnArrow; } else { if (window != g.HoveredWindow || !is_mouse_x_over_arrow) - button_flags |= ImGuiButtonFlags_NoKeyModsAllowed; + button_flags |= ImGuiButtonFlags_NoKeyModifiers; } bool hovered, held; @@ -6681,20 +6513,18 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l { if (pressed && g.DragDropHoldJustPressedId != id) { - if ((flags & ImGuiTreeNodeFlags_OpenOnMask_) == 0 || (g.NavActivateId == id && !is_multi_select)) - toggled = true; // Single click + if ((flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) == 0 || (g.NavActivateId == id && !is_multi_select)) + toggled = true; if (flags & ImGuiTreeNodeFlags_OpenOnArrow) - toggled |= is_mouse_x_over_arrow && !g.NavHighlightItemUnderNav; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job + toggled |= is_mouse_x_over_arrow && !g.NavDisableMouseHover; // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseClickedCount[0] == 2) - toggled = true; // Double click + toggled = true; } else if (pressed && g.DragDropHoldJustPressedId == id) { IM_ASSERT(button_flags & ImGuiButtonFlags_PressedOnDragDropHold); if (!is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. toggled = true; - else - pressed = false; // Cancel press so it doesn't trigger selection. } if (g.NavId == id && g.NavMoveDir == ImGuiDir_Left && is_open) @@ -6731,57 +6561,52 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection; // Render + const ImU32 text_col = GetColorU32(ImGuiCol_Text); + ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_Compact; + if (is_multi_select) + nav_highlight_flags |= ImGuiNavHighlightFlags_AlwaysDraw; // Always show the nav rectangle + if (display_frame) { - const ImU32 text_col = GetColorU32(ImGuiCol_Text); - ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact; - if (is_multi_select) - nav_render_cursor_flags |= ImGuiNavRenderCursorFlags_AlwaysDraw; // Always show the nav rectangle - if (display_frame) - { - // Framed type - const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); - RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding); - RenderNavCursor(frame_bb, id, nav_render_cursor_flags); - if (flags & ImGuiTreeNodeFlags_Bullet) - RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col); - else if (!is_leaf) - RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 1.0f); - else // Leaf without bullet, left-adjusted text - text_pos.x -= text_offset_x - padding.x; - if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) - frame_bb.Max.x -= g.FontSize + style.FramePadding.x; - if (g.LogEnabled) - LogSetNextTextDecoration("###", "###"); - } - else - { - // Unframed typed for tree nodes - if (hovered || selected) - { - const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); - RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false); - } - RenderNavCursor(frame_bb, id, nav_render_cursor_flags); - if (flags & ImGuiTreeNodeFlags_Bullet) - RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); - else if (!is_leaf) - RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 0.70f); - if (g.LogEnabled) - LogSetNextTextDecoration(">", NULL); - } - - if (span_all_columns && !span_all_columns_label) - TablePopBackgroundChannel(); - - // Label - if (display_frame) - RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); - else - RenderText(text_pos, label, label_end, false); - - if (span_all_columns_label) - TablePopBackgroundChannel(); + // Framed type + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding); + RenderNavHighlight(frame_bb, id, nav_highlight_flags); + if (flags & ImGuiTreeNodeFlags_Bullet) + RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col); + else if (!is_leaf) + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 1.0f); + else // Leaf without bullet, left-adjusted text + text_pos.x -= text_offset_x -padding.x; + if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) + frame_bb.Max.x -= g.FontSize + style.FramePadding.x; + if (g.LogEnabled) + LogSetNextTextDecoration("###", "###"); } + else + { + // Unframed typed for tree nodes + if (hovered || selected) + { + const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false); + } + RenderNavHighlight(frame_bb, id, nav_highlight_flags); + if (flags & ImGuiTreeNodeFlags_Bullet) + RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); + else if (!is_leaf) + RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 0.70f); + if (g.LogEnabled) + LogSetNextTextDecoration(">", NULL); + } + + if (span_all_columns) + TablePopBackgroundChannel(); + + // Label + if (display_frame) + RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); + else + RenderText(text_pos, label, label_end, false); if (store_tree_node_stack_data && is_open) TreeNodeStoreStackData(flags); // Call before TreePushOverrideID() @@ -6857,21 +6682,11 @@ void ImGui::SetNextItemOpen(bool is_open, ImGuiCond cond) ImGuiContext& g = *GImGui; if (g.CurrentWindow->SkipItems) return; - g.NextItemData.HasFlags |= ImGuiNextItemDataFlags_HasOpen; + g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasOpen; g.NextItemData.OpenVal = is_open; g.NextItemData.OpenCond = (ImU8)(cond ? cond : ImGuiCond_Always); } -// Set next TreeNode/CollapsingHeader storage id. -void ImGui::SetNextItemStorageID(ImGuiID storage_id) -{ - ImGuiContext& g = *GImGui; - if (g.CurrentWindow->SkipItems) - return; - g.NextItemData.HasFlags |= ImGuiNextItemDataFlags_HasStorageID; - g.NextItemData.StorageId = storage_id; -} - // CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag). // This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode(). bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) @@ -6880,7 +6695,7 @@ bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags) if (window->SkipItems) return false; ImGuiID id = window->GetID(label); - return TreeNodeBehavior(id, flags | ImGuiTreeNodeFlags_CollapsingHeader, label); + return TreeNodeBehavior(id, id, flags | ImGuiTreeNodeFlags_CollapsingHeader, label); } // p_visible == NULL : regular collapsing header @@ -6900,7 +6715,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl flags |= ImGuiTreeNodeFlags_CollapsingHeader; if (p_visible) flags |= ImGuiTreeNodeFlags_AllowOverlap | (ImGuiTreeNodeFlags)ImGuiTreeNodeFlags_ClipLabelForTrailingButton; - bool is_open = TreeNodeBehavior(id, flags, label); + bool is_open = TreeNodeBehavior(id, id, flags, label); if (p_visible != NULL) { // Create a small overlapping close button @@ -6955,9 +6770,13 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth)) size.x = ImMax(label_size.x, max_x - min_x); + // Text stays at the submission position, but bounding box may be extended on both sides + const ImVec2 text_min = pos; + const ImVec2 text_max(min_x + size.x, pos.y + size.y); + // Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable. - // FIXME: Not part of layout so not included in clipper calculation, but ItemSize currently doesn't allow offsetting CursorPos. - ImRect bb(min_x, pos.y, min_x + size.x, pos.y + size.y); + // FIXME: Not part of layout so not included in clipper calculation, but ItemSize currenty doesn't allow offsetting CursorPos. + ImRect bb(min_x, pos.y, text_max.x, text_max.y); if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0) { const float spacing_x = span_all_columns ? 0.0f : style.ItemSpacing.x; @@ -6971,26 +6790,25 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl } //if (g.IO.KeyCtrl) { GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(0, 255, 0, 255)); } - const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0; - const ImGuiItemFlags extra_item_flags = disabled_item ? (ImGuiItemFlags)ImGuiItemFlags_Disabled : ImGuiItemFlags_None; - bool is_visible; + // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable.. + const float backup_clip_rect_min_x = window->ClipRect.Min.x; + const float backup_clip_rect_max_x = window->ClipRect.Max.x; if (span_all_columns) { - // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable.. - const float backup_clip_rect_min_x = window->ClipRect.Min.x; - const float backup_clip_rect_max_x = window->ClipRect.Max.x; window->ClipRect.Min.x = window->ParentWorkRect.Min.x; window->ClipRect.Max.x = window->ParentWorkRect.Max.x; - is_visible = ItemAdd(bb, id, NULL, extra_item_flags); + } + + const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0; + const bool is_visible = ItemAdd(bb, id, NULL, disabled_item ? (ImGuiItemFlags)ImGuiItemFlags_Disabled : ImGuiItemFlags_None); + + if (span_all_columns) + { window->ClipRect.Min.x = backup_clip_rect_min_x; window->ClipRect.Max.x = backup_clip_rect_max_x; } - else - { - is_visible = ItemAdd(bb, id, NULL, extra_item_flags); - } - const bool is_multi_select = (g.LastItemData.ItemFlags & ImGuiItemFlags_IsMultiSelect) != 0; + const bool is_multi_select = (g.LastItemData.InFlags & ImGuiItemFlags_IsMultiSelect) != 0; if (!is_visible) if (!is_multi_select || !g.BoxSelectState.UnclipMode || !g.BoxSelectState.UnclipRect.Overlaps(bb)) // Extra layer of "no logic clip" for box-select support (would be more overhead to add to ItemAdd) return false; @@ -7018,7 +6836,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } - if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.ItemFlags & ImGuiItemFlags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; } + if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; } // Multi-selection support (header) const bool was_selected = selected; @@ -7050,14 +6868,13 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl selected = pressed = true; } - // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with keyboard/gamepad + // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) { - if (!g.NavHighlightItemUnderNav && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) + if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent) { SetNavID(id, window->DC.NavLayerCurrent, g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb)); // (bb == NavRect) - if (g.IO.ConfigNavCursorVisibleAuto) - g.NavCursorVisible = false; + g.NavDisableHighlight = true; } } if (pressed) @@ -7069,19 +6886,22 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl // Render if (is_visible) { - const bool highlighted = hovered || (flags & ImGuiSelectableFlags_Highlight); - if (highlighted || selected) + if (hovered || selected) { - // Between 1.91.0 and 1.91.4 we made selected Selectable use an arbitrary lerp between _Header and _HeaderHovered. Removed that now. (#8106) - ImU32 col = GetColorU32((held && highlighted) ? ImGuiCol_HeaderActive : highlighted ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + // FIXME-MULTISELECT: Styling: Color for 'selected' elements? ImGuiCol_HeaderSelected + ImU32 col; + if (selected && !hovered) + col = GetColorU32(ImLerp(GetStyleColorVec4(ImGuiCol_Header), GetStyleColorVec4(ImGuiCol_HeaderHovered), 0.5f)); + else + col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); RenderFrame(bb.Min, bb.Max, col, false, 0.0f); } if (g.NavId == id) { - ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding; + ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_Compact | ImGuiNavHighlightFlags_NoRounding; if (is_multi_select) - nav_render_cursor_flags |= ImGuiNavRenderCursorFlags_AlwaysDraw; // Always show the nav rectangle - RenderNavCursor(bb, id, nav_render_cursor_flags); + nav_highlight_flags |= ImGuiNavHighlightFlags_AlwaysDraw; // Always show the nav rectangle + RenderNavHighlight(bb, id, nav_highlight_flags); } } @@ -7093,12 +6913,11 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl PopColumnsBackground(); } - // Text stays at the submission position. Alignment/clipping extents ignore SpanAllColumns. if (is_visible) - RenderTextClipped(pos, ImVec2(window->WorkRect.Max.x, pos.y + size.y), label, NULL, &label_size, style.SelectableTextAlign, &bb); + RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb); // Automatically close popups - if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups)) + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.InFlags & ImGuiItemFlags_AutoClosePopups)) CloseCurrentPopup(); if (disabled_item && !disabled_global) @@ -7242,7 +7061,7 @@ static int ImStrimatchlen(const char* s1, const char* s1_end, const char* s2) // When SingleCharMode is set: // - it is better to NOT display a tooltip of other on-screen display indicator. // - the index of the currently focused item is required. -// if your SetNextItemSelectionUserData() values are indices, you can obtain it from ImGuiMultiSelectIO::NavIdItem, otherwise from g.NavLastValidSelectionUserData. +// if your SetNextItemSelectionData() values are indices, you can obtain it from ImGuiMultiSelectIO::NavIdItem, otherwise from g.NavLastValidSelectionUserData. int ImGui::TypingSelectFindMatch(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data, int nav_item_idx) { if (req == NULL || req->SelectRequest == false) // Support NULL parameter so both calls can be done from same spot. @@ -7253,7 +7072,7 @@ int ImGui::TypingSelectFindMatch(ImGuiTypingSelectRequest* req, int items_count, else idx = TypingSelectFindBestLeadingMatch(req, items_count, get_item_name_func, user_data); if (idx != -1) - SetNavCursorVisibleAfterMove(); + NavRestoreHighlightAfterMove(); return idx; } @@ -7334,7 +7153,6 @@ static void BoxSelectPreStartDrag(ImGuiID id, ImGuiSelectionUserData clicked_ite bs->ID = id; bs->IsStarting = true; // Consider starting box-select. bs->IsStartedFromVoid = (clicked_item == ImGuiSelectionUserData_Invalid); - bs->IsStartedSetNavIdOnce = bs->IsStartedFromVoid; bs->KeyMods = g.IO.KeyMods; bs->StartPosRel = bs->EndPosRel = ImGui::WindowPosAbsToRel(g.CurrentWindow, g.IO.MousePos); bs->ScrollAccum = ImVec2(0.0f, 0.0f); @@ -7393,7 +7211,7 @@ static void BoxSelectScrollWithMouseDrag(ImGuiBoxSelectState* bs, ImGuiWindow* w } } -bool ImGui::BeginBoxSelect(const ImRect& scope_rect, ImGuiWindow* window, ImGuiID box_select_id, ImGuiMultiSelectFlags ms_flags) +bool ImGui::BeginBoxSelect(ImGuiWindow* window, ImGuiID box_select_id, ImGuiMultiSelectFlags ms_flags) { ImGuiContext& g = *GImGui; ImGuiBoxSelectState* bs = &g.BoxSelectState; @@ -7413,10 +7231,11 @@ bool ImGui::BeginBoxSelect(const ImRect& scope_rect, ImGuiWindow* window, ImGuiI // Current frame absolute prev/current rectangles are used to toggle selection. // They are derived from positions relative to scrolling space. + const ImRect scope_rect = window->InnerClipRect; ImVec2 start_pos_abs = WindowPosRelToAbs(window, bs->StartPosRel); ImVec2 prev_end_pos_abs = WindowPosRelToAbs(window, bs->EndPosRel); // Clamped already ImVec2 curr_end_pos_abs = g.IO.MousePos; - if (ms_flags & ImGuiMultiSelectFlags_ScopeWindow) // Box-select scrolling only happens with ScopeWindow + if (ms_flags & ImGuiMultiSelectFlags_ScopeWindow) // Box-select scrolling only happens with ScopeWindow curr_end_pos_abs = ImClamp(curr_end_pos_abs, scope_rect.Min, scope_rect.Max); bs->BoxSelectRectPrev.Min = ImMin(start_pos_abs, prev_end_pos_abs); bs->BoxSelectRectPrev.Max = ImMax(start_pos_abs, prev_end_pos_abs); @@ -7452,7 +7271,7 @@ void ImGui::EndBoxSelect(const ImRect& scope_rect, ImGuiMultiSelectFlags ms_flag ImRect box_select_r = bs->BoxSelectRectCurr; box_select_r.ClipWith(scope_rect); window->DrawList->AddRectFilled(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_SeparatorHovered, 0.30f)); // FIXME-MULTISELECT: Styling - window->DrawList->AddRect(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_NavCursor)); // FIXME-MULTISELECT: Styling + window->DrawList->AddRect(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_NavHighlight)); // FIXME-MULTISELECT: Styling // Scroll const bool enable_scroll = (ms_flags & ImGuiMultiSelectFlags_ScopeWindow) && (ms_flags & ImGuiMultiSelectFlags_BoxSelectNoScroll) == 0; @@ -7470,7 +7289,6 @@ void ImGui::EndBoxSelect(const ImRect& scope_rect, ImGuiMultiSelectFlags ms_flag // [SECTION] Widgets: Multi-Select support //------------------------------------------------------------------------- // - DebugLogMultiSelectRequests() [Internal] -// - CalcScopeRect() [Internal] // - BeginMultiSelect() // - EndMultiSelect() // - SetNextItemSelectionUserData() @@ -7482,7 +7300,6 @@ void ImGui::EndBoxSelect(const ImRect& scope_rect, ImGuiMultiSelectFlags ms_flag static void DebugLogMultiSelectRequests(const char* function, const ImGuiMultiSelectIO* io) { ImGuiContext& g = *GImGui; - IM_UNUSED(function); for (const ImGuiSelectionRequest& req : io->Requests) { if (req.Type == ImGuiSelectionRequestType_SetAll) IMGUI_DEBUG_LOG_SELECTION("[selection] %s: Request: SetAll %d (= %s)\n", function, req.Selected, req.Selected ? "SelectAll" : "Clear"); @@ -7490,27 +7307,6 @@ static void DebugLogMultiSelectRequests(const char* function, const ImGuiMultiSe } } -static ImRect CalcScopeRect(ImGuiMultiSelectTempData* ms, ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - if (ms->Flags & ImGuiMultiSelectFlags_ScopeRect) - { - // Warning: this depends on CursorMaxPos so it means to be called by EndMultiSelect() only - return ImRect(ms->ScopeRectMin, ImMax(window->DC.CursorMaxPos, ms->ScopeRectMin)); - } - else - { - // When a table, pull HostClipRect, which allows us to predict ClipRect before first row/layout is performed. (#7970) - ImRect scope_rect = window->InnerClipRect; - if (g.CurrentTable != NULL) - scope_rect = g.CurrentTable->HostClipRect; - - // Add inner table decoration (#7821) // FIXME: Why not baking in InnerClipRect? - scope_rect.Min = ImMin(scope_rect.Min + ImVec2(window->DecoInnerSizeX1, window->DecoInnerSizeY1), scope_rect.Max); - return scope_rect; - } -} - // Return ImGuiMultiSelectIO structure. // Lifetime: don't hold on ImGuiMultiSelectIO* pointers over multiple frames or past any subsequent call to BeginMultiSelect() or EndMultiSelect(). // Passing 'selection_size' and 'items_count' parameters is currently optional. @@ -7536,12 +7332,6 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel if (flags & ImGuiMultiSelectFlags_BoxSelect2d) flags &= ~ImGuiMultiSelectFlags_BoxSelect1d; - // FIXME: Workaround to the fact we override CursorMaxPos, meaning size measurement are lost. (#8250) - // They should perhaps be stacked properly? - if (ImGuiTable* table = g.CurrentTable) - if (table->CurrentColumn != -1) - TableEndCell(table); // This is currently safe to call multiple time. If that properly is lost we can extract the "save measurement" part of it. - // FIXME: BeginFocusScope() const ImGuiID id = window->IDStack.back(); ms->Clear(); @@ -7599,7 +7389,8 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel if (flags & (ImGuiMultiSelectFlags_BoxSelect1d | ImGuiMultiSelectFlags_BoxSelect2d)) { ms->BoxSelectId = GetID("##BoxSelect"); - if (BeginBoxSelect(CalcScopeRect(ms, window), window, ms->BoxSelectId, flags)) + ms->BoxSelectLastitem = ImGuiSelectionUserData_Invalid; + if (BeginBoxSelect(window, ms->BoxSelectId, flags)) request_clear |= bs->RequestClear; } @@ -7627,12 +7418,12 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel if (request_clear || request_select_all) { - MultiSelectAddSetAll(ms, request_select_all); + ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, request_select_all, 0, ImGuiSelectionUserData_Invalid, ImGuiSelectionUserData_Invalid }; if (!request_select_all) storage->LastSelectionSize = 0; + ms->IO.Requests.push_back(req); } ms->LoopRequestSetAll = request_select_all ? 1 : request_clear ? 0 : -1; - ms->LastSubmittedItem = ImGuiSelectionUserData_Invalid; if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection) DebugLogMultiSelectRequests("BeginMultiSelect", &ms->IO); @@ -7648,11 +7439,11 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() ImGuiMultiSelectTempData* ms = g.CurrentMultiSelect; ImGuiMultiSelectState* storage = ms->Storage; ImGuiWindow* window = g.CurrentWindow; - IM_ASSERT_USER_ERROR(ms->FocusScopeId == g.CurrentFocusScopeId, "EndMultiSelect() FocusScope mismatch!"); + IM_ASSERT(ms->FocusScopeId == g.CurrentFocusScopeId); IM_ASSERT(g.CurrentMultiSelect != NULL && storage->Window == g.CurrentWindow); IM_ASSERT(g.MultiSelectTempDataStacked > 0 && &g.MultiSelectTempData[g.MultiSelectTempDataStacked - 1] == g.CurrentMultiSelect); - ImRect scope_rect = CalcScopeRect(ms, window); + const ImRect scope_rect = (ms->Flags & ImGuiMultiSelectFlags_ScopeRect) ? ImRect(ms->ScopeRectMin, ImMax(window->DC.CursorMaxPos, ms->ScopeRectMin)) : window->InnerClipRect; if (ms->IsFocused) { // We currently don't allow user code to modify RangeSrcItem by writing to BeginIO's version, but that would be an easy change here. @@ -7697,7 +7488,11 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() if (ms->Flags & ImGuiMultiSelectFlags_ClearOnClickVoid) if (IsMouseReleased(0) && IsMouseDragPastThreshold(0) == false && g.IO.KeyMods == ImGuiMod_None) - MultiSelectAddSetAll(ms, false); + { + ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, false, 0, ImGuiSelectionUserData_Invalid, ImGuiSelectionUserData_Invalid }; + ms->IO.Requests.resize(0); + ms->IO.Requests.push_back(req); + } } // Courtesy nav wrapping helper flag @@ -7884,18 +7679,24 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) const bool rect_overlap_prev = bs->BoxSelectRectPrev.Overlaps(g.LastItemData.Rect); if ((rect_overlap_curr && !rect_overlap_prev && !selected) || (rect_overlap_prev && !rect_overlap_curr)) { - if (storage->LastSelectionSize <= 0 && bs->IsStartedSetNavIdOnce) + if (storage->LastSelectionSize <= 0 && bs->IsStartedFromVoid) { pressed = true; // First item act as a pressed: code below will emit selection request and set NavId (whatever we emit here will be overridden anyway) - bs->IsStartedSetNavIdOnce = false; } else { selected = !selected; - MultiSelectAddSetRange(ms, selected, +1, item_data, item_data); + ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange, selected, +1, item_data, item_data }; + // Merge continuous ranges (unless NoRangeSelect is set) + ImGuiSelectionRequest* prev = ms->IO.Requests.Size > 0 ? &ms->IO.Requests.Data[ms->IO.Requests.Size - 1] : NULL; + if (prev && prev->Type == ImGuiSelectionRequestType_SetRange && prev->RangeLastItem == ms->BoxSelectLastitem && prev->Selected == selected && (ms->Flags & ImGuiMultiSelectFlags_NoRangeSelect) == 0) + prev->RangeLastItem = item_data; // Merge span into same request + else + ms->IO.Requests.push_back(req); } storage->LastSelectionSize = ImMax(storage->LastSelectionSize + 1, 1); } + ms->BoxSelectLastitem = item_data; } // Right-click handling. @@ -7953,7 +7754,11 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) else if ((input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Gamepad) && is_shift && !is_ctrl) request_clear = true; // With is_shift==false the RequestClear was done in BeginIO, not necessary to do again. if (request_clear) - MultiSelectAddSetAll(ms, false); + { + ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, false, 0, ImGuiSelectionUserData_Invalid, ImGuiSelectionUserData_Invalid }; + ms->IO.Requests.resize(0); + ms->IO.Requests.push_back(req); + } } int range_direction; @@ -7991,7 +7796,9 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) range_selected = selected; range_direction = +1; } - MultiSelectAddSetRange(ms, range_selected, range_direction, storage->RangeSrcItem, item_data); + ImGuiSelectionUserData range_dst_item = item_data; + ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange, range_selected, (ImS8)range_direction, (range_direction > 0) ? storage->RangeSrcItem : range_dst_item, (range_direction > 0) ? range_dst_item : storage->RangeSrcItem }; + ms->IO.Requests.push_back(req); } // Update/store the selection state of the Source item (used by CTRL+SHIFT, when Source is unselected we perform a range unselect) @@ -8006,36 +7813,11 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) } if (storage->NavIdItem == item_data) ms->NavIdPassedBy = true; - ms->LastSubmittedItem = item_data; *p_selected = selected; *p_pressed = pressed; } -void ImGui::MultiSelectAddSetAll(ImGuiMultiSelectTempData* ms, bool selected) -{ - ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetAll, selected, 0, ImGuiSelectionUserData_Invalid, ImGuiSelectionUserData_Invalid }; - ms->IO.Requests.resize(0); // Can always clear previous requests - ms->IO.Requests.push_back(req); // Add new request -} - -void ImGui::MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, int range_dir, ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item) -{ - // Merge contiguous spans into same request (unless NoRangeSelect is set which guarantees single-item ranges) - if (ms->IO.Requests.Size > 0 && first_item == last_item && (ms->Flags & ImGuiMultiSelectFlags_NoRangeSelect) == 0) - { - ImGuiSelectionRequest* prev = &ms->IO.Requests.Data[ms->IO.Requests.Size - 1]; - if (prev->Type == ImGuiSelectionRequestType_SetRange && prev->RangeLastItem == ms->LastSubmittedItem && prev->Selected == selected) - { - prev->RangeLastItem = last_item; - return; - } - } - - ImGuiSelectionRequest req = { ImGuiSelectionRequestType_SetRange, selected, (ImS8)range_dir, (range_dir > 0) ? first_item : last_item, (range_dir > 0) ? last_item : first_item }; - ms->IO.Requests.push_back(req); // Add new request -} - void ImGui::DebugNodeMultiSelectState(ImGuiMultiSelectState* storage) { #ifndef IMGUI_DISABLE_DEBUG_TOOLS @@ -8255,10 +8037,8 @@ void ImGuiSelectionExternalStorage::ApplyRequests(ImGuiMultiSelectIO* ms_io) //------------------------------------------------------------------------- // This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. -// This handle some subtleties with capturing info from the label. -// If you don't need a label you can pretty much directly use ImGui::BeginChild() with ImGuiChildFlags_FrameStyle. // Tip: To have a list filling the entire window width, use size.x = -FLT_MIN and pass an non-visible label e.g. "##empty" -// Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.5f * item_height). +// Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.25 * item_height). bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg) { ImGuiContext& g = *GImGui; @@ -8394,10 +8174,9 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0)); ItemSize(total_bb, style.FramePadding.y); - if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_NoNav)) + if (!ItemAdd(total_bb, 0, &frame_bb)) return -1; - bool hovered; - ButtonBehavior(frame_bb, id, &hovered, NULL); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); // Determine scale from values if not specified if (scale_min == FLT_MAX || scale_max == FLT_MAX) @@ -8637,14 +8416,12 @@ bool ImGui::BeginMenuBar() IM_ASSERT(!window->DC.MenuBarAppending); BeginGroup(); // Backup position on layer 0 // FIXME: Misleading to use a group for that backup/restore - PushID("##MenuBar"); + PushID("##menubar"); // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. - const float border_top = ImMax(IM_ROUND(window->WindowBorderSize * 0.5f - window->TitleBarHeight), 0.0f); - const float border_half = IM_ROUND(window->WindowBorderSize * 0.5f); ImRect bar_rect = window->MenuBarRect(); - ImRect clip_rect(ImFloor(bar_rect.Min.x + border_half), ImFloor(bar_rect.Min.y + border_top), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, border_half))), ImFloor(bar_rect.Max.y)); + ImRect clip_rect(ImFloor(bar_rect.Min.x + window->WindowBorderSize), ImFloor(bar_rect.Min.y + window->WindowBorderSize), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize))), ImFloor(bar_rect.Max.y)); clip_rect.ClipWith(window->OuterRectClipped); PushClipRect(clip_rect.Min, clip_rect.Max, false); @@ -8665,10 +8442,6 @@ void ImGui::EndMenuBar() return; ImGuiContext& g = *GImGui; - IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" - IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); - IM_ASSERT(window->DC.MenuBarAppending); - // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings. if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) { @@ -8684,17 +8457,15 @@ void ImGui::EndMenuBar() IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer)); // Sanity check (FIXME: Seems unnecessary) FocusWindow(window); SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]); - // FIXME-NAV: How to deal with this when not using g.IO.ConfigNavCursorVisibleAuto? - if (g.NavCursorVisible) - { - g.NavCursorVisible = false; // Hide nav cursor for the current frame so we don't see the intermediary selection. Will be set again - g.NavCursorHideFrames = 2; - } - g.NavHighlightItemUnderNav = g.NavMousePosDirty = true; + g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection. + g.NavDisableMouseHover = g.NavMousePosDirty = true; NavMoveRequestForward(g.NavMoveDir, g.NavMoveClipDir, g.NavMoveFlags, g.NavMoveScrollFlags); // Repeat } } + IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" + IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); + IM_ASSERT(window->DC.MenuBarAppending); PopClipRect(); PopID(); window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->Pos.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. @@ -8736,9 +8507,9 @@ bool ImGui::BeginViewportSideBar(const char* name, ImGuiViewport* viewport_p, Im // Report our size into work area (for next frame) using actual window size if (dir == ImGuiDir_Up || dir == ImGuiDir_Left) - viewport->BuildWorkInsetMin[axis] += axis_size; + viewport->BuildWorkOffsetMin[axis] += axis_size; else if (dir == ImGuiDir_Down || dir == ImGuiDir_Right) - viewport->BuildWorkInsetMax[axis] += axis_size; + viewport->BuildWorkOffsetMax[axis] -= axis_size; } window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDocking; @@ -8767,33 +8538,22 @@ bool ImGui::BeginMainMenuBar() float height = GetFrameHeight(); bool is_open = BeginViewportSideBar("##MainMenuBar", viewport, ImGuiDir_Up, height, window_flags); g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); - if (!is_open) - { - End(); - return false; - } - // Temporarily disable _NoSavedSettings, in the off-chance that tables or child windows submitted within the menu-bar may want to use settings. (#8356) - g.CurrentWindow->Flags &= ~ImGuiWindowFlags_NoSavedSettings; - BeginMenuBar(); + if (is_open) + BeginMenuBar(); + else + End(); return is_open; } void ImGui::EndMainMenuBar() { - ImGuiContext& g = *GImGui; - if (!g.CurrentWindow->DC.MenuBarAppending) - { - IM_ASSERT_USER_ERROR(0, "Calling EndMainMenuBar() not from a menu-bar!"); // Not technically testing that it is the main menu bar - return; - } - EndMenuBar(); - g.CurrentWindow->Flags |= ImGuiWindowFlags_NoSavedSettings; // Restore _NoSavedSettings (#8356) // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window // FIXME: With this strategy we won't be able to restore a NULL focus. - if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest && g.ActiveId == 0) + ImGuiContext& g = *GImGui; + if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest) FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal | ImGuiFocusRequestFlags_RestoreFocusedChild); End(); @@ -8882,11 +8642,10 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() popup_pos = ImVec2(pos.x - 1.0f - IM_TRUNC(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight); window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f); - PushStyleVarX(ImGuiStyleVar_ItemSpacing, style.ItemSpacing.x * 2.0f); + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); float w = label_size.x; ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, label_size.y)); - LogSetNextTextDecoration("[", "]"); RenderText(text_pos, label); PopStyleVar(); window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). @@ -8903,7 +8662,6 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); - LogSetNextTextDecoration("", ">"); RenderText(text_pos, label); if (icon_w > 0.0f) RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); @@ -8912,7 +8670,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) if (!enabled) EndDisabled(); - const bool hovered = (g.HoveredId == id) && enabled && !g.NavHighlightItemUnderNav; + const bool hovered = (g.HoveredId == id) && enabled && !g.NavDisableMouseHover; if (menuset_is_open) PopItemFlag(); @@ -8947,7 +8705,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) // The 'HovereWindow == window' check creates an inconsistency (e.g. moving away from menu slowly tends to hit same window, whereas moving away fast does not) // But we also need to not close the top-menu menu when moving over void. Perhaps we should extend the triangle check to a larger polygon. // (Remember to test this on BeginPopup("A")->BeginMenu("B") sequence which behaves slightly differently as B isn't a Child of A and hovering isn't shared.) - if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu && !g.NavHighlightItemUnderNav && g.ActiveId == 0) + if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu && !g.NavDisableMouseHover && g.ActiveId == 0) want_close = true; // Open @@ -8962,7 +8720,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) { want_open = want_open_nav_init = true; NavMoveRequestCancel(); - SetNavCursorVisibleAfterMove(); + NavRestoreHighlightAfterMove(); } } else @@ -9091,7 +8849,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut float w = label_size.x; window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f); ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); - PushStyleVarX(ImGuiStyleVar_ItemSpacing, style.ItemSpacing.x * 2.0f); + PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y)); pressed = Selectable("", selected, selectable_flags, ImVec2(w, 0.0f)); PopStyleVar(); if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) @@ -9117,7 +8875,6 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut if (shortcut_w > 0.0f) { PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); - LogSetNextTextDecoration("(", ")"); RenderText(pos + ImVec2(offsets->OffsetShortcut + stretch_w, 0.0f), shortcut, NULL, false); PopStyleColor(); } @@ -9274,7 +9031,6 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG // Add to stack g.CurrentTabBarStack.push_back(GetTabBarRefFromTabBar(tab_bar)); g.CurrentTabBar = tab_bar; - tab_bar->Window = window; // Append with multiple BeginTabBar()/EndTabBar() pairs. tab_bar->BackupCursorPos = window->DC.CursorPos; @@ -9789,13 +9545,6 @@ void ImGui::TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) tab_bar->NextSelectedTabId = tab->ID; } -void ImGui::TabBarQueueFocus(ImGuiTabBar* tab_bar, const char* tab_name) -{ - IM_ASSERT((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0); // Only supported for manual/explicit tab bars - ImGuiID tab_id = TabBarCalcTabID(tab_bar, tab_name, NULL); - tab_bar->NextSelectedTabId = tab_id; -} - void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset) { IM_ASSERT(offset != 0); @@ -9888,19 +9637,17 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar) PushStyleColor(ImGuiCol_Text, arrow_col); PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); const float backup_repeat_delay = g.IO.KeyRepeatDelay; const float backup_repeat_rate = g.IO.KeyRepeatRate; g.IO.KeyRepeatDelay = 0.250f; g.IO.KeyRepeatRate = 0.200f; float x = ImMax(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.x - scrolling_buttons_width); window->DC.CursorPos = ImVec2(x, tab_bar->BarRect.Min.y); - if (ArrowButtonEx("##<", ImGuiDir_Left, arrow_button_size, ImGuiButtonFlags_PressedOnClick)) + if (ArrowButtonEx("##<", ImGuiDir_Left, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) select_dir = -1; window->DC.CursorPos = ImVec2(x + arrow_button_size.x, tab_bar->BarRect.Min.y); - if (ArrowButtonEx("##>", ImGuiDir_Right, arrow_button_size, ImGuiButtonFlags_PressedOnClick)) + if (ArrowButtonEx("##>", ImGuiDir_Right, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat)) select_dir = +1; - PopItemFlag(); PopStyleColor(2); g.IO.KeyRepeatRate = backup_repeat_rate; g.IO.KeyRepeatDelay = backup_repeat_delay; @@ -9998,7 +9745,7 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f IM_ASSERT_USER_ERROR(tab_bar, "Needs to be called between BeginTabBar() and EndTabBar()!"); return false; } - IM_ASSERT((flags & ImGuiTabItemFlags_Button) == 0); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead! + IM_ASSERT((flags & ImGuiTabItemFlags_Button) == 0); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead! bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL); if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) @@ -10044,23 +9791,6 @@ bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags) return TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder, NULL); } -void ImGui::TabItemSpacing(const char* str_id, ImGuiTabItemFlags flags, float width) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - if (window->SkipItems) - return; - - ImGuiTabBar* tab_bar = g.CurrentTabBar; - if (tab_bar == NULL) - { - IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); - return; - } - SetNextItemWidth(width); - TabItemEx(tab_bar, str_id, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder | ImGuiTabItemFlags_Invisible, NULL); -} - bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window) { // Layout whole tab bar if not already done @@ -10111,7 +9841,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, // Calculate tab contents size ImVec2 size = TabItemCalcSize(label, (p_open != NULL) || (flags & ImGuiTabItemFlags_UnsavedDocument)); tab->RequestedWidth = -1.0f; - if (g.NextItemData.HasFlags & ImGuiNextItemDataFlags_HasWidth) + if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth) size.x = tab->RequestedWidth = g.NextItemData.Width; if (tab_is_new) tab->Width = ImMax(1.0f, size.x); @@ -10208,11 +9938,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap); if (g.DragDropActive && !g.DragDropPayload.IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW)) // FIXME: May be an opt-in property of the payload to disable this button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; - bool hovered, held, pressed; - if (flags & ImGuiTabItemFlags_Invisible) - hovered = held = pressed = false; - else - pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + bool hovered, held; + bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); if (pressed && !is_tab_button) TabBarQueueFocus(tab_bar, tab); @@ -10297,71 +10024,57 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, #endif // Render tab shape - const bool is_visible = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) && !(flags & ImGuiTabItemFlags_Invisible); - if (is_visible) + ImDrawList* display_draw_list = window->DrawList; + const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabDimmed)); + TabItemBackground(display_draw_list, bb, flags, tab_col); + if (tab_contents_visible && (tab_bar->Flags & ImGuiTabBarFlags_DrawSelectedOverline)) { - ImDrawList* display_draw_list = window->DrawList; - const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabDimmed)); - TabItemBackground(display_draw_list, bb, flags, tab_col); - if (tab_contents_visible && (tab_bar->Flags & ImGuiTabBarFlags_DrawSelectedOverline) && style.TabBarOverlineSize > 0.0f) - { - // Might be moved to TabItemBackground() ? - ImVec2 tl = bb.GetTL() + ImVec2(0, 1.0f * g.CurrentDpiScale); - ImVec2 tr = bb.GetTR() + ImVec2(0, 1.0f * g.CurrentDpiScale); - ImU32 overline_col = GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline); - if (style.TabRounding > 0.0f) - { - float rounding = style.TabRounding; - display_draw_list->PathArcToFast(tl + ImVec2(+rounding, +rounding), rounding, 7, 9); - display_draw_list->PathArcToFast(tr + ImVec2(-rounding, +rounding), rounding, 9, 11); - display_draw_list->PathStroke(overline_col, 0, style.TabBarOverlineSize); - } - else - { - display_draw_list->AddLine(tl - ImVec2(0.5f, 0.5f), tr - ImVec2(0.5f, 0.5f), overline_col, style.TabBarOverlineSize); - } - } - RenderNavCursor(bb, id); - - // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. - const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); - if (tab_bar->SelectedTabId != tab->ID && hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button) - TabBarQueueFocus(tab_bar, tab); - - if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) - flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; - - // Render tab label, process close button - const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, docked_window ? docked_window->ID : id) : 0; - bool just_closed; - bool text_clipped; - TabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped); - if (just_closed && p_open != NULL) - { - *p_open = false; - TabBarCloseTab(tab_bar, tab); - } - - // Forward Hovered state so IsItemHovered() after Begin() can work (even though we are technically hovering our parent) - // That state is copied to window->DockTabItemStatusFlags by our caller. - if (docked_window && (hovered || g.HoveredId == close_button_id)) - g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; - - // Tooltip - // (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok) - // (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores) - // FIXME: This is a mess. - // FIXME: We may want disabled tab to still display the tooltip? - if (text_clipped && g.HoveredId == id && !held) - if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip)) - SetItemTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); + float x_offset = IM_TRUNC(0.4f * style.TabRounding); + if (x_offset < 2.0f * g.CurrentDpiScale) + x_offset = 0.0f; + float y_offset = 1.0f * g.CurrentDpiScale; + display_draw_list->AddLine(bb.GetTL() + ImVec2(x_offset, y_offset), bb.GetTR() + ImVec2(-x_offset, y_offset), GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline), 2.0f * g.CurrentDpiScale); } + RenderNavHighlight(bb, id); + + // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. + const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); + if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button) + TabBarQueueFocus(tab_bar, tab); + + if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) + flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; + + // Render tab label, process close button + const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, docked_window ? docked_window->ID : id) : 0; + bool just_closed; + bool text_clipped; + TabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped); + if (just_closed && p_open != NULL) + { + *p_open = false; + TabBarCloseTab(tab_bar, tab); + } + + // Forward Hovered state so IsItemHovered() after Begin() can work (even though we are technically hovering our parent) + // That state is copied to window->DockTabItemStatusFlags by our caller. + if (docked_window && (hovered || g.HoveredId == close_button_id)) + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; // Restore main window position so user can draw there if (want_clip_rect) PopClipRect(); window->DC.CursorPos = backup_main_cursor_pos; + // Tooltip + // (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok) + // (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores) + // FIXME: This is a mess. + // FIXME: We may want disabled tab to still display the tooltip? + if (text_clipped && g.HoveredId == id && !held) + if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip)) + SetItemTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); + IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected if (is_tab_button) return pressed; @@ -10513,7 +10226,6 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, text_ellipsis_clip_bb.Max.x -= unsaved_marker_visible ? (button_sz * 0.80f) : 0.0f; ellipsis_max_x = text_pixel_clip_bb.Max.x; } - LogSetNextTextDecoration("/", "\\"); RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb.Max.x, ellipsis_max_x, label, NULL, &label_size); #if 0 diff --git a/3rdparty/imgui/imstb_textedit.h b/3rdparty/imgui/imstb_textedit.h index b7a761c..783054a 100644 --- a/3rdparty/imgui/imstb_textedit.h +++ b/3rdparty/imgui/imstb_textedit.h @@ -3,8 +3,6 @@ // Those changes would need to be pushed into nothings/stb: // - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321) // - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783) -// - Added name to struct or it may be forward declared in our code. -// - Added UTF-8 support (see https://github.com/nothings/stb/issues/188 + https://github.com/ocornut/imgui/pull/7925) // Grep for [DEAR IMGUI] to find the changes. // - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_* @@ -211,7 +209,6 @@ // int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) // int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len) // void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key) -// void stb_textedit_text(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int text_len) // // Each of these functions potentially updates the string and updates the // state. @@ -246,12 +243,7 @@ // various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit // set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is // clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to -// anything other type you want before including. -// if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are -// transformed into text and stb_textedit_text() is automatically called. -// -// text: [DEAR IMGUI] added 2024-09 -// call this to text inputs sent to the textfield. +// anything other type you wante before including. // // // When rendering, you can read the cursor position and selection state from @@ -326,7 +318,7 @@ typedef struct int undo_char_point, redo_char_point; } StbUndoState; -typedef struct STB_TexteditState +typedef struct { ///////////////////// // @@ -446,13 +438,13 @@ static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y) if (x < r.x1) { // search characters in row for one that straddles 'x' prev_x = r.x0; - for (k=0; k < r.num_chars; k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k) - i) { + for (k=0; k < r.num_chars; ++k) { float w = STB_TEXTEDIT_GETWIDTH(str, i, k); if (x < prev_x+w) { if (x < prev_x+w/2) return k+i; else - return IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k); + return k+i+1; } prev_x += w; } @@ -571,7 +563,7 @@ static void stb_textedit_find_charpos(StbFindState *find, IMSTB_TEXTEDIT_STRING // now scan to find xpos find->x = r.x0; - for (i=0; first+i < n; i = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, first + i) - first) + for (i=0; first+i < n; ++i) find->x += STB_TEXTEDIT_GETWIDTH(str, first, i); } @@ -648,17 +640,6 @@ static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str, STB_TexteditSt } } -// [DEAR IMGUI] -// Functions must be implemented for UTF8 support -// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit. -// There is not necessarily a '[DEAR IMGUI]' at the usage sites. -#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX -#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx) (idx - 1) -#endif -#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX -#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx) (idx + 1) -#endif - #ifdef STB_TEXTEDIT_IS_SPACE static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx ) { @@ -739,44 +720,36 @@ static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditS #define STB_TEXTEDIT_KEYTYPE int #endif -// [DEAR IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility. -static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len) -{ - // can't add newline in single-line mode - if (text[0] == '\n' && state->single_line) - return; - - if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { - stb_text_makeundo_replace(str, state, state->cursor, 1, 1); - STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); - if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) { - state->cursor += text_len; - state->has_preferred_x = 0; - } - } - else { - stb_textedit_delete_selection(str, state); // implicitly clamps - if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) { - stb_text_makeundo_insert(state, state->cursor, text_len); - state->cursor += text_len; - state->has_preferred_x = 0; - } - } -} - // API key: process a keyboard input static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key) { retry: switch (key) { default: { -#ifdef STB_TEXTEDIT_KEYTOTEXT int c = STB_TEXTEDIT_KEYTOTEXT(key); if (c > 0) { - IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c; - stb_textedit_text(str, state, &ch, 1); + IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE) c; + + // can't add newline in single-line mode + if (c == '\n' && state->single_line) + break; + + if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) { + stb_text_makeundo_replace(str, state, state->cursor, 1, 1); + STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1); + if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { + ++state->cursor; + state->has_preferred_x = 0; + } + } else { + stb_textedit_delete_selection(str,state); // implicitly clamps + if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { + stb_text_makeundo_insert(state, state->cursor, 1); + ++state->cursor; + state->has_preferred_x = 0; + } + } } -#endif break; } @@ -802,7 +775,7 @@ retry: stb_textedit_move_to_first(state); else if (state->cursor > 0) - state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor); + --state->cursor; state->has_preferred_x = 0; break; @@ -811,7 +784,7 @@ retry: if (STB_TEXT_HAS_SELECTION(state)) stb_textedit_move_to_last(str, state); else - state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor); + ++state->cursor; stb_textedit_clamp(str, state); state->has_preferred_x = 0; break; @@ -821,7 +794,7 @@ retry: stb_textedit_prep_selection_at_cursor(state); // move selection left if (state->select_end > 0) - state->select_end = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->select_end); + --state->select_end; state->cursor = state->select_end; state->has_preferred_x = 0; break; @@ -871,7 +844,7 @@ retry: case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT: stb_textedit_prep_selection_at_cursor(state); // move selection right - state->select_end = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->select_end); + ++state->select_end; stb_textedit_clamp(str, state); state->cursor = state->select_end; state->has_preferred_x = 0; @@ -927,7 +900,7 @@ retry: x += dx; if (x > goal_x) break; - state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor); + ++state->cursor; } stb_textedit_clamp(str, state); @@ -989,7 +962,7 @@ retry: x += dx; if (x > goal_x) break; - state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor); + ++state->cursor; } stb_textedit_clamp(str, state); @@ -1017,7 +990,7 @@ retry: else { int n = STB_TEXTEDIT_STRINGLEN(str); if (state->cursor < n) - stb_textedit_delete(str, state, state->cursor, IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor) - state->cursor); + stb_textedit_delete(str, state, state->cursor, 1); } state->has_preferred_x = 0; break; @@ -1029,9 +1002,8 @@ retry: else { stb_textedit_clamp(str, state); if (state->cursor > 0) { - int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor); - stb_textedit_delete(str, state, prev, state->cursor - prev); - state->cursor = prev; + stb_textedit_delete(str, state, state->cursor-1, 1); + --state->cursor; } } state->has_preferred_x = 0; diff --git a/3rdparty/imgui/misc/cpp/imgui_stdlib.cpp b/3rdparty/imgui/misc/cpp/imgui_stdlib.cpp index c04d487..cf69aa8 100644 --- a/3rdparty/imgui/misc/cpp/imgui_stdlib.cpp +++ b/3rdparty/imgui/misc/cpp/imgui_stdlib.cpp @@ -8,7 +8,6 @@ // https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness #include "imgui.h" -#ifndef IMGUI_DISABLE #include "imgui_stdlib.h" // Clang warnings with -Weverything @@ -84,5 +83,3 @@ bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* #if defined(__clang__) #pragma clang diagnostic pop #endif - -#endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/misc/cpp/imgui_stdlib.h b/3rdparty/imgui/misc/cpp/imgui_stdlib.h index 697fc34..835a808 100644 --- a/3rdparty/imgui/misc/cpp/imgui_stdlib.h +++ b/3rdparty/imgui/misc/cpp/imgui_stdlib.h @@ -9,8 +9,6 @@ #pragma once -#ifndef IMGUI_DISABLE - #include namespace ImGui @@ -21,5 +19,3 @@ namespace ImGui IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr); IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr); } - -#endif // #ifndef IMGUI_DISABLE diff --git a/3rdparty/imgui/misc/fonts/binary_to_compressed_c.cpp b/3rdparty/imgui/misc/fonts/binary_to_compressed_c.cpp index b0a243a..f41d20f 100644 --- a/3rdparty/imgui/misc/fonts/binary_to_compressed_c.cpp +++ b/3rdparty/imgui/misc/fonts/binary_to_compressed_c.cpp @@ -2,11 +2,10 @@ // (binary_to_compressed_c.cpp) // Helper tool to turn a file into a C array, if you want to embed font data in your source code. -// The data is first compressed with stb_compress() to reduce source code size. -// Then stored in a C array: -// - Base85: ~5 bytes of source code for 4 bytes of input data. 5 bytes stored in binary (suggested by @mmalex). -// - As int: ~11 bytes of source code for 4 bytes of input data. 4 bytes stored in binary. Endianness dependant, need swapping on big-endian CPU. -// - As char: ~12 bytes of source code for 4 bytes of input data. 4 bytes stored in binary. Not endianness dependant. +// The data is first compressed with stb_compress() to reduce source code size, +// then encoded in Base85 to fit in a string so we can fit roughly 4 bytes of compressed data into 5 bytes of source code (suggested by @mmalex) +// (If we used 32-bit constants it would require take 11 bytes of source code to encode 4 bytes, and be endianness dependent) +// Note that even with compression, the output array is likely to be bigger than the binary file.. // Load compressed TTF fonts with ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF() // Build with, e.g: @@ -16,12 +15,10 @@ // You can also find a precompiled Windows binary in the binary/demo package available from https://github.com/ocornut/imgui // Usage: -// binary_to_compressed_c.exe [-nocompress] [-nostatic] [-base85] +// binary_to_compressed_c.exe [-base85] [-nocompress] [-nostatic] // Usage example: // # binary_to_compressed_c.exe myfont.ttf MyFont > myfont.cpp // # binary_to_compressed_c.exe -base85 myfont.ttf MyFont > myfont.cpp -// Note: -// Base85 encoding will be obsoleted by future version of Dear ImGui! #define _CRT_SECURE_NO_WARNINGS #include @@ -34,36 +31,23 @@ typedef unsigned int stb_uint; typedef unsigned char stb_uchar; stb_uint stb_compress(stb_uchar* out, stb_uchar* in, stb_uint len); -enum SourceEncoding -{ - SourceEncoding_U8, // New default since 2024/11 - SourceEncoding_U32, - SourceEncoding_Base85, -}; - -static bool binary_to_compressed_c(const char* filename, const char* symbol, SourceEncoding source_encoding, bool use_compression, bool use_static); +static bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_base85_encoding, bool use_compression, bool use_static); int main(int argc, char** argv) { if (argc < 3) { - printf("Syntax: %s [-u8|-u32|-base85] [-nocompress] [-nostatic] \n", argv[0]); - printf("Source encoding types:\n"); - printf(" -u8 = ~12 bytes of source per 4 bytes of data. 4 bytes in binary.\n"); - printf(" -u32 = ~11 bytes of source per 4 bytes of data. 4 bytes in binary. Need endianness swapping on big-endian.\n"); - printf(" -base85 = ~5 bytes of source per 4 bytes of data. 5 bytes in binary. Need decoder.\n"); + printf("Syntax: %s [-base85] [-nocompress] [-nostatic] \n", argv[0]); return 0; } int argn = 1; + bool use_base85_encoding = false; bool use_compression = true; bool use_static = true; - SourceEncoding source_encoding = SourceEncoding_U8; // New default while (argn < (argc - 2) && argv[argn][0] == '-') { - if (strcmp(argv[argn], "-u8") == 0) { source_encoding = SourceEncoding_U8; argn++; } - else if (strcmp(argv[argn], "-u32") == 0) { source_encoding = SourceEncoding_U32; argn++; } - else if (strcmp(argv[argn], "-base85") == 0) { source_encoding = SourceEncoding_Base85; argn++; } + if (strcmp(argv[argn], "-base85") == 0) { use_base85_encoding = true; argn++; } else if (strcmp(argv[argn], "-nocompress") == 0) { use_compression = false; argn++; } else if (strcmp(argv[argn], "-nostatic") == 0) { use_static = false; argn++; } else @@ -73,7 +57,7 @@ int main(int argc, char** argv) } } - bool ret = binary_to_compressed_c(argv[argn], argv[argn + 1], source_encoding, use_compression, use_static); + bool ret = binary_to_compressed_c(argv[argn], argv[argn + 1], use_base85_encoding, use_compression, use_static); if (!ret) fprintf(stderr, "Error opening or reading file: '%s'\n", argv[argn]); return ret ? 0 : 1; @@ -85,7 +69,7 @@ char Encode85Byte(unsigned int x) return (char)((x >= '\\') ? x + 1 : x); } -bool binary_to_compressed_c(const char* filename, const char* symbol, SourceEncoding source_encoding, bool use_compression, bool use_static) +bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_base85_encoding, bool use_compression, bool use_static) { // Read file FILE* f = fopen(filename, "rb"); @@ -107,11 +91,11 @@ bool binary_to_compressed_c(const char* filename, const char* symbol, SourceEnco // Output as Base85 encoded FILE* out = stdout; fprintf(out, "// File: '%s' (%d bytes)\n", filename, (int)data_sz); + fprintf(out, "// Exported using binary_to_compressed_c.cpp\n"); const char* static_str = use_static ? "static " : ""; const char* compressed_str = use_compression ? "compressed_" : ""; - if (source_encoding == SourceEncoding_Base85) + if (use_base85_encoding) { - fprintf(out, "// Exported using binary_to_compressed_c.exe -base85 \"%s\" %s\n", filename, symbol); fprintf(out, "%sconst char %s_%sdata_base85[%d+1] =\n \"", static_str, symbol, compressed_str, (int)((compressed_sz + 3) / 4)*5); char prev_c = 0; for (int src_i = 0; src_i < compressed_sz; src_i += 4) @@ -129,35 +113,15 @@ bool binary_to_compressed_c(const char* filename, const char* symbol, SourceEnco } fprintf(out, "\";\n\n"); } - else if (source_encoding == SourceEncoding_U8) + else { - // As individual bytes, not subject to endianness issues. - fprintf(out, "// Exported using binary_to_compressed_c.exe -u8 \"%s\" %s\n", filename, symbol); - fprintf(out, "%sconst unsigned int %s_%ssize = %d;\n", static_str, symbol, compressed_str, (int)compressed_sz); - fprintf(out, "%sconst unsigned char %s_%sdata[%d] =\n{", static_str, symbol, compressed_str, (int)compressed_sz); - int column = 0; - for (int i = 0; i < compressed_sz; i++) - { - unsigned char d = *(unsigned char*)(compressed + i); - if (column == 0) - fprintf(out, "\n "); - column += fprintf(out, "%d,", d); - if (column >= 180) - column = 0; - } - fprintf(out, "\n};\n\n"); - } - else if (source_encoding == SourceEncoding_U32) - { - // As integers - fprintf(out, "// Exported using binary_to_compressed_c.exe -u32 \"%s\" %s\n", filename, symbol); fprintf(out, "%sconst unsigned int %s_%ssize = %d;\n", static_str, symbol, compressed_str, (int)compressed_sz); fprintf(out, "%sconst unsigned int %s_%sdata[%d/4] =\n{", static_str, symbol, compressed_str, (int)((compressed_sz + 3) / 4)*4); int column = 0; for (int i = 0; i < compressed_sz; i += 4) { unsigned int d = *(unsigned int*)(compressed + i); - if ((column++ % 14) == 0) + if ((column++ % 12) == 0) fprintf(out, "\n 0x%08x, ", d); else fprintf(out, "0x%08x, ", d); diff --git a/3rdparty/imgui/misc/freetype/README.md b/3rdparty/imgui/misc/freetype/README.md index 3955b08..275a538 100644 --- a/3rdparty/imgui/misc/freetype/README.md +++ b/3rdparty/imgui/misc/freetype/README.md @@ -38,25 +38,7 @@ You can use the `ImGuiFreeTypeBuilderFlags_LoadColor` flag to load certain color ### Using OpenType SVG fonts (SVGinOT) - *SVG in Open Type* is a standard by Adobe and Mozilla for color OpenType and Open Font Format fonts. It allows font creators to embed complete SVG files within a font enabling full color and even animations. -- Popular fonts such as [twemoji](https://github.com/13rac1/twemoji-color-font) and fonts made with [scfbuild](https://github.com/13rac1/scfbuild) is SVGinOT -- Two alternatives are possible to render SVG fonts: use "lunasvg" or "plutosvg". plutosvg will support some more fonts (e.g. NotoColorEmoji-Regular) and may load them faster. - -#### Using lunasvg -Requires: [lunasvg](https://github.com/sammycage/lunasvg) v2.3.2 and above -- Add `#define IMGUI_ENABLE_FREETYPE_LUNASVG` in your `imconfig.h`. -- Get latest lunasvg binaries or build yourself. Under Windows you may use vcpkg with: `vcpkg install lunasvg --triplet=x64-windows`. - -#### Using plutosvg (and plutovg) -- Add `#define IMGUI_ENABLE_FREETYPE_PLUTOSVG` in your `imconfig.h`. -- Compile and link with plutosvg *and* plutovg (which is required by plutosvg) - -_Compilation hints for plutovg_ -- Compile all source files in `plutovg/source/*.c` -- Add include directory: `plutovg/include` + `plutovg/stb` - -_Compilation hints for plutosvg_ -- Compile `plutosvg/source/plutosvg.c` -- Add include directory: `plutosvg/source` -- Add define: `PLUTOSVG_HAS_FREETYPE` -- Link with: plutovg, freetype - +- Popular fonts such as [twemoji](https://github.com/13rac1/twemoji-color-font) and fonts made with [scfbuild](https://github.com/13rac1/scfbuild) is SVGinOT +- Requires: [lunasvg](https://github.com/sammycage/lunasvg) v2.3.2 and above + 1. Add `#define IMGUI_ENABLE_FREETYPE_LUNASVG` in your `imconfig.h`. + 2. Get latest lunasvg binaries or build yourself. Under Windows you may use vcpkg with: `vcpkg install lunasvg --triplet=x64-windows`. diff --git a/3rdparty/imgui/misc/freetype/imgui_freetype.cpp b/3rdparty/imgui/misc/freetype/imgui_freetype.cpp index 029991b..68e38ed 100644 --- a/3rdparty/imgui/misc/freetype/imgui_freetype.cpp +++ b/3rdparty/imgui/misc/freetype/imgui_freetype.cpp @@ -6,11 +6,10 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2024/10/17: added plutosvg support for SVG Fonts (seems faster/better than lunasvg). Enable by using '#define IMGUI_ENABLE_FREETYPE_PLUTOSVG'. (#7927) // 2023/11/13: added support for ImFontConfig::RasterizationDensity field for scaling render density without scaling metrics. -// 2023/08/01: added support for SVG fonts, enable by using '#define IMGUI_ENABLE_FREETYPE_LUNASVG'. (#6591) +// 2023/08/01: added support for SVG fonts, enable by using '#define IMGUI_ENABLE_FREETYPE_LUNASVG' (#6591) // 2023/01/04: fixed a packing issue which in some occurrences would prevent large amount of glyphs from being packed correctly. -// 2021/08/23: fixed crash when FT_Render_Glyph() fails to render a glyph and returns nullptr. +// 2021/08/23: fixed crash when FT_Render_Glyph() fails to render a glyph and returns NULL. // 2021/03/05: added ImGuiFreeTypeBuilderFlags_Bitmap to load bitmap glyphs. // 2021/03/02: set 'atlas->TexPixelsUseColors = true' to help some backends with deciding of a preferred texture format. // 2021/01/28: added support for color-layered glyphs via ImGuiFreeTypeBuilderFlags_LoadColor (require Freetype 2.10+). @@ -33,7 +32,7 @@ // - For correct results you need to be using sRGB and convert to linear space in the pixel shader output. // - The default dear imgui styles will be impacted by this change (alpha values will need tweaking). -// FIXME: cfg.OversampleH, OversampleV are not supported, but generally not necessary with this rasterizer because Hinting makes everything look better. +// FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer). #include "imgui.h" #ifndef IMGUI_DISABLE @@ -46,21 +45,12 @@ #include FT_GLYPH_H // #include FT_SYNTHESIS_H // -// Handle LunaSVG and PlutoSVG -#if defined(IMGUI_ENABLE_FREETYPE_LUNASVG) && defined(IMGUI_ENABLE_FREETYPE_PLUTOSVG) -#error "Cannot enable both IMGUI_ENABLE_FREETYPE_LUNASVG and IMGUI_ENABLE_FREETYPE_PLUTOSVG" -#endif -#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG +#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG #include FT_OTSVG_H // #include FT_BBOX_H // #include -#endif -#ifdef IMGUI_ENABLE_FREETYPE_PLUTOSVG -#include -#endif -#if defined(IMGUI_ENABLE_FREETYPE_LUNASVG) || defined (IMGUI_ENABLE_FREETYPE_PLUTOSVG) #if !((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) -#error IMGUI_ENABLE_FREETYPE_PLUTOSVG or IMGUI_ENABLE_FREETYPE_LUNASVG requires FreeType version >= 2.12 +#error IMGUI_ENABLE_FREETYPE_LUNASVG requires FreeType version >= 2.12 #endif #endif @@ -104,9 +94,6 @@ static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_ // Code //------------------------------------------------------------------------- -#define FT_CEIL(X) (((X + 63) & -64) / 64) // From SDL_ttf: Handy routines for converting from fixed point -#define FT_SCALEFACTOR 64.0f - namespace { // Glyph metrics: @@ -172,7 +159,6 @@ namespace const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info); void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = nullptr); - FreeTypeFont() { memset((void*)this, 0, sizeof(*this)); } ~FreeTypeFont() { CloseFont(); } // [Internals] @@ -185,6 +171,9 @@ namespace float InvRasterizationDensity; }; + // From SDL_ttf: Handy routines for converting from fixed point + #define FT_CEIL(X) (((X + 63) & -64) / 64) + bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_font_builder_flags) { FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face); @@ -280,11 +269,11 @@ namespace // Need an outline for this to work FT_GlyphSlot slot = Face->glyph; -#if defined(IMGUI_ENABLE_FREETYPE_LUNASVG) || defined(IMGUI_ENABLE_FREETYPE_PLUTOSVG) +#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP || slot->format == FT_GLYPH_FORMAT_SVG); #else #if ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) - IM_ASSERT(slot->format != FT_GLYPH_FORMAT_SVG && "The font contains SVG glyphs, you'll need to enable IMGUI_ENABLE_FREETYPE_PLUTOSVG or IMGUI_ENABLE_FREETYPE_LUNASVG in imconfig.h and install required libraries in order to use this font"); + IM_ASSERT(slot->format != FT_GLYPH_FORMAT_SVG && "The font contains SVG glyphs, you'll need to enable IMGUI_ENABLE_FREETYPE_LUNASVG in imconfig.h and install required libraries in order to use this font"); #endif IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP); #endif // IMGUI_ENABLE_FREETYPE_LUNASVG @@ -316,7 +305,7 @@ namespace out_glyph_info->Height = (int)ft_bitmap->rows; out_glyph_info->OffsetX = Face->glyph->bitmap_left; out_glyph_info->OffsetY = -Face->glyph->bitmap_top; - out_glyph_info->AdvanceX = (float)slot->advance.x / FT_SCALEFACTOR; + out_glyph_info->AdvanceX = (float)FT_CEIL(slot->advance.x); out_glyph_info->IsColored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA); return ft_bitmap; @@ -491,9 +480,8 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) { // Check for valid range. This may also help detect *some* dangling pointers, because a common - // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent, - // or to forget to zero-terminate the glyph range array. - IM_ASSERT(src_range[0] <= src_range[1] && "Invalid range: is your glyph range array persistent? it is zero-terminated?"); + // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent. + IM_ASSERT(src_range[0] <= src_range[1]); src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); } dst_tmp.SrcCount++; @@ -573,7 +561,6 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u // 8. Render/rasterize font characters into the texture int total_surface = 0; int buf_rects_out_n = 0; - const int pack_padding = atlas->TexGlyphPadding; for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) { ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; @@ -591,6 +578,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); // Gather the sizes of all rectangles we will need to pack + const int padding = atlas->TexGlyphPadding; for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) { ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i]; @@ -618,13 +606,11 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u buf_bitmap_current_used_bytes += bitmap_size_in_bytes; src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width, multiply_enabled ? multiply_table : nullptr); - src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + pack_padding); - src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + pack_padding); + src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + padding); + src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + padding); total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; } } - for (int i = 0; i < atlas->CustomRects.Size; i++) - total_surface += (atlas->CustomRects[i].Width + pack_padding) * (atlas->CustomRects[i].Height + pack_padding); // We need a width for the skyline algorithm, any width! // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. @@ -684,6 +670,8 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) { ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; + if (src_tmp.GlyphsCount == 0) + continue; // When merging fonts with MergeMode=true: // - We can have multiple input fonts writing into a same destination font. @@ -694,9 +682,6 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u const float ascent = src_tmp.Font.Info.Ascender; const float descent = src_tmp.Font.Info.Descender; ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); - - if (src_tmp.GlyphsCount == 0) - continue; const float font_off_x = cfg.GlyphOffset.x; const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent); @@ -824,10 +809,6 @@ static bool ImFontAtlasBuildWithFreeType(ImFontAtlas* atlas) SVG_RendererHooks hooks = { ImGuiLunasvgPortInit, ImGuiLunasvgPortFree, ImGuiLunasvgPortRender, ImGuiLunasvgPortPresetSlot }; FT_Property_Set(ft_library, "ot-svg", "svg-hooks", &hooks); #endif // IMGUI_ENABLE_FREETYPE_LUNASVG -#ifdef IMGUI_ENABLE_FREETYPE_PLUTOSVG - // With plutosvg, use provided hooks - FT_Property_Set(ft_library, "ot-svg", "svg-hooks", plutosvg_ft_svg_hooks()); -#endif // IMGUI_ENABLE_FREETYPE_PLUTOSVG bool ret = ImFontAtlasBuildWithFreeTypeEx(ft_library, atlas, atlas->FontBuilderFlags); FT_Done_Library(ft_library); diff --git a/3rdparty/imgui/misc/freetype/imgui_freetype.h b/3rdparty/imgui/misc/freetype/imgui_freetype.h index 6572b15..b4e1d48 100644 --- a/3rdparty/imgui/misc/freetype/imgui_freetype.h +++ b/3rdparty/imgui/misc/freetype/imgui_freetype.h @@ -5,13 +5,6 @@ #include "imgui.h" // IMGUI_API #ifndef IMGUI_DISABLE -// Usage: -// - Add '#define IMGUI_ENABLE_FREETYPE' in your imconfig to enable support for imgui_freetype in imgui. - -// Optional support for OpenType SVG fonts: -// - Add '#define IMGUI_ENABLE_FREETYPE_PLUTOSVG' to use plutosvg (not provided). See #7927. -// - Add '#define IMGUI_ENABLE_FREETYPE_LUNASVG' to use lunasvg (not provided). See #6591. - // Forward declarations struct ImFontAtlas; struct ImFontBuilderIO; diff --git a/src/main.cc b/src/main.cc index 13c0b5d..123f265 100644 --- a/src/main.cc +++ b/src/main.cc @@ -5,6 +5,7 @@ //------------------------------------------------------------------------------ #include "backends/imgui_impl_glfw.h" +#include "backends/imgui_impl_opengl3.h" #include "imgui.h" #include "imnodes.h" #define SOKOL_IMPL @@ -438,22 +439,23 @@ void sokol_logger( int main() { // window and GL context via GLFW and flextGL glfwInit(); + const char* glsl_version = "#version 130"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE); glfwWindowHint(GLFW_SAMPLES, cMSAASampleCount); - GLFWwindow* w = + GLFWwindow* window = glfwCreateWindow(Width, Height, "ATP Editor", nullptr, nullptr); - glfwMakeContextCurrent(w); + glfwMakeContextCurrent(window); glfwSwapInterval(1); load_application_config("animtestbed_config.json"); if (gApplicationConfig.window_position[0] != 0 || gApplicationConfig.window_position[1] != 0) { glfwSetWindowPos( - w, + window, gApplicationConfig.window_position[0], gApplicationConfig.window_position[1]); } @@ -461,30 +463,11 @@ int main() { if (gApplicationConfig.window_size[0] != 0 || gApplicationConfig.window_size[1] != 0) { glfwSetWindowSize( - w, + window, gApplicationConfig.window_size[0], gApplicationConfig.window_size[1]); } - // GLFW to ImGui input forwarding - glfwSetMouseButtonCallback( - w, - [](GLFWwindow*, int btn, int action, int /*mods*/) { - if ((btn >= 0) && (btn < 3)) { - ImGui::GetIO().MouseDown[btn] = (action == GLFW_PRESS); - } - }); - glfwSetCursorPosCallback(w, [](GLFWwindow*, double pos_x, double pos_y) { - ImGui::GetIO().MousePos.x = float(pos_x); - ImGui::GetIO().MousePos.y = float(pos_y); - }); - glfwSetScrollCallback(w, [](GLFWwindow*, double /*pos_x*/, double pos_y) { - ImGui::GetIO().MouseWheel = float(pos_y); - }); - - glfwSetKeyCallback(w, ImGui_ImplGlfw_KeyCallback); - glfwSetCharCallback(w, ImGui_ImplGlfw_CharCallback); - // setup sokol_gfx and sokol_time stm_setup(); sg_desc desc = { @@ -541,6 +524,9 @@ int main() { 14, &font_config); + ImGui_ImplGlfw_InitForOpenGL(window, true); + ImGui_ImplOpenGL3_Init(glsl_version); + // ImNodes ImNodes::CreateContext(); @@ -633,7 +619,7 @@ int main() { ax::NodeEditor::CreateEditor(&gApplicationConfig.graph_editor.config); // draw loop - while (!glfwWindowShouldClose(w)) { + while (!glfwWindowShouldClose(window)) { // Update time state.time.frame = stm_sec( stm_round_to_common_refresh_rate(stm_laptime(&state.time.laptime))); @@ -652,17 +638,17 @@ int main() { // Update window state glfwGetWindowPos( - w, + window, &gApplicationConfig.window_position[0], &gApplicationConfig.window_position[1]); glfwGetWindowSize( - w, + window, &gApplicationConfig.window_size[0], &gApplicationConfig.window_size[1]); int cur_width, cur_height; - glfwGetFramebufferSize(w, &cur_width, &cur_height); + glfwGetFramebufferSize(window, &cur_width, &cur_height); // this is standard ImGui demo code io.DisplaySize = ImVec2(float(cur_width), float(cur_height)); @@ -670,11 +656,11 @@ int main() { ImGui::NewFrame(); // handle input - handle_mouse(w, &gGuiInputState); + handle_mouse(window, &gGuiInputState); - if (!glfwGetMouseButton(w, GLFW_MOUSE_BUTTON_RIGHT)) { + if (!glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT)) { gControlMode = ControlMode::ControlModeNone; - glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); Camera_Update( &state.camera, offscreen_viewport.size[0], @@ -689,28 +675,28 @@ int main() { float camera_accel[3] = {0.f, 0.f, 0.f}; float accel_scale = 100.0; - if (glfwGetKey(w, GLFW_KEY_LEFT_SHIFT)) { + if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT)) { accel_scale *= 3.; - } else if (glfwGetKey(w, GLFW_KEY_LEFT_CONTROL)) { + } else if (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL)) { accel_scale /= 3.; } - if (glfwGetKey(w, GLFW_KEY_W)) { + if (glfwGetKey(window, GLFW_KEY_W)) { camera_accel[0] -= accel_scale; } - if (glfwGetKey(w, GLFW_KEY_S)) { + if (glfwGetKey(window, GLFW_KEY_S)) { camera_accel[0] += accel_scale; } - if (glfwGetKey(w, GLFW_KEY_C)) { + if (glfwGetKey(window, GLFW_KEY_C)) { camera_accel[1] -= accel_scale; } - if (glfwGetKey(w, GLFW_KEY_SPACE)) { + if (glfwGetKey(window, GLFW_KEY_SPACE)) { camera_accel[1] += accel_scale; } - if (glfwGetKey(w, GLFW_KEY_A)) { + if (glfwGetKey(window, GLFW_KEY_A)) { camera_accel[2] -= accel_scale; } - if (glfwGetKey(w, GLFW_KEY_D)) { + if (glfwGetKey(window, GLFW_KEY_D)) { camera_accel[2] += accel_scale; } @@ -729,7 +715,7 @@ int main() { if (ImGui::BeginMainMenuBar()) { if (ImGui::BeginMenu("File")) { if (ImGui::MenuItem("Quit")) { - glfwSetWindowShouldClose(w, true); + glfwSetWindowShouldClose(window, true); } ImGui::EndMenu(); } @@ -804,7 +790,7 @@ int main() { if (gControlMode == ControlMode::ControlModeNone) { gControlMode = ControlMode::ControlModeFPS; Camera_CalcFromMatrix(&state.camera, &state.camera.mtxView[0]); - glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); } } @@ -1068,7 +1054,7 @@ int main() { sg_end_pass(); sg_commit(); - glfwSwapBuffers(w); + glfwSwapBuffers(window); glfwPollEvents(); }