Compare commits

...

66 Commits

Author SHA1 Message Date
ocornut
d150220c1a Demo: added variety of usage scenarios, hooking Alt, Mouse Wheel, Home, CTRL+Tab demos.
(relate to issues: 456, 2637, 2620, 2891, 3370, 3724, 4828, 5108, 5242, 5641)
2025-08-11 16:57:12 +02:00
ocornut
47d075fca2 Demo: added SetKeyOwner(), ImGuiInputFlags_LockThisFrame, ImGuiInputFlags_LockUntilRelease demo.
(relate to issues: 456, 2637, 2620, 2891, 3370, 3724, 4828, 5108, 5242, 5641)
2025-08-11 16:57:12 +02:00
ocornut
2b24f5fa71 Version 1.92.2 2025-08-11 16:47:06 +02:00
ocornut
e10300ed3c Docs: Special thanks. 2025-08-11 16:26:10 +02:00
ocornut
5a6fa33b88 Fixed an inconsistency between IsItemHovered() and internal hovering check, where IsItemHovered() would return true if mouse was first clicked on the background of a non-moveable window. (#8877) 2025-08-11 15:41:38 +02:00
ocornut
8239a0e0c4 Nav, Tables: fix NavIsScrollPushableX logic clamping value stored in NavApplyItemToResult(), which would break scrolling. (#8816, #2221)
Amend 47c4148.
2025-08-11 15:17:02 +02:00
ocornut
50115596dc Demo: About Box: include IMGUI_ENABLE_TEST_ENGINE in Config/Build info. 2025-08-11 12:29:13 +02:00
ocornut
1c57dc21c2 Misc: fixes zealous MSVC static analyzer warnings + make GetInputSourceName(), GetMouseSourceName() a little more tolerant. (#8876) 2025-08-11 11:04:13 +02:00
ocornut
47c41483bd Tables, Nav: fixed navigation within scrolling tables when item boundaries goes beyond columns limits. (#8816, #2221)
Amend 00d3f9295e.
2025-08-11 10:49:20 +02:00
Ian
ea075ed973 ImVector: skip memcpy in operator= if Data isn't initialized to play nice with -fsanitize=undefined. (#8874) 2025-08-11 09:53:01 +02:00
ocornut
b6614f6c7c Backends: SDL_GPU3: removed ImGui_ImplSDLGPU3_Texture struct extraneous indirection now that we only need to store SDL_GPUTexture*. (#8866, #8163, #7998, #7988, #8465) 2025-08-08 15:51:17 +02:00
ocornut
9ee3d731b5 Backends: SDL_GPU3: changed ImTextureID type from SDL_GPUTextureSamplerBinding* to SDL_GPUTexture*. Added ImGui_ImplSDLGPU3_RenderState. (#8866, #8163, #7998, #7988) 2025-08-08 15:51:16 +02:00
LEE KYOUNGHEON
e7d0ad092c Removed static inline usages from free functions. (#8867, #8813)
For C++20 module compatibility. See https://github.com/stripe2933/imgui-module/
2025-08-07 17:01:23 +02:00
ocornut
412daf7362 Tabs: attempt to fix infinite loop in tab-bar ShrinkWidth() by using an epsilon. (#5652, #3421, #8800) 2025-08-07 16:41:21 +02:00
ocornut
c22af8c346 Fonts: fixes comment (amend d8da97f7). 2025-08-07 16:19:07 +02:00
ocornut
1bf41a0762 Fonts, Tables: fixed PushFont() having no effect when called after submitting a hidden column. (#8865)
Amend 0e769c5
2025-08-07 16:16:12 +02:00
ocornut
284283615b InputText: minor tweak to an expression.
Primarily to make PVS Studio static analysis go silent but it is a perfectly valid suggestion.
2025-08-06 10:48:01 +09:00
Adem Budak
d163e20f63 Examples: Win32+OpenGL3: Replace legacy 'GL/GL.h' with 'GL/gl.h' (#8861) 2025-08-06 10:43:57 +09:00
Christian Fillion
f7eae45ae9 Fonts: show ImFontConfig::FontNo in DebugNodeFont(). (#8863)
Thanks!
2025-08-06 10:42:34 +09:00
Elliot Prior
ff2dfc8422 Fonts: fixed a crash when modifying different texture format with a legacy backend. (#8824) 2025-08-04 18:39:30 +09:00
ocornut
7e701c18c8 Fonts: fixed an issue when a font using MergeMode has a reference size specified but the target font doesn't. 2025-08-04 18:21:38 +09:00
Michael Böhme
90025a62c7 Backends: Vulkan: Avoid calling vkCmdBindDescriptorSets() when texture has not changed. (#8666) 2025-08-04 18:10:00 +09:00
ocornut
902b8cc39a Examples: SDL3+SDL_GPU: use SDL_GPU_PRESENTMODE_VSYNC present mode. (#8830) 2025-08-04 15:30:25 +09:00
o:tone
70cfc02811 Examples: SDL3+SDL_GPU: use SDL_WaitAndAcquireGPUSwapchainTexture() instead of SDL_AcquireGPUSwapchainTexture(). (#8830) 2025-08-04 15:28:38 +09:00
ocornut
250bd66b76 Tabs: fixed ImGuiTabBarFlags_FittingPolicyScroll not triggering (regression in 3ef6c84). (#3421, #8800) 2025-08-04 15:19:16 +09:00
ocornut
c14d83d4e0 Tabs: made scrolling buttons never keyboard/gamepad navigation candidates. 2025-08-04 15:12:23 +09:00
ocornut
7d5fef8642 Nav: fixed a bug where GamepadMenu couldn't toggle between main and menu layer while navigating a Modal window. (#8834)
Amend 901d432cb but for Gamepad.
2025-08-04 15:06:14 +09:00
Christian Fillion
22fe9fce4c Textures: fixed assertion in DebugNodeTexture() when ImTextureID_Invalid is non-zero. (#8860, #8745)
ImFontAtlas's constructor resets ImTextureRef::_TexID to 0 instead of ImTextureID_Invalid.
Amend bc051dc
2025-08-04 14:10:20 +09:00
ocornut
320c94bfaa Tabs: when scrolling is enabled, track selected tabs when resizing down parent container. (#3421, #8800) 2025-07-31 23:42:30 +09:00
ocornut
3ef6c8410a Tabs: added new fitting policy ImGuiTabBarFlags_FittingPolicyMixed, new default. (#3421, #8800) 2025-07-31 23:42:25 +09:00
ocornut
cc1fbcc9a9 Fonts: undo change done in b884533 since 19d1ad0 made them unnecessary. (#8794, #8850) 2025-07-31 23:04:35 +09:00
ocornut
78d11cd781 Tabs: (Breaking) renamed ImGuiTabBarFlags_FittingPolicyResizeDown to ImGuiTabBarFlags_FittingPolicyShrink. (#261, #351)
Amend 54a60aaa40
2025-07-31 22:58:01 +09:00
ocornut
7278cda039 Tabs: added TabMinWidthBase, ImGuiStyleVar_TabMinWidthBase. 2025-07-31 22:57:11 +09:00
ocornut
7bb9db501c Tabs: fixed 046a8ea (commited a modified file). 2025-07-31 22:05:19 +09:00
ocornut
046a8eae0f Tabs: fixed tab bar underline not drawing below scroll buttons. (#6820, #4859, #5022, #5239)
Fix ef8ff1b5d8 which accidentally meant we are using BarRect after it may have been modified by TabBarScrollingButtons().
2025-07-31 22:04:01 +09:00
ocornut
a0cdac48e0 Tables: fixed TableGetHoveredRow() (#7350, #6588, #6250) + TableGetRowIndex() which never correctly worked when using a clipper.
Amend e09454aec. Can't understand the comment nor why code was commented. Code looks alright. Compared TableEndRow() between 1.80 and current as well.
2025-07-31 13:21:26 +09:00
ocornut
2ab3946ecb Windows: add StopMouseMovingWindow(), partial merge 80d78fa from docking. 2025-07-30 18:46:49 +09:00
ocornut
87d7f7744e Fonts: (Internal) Added undocumented ImFontBaked::LoadNoRenderOnLayout. (#8758, #8465)
Amend fd75bdccb0.
2025-07-27 20:33:57 +09:00
ocornut
10dc1882c8 Fonts: (Internal) rename ImFontBaked::LockLoadingFallback to ImFontBaked::LoadNoFallback. 2025-07-27 20:31:37 +09:00
ocornut
c6c0c3be08 Docs: amend 1.92.0 logs on the fact that font->CalcTextSizeA() used to be thread-safe. 2025-07-27 20:15:21 +09:00
ocornut
da6c97203e Fixed comments for io.KeyCtrl / io.KeySuper to match the one for ImGuiMod_Ctrl, ImGuiMod_Super. (#8839) 2025-07-27 19:37:30 +09:00
Miolith
853a46e021 Backends: Vulkan: fixed texture update corruption introduced in 1.92.0. (#8801, #8755, #8840, #8465)
Fix abe294bfd0
2025-07-27 19:33:30 +09:00
Ori Avtalion
075ad676aa Demo: Fix '= =' typo in text (#8836) 2025-07-25 17:36:23 +09:00
ocornut
19d1ad04f4 Fonts: stop using stb_truetype.h implementation functions. Fix using IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION. (#8794) 2025-07-23 16:42:00 +09:00
ocornut
b884533957 Document/workaround an issue using IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION since 1.92.0. (#8794) 2025-07-23 16:30:30 +09:00
ocornut
174f37bdaf Fixed building with IMGUI_DISABLE_DEBUG_TOOLS only. (#8796) 2025-07-23 16:17:35 +09:00
ocornut
4f00774006 Examples: SDL3+Metal: Amend example. (#8827, #8825)
Amend 8403c49
2025-07-23 16:11:47 +09:00
Shi Yan
8403c49484 Examples: SDL3+Metal: Added example. (#8827, #8825) 2025-07-23 15:58:13 +09:00
ocornut
06ab541e2f CI: Adjust policies to more frequently build Win64 SDL3+SDL_Renderer, SDL3+SDL_GPU, and tweak others. 2025-07-22 17:01:26 +09:00
scribam
7babc24ad4 CI: Add SDL3 builds to MacOS and Windows. (#8819, #8778) 2025-07-22 16:52:20 +09:00
scribam
c96e9c8273 CI: Update Windows CI to use a more recent SDL2. (#8819, #8778) 2025-07-22 16:51:20 +09:00
Tim-Rex
4a51295c9e Backends: OpenGL3: add and call embedded loader shutdown in ImGui_ImplOpenGL3_Shutdown(). (#8792)
Include update of imgui_impl_opengl3_loader.h as submitted to gl3w_stripped repository, which adds imgl3wShutdown().
2025-07-22 16:46:35 +09:00
gomkyung2
9c392896b7 Misc: removed more redundant inline static linkage from imgui_internal.h. (#8813, #8682, #8358) 2025-07-22 16:31:10 +09:00
ocornut
ea613e181c Windows: fixed an issue where resizable child windows would emit border logic when hidden/non-visible. (#8815)
This makes more sense in docking branch but may be merged in master right away.
2025-07-22 16:22:53 +09:00
ocornut
ed5bd1f9ef Changed ImTextCharToUtf8() to return bytes count rather than original pointer. (#8820)
Amend c2bf4abfa1
2025-07-22 14:17:11 +09:00
Rhys Pounder
3401dbde92 Docs: Fixed typo. (#8817) 2025-07-21 15:42:16 +09:00
ocornut
c9e0208de4 Textures: moved UpdateTexturesNewFrame(), UpdateTexturesEndFrame() to a more suitable location in the file. 2025-07-21 15:35:53 +09:00
ocornut
57a816ae60 Texutres: minor comments, tweaks. 2025-07-21 15:27:17 +09:00
ocornut
643f0e3abf Backends: OpenGL3: restore update path on non-WebGL non-ES targets that doesn't require a CPU copy. (#8802, #8465)
Amend/fix dbb91a5
2025-07-15 14:34:40 +02:00
ocornut
8744d10235 Backends: OpenGL2, OpenGL3: set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) 2025-07-15 14:30:50 +02:00
ocornut
336d9212fc Backends: using range-for to iterate draw_data->CmdLists[]. 2025-07-11 17:41:52 +02:00
ocornut
79d88e2d0b Error Handling, Tables: TableGetSortSpecs() silently return NULL when no table (matching most other table getters). TableSetBgColor() uses IM_ASSERT_USER_ERROR. 2025-07-11 16:57:43 +02:00
ocornut
a0d3e405a3 Textures: ImTextureData::Create() sets status. RegisterUserTexture() increases RefCount. Added comments about ImTextureData::GetTexRef(). (#8789) 2025-07-11 16:49:28 +02:00
ocornut
0e6e876f23 Docs: update docs/comments about ImTextureRef, ImTextureID. (#8783) 2025-07-10 19:07:28 +02:00
ocornut
c680f54e6c FIxed IsWindowFocused() using wrong flag types (harmless as values were identical). (#8786) 2025-07-10 18:42:39 +02:00
ocornut
4d745bc602 Version 1.92.2 WIP 2025-07-10 18:41:05 +02:00
33 changed files with 1301 additions and 397 deletions

View File

@@ -27,9 +27,13 @@ jobs:
- name: Install Dependencies
shell: powershell
run: |
Invoke-WebRequest -Uri "https://www.libsdl.org/release/SDL2-devel-2.26.3-VC.zip" -OutFile "SDL2-devel-2.26.3-VC.zip"
Expand-Archive -Path SDL2-devel-2.26.3-VC.zip
echo "SDL2_DIR=$(pwd)\SDL2-devel-2.26.3-VC\SDL2-2.26.3\" >>${env:GITHUB_ENV}
Invoke-WebRequest -Uri "https://www.libsdl.org/release/SDL2-devel-2.32.8-VC.zip" -OutFile "SDL2-devel-2.32.8-VC.zip"
Expand-Archive -Path SDL2-devel-2.32.8-VC.zip
echo "SDL2_DIR=$(pwd)\SDL2-devel-2.32.8-VC\SDL2-2.32.8\" >>${env:GITHUB_ENV}
Invoke-WebRequest -Uri "https://www.libsdl.org/release/SDL3-devel-3.2.18-VC.zip" -OutFile "SDL3-devel-3.2.18-VC.zip"
Expand-Archive -Path SDL3-devel-3.2.18-VC.zip
echo "SDL3_DIR=$(pwd)\SDL3-devel-3.2.18-VC\SDL3-3.2.18\" >>${env:GITHUB_ENV}
Invoke-WebRequest -Uri "https://github.com/ocornut/imgui/files/3789205/vulkan-sdk-1.1.121.2.zip" -OutFile vulkan-sdk-1.1.121.2.zip
Expand-Archive -Path vulkan-sdk-1.1.121.2.zip
@@ -102,9 +106,12 @@ jobs:
cl.exe /D_USRDLL /D_WINDLL /I. example_single_file.cpp /LD /FeImGui.dll /link
cl.exe /DIMGUI_API=__declspec(dllimport) /I. ImGui.lib /Feexample_null.exe examples/example_null/main.cpp
# Win64 examples are more frequently compilted than the Win32 examples.
# More of the Win32 examples requires 'workflow_run' to reduce waste.
- name: Build Win32 example_glfw_opengl2
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj /p:Platform=Win32 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build Win32 example_glfw_opengl3
shell: cmd
@@ -140,72 +147,111 @@ jobs:
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj /p:Platform=Win32 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build Win32 example_sdl3_opengl3
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj /p:Platform=Win32 /p:Configuration=Release'
- name: Build Win32 example_sdl3_sdlgpu3
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj /p:Platform=Win32 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build Win32 example_sdl3_sdlrenderer3
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj /p:Platform=Win32 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build Win32 example_sdl3_vulkan
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj /p:Platform=Win32 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build Win32 example_win32_directx9
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx9/example_win32_directx9.vcxproj /p:Platform=Win32 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build Win32 example_win32_directx10
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx10/example_win32_directx10.vcxproj /p:Platform=Win32 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build Win32 example_win32_directx11
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx11/example_win32_directx11.vcxproj /p:Platform=Win32 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build x64 example_glfw_opengl2
# Windows 64-bits
- name: Build Win64 example_glfw_opengl2
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj /p:Platform=x64 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build x64 example_glfw_opengl3
- name: Build Win64 example_glfw_opengl3
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj /p:Platform=x64 /p:Configuration=Release'
- name: Build x64 example_glfw_vulkan
- name: Build Win64 example_glfw_vulkan
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release'
- name: Build x64 example_sdl2_sdlrenderer2
- name: Build Win64 example_sdl2_sdlrenderer2
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj /p:Platform=x64 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build x64 example_sdl2_vulkan
- name: Build Win64 example_sdl2_vulkan
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build x64 example_sdl2_opengl2
- name: Build Win64 example_sdl2_opengl2
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj /p:Platform=x64 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build x64 example_sdl2_opengl3
- name: Build Win64 example_sdl2_opengl3
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj /p:Platform=x64 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build x64 example_sdl2_directx11
- name: Build Win64 example_sdl2_directx11
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj /p:Platform=x64 /p:Configuration=Release'
- name: Build x64 example_win32_directx9
- name: Build Win64 example_sdl3_opengl3
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj /p:Platform=x64 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build Win64 example_sdl3_sdlgpu3
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj /p:Platform=x64 /p:Configuration=Release'
- name: Build Win64 example_sdl3_sdlrenderer3
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj /p:Platform=x64 /p:Configuration=Release'
- name: Build Win64 example_sdl3_vulkan
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build Win64 example_win32_directx9
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx9/example_win32_directx9.vcxproj /p:Platform=x64 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build x64 example_win32_directx10
- name: Build Win64 example_win32_directx10
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx10/example_win32_directx10.vcxproj /p:Platform=x64 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build x64 example_win32_directx11
- name: Build Win64 example_win32_directx11
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx11/example_win32_directx11.vcxproj /p:Platform=x64 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build x64 example_win32_directx12
- name: Build Win64 example_win32_directx12
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx12/example_win32_directx12.vcxproj /p:Platform=x64 /p:Configuration=Release'
@@ -433,7 +479,7 @@ jobs:
- name: Install Dependencies
run: |
brew install glfw3 sdl2
brew install glfw3 sdl2 sdl3
- name: Build example_null (extra warnings, clang 64-bit)
run: make -C examples/example_null WITH_EXTRA_WARNINGS=1
@@ -491,6 +537,9 @@ jobs:
- name: Build example_sdl2_opengl3
run: make -C examples/example_sdl2_opengl3
- name: Build example_sdl3_opengl3
run: make -C examples/example_sdl3_opengl3
- name: Build example_apple_metal
run: xcodebuild -project examples/example_apple_metal/example_apple_metal.xcodeproj -target example_apple_metal_macos

1
.gitignore vendored
View File

@@ -68,6 +68,7 @@ examples/example_sdl2_opengl2/example_sdl2_opengl2
examples/example_sdl2_opengl3/example_sdl2_opengl3
examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2
examples/example_sdl2_vulkan/example_sdl2_vulkan
examples/example_sdl3_metal/example_sdl3_metal
examples/example_sdl3_opengl3/example_sdl3_opengl3
examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3
examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3

View File

@@ -160,10 +160,8 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
ImGui_ImplAllegro5_SetupRenderState(draw_data);
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* draw_list = draw_data->CmdLists[n];
ImVector<ImDrawVertAllegro>& vertices = bd->BufVertices;
#if ALLEGRO_HAS_DRAW_INDEXED_PRIM
vertices.resize(draw_list->VtxBuffer.Size);

View File

@@ -200,9 +200,8 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
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++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
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;
@@ -268,9 +267,8 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
int global_idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
ImVec2 clip_scale = draw_data->FramebufferScale;
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* draw_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];

View File

@@ -208,9 +208,8 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
return;
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
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;
@@ -282,9 +281,8 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
int global_vtx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
ImVec2 clip_scale = draw_data->FramebufferScale;
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* draw_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];

View File

@@ -262,9 +262,8 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
return;
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource;
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource;
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
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;
@@ -295,9 +294,8 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
int global_idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
ImVec2 clip_scale = draw_data->FramebufferScale;
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* draw_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];

View File

@@ -228,9 +228,8 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
// FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and
// 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR
// 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++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
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++)
{
@@ -260,9 +259,8 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
int global_vtx_offset = 0;
int global_idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* draw_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];

View File

@@ -223,7 +223,7 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer>
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdListsCount == 0)
if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0)
return;
// Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
@@ -259,10 +259,8 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer>
// Render command lists
size_t vertexBufferOffset = 0;
size_t indexBufferOffset = 0;
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* draw_list = draw_data->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));

View File

@@ -25,6 +25,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802)
// 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL2_CreateFontsTexture() and ImGui_ImplOpenGL2_DestroyFontsTexture().
// 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap.
// 2024-06-28: OpenGL: ImGui_ImplOpenGL2_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL2_DestroyFontsTexture(). (#7748)
@@ -208,9 +209,8 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* draw_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data;
const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data;
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + offsetof(ImDrawVert, pos)));
@@ -286,6 +286,7 @@ void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex)
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP));
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
// Store identifiers
@@ -305,6 +306,7 @@ void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex)
GLuint gl_tex_id = (GLuint)(intptr_t)tex->TexID;
GL_CALL(glBindTexture(GL_TEXTURE_2D, gl_tex_id));
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->Width));
GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
for (ImTextureRect& r : tex->Updates)
GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, r.x, r.y, r.w, r.h, GL_RGBA, GL_UNSIGNED_BYTE, tex->GetPixelsAt(r.x, r.y)));
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));

View File

@@ -23,6 +23,8 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2025-07-22: OpenGL: Add and call embedded loader shutdown during ImGui_ImplOpenGL3_Shutdown() to facilitate multiple init/shutdown cycles in same process. (#8792)
// 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures (#8802) + restore non-WebGL/ES update path that doesn't require a CPU-side copy.
// 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL3_CreateFontsTexture() and ImGui_ImplOpenGL3_DestroyFontsTexture().
// 2025-06-04: OpenGL: Made GLES 3.20 contexts not access GL_CONTEXT_PROFILE_MASK nor GL_PRIMITIVE_RESTART. (#8664)
// 2025-02-18: OpenGL: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406)
@@ -421,6 +423,10 @@ void ImGui_ImplOpenGL3_Shutdown()
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
IM_DELETE(bd);
#ifdef IMGUI_IMPL_OPENGL_LOADER_IMGL3W
imgl3wShutdown();
#endif
}
void ImGui_ImplOpenGL3_NewFrame()
@@ -584,10 +590,8 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* draw_list = draw_data->CmdLists[n];
// Upload vertex/index buffers
// - OpenGL drivers are in a very sorry state nowadays....
// During 2021 we attempted to switch from glBufferData() to orphaning+glBufferSubData() following reports
@@ -711,6 +715,17 @@ static void ImGui_ImplOpenGL3_DestroyTexture(ImTextureData* tex)
void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex)
{
// FIXME: Consider backing up and restoring
if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates)
{
#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
#endif
#ifdef GL_UNPACK_ALIGNMENT
GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
#endif
}
if (tex->Status == ImTextureStatus_WantCreate)
{
// Create and upload new texture to graphics system
@@ -730,9 +745,6 @@ void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex)
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, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
// Store identifiers
@@ -751,7 +763,7 @@ void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex)
GLuint gl_tex_id = (GLuint)(intptr_t)tex->TexID;
GL_CALL(glBindTexture(GL_TEXTURE_2D, gl_tex_id));
#if 0// GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
#if GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->Width));
for (ImTextureRect& r : tex->Updates)
GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, r.x, r.y, r.w, r.h, GL_RGBA, GL_UNSIGNED_BYTE, tex->GetPixelsAt(r.x, r.y)));

View File

@@ -166,6 +166,7 @@ typedef khronos_uint8_t GLubyte;
#define GL_SCISSOR_BOX 0x0C10
#define GL_SCISSOR_TEST 0x0C11
#define GL_UNPACK_ROW_LENGTH 0x0CF2
#define GL_UNPACK_ALIGNMENT 0x0CF5
#define GL_PACK_ALIGNMENT 0x0D05
#define GL_MAX_TEXTURE_SIZE 0x0D33
#define GL_TEXTURE_2D 0x0DE1
@@ -476,6 +477,7 @@ typedef GL3WglProc (*GL3WGetProcAddressProc)(const char *proc);
/* gl3w api */
GL3W_API int imgl3wInit(void);
GL3W_API int imgl3wInit2(GL3WGetProcAddressProc proc);
GL3W_API void imgl3wShutdown(void);
GL3W_API int imgl3wIsSupported(int major, int minor);
GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc);
@@ -631,7 +633,7 @@ extern "C" {
#endif
#include <windows.h>
static HMODULE libgl;
static HMODULE libgl = NULL;
typedef PROC(__stdcall* GL3WglGetProcAddr)(LPCSTR);
static GL3WglGetProcAddr wgl_get_proc_address;
@@ -644,7 +646,7 @@ static int open_libgl(void)
return GL3W_OK;
}
static void close_libgl(void) { FreeLibrary(libgl); }
static void close_libgl(void) { FreeLibrary(libgl); libgl = NULL; }
static GL3WglProc get_proc(const char *proc)
{
GL3WglProc res;
@@ -656,7 +658,7 @@ static GL3WglProc get_proc(const char *proc)
#elif defined(__APPLE__)
#include <dlfcn.h>
static void *libgl;
static void *libgl = NULL;
static int open_libgl(void)
{
libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY | RTLD_LOCAL);
@@ -665,7 +667,7 @@ static int open_libgl(void)
return GL3W_OK;
}
static void close_libgl(void) { dlclose(libgl); }
static void close_libgl(void) { dlclose(libgl); libgl = NULL; }
static GL3WglProc get_proc(const char *proc)
{
@@ -833,6 +835,11 @@ int imgl3wInit2(GL3WGetProcAddressProc proc)
return parse_version();
}
void imgl3wShutdown(void)
{
close_libgl();
}
int imgl3wIsSupported(int major, int minor)
{
if (major < 2)

View File

@@ -2,7 +2,7 @@
// This needs to be used along with the SDL3 Platform Backend
// Implemented features:
// [X] Renderer: User texture binding. Use simply cast a reference to your SDL_GPUTextureSamplerBinding to ImTextureID.
// [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct.
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
@@ -22,6 +22,8 @@
// Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info.
// CHANGELOG
// 2025-08-08: *BREAKING* Changed ImTextureID type from SDL_GPUTextureSamplerBinding* to SDL_GPUTexture*, which is more natural and easier for user to manage. If you need to change the current sampler, you can access the ImGui_ImplSDLGPU3_RenderState struct. (#8866, #8163, #7998, #7988)
// 2025-08-08: Expose SamplerDefault and SamplerCurrent in ImGui_ImplSDLGPU3_RenderState. Allow callback to change sampler.
// 2025-06-25: Mapping transfer buffer for texture update use cycle=true. Fixes artifacts e.g. on Metal backend.
// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLGPU3_CreateFontsTexture() and ImGui_ImplSDLGPU3_DestroyFontsTexture().
// 2025-04-28: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
@@ -36,11 +38,6 @@
#include "imgui_impl_sdlgpu3_shaders.h"
// SDL_GPU Data
struct ImGui_ImplSDLGPU3_Texture
{
SDL_GPUTexture* Texture = nullptr;
SDL_GPUTextureSamplerBinding TextureSamplerBinding = { nullptr, nullptr };
};
// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplSDLGPU3_RenderDrawData()
struct ImGui_ImplSDLGPU3_FrameData
@@ -84,12 +81,13 @@ static ImGui_ImplSDLGPU3_Data* ImGui_ImplSDLGPU3_GetBackendData()
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLGPU3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}
static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass * render_pass, ImGui_ImplSDLGPU3_FrameData* fd, uint32_t fb_width, uint32_t fb_height)
static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, ImGui_ImplSDLGPU3_RenderState* render_state, SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, ImGui_ImplSDLGPU3_FrameData* fd, uint32_t fb_width, uint32_t fb_height)
{
//ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData();
ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData();
render_state->SamplerCurrent = render_state->SamplerCurrent = bd->TexSampler;
// Bind graphics pipeline
SDL_BindGPUGraphicsPipeline(render_pass,pipeline);
SDL_BindGPUGraphicsPipeline(render_pass, pipeline);
// Bind Vertex And Index Buffers
if (draw_data->TotalVtxCount > 0)
@@ -180,9 +178,8 @@ void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff
ImDrawVert* vtx_dst = (ImDrawVert*)SDL_MapGPUTransferBuffer(v->Device, fd->VertexTransferBuffer, true);
ImDrawIdx* idx_dst = (ImDrawIdx*)SDL_MapGPUTransferBuffer(v->Device, fd->IndexTransferBuffer, true);
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
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;
@@ -228,19 +225,25 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe
if (pipeline == nullptr)
pipeline = bd->Pipeline;
ImGui_ImplSDLGPU3_SetupRenderState(draw_data, pipeline, command_buffer, render_pass, fd, fb_width, fb_height);
// 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)
// Setup render state structure (for callbacks and custom texture bindings)
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplSDLGPU3_RenderState render_state;
render_state.Device = bd->InitInfo.Device;
render_state.SamplerDefault = render_state.SamplerCurrent = bd->TexSampler;
platform_io.Renderer_RenderState = &render_state;
ImGui_ImplSDLGPU3_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, render_pass, fd, fb_width, fb_height);
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
int global_vtx_offset = 0;
int global_idx_offset = 0;
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* draw_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
@@ -249,7 +252,7 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe
// 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_ImplSDLGPU3_SetupRenderState(draw_data, pipeline, command_buffer, render_pass, fd, fb_width, fb_height);
ImGui_ImplSDLGPU3_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, render_pass, fd, fb_width, fb_height);
else
pcmd->UserCallback(draw_list, pcmd);
}
@@ -276,9 +279,14 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe
SDL_SetGPUScissor(render_pass,&scissor_rect);
// Bind DescriptorSet with font or user texture
SDL_BindGPUFragmentSamplers(render_pass, 0, (SDL_GPUTextureSamplerBinding*)pcmd->GetTexID(), 1);
SDL_GPUTextureSamplerBinding texture_sampler_binding;
texture_sampler_binding.texture = (SDL_GPUTexture*)(intptr_t)pcmd->GetTexID();
texture_sampler_binding.sampler = render_state.SamplerCurrent;
SDL_BindGPUFragmentSamplers(render_pass, 0, &texture_sampler_binding, 1);
// Draw
// **IF YOU GET A CRASH HERE** In 1.92.2 on 2025/08/08 we have changed ImTextureID to store 'SDL_GPUTexture*' instead of storing 'SDL_GPUTextureSamplerBinding'.
// Any code loading custom texture using this backend needs to be updated.
SDL_DrawGPUIndexedPrimitives(render_pass, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
}
}
@@ -297,18 +305,13 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe
static void ImGui_ImplSDLGPU3_DestroyTexture(ImTextureData* tex)
{
ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData();
ImGui_ImplSDLGPU3_Texture* backend_tex = (ImGui_ImplSDLGPU3_Texture*)tex->BackendUserData;
if (backend_tex == nullptr)
return;
SDL_GPUTextureSamplerBinding* binding = (SDL_GPUTextureSamplerBinding*)(intptr_t)tex->BackendUserData;
IM_ASSERT(backend_tex->Texture == binding->texture);
SDL_ReleaseGPUTexture(bd->InitInfo.Device, backend_tex->Texture);
IM_DELETE(backend_tex);
SDL_GPUTexture* raw_tex = (SDL_GPUTexture*)(intptr_t)tex->GetTexID();
if (raw_tex != nullptr)
SDL_ReleaseGPUTexture(bd->InitInfo.Device, raw_tex);
// Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
tex->SetTexID(ImTextureID_Invalid);
tex->SetStatus(ImTextureStatus_Destroyed);
tex->BackendUserData = nullptr;
}
void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex)
@@ -322,7 +325,6 @@ void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex)
//IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
ImGui_ImplSDLGPU3_Texture* backend_tex = IM_NEW(ImGui_ImplSDLGPU3_Texture)();
// Create texture
SDL_GPUTextureCreateInfo texture_info = {};
@@ -335,19 +337,16 @@ void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex)
texture_info.num_levels = 1;
texture_info.sample_count = SDL_GPU_SAMPLECOUNT_1;
backend_tex->Texture = SDL_CreateGPUTexture(v->Device, &texture_info);
backend_tex->TextureSamplerBinding.texture = backend_tex->Texture;
backend_tex->TextureSamplerBinding.sampler = bd->TexSampler;
IM_ASSERT(backend_tex->Texture && "Failed to create font texture, call SDL_GetError() for more info");
SDL_GPUTexture* raw_tex = SDL_CreateGPUTexture(v->Device, &texture_info);
IM_ASSERT(raw_tex != nullptr && "Failed to create font texture, call SDL_GetError() for more info");
// Store identifiers
tex->SetTexID((ImTextureID)(intptr_t)&backend_tex->TextureSamplerBinding);
tex->BackendUserData = backend_tex;
tex->SetTexID((ImTextureID)(intptr_t)raw_tex);
}
if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates)
{
ImGui_ImplSDLGPU3_Texture* backend_tex = (ImGui_ImplSDLGPU3_Texture*)tex->BackendUserData;
SDL_GPUTexture* raw_tex = (SDL_GPUTexture*)(intptr_t)tex->GetTexID();
IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
// Update full texture or selected blocks. We only ever write to textures regions which have never been used before!
@@ -385,7 +384,7 @@ void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex)
transfer_info.transfer_buffer = bd->TexTransferBuffer;
SDL_GPUTextureRegion texture_region = {};
texture_region.texture = backend_tex->Texture;
texture_region.texture = raw_tex;
texture_region.x = (Uint32)upload_x;
texture_region.y = (Uint32)upload_y;
texture_region.w = (Uint32)upload_w;

View File

@@ -2,7 +2,7 @@
// This needs to be used along with the SDL3 Platform Backend
// Implemented features:
// [X] Renderer: User texture binding. Use simply cast a reference to your SDL_GPUTextureSamplerBinding to ImTextureID.
// [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct.
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
@@ -49,4 +49,14 @@ IMGUI_IMPL_API void ImGui_ImplSDLGPU3_DestroyDeviceObjects();
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
IMGUI_IMPL_API void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex);
// [BETA] Selected render state data shared with callbacks.
// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplSDLGPU3_RenderDrawData() call.
// (Please open an issue if you feel you need access to more data)
struct ImGui_ImplSDLGPU3_RenderState
{
SDL_GPUDevice* Device;
SDL_GPUSampler* SamplerDefault; // Default sampler (bilinear filtering)
SDL_GPUSampler* SamplerCurrent; // Current sampler (may be changed by callback)
};
#endif // #ifndef IMGUI_DISABLE

View File

@@ -169,9 +169,8 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer*
ImVec2 clip_scale = render_scale;
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* draw_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data;
const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data;

View File

@@ -189,9 +189,8 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer*
ImVec2 clip_scale = render_scale;
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* draw_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data;
const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data;

View File

@@ -27,6 +27,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2025-07-27: Vulkan: Fixed texture update corruption introduced on 2025-06-11. (#8801, #8755, #8840)
// 2025-07-07: Vulkan: Fixed texture synchronization issue introduced on 2025-06-11. (#8772)
// 2025-06-27: Vulkan: Fixed validation errors during texture upload/update by aligning upload size to 'nonCoherentAtomSize'. (#8743, #8744)
// 2025-06-11: Vulkan: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplVulkan_CreateFontsTexture() and ImGui_ImplVulkan_DestroyFontsTexture().
@@ -550,9 +551,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
check_vk_result(err);
err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)&idx_dst);
check_vk_result(err);
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
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;
@@ -588,11 +588,11 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
VkDescriptorSet last_desc_set = VK_NULL_HANDLE;
int global_vtx_offset = 0;
int global_idx_offset = 0;
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* draw_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
@@ -604,6 +604,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height);
else
pcmd->UserCallback(draw_list, pcmd);
last_desc_set = VK_NULL_HANDLE;
}
else
{
@@ -629,7 +630,9 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
// 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);
if (desc_set != last_desc_set)
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &desc_set, 0, nullptr);
last_desc_set = desc_set;
// Draw
vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
@@ -820,7 +823,7 @@ void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex)
VkImageMemoryBarrier copy_barrier[1] = {};
copy_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
copy_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
copy_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
copy_barrier[0].oldLayout = (tex->Status == ImTextureStatus_WantCreate) ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
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;

View File

@@ -367,7 +367,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
// Avoid rendering when minimized
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdListsCount == 0)
if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0)
return;
// Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
@@ -442,9 +442,8 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
// Upload vertex/index data into a single contiguous GPU buffer
ImDrawVert* vtx_dst = (ImDrawVert*)fr->VertexBufferHost;
ImDrawIdx* idx_dst = (ImDrawIdx*)fr->IndexBufferHost;
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
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;
@@ -471,9 +470,8 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
int global_idx_offset = 0;
ImVec2 clip_scale = draw_data->FramebufferScale;
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* draw_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];

View File

@@ -245,9 +245,8 @@ void MyImGuiBackend_RenderDrawData(ImDrawData* draw_data)
// Render command lists
ImVec2 clip_off = draw_data->DisplayPos;
ImVec2 clip_scale = draw_data->FramebufferScale;
for (int n = 0; n < draw_data->CmdListsCount; n++)
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)

View File

@@ -35,6 +35,93 @@ HOW TO UPDATE?
and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users.
- Please report any issue!
-----------------------------------------------------------------------
VERSION 1.92.2 (Released 2025-08-11)
-----------------------------------------------------------------------
Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.92.2
Breaking Changes:
- Tabs: Renamed ImGuiTabBarFlags_FittingPolicyResizeDown to ImGuiTabBarFlags_FittingPolicyShrink.
Kept inline redirection enum (will obsolete). (#261, #351)
- Backends: SDL_GPU3: changed ImTextureID type from SDL_GPUTextureSamplerBinding* to SDL_GPUTexture*,
which is more natural and easier for user to manage. If you need to change the current sampler,
you can access the ImGui_ImplSDLGPU3_RenderState struct. (#8866, #8163, #7998, #7988)
Other Changes:
- Fixed an old inconsistency between IsItemHovered() and internal hovering check,
where IsItemHovered() would return true to mouse was first clicked on the
background of a non-moveable window then moved over the item or button.
Note that while it is consistent with other logic, there is a possibility
that some third-party code may accidentally relied on this. One can always use
ImGuiHoveredFlags_AllowWhenBlockedByActiveItem to bypass the active id check.
(#8877) [@achabense, @ocornut]
- Fonts: fixed an issue when a font using MergeMode has a reference size
specified but the target font doesn't. Usually either all fonts should
have a reference size (only required when specifying e.g. GlyphOffset),
or none should have a reference size.
- Fonts: fixed a crash when changing texture format when using a legacy
backend. Most commonly would happen when calling GetTexDataAsRGBA32()
then immediately calling GetTexDataAsAlpha8(). (#8824)
- Windows: fixed an issue where resizable child windows would emit border
logic when hidden/non-visible (e.g. when in a docked window that is not
selected), impacting code not checking for BeginChild() return value. (#8815)
- Textures: Fixed support for `#define ImTextureID_Invalid` to non-zero value:
ImFontAtlas() was incorrectly cleared with zeroes. (#8860, #8745) [@cfillion]
- Tables: fixed TableGetRowIndex() which never correctly worked when using
a clipper (it exists for consistency but is almost never used, as it is
often more convenient to use index in caller-code, whereas TableGetRowIndex()
includes header rows).
- Tables: fixed imgui_internal.h's TableGetHoveredRow() the same way. (#7350, #6588, #6250)
- Tabs: added new fitting policy ImGuiTabBarFlags_FittingPolicyMixed
and made it the default. This policy shrink tab width down to a given amount,
and then beyond that it enable scrolling buttons. (#3421, #8800)
- Tabs: added style.TabMinWidthShrink, ImGuiStyleVar_TabMinWidthShrink to
control the width to shrink to in ImGuiTabBarFlags_FittingPolicyMixed mode.
(#3421, #8800).
- Tabs: when scrolling is enabled, track selected tabs when resizing down
parent container. This does not prevent to horizontally scroll it out of
view during normal operations. (#3421, #8800)
- Tabs: added style.TabMinWidthBase, ImGuiStyleVar_TabMinWidthBase to control
the base minimum width of a tab (default to 1.0f). This is the size before
any potential shrinking is applied.
- Tabs: fixed tab bar underline not drawing below scroll buttons, when
they are enabled (minor regression from 1.90). (#6820, #4859, #5022, #5239)
- Tabs: made scrolling buttons never keyboard/gamepad navigation candidates.
- Nav, Tables: fixed navigation within scrolling tables when item boundaries
goes beyond columns limits. The fix done in 1.89.6 didn't work correctly
on scrolling windows. (#8816, #2221)
- Nav: fixed a bug where ImGuiKey_NavGamepadMenu (==ImGuiKey_GamepadFaceLeft)
button couldn't toggle between main and menu layers while navigating a Modal
window. (#8834)
- Error Handling: minor improvements to error handling for TableGetSortSpecs()
and TableSetBgColor() calls. (#1651, #8499)
- Misc: fixed building with IMGUI_DISABLE_DEBUG_TOOLS only. (#8796)
- Misc: fixed building with IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION. (#8794)
- Misc: removed more redundant inline static linkage from imgui_internal.h to
facilitate using in C++ modules. (#8813, #8682, #8358) [@stripe2933]
- Misc: ImVector: skip memcpy in operator= if `Data` isn't initialized in order
to play nice with -fsanitize=undefined. (#8874) [@i25e]
- CI: Added SDL3 builds to MacOS and Windows. (#8819, #8778) [@scribam]
- CI: Updated Windows CI to use a more recent SDL2. (#8819, #8778) [@scribam]
- Examples: SDL3+Metal: added SDL3+Metal example. (#8827, #8825) [@shi-yan]
- Examples: SDL3+SDL_GPU: use SDL_WaitAndAcquireGPUSwapchainTexture() instead
of SDL_AcquireGPUSwapchainTexture(). (#8830) [@itsdanott]
- Examples: SDL3+SDL_GPU: use SDL_GPU_PRESENTMODE_VSYNC present mode.
- Backends: OpenGL3: add and call embedded loader shutdown in ImGui_ImplOpenGL3_Shutdown()
to facilitate multiple init/shutdown cycles in same process. (#8792) [@tim-rex]
- Backends: OpenGL2, OpenGL3: set GL_UNPACK_ALIGNMENT to 1 before updating
textures. (#8802) [@Daandelange]
- Backends: SDL_GPU3: expose current SDL_GPUSampler* in the ImGui_ImplSDLGPU3_RenderState
struct. (#8866, #8163, #7998, #7988)
- Backends: Vulkan: Fixed texture update corruption introduced in 1.92.0,
affecting some drivers/setups. (#8801, #8755, #8840) [@Retro52, @Miolith]
- Backends: Vulkan: Avoid calling vkCmdBindDescriptorSets() when texture
has not changed. (#8666) [@micb25]
-----------------------------------------------------------------------
VERSION 1.92.1 (Released 2025-07-09)
-----------------------------------------------------------------------
@@ -56,6 +143,8 @@ Changes:
to pass full range of information into e.g. FreeType's face_index, as higher
bits are used from FreeType 2.6.1. (#8775) [@Valakor]
(the field has been erroneously reduced from 32-bits to 8-bit in 1.92.0)
- Fonts, Tables: fixed PushFont() having no effect when called after submitting
a hidden column. (#8865)
- Textures: Fixed support for `#define ImTextureID_Invalid` to non-zero value:
ImTextureData() was incorrectly cleared with zeroes. (#8745) [@rachit7645]
- Demo: Added "Text -> Font Size" demo section. (#8738) [@Demonese]
@@ -64,13 +153,13 @@ Changes:
- Debug Tools: added IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS to detect
id conflicts _before_ hovering. This is very slow and should only be used
temporarily. (#8651, #7961, #7669)
- Examples: GLFW+OpenGL3, GLFW+WGPU: Emscripten Makefiles uses GLFW port
- Examples: GLFW+OpenGL3, GLFW+WGPU: Emscripten Makefiles uses GLFW port
'contrib.glfw3' which offers better HiDPI support. (#8742) [@pthom]
- Backends: GLFW, SDL2 made ImGui_ImplGLFW_GetContentScaleXXX() and
ImGui_ImplSDL2_GetContentScaleXXXX() helpers return 1.0f on Emscripten
- Backends: GLFW, SDL2 made ImGui_ImplGLFW_GetContentScaleXXX() and
ImGui_ImplSDL2_GetContentScaleXXXX() helpers return 1.0f on Emscripten
and Android platforms, matching macOS logic. (#8742, #8733) [@pthom]
- Backends: SDL3: avoid calling SDL_StartTextInput() again if already active.
(fixes e.g.: an issue on iOS where the keyboard animation will popup every
(fixes e.g.: an issue on iOS where the keyboard animation will popup every
time the user types a key + probably other things) (#8727) [@morrazzzz]
- Backends: OSX: added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress
mouse cursor support. (#8739) [@cfillion]
@@ -162,6 +251,10 @@ Breaking changes:
- You can use `Metrics/Debugger->Fonts->Font->Input Glyphs Overlap Detection Tool` to
see list of glyphs available in multiple font sources. This can facilitate understanding
which font input is providing which glyph.
- Fonts: **IMPORTANT** on Thread Safety:
- A few functions such as font->CalcTextSizeA() were by sheer luck (== accidentally)
thread-safe even thou we had never provided that guarantee before. They are
definitively not thread-safe anymore as new glyphs may be loaded.
- Textures:
- All API functions taking a 'ImTextureID' parameter are now taking a 'ImTextureRef':

View File

@@ -149,6 +149,10 @@ SDL2 (Win32, Mac, Linux, etc.) + Vulkan example. <BR>
This is quite long and tedious, because: Vulkan. <BR>
For this example, the main.cpp file exceptionally use helpers function from imgui_impl_vulkan.h/cpp.
[example_sdl3_metal/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_metal/) <BR>
SDL3 + Metal example (Mac). <BR>
= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_metal.mm <BR>
[example_sdl3_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_opengl3/) <BR>
SDL3 (Win32, Mac, Linux, etc.) + OpenGL3+/ES2/ES3 example. <BR>
= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_opengl3.cpp <BR>

View File

@@ -389,8 +389,8 @@ node open/closed state differently. See what makes more sense in your situation!
### Q: What are ImTextureID/ImTextureRef?
**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.
- To load and display your own textures, 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).
- 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.
@@ -398,12 +398,20 @@ node open/closed state differently. See what makes more sense in your situation!
**Details:**
1.92 introduced `ImTextureRef` in June 2025.
- Most drawing functions using ImTextureID were changed to use ImTextureRef.
- We intentionally do not provide an implicit ImTextureRef -> ImTextureID cast operator because it is technically lossy to convert ImTextureRef to ImTextureID before rendering.
- All drawing functions using `ImTextureID` were changed to use `ImTextureRef`.
- You can trivially create a `ImTextureRef` from a `ImTextureID`.
- **If you use Image functions with textures that you have loaded/created yourself, you will mostly likely only ever store/manipulate `ImTextureID` and then pass them as `ImTextureRef`.**
- You only NEED to manipulate `ImTextureRef` when dealing with textures managed by the backend itself, aka mainly the atlas texture for now.
- We intentionally do not provide an implicit `ImTextureRef` -> `ImTextureID` cast operator because it is technically lossy to convert ImTextureRef to ImTextureID before rendering.
**ImTextureID = backend specific, low-level identifier for a texture uploaded in GPU/graphics system.**
```cpp
#ifndef ImTextureID
typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or integer). A majority of backends are ok with that.
#endif
```
- When a Rendered Backend creates a texture, it store its native identifier into a ImTextureID value (e.g. Used by DX11 backend to a `ID3D11ShaderResourceView*`; Used by OpenGL backends to store `GLuint`; Used by SDLGPU backend to store a `SDL_GPUTextureSamplerBinding*`, etc.).
- User may submit their own textures to e.g. ImGui::Image() function by passing the same type.
- User may submit their own textures to e.g. `ImGui::Image()` function by passing this value.
- During the rendering loop, the Renderer Backend retrieve the ImTextureID, which stored inside a ImTextureRef, which is stored inside ImDrawCmd.
- Compile-time type configuration:
- To use something other than a 64-bit value: add '#define ImTextureID MyTextureType*' in your imconfig.h file.
@@ -411,13 +419,29 @@ node open/closed state differently. See what makes more sense in your situation!
- You may decide to store a higher-level structure containing texture, sampler, shader etc. with various constructors if you like. You will need to implement ==/!= operators.
**ImTextureRef = higher-level identifier for a texture.**
```cpp
// Store a ImTextureID _or_ a ImTextureData*.
struct ImTextureRef
{
ImTextureRef() { _TexData = NULL; _TexID = ImTextureID_Invalid; }
ImTextureRef(ImTextureID tex_id) { _TexData = NULL; _TexID = tex_id; }
inline ImTextureID GetTexID() const { return _TexData ? _TexData->TexID : _TexID; }
// Members (either are set, never both!)
ImTextureData* _TexData; // A texture, generally owned by a ImFontAtlas. Will convert to ImTextureID during render loop, after texture has been uploaded.
ImTextureID _TexID; // _OR_ Low-level backend texture identifier, if already uploaded or created by user/app. Generally provided to e.g. ImGui::Image() calls.
};
```
- The identifier is valid even before the texture has been uploaded to the GPU/graphics system.
- This is what gets passed to functions such as `ImGui::Image()`, `ImDrawList::AddImage()`.
- This is what gets stored in draw commands (`ImDrawCmd`) to identify a texture during rendering.
- When a texture is created by user code (e.g. custom images), we directly stores the low-level `ImTextureID`.
- When a texture is created by the backend, we stores a `ImTextureData*` which becomes an indirection to extract the `ImTextureID` value during rendering, after texture upload has happened.
- There is no constructor to create a `ImTextureID` from a `ImTextureData*` as we don't expect this to be useful to the end-user, and it would be erroneously called by many legacy code.
- If you want to bind the current atlas when using custom rectangle, you can use `io.Fonts->TexRef`.
- When a texture is created by user code (e.g. custom images), we directly store the low-level `ImTextureID`.
- Because of this, when displaying your own texture you are likely to ever only manage ImTextureID values on your side.
- When a texture is created by the backend, we store a `ImTextureData*` which becomes an indirection to extract the `ImTextureID` value during rendering, after texture upload has happened.
- To create a `ImTextureRef` from a `ImTextureData*` you can use `ImTextureData::GetTexRef()`.
We intentionally do not provide an `ImTextureRef` constructor for this: we don't expect this to be frequently useful to the end-user, and it would be erroneously called by many legacy code.
- There is no constructor to create a `ImTextureRef` from a `ImTextureData*` as we don't expect this to be useful to the end-user, and it would be erroneously called by many legacy code.
- If you want to bind the current atlas when using custom rectangles, you can use `io.Fonts->TexRef`.
- Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. `inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; }`
**Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward.**

View File

@@ -16,7 +16,7 @@ Businesses: support continued development and maintenance via invoiced sponsorin
| [The Pitch](#the-pitch) - [Usage](#usage) - [How it works](#how-it-works) - [Releases & Changelogs](#releases--changelogs) - [Demo](#demo) - [Getting Started & Integration](#getting-started--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) |
| [Wiki](https://github.com/ocornut/imgui/wiki) - [Extensions](https://github.com/ocornut/imgui/wiki/Useful-Extensions) - [Language bindings & framework 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) |
### The Pitch
@@ -184,7 +184,7 @@ How to help
- See [GitHub Forum/Issues](https://github.com/ocornut/imgui/issues).
- You may help with development and submit pull requests! Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance forever. PR should be crafted both in the interest of the end-users and also to ease the maintainer into understanding and accepting it.
- See [Help wanted](https://github.com/ocornut/imgui/wiki/Help-Wanted) on the [Wiki](https://github.com/ocornut/imgui/wiki/) for some more ideas.
- Be a [Funding Supporter](https://github.com/ocornut/imgui/wiki/Funding)! Have your company financially support this project via invoiced sponsors/maintenance or by buying a license for [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine) (please reach out: omar AT dearimgui DOT com).
- Be a [Funding Supporter](https://github.com/ocornut/imgui/wiki/Funding)! Have your company financially support this project via invoiced sponsors/maintenance or by buying a license for [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine) (please reach out: contact AT dearimgui DOT com).
Sponsors
--------
@@ -214,7 +214,7 @@ Omar: "I first discovered the IMGUI paradigm at [Q-Games](https://www.q-games.co
Embeds [ProggyClean.ttf](https://www.proggyfonts.net) font by Tristan Grimmer (MIT license).
<br>Embeds [stb_textedit.h, stb_truetype.h, stb_rect_pack.h](https://github.com/nothings/stb/) by Sean Barrett (public domain).
Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. Also thank you to everyone posting feedback, questions and patches on GitHub.
Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. Special thanks to Alex Evans, Patrick Doane, Marco Koegler for kindly helping. Also thank you to everyone posting feedback, questions and patches on GitHub.
License
-------

View File

@@ -0,0 +1,48 @@
#
# You will need SDL3 (http://www.libsdl.org):
# brew install sdl3
#
#CXX = g++
#CXX = clang++
EXE = example_sdl3_metal
IMGUI_DIR = ../..
SOURCES = main.mm
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_metal.mm
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
LIBS = -framework Metal -framework MetalKit -framework Cocoa -framework IOKit -framework CoreVideo -framework QuartzCore
LIBS += `pkg-config --libs sdl3`
LIBS += -L/usr/local/lib -L/opt/local/lib
CXXFLAGS += `pkg-config --cflags sdl3`
CXXFLAGS += -I/usr/local/include -I/opt/local/include
CXXFLAGS += -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
CXXFLAGS += -Wall -Wformat
CFLAGS = $(CXXFLAGS)
%.o:%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
%.o:$(IMGUI_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
%.o:$(IMGUI_DIR)/backends/%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
%.o:%.mm
$(CXX) $(CXXFLAGS) -ObjC++ -fobjc-weak -fobjc-arc -c -o $@ $<
%.o:$(IMGUI_DIR)/backends/%.mm
$(CXX) $(CXXFLAGS) -ObjC++ -fobjc-weak -fobjc-arc -c -o $@ $<
all: $(EXE)
@echo Build complete
$(EXE): $(OBJS)
$(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS)
clean:
rm -f $(EXE) $(OBJS)

View File

@@ -0,0 +1,208 @@
// Dear ImGui: standalone example application for SDL3 + Metal
// (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.)
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#include "imgui.h"
#include "imgui_impl_sdl3.h"
#include "imgui_impl_metal.h"
#include <stdio.h> // printf, fprintf
#include <SDL3/SDL.h>
#import <Metal/Metal.h>
#import <QuartzCore/QuartzCore.h>
// Main code
int main(int, char**)
{
// Setup SDL
// [If using SDL_MAIN_USE_CALLBACKS: all code below until the main loop starts would likely be your SDL_AppInit() function]
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD))
{
printf("Error: SDL_Init(): %s\n", SDL_GetError());
return -1;
}
// Create SDL window graphics context
float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
SDL_WindowFlags window_flags = SDL_WINDOW_METAL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY;
SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+Metal example", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags);
if (window == nullptr)
{
printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError());
return -1;
}
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
SDL_ShowWindow(window);
// Create Metal device _before_ creating the view/layer
id<MTLDevice> metalDevice = MTLCreateSystemDefaultDevice();
if (!metalDevice)
{
printf("Error: failed to create Metal device.\n");
SDL_DestroyWindow(window);
SDL_Quit();
return -1;
}
SDL_MetalView view = SDL_Metal_CreateView(window);
CAMetalLayer* layer = (__bridge CAMetalLayer*)SDL_Metal_GetLayer(view);
layer.device = metalDevice;
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
id<MTLCommandQueue> commandQueue = [layer.device newCommandQueue];
MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor new];
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsLight();
// Setup scaling
ImGuiStyle& style = ImGui::GetStyle();
style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose)
// Setup Platform/Renderer backends
ImGui_ImplMetal_Init(layer.device);
ImGui_ImplSDL3_InitForMetal(window);
// 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.
// - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering.
// - Read 'docs/FONTS.md' for more instructions and details.
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
//style.FontSizeBase = 20.0f;
//io.Fonts->AddFontDefault();
//io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf");
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf");
//IM_ASSERT(font != nullptr);
// Our state
bool show_demo_window = true;
bool show_another_window = false;
float clear_color[4] = { 0.45f, 0.55f, 0.60f, 1.00f };
// Main loop
bool done = false;
while (!done)
{
@autoreleasepool
{
// Poll and handle events (inputs, window resize, etc.)
// 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 using SDL_MAIN_USE_CALLBACKS: call ImGui_ImplSDL3_ProcessEvent() from your SDL_AppEvent() function]
SDL_Event event;
while (SDL_PollEvent(&event))
{
ImGui_ImplSDL3_ProcessEvent(&event);
if (event.type == SDL_EVENT_QUIT)
done = true;
if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window))
done = true;
}
// [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppIterate() function]
if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)
{
SDL_Delay(10);
continue;
}
int width, height;
SDL_GetWindowSizeInPixels(window, &width, &height);
layer.drawableSize = CGSizeMake(width, height);
id<CAMetalDrawable> drawable = [layer nextDrawable];
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(clear_color[0] * clear_color[3], clear_color[1] * clear_color[3], clear_color[2] * clear_color[3], clear_color[3]);
renderPassDescriptor.colorAttachments[0].texture = drawable.texture;
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
id <MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
[renderEncoder pushDebugGroup:@"ImGui demo"];
// Start the Dear ImGui frame
ImGui_ImplMetal_NewFrame(renderPassDescriptor);
ImGui_ImplSDL3_NewFrame();
ImGui::NewFrame();
// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window);
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
{
static float f = 0.0f;
static int counter = 0;
ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
counter++;
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}
// 3. Show another simple window.
if (show_another_window)
{
ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
ImGui::Text("Hello from another window!");
if (ImGui::Button("Close Me"))
show_another_window = false;
ImGui::End();
}
// Rendering
ImGui::Render();
ImDrawData* draw_data = ImGui::GetDrawData();
ImGui_ImplMetal_RenderDrawData(draw_data, commandBuffer, renderEncoder);
[renderEncoder popDebugGroup];
[renderEncoder endEncoding];
[commandBuffer presentDrawable:drawable];
[commandBuffer commit];
}
}
// Cleanup
// [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppQuit() function]
ImGui_ImplMetal_Shutdown();
ImGui_ImplSDL3_Shutdown();
ImGui::DestroyContext();
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}

View File

@@ -1,4 +1,5 @@
// Dear ImGui: standalone example application for SDL3 + SDL_GPU
// (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.)
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
@@ -59,7 +60,7 @@ int main(int, char**)
printf("Error: SDL_ClaimWindowForGPUDevice(): %s\n", SDL_GetError());
return -1;
}
SDL_SetGPUSwapchainParameters(gpu_device, window, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_MAILBOX);
SDL_SetGPUSwapchainParameters(gpu_device, window, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_VSYNC);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
@@ -154,7 +155,7 @@ int main(int, char**)
ImGui::Checkbox("Another Window", &show_another_window);
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit4("clear color", (float*)&clear_color); // Edit 3 floats representing a color
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
counter++;
@@ -183,7 +184,7 @@ int main(int, char**)
SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(gpu_device); // Acquire a GPU command buffer
SDL_GPUTexture* swapchain_texture;
SDL_AcquireGPUSwapchainTexture(command_buffer, window, &swapchain_texture, nullptr, nullptr); // Acquire a swapchain texture
SDL_WaitAndAcquireGPUSwapchainTexture(command_buffer, window, &swapchain_texture, nullptr, nullptr); // Acquire a swapchain texture
if (swapchain_texture != nullptr && !is_minimized)
{

View File

@@ -15,7 +15,7 @@
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <GL/GL.h>
#include <GL/gl.h>
#include <tchar.h>
// Data stored per platform window

261
imgui.cpp
View File

@@ -1,4 +1,4 @@
// dear imgui, v1.92.1
// dear imgui, v1.92.2
// (main code and documentation)
// Help:
@@ -24,7 +24,7 @@
// For first-time users having issues compiling/linking/running:
// 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.
// Since 1.92, we encourage font loading question to also be posted in 'Issues'.
// Since 1.92, we encourage font loading questions to also be posted in 'Issues'.
// Copyright (c) 2014-2025 Omar Cornut
// Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
@@ -78,7 +78,7 @@ CODE
// [SECTION] RENDER HELPERS
// [SECTION] INITIALIZATION, SHUTDOWN
// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
// [SECTION] FONTS
// [SECTION] FONTS, TEXTURES
// [SECTION] ID STACK
// [SECTION] INPUTS
// [SECTION] ERROR CHECKING, STATE RECOVERY
@@ -392,7 +392,9 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
- 2025/06/25 (1.92.0) - layout: commented out legacy ErrorCheckUsingSetCursorPosToExtendParentBoundaries() fallback obsoleted in 1.89 (August 2022) which allowed a SetCursorPos()/SetCursorScreenPos() call WITHOUT AN ITEM
- 2025/08/08 (1.92.2) - Backends: SDL_GPU3: Changed ImTextureID type from SDL_GPUTextureSamplerBinding* to SDL_GPUTexture*, which is more natural and easier for user to manage. If you need to change the current sampler, you can access the ImGui_ImplSDLGPU3_RenderState struct. (#8866, #8163, #7998, #7988)
- 2025/07/31 (1.92.2) - Tabs: Renamed ImGuiTabBarFlags_FittingPolicyResizeDown to ImGuiTabBarFlags_FittingPolicyShrink. Kept inline redirection enum (will obsolete).
- 2025/06/25 (1.92.0) - Layout: commented out legacy ErrorCheckUsingSetCursorPosToExtendParentBoundaries() fallback obsoleted in 1.89 (August 2022) which allowed a SetCursorPos()/SetCursorScreenPos() call WITHOUT AN ITEM
to extend parent window/cell boundaries. Replaced with assert/tooltip that would already happens if previously using IMGUI_DISABLE_OBSOLETE_FUNCTIONS. (#5548, #4510, #3355, #1760, #1490, #4152, #150)
- Incorrect way to make a window content size 200x200:
Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End();
@@ -432,6 +434,8 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
cfg2.MergeMode = true;
io.Fonts->AddFontFromFileTTF("FontAwesome4.ttf", 0.0f, &cfg2);
- You can use `Metrics/Debugger->Fonts->Font->Input Glyphs Overlap Detection Tool` to see list of glyphs available in multiple font sources. This can facilitate unde
- Fonts: **IMPORTANT** on Thread Safety:
- A few functions such as font->CalcTextSizeA() were, by sheer luck (== accidentally) thread-safe even thou we had never provided that guarantee. They are definitively not thread-safe anymore as new glyphs may be loaded.
- Fonts: ImFont::FontSize was removed and does not make sense anymore. ImFont::LegacySize is the size passed to AddFont().
- Fonts: Removed support for PushFont(NULL) which was a shortcut for "default font".
- Fonts: Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'.
@@ -1287,7 +1291,7 @@ static float NavUpdatePageUpPageDown();
static inline void NavUpdateAnyRequestFlag();
static void NavUpdateCreateWrappingRequest();
static void NavEndFrame();
static bool NavScoreItem(ImGuiNavItemData* result);
static bool NavScoreItem(ImGuiNavItemData* result, const ImRect& nav_bb);
static void NavApplyItemToResult(ImGuiNavItemData* result);
static void NavProcessItem();
static void NavProcessItemForTabbingRequest(ImGuiID id, ImGuiItemFlags item_flags, ImGuiNavMoveFlags move_flags);
@@ -1415,6 +1419,8 @@ ImGuiStyle::ImGuiStyle()
ImageBorderSize = 0.0f; // Thickness of border around tabs.
TabRounding = 5.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
TabBorderSize = 0.0f; // Thickness of border around tabs.
TabMinWidthBase = 1.0f; // Minimum tab width, to make tabs larger than their contents. TabBar buttons are not affected.
TabMinWidthShrink = 80.0f; // Minimum tab width after shrinking, when using ImGuiTabBarFlags_FittingPolicyMixed policy.
TabCloseButtonMinWidthSelected = -1.0f; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width.
TabCloseButtonMinWidthUnselected = 0.0f; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never show close button when unselected.
TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
@@ -1481,6 +1487,8 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor)
LogSliderDeadzone = ImTrunc(LogSliderDeadzone * scale_factor);
ImageBorderSize = ImTrunc(ImageBorderSize * scale_factor);
TabRounding = ImTrunc(TabRounding * scale_factor);
TabMinWidthBase = ImTrunc(TabMinWidthBase * scale_factor);
TabMinWidthShrink = ImTrunc(TabMinWidthShrink * scale_factor);
TabCloseButtonMinWidthSelected = (TabCloseButtonMinWidthSelected > 0.0f && TabCloseButtonMinWidthSelected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthSelected * scale_factor) : TabCloseButtonMinWidthSelected;
TabCloseButtonMinWidthUnselected = (TabCloseButtonMinWidthUnselected > 0.0f && TabCloseButtonMinWidthUnselected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthUnselected * scale_factor) : TabCloseButtonMinWidthUnselected;
TabBarOverlineSize = ImTrunc(TabBarOverlineSize * scale_factor);
@@ -2582,11 +2590,11 @@ static inline int ImTextCharToUtf8_inline(char* buf, int buf_size, unsigned int
return 0;
}
const char* ImTextCharToUtf8(char out_buf[5], unsigned int c)
int ImTextCharToUtf8(char out_buf[5], unsigned int c)
{
int count = ImTextCharToUtf8_inline(out_buf, 5, c);
out_buf[count] = 0;
return out_buf;
return count;
}
// Not optimal but we very rarely use this function.
@@ -3123,7 +3131,7 @@ static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_
ImGui::TableEndRow(table);
table->RowPosY2 = window->DC.CursorPos.y;
const int row_increase = (int)((off_y / line_height) + 0.5f);
//table->CurrentRow += row_increase; // Can't do without fixing TableEndRow()
table->CurrentRow += row_increase;
table->RowBgColorCounter += row_increase;
}
}
@@ -3500,6 +3508,8 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] =
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ImageBorderSize) }, // ImGuiStyleVar_ImageBorderSize
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabBorderSize) }, // ImGuiStyleVar_TabBorderSize
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabMinWidthBase) }, // ImGuiStyleVar_TabMinWidthBase
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabMinWidthShrink) }, // ImGuiStyleVar_TabMinWidthShrink
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabBarBorderSize) }, // ImGuiStyleVar_TabBarBorderSize
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabBarOverlineSize) }, // ImGuiStyleVar_TabBarOverlineSize
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersAngle)}, // ImGuiStyleVar_TableAngledHeadersAngle
@@ -4501,15 +4511,6 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
// Clear previous active id
if (g.ActiveId != 0)
{
// While most behaved code would make an effort to not steal active id during window move/drag operations,
// we at least need to be resilient to it. Canceling the move is rather aggressive and users of 'master' branch
// may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that.
if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId)
{
IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n");
g.MovingWindow = NULL;
}
// Store deactivate data
ImGuiDeactivatedItemData* deactivated_data = &g.DeactivatedItemData;
deactivated_data->ID = g.ActiveId;
@@ -4522,6 +4523,15 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
// One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveID()
if (g.InputTextState.ID == g.ActiveId)
InputTextDeactivateHook(g.ActiveId);
// While most behaved code would make an effort to not steal active id during window move/drag operations,
// we at least need to be resilient to it. Canceling the move is rather aggressive and users of 'master' branch
// may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that.
if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId)
{
IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n");
StopMouseMovingWindow();
}
}
// Set active id
@@ -4646,7 +4656,6 @@ static ImGuiHoveredFlags ApplyHoverFlagsForTooltip(ImGuiHoveredFlags user_flags,
}
// This is roughly matching the behavior of internal-facing ItemHoverable()
// - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered()
// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId
bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
{
@@ -4688,8 +4697,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
const ImGuiID id = g.LastItemData.ID;
if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0)
if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
if (g.ActiveId != window->MoveId)
return false;
return false;
// Test if interactions on this window are blocked by an active popup or modal.
// The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here.
@@ -5075,6 +5083,19 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
g.MovingWindow = window;
}
// This is not 100% symetric with StartMouseMovingWindow().
// We do NOT clear ActiveID, because:
// - It would lead to rather confusing recursive code paths. Caller can call ClearActiveID() if desired.
// - Some code intentionally cancel moving but keep the ActiveID to lock inputs (e.g. code path taken when clicking a disabled item).
void ImGui::StopMouseMovingWindow()
{
ImGuiContext& g = *GImGui;
// [nb: docking branch has more stuff in this function]
g.MovingWindow = NULL;
}
// Handle mouse moving window
// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing()
// FIXME: We don't have strong guarantee that g.MovingWindow stay synced with g.ActiveId == g.MovingWindow->MoveId.
@@ -5098,7 +5119,7 @@ void ImGui::UpdateMouseMovingWindowNewFrame()
}
else
{
g.MovingWindow = NULL;
StopMouseMovingWindow();
ClearActiveID();
}
}
@@ -5140,6 +5161,9 @@ void ImGui::UpdateMouseMovingWindowEndFrame()
{
StartMouseMovingWindow(g.HoveredWindow); //-V595
// FIXME: In principal we might be able to call StopMouseMovingWindow() below.
// Please note how StartMouseMovingWindow() and StopMouseMovingWindow() and not entirely symetrical, at the later doesn't clear ActiveId.
// Cancel moving if clicked outside of title bar
if (g.IO.ConfigWindowsMoveFromTitleBarOnly)
if (!(root_window->Flags & ImGuiWindowFlags_NoTitleBar))
@@ -5261,46 +5285,6 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos)
io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
}
static void ImGui::UpdateTexturesNewFrame()
{
// Cannot update every atlases based on atlas's FrameCount < g.FrameCount, because an atlas may be shared by multiple contexts with different frame count.
ImGuiContext& g = *GImGui;
const bool has_textures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0;
for (ImFontAtlas* atlas : g.FontAtlases)
{
if (atlas->OwnerContext == &g)
{
ImFontAtlasUpdateNewFrame(atlas, g.FrameCount, has_textures);
}
else
{
// (1) If you manage font atlases yourself, e.g. create a ImFontAtlas yourself you need to call ImFontAtlasUpdateNewFrame() on it.
// Otherwise, calling ImGui::CreateContext() without parameter will create an atlas owned by the context.
// (2) If you have multiple font atlases, make sure the 'atlas->RendererHasTextures' as specified in the ImFontAtlasUpdateNewFrame() call matches for that.
// (3) If you have multiple imgui contexts, they also need to have a matching value for ImGuiBackendFlags_RendererHasTextures.
IM_ASSERT(atlas->Builder != NULL && atlas->Builder->FrameCount != -1);
IM_ASSERT(atlas->RendererHasTextures == has_textures);
}
}
}
// Build a single texture list
static void ImGui::UpdateTexturesEndFrame()
{
ImGuiContext& g = *GImGui;
g.PlatformIO.Textures.resize(0);
for (ImFontAtlas* atlas : g.FontAtlases)
for (ImTextureData* tex : atlas->TexList)
{
// We provide this information so backends can decide whether to destroy textures.
// This means in practice that if N imgui contexts are created with a shared atlas, we assume all of them have a backend initialized.
tex->RefCount = (unsigned short)atlas->RefCount;
g.PlatformIO.Textures.push_back(tex);
}
for (ImTextureData* tex : g.UserTextures)
g.PlatformIO.Textures.push_back(tex);
}
// Called once a frame. Followed by SetCurrentFont() which sets up the remaining data.
// FIXME-VIEWPORT: the concept of a single ClipRectFullscreen is not ideal!
static void SetupDrawListSharedData()
@@ -7618,12 +7602,19 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
}
#endif
// Decide if we are going to handle borders and resize grips
// 'window->SkipItems' is not updated yet so for child windows we rely on ParentWindow to avoid submitting decorations. (#8815)
// Whenever we add support for full decorated child windows we will likely make this logic more general.
bool handle_borders_and_resize_grips = true;
if ((flags & ImGuiWindowFlags_ChildWindow) && window->ParentWindow->SkipItems)
handle_borders_and_resize_grips = false;
// Handle manual resize: Resize Grips, Borders, Gamepad
int border_hovered = -1, border_held = -1;
ImU32 resize_grip_col[4] = {};
const int resize_grip_count = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup)) ? 0 : g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.
const float resize_grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
if (!window->Collapsed)
if (handle_borders_and_resize_grips && !window->Collapsed)
if (int auto_fit_mask = UpdateWindowManualResize(window, size_auto_fit, &border_hovered, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect))
{
if (auto_fit_mask & (1 << ImGuiAxis_X))
@@ -7760,7 +7751,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Handle title bar, scrollbar, resize grips and resize borders
const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow;
const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight);
const bool handle_borders_and_resize_grips = true; // This exists to facilitate merge with 'docking' branch.
RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, handle_borders_and_resize_grips, resize_grip_count, resize_grip_col, resize_grip_draw_size);
if (render_decorations_in_parent)
@@ -8671,11 +8661,13 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
}
//-----------------------------------------------------------------------------
// [SECTION] FONTS
// [SECTION] FONTS, TEXTURES
//-----------------------------------------------------------------------------
// Most of the relevant font logic is in imgui_draw.cpp.
// Those are high-level support functions.
//-----------------------------------------------------------------------------
// - UpdateTexturesNewFrame() [Internal]
// - UpdateTexturesEndFrame() [Internal]
// - UpdateFontsNewFrame() [Internal]
// - UpdateFontsEndFrame() [Internal]
// - GetDefaultFont() [Internal]
@@ -8690,6 +8682,46 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
// - PopFont()
//-----------------------------------------------------------------------------
static void ImGui::UpdateTexturesNewFrame()
{
// Cannot update every atlases based on atlas's FrameCount < g.FrameCount, because an atlas may be shared by multiple contexts with different frame count.
ImGuiContext& g = *GImGui;
const bool has_textures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0;
for (ImFontAtlas* atlas : g.FontAtlases)
{
if (atlas->OwnerContext == &g)
{
ImFontAtlasUpdateNewFrame(atlas, g.FrameCount, has_textures);
}
else
{
// (1) If you manage font atlases yourself, e.g. create a ImFontAtlas yourself you need to call ImFontAtlasUpdateNewFrame() on it.
// Otherwise, calling ImGui::CreateContext() without parameter will create an atlas owned by the context.
// (2) If you have multiple font atlases, make sure the 'atlas->RendererHasTextures' as specified in the ImFontAtlasUpdateNewFrame() call matches for that.
// (3) If you have multiple imgui contexts, they also need to have a matching value for ImGuiBackendFlags_RendererHasTextures.
IM_ASSERT(atlas->Builder != NULL && atlas->Builder->FrameCount != -1);
IM_ASSERT(atlas->RendererHasTextures == has_textures);
}
}
}
// Build a single texture list
static void ImGui::UpdateTexturesEndFrame()
{
ImGuiContext& g = *GImGui;
g.PlatformIO.Textures.resize(0);
for (ImFontAtlas* atlas : g.FontAtlases)
for (ImTextureData* tex : atlas->TexList)
{
// We provide this information so backends can decide whether to destroy textures.
// This means in practice that if N imgui contexts are created with a shared atlas, we assume all of them have a backend initialized.
tex->RefCount = (unsigned short)atlas->RefCount;
g.PlatformIO.Textures.push_back(tex);
}
for (ImTextureData* tex : g.UserTextures)
g.PlatformIO.Textures.push_back(tex);
}
void ImGui::UpdateFontsNewFrame()
{
ImGuiContext& g = *GImGui;
@@ -8732,16 +8764,19 @@ ImFont* ImGui::GetDefaultFont()
return g.IO.FontDefault ? g.IO.FontDefault : atlas->Fonts[0];
}
// EXPERIMENTAL: DO NOT USE YET.
void ImGui::RegisterUserTexture(ImTextureData* tex)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(tex->RefCount > 0);
tex->RefCount++;
g.UserTextures.push_back(tex);
}
void ImGui::UnregisterUserTexture(ImTextureData* tex)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(tex->RefCount > 0);
tex->RefCount--;
g.UserTextures.find_erase(tex);
}
@@ -8802,11 +8837,14 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling)
g.Style.FontSizeBase = g.FontSizeBase;
// Early out to avoid hidden window keeping bakes referenced and out of GC reach.
// However this would leave a pretty subtle and damning error surface area if g.FontBaked was mismatching, so for now we null it.
// However this would leave a pretty subtle and damning error surface area if g.FontBaked was mismatching.
// FIXME: perhaps g.FontSize should be updated?
if (window != NULL && window->SkipItems)
if (g.CurrentTable == NULL || g.CurrentTable->CurrentColumn != -1) // See 8465#issuecomment-2951509561. Ideally the SkipItems=true in tables would be amended with extra data.
{
ImGuiTable* table = g.CurrentTable;
if (table == NULL || (table->CurrentColumn != -1 && table->Columns[table->CurrentColumn].IsSkipItems == false)) // See 8465#issuecomment-2951509561 and #8865. Ideally the SkipItems=true in tables would be amended with extra data.
return;
}
// Restoring is pretty much only used by PopFont()
float final_size = (restore_font_size_after_scaling > 0.0f) ? restore_font_size_after_scaling : 0.0f;
@@ -10135,13 +10173,17 @@ void ImGui::SetNextFrameWantCaptureMouse(bool want_capture_mouse)
static const char* GetInputSourceName(ImGuiInputSource source)
{
const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad" };
IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && source >= 0 && source < ImGuiInputSource_COUNT);
IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
if (source < 0 || source >= ImGuiInputSource_COUNT)
return "Unknown";
return input_source_names[source];
}
static const char* GetMouseSourceName(ImGuiMouseSource source)
{
const char* mouse_source_names[] = { "Mouse", "TouchScreen", "Pen" };
IM_ASSERT(IM_ARRAYSIZE(mouse_source_names) == ImGuiMouseSource_COUNT && source >= 0 && source < ImGuiMouseSource_COUNT);
IM_ASSERT(IM_ARRAYSIZE(mouse_source_names) == ImGuiMouseSource_COUNT);
if (source < 0 || source >= ImGuiMouseSource_COUNT)
return "Unknown";
return mouse_source_names[source];
}
static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e)
@@ -12501,10 +12543,10 @@ bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags)
IM_ASSERT(cur_window); // Not inside a Begin()/End()
const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0;
if (flags & ImGuiHoveredFlags_RootWindow)
if (flags & ImGuiFocusedFlags_RootWindow)
cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy);
if (flags & ImGuiHoveredFlags_ChildWindows)
if (flags & ImGuiFocusedFlags_ChildWindows)
return IsWindowChildOf(ref_window, cur_window, popup_hierarchy);
else
return (ref_window == cur_window);
@@ -12826,7 +12868,7 @@ static float inline NavScoreItemDistInterval(float cand_min, float cand_max, flo
}
// Scoring function for keyboard/gamepad directional navigation. Based on https://gist.github.com/rygorous/6981057
static bool ImGui::NavScoreItem(ImGuiNavItemData* result)
static bool ImGui::NavScoreItem(ImGuiNavItemData* result, const ImRect& nav_bb)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
@@ -12834,7 +12876,7 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result)
return false;
// FIXME: Those are not good variables names
ImRect cand = g.LastItemData.NavRect; // Current item nav rectangle
ImRect cand = nav_bb; // Current item nav rectangle
const ImRect curr = g.NavScoringRect; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width)
g.NavScoringDebugCount++;
@@ -13001,13 +13043,13 @@ static void ImGui::NavProcessItem()
const ImGuiID id = g.LastItemData.ID;
const ImGuiItemFlags item_flags = g.LastItemData.ItemFlags;
// When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221)
// When inside a container that isn't scrollable with Left<>Right, clip NavRect accordingly (#2221, #8816)
ImRect nav_bb = g.LastItemData.NavRect;
if (window->DC.NavIsScrollPushableX == false)
{
g.LastItemData.NavRect.Min.x = ImClamp(g.LastItemData.NavRect.Min.x, window->ClipRect.Min.x, window->ClipRect.Max.x);
g.LastItemData.NavRect.Max.x = ImClamp(g.LastItemData.NavRect.Max.x, window->ClipRect.Min.x, window->ClipRect.Max.x);
nav_bb.Min.x = ImClamp(nav_bb.Min.x, window->ClipRect.Min.x, window->ClipRect.Max.x);
nav_bb.Max.x = ImClamp(nav_bb.Max.x, window->ClipRect.Min.x, window->ClipRect.Max.x);
}
const ImRect nav_bb = g.LastItemData.NavRect;
// Process Init Request
if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent && (item_flags & ImGuiItemFlags_Disabled) == 0)
@@ -13039,14 +13081,14 @@ static void ImGui::NavProcessItem()
else if (g.NavId != id || (g.NavMoveFlags & ImGuiNavMoveFlags_AllowCurrentNavId))
{
ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
if (NavScoreItem(result))
if (NavScoreItem(result, nav_bb))
NavApplyItemToResult(result);
// Features like PageUp/PageDown need to maintain a separate score for the visible set of items.
const float VISIBLE_RATIO = 0.70f;
if ((g.NavMoveFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb))
if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO)
if (NavScoreItem(&g.NavMoveResultLocalVisible))
if (NavScoreItem(&g.NavMoveResultLocalVisible, nav_bb))
NavApplyItemToResult(&g.NavMoveResultLocalVisible);
}
}
@@ -13706,6 +13748,7 @@ void ImGui::NavUpdateCreateMoveRequest()
}
}
// Prepare scoring rectangle.
// For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
ImRect scoring_rect;
if (window != NULL)
@@ -14116,6 +14159,7 @@ static void ImGui::NavUpdateWindowingApplyFocus(ImGuiWindow* apply_focus_window)
SetNavCursorVisibleAfterMove();
ClosePopupsOverWindow(apply_focus_window, false);
FocusWindow(apply_focus_window, ImGuiFocusRequestFlags_RestoreFocusedChild);
IM_ASSERT(g.NavWindow != NULL);
apply_focus_window = g.NavWindow;
if (apply_focus_window->NavLastIds[0] == 0)
NavInitWindow(apply_focus_window, false);
@@ -14164,9 +14208,16 @@ static void ImGui::NavUpdateWindowing()
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 && Shortcut(ImGuiKey_NavGamepadMenu, ImGuiInputFlags_RouteAlways, owner_id);
const bool start_toggling_with_gamepad = nav_gamepad_active && !g.NavWindowingTarget && Shortcut(ImGuiKey_NavGamepadMenu, ImGuiInputFlags_RouteAlways, owner_id);
const bool start_windowing_with_gamepad = allow_windowing && start_toggling_with_gamepad;
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_toggling_with_gamepad)
{
g.NavWindowingToggleLayer = true; // Gamepad starts toggling layer
g.NavWindowingToggleKey = ImGuiKey_NavGamepadMenu;
g.NavWindowingInputSource = g.NavInputSource = ImGuiInputSource_Gamepad;
}
if (start_windowing_with_gamepad || start_windowing_with_keyboard)
if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
{
@@ -14174,7 +14225,6 @@ static void ImGui::NavUpdateWindowing()
g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // Current location
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.NavWindowingInputSource = g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad;
if (g.NavWindow == NULL)
just_started_windowing_from_null_focus = true;
@@ -15654,10 +15704,14 @@ static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport*, ImG
//-----------------------------------------------------------------------------
// [SECTION] METRICS/DEBUGGER WINDOW
//-----------------------------------------------------------------------------
// - MetricsHelpMarker() [Internal]
// - DebugRenderViewportThumbnail() [Internal]
// - RenderViewportsThumbnails() [Internal]
// - DebugRenderKeyboardPreview() [Internal]
// - DebugTextEncoding()
// - MetricsHelpMarker() [Internal]
// - DebugFlashStyleColorStop() [Internal]
// - DebugFlashStyleColor()
// - UpdateDebugToolFlashStyleColor() [Internal]
// - ShowFontAtlas() [Internal but called by Demo!]
// - DebugNodeTexture() [Internal]
// - ShowMetricsWindow()
@@ -15675,6 +15729,21 @@ static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport*, ImG
// - DebugNodeWindowsListByBeginStackParent() [Internal]
//-----------------------------------------------------------------------------
#if !defined(IMGUI_DISABLE_DEMO_WINDOWS) || !defined(IMGUI_DISABLE_DEBUG_TOOLS)
// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds.
static void MetricsHelpMarker(const char* desc)
{
ImGui::TextDisabled("(?)");
if (ImGui::BeginItemTooltip())
{
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
#endif
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
void ImGui::DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb)
@@ -15863,19 +15932,6 @@ static const char* FormatTextureIDForDebugDisplay(char* buf, int buf_size, const
return FormatTextureIDForDebugDisplay(buf, (int)(buf_end - buf), cmd->TexRef.GetTexID()); // Calling TexRef::GetTexID() to avoid assert of cmd->GetTexID()
}
// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds.
static void MetricsHelpMarker(const char* desc)
{
ImGui::TextDisabled("(?)");
if (ImGui::BeginItemTooltip())
{
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
#ifdef IMGUI_ENABLE_FREETYPE
namespace ImGuiFreeType { IMGUI_API const ImFontLoader* GetFontLoader(); IMGUI_API bool DebugEditFontLoaderFlags(unsigned int* p_font_builder_flags); }
#endif
@@ -16917,14 +16973,16 @@ void ImGui::DebugNodeFont(ImFont* font)
#endif
char c_str[5];
Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar);
Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar);
ImTextCharToUtf8(c_str, font->FallbackChar);
Text("Fallback character: '%s' (U+%04X)", c_str, font->FallbackChar);
ImTextCharToUtf8(c_str, font->EllipsisChar);
Text("Ellipsis character: '%s' (U+%04X)", c_str, font->EllipsisChar);
for (int src_n = 0; src_n < font->Sources.Size; src_n++)
{
ImFontConfig* src = font->Sources[src_n];
if (TreeNode(src, "Input %d: \'%s\', Oversample: %d,%d, PixelSnapH: %d, Offset: (%.1f,%.1f)",
src_n, src->Name, src->OversampleH, src->OversampleV, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y))
if (TreeNode(src, "Input %d: \'%s\' [%d], Oversample: %d,%d, PixelSnapH: %d, Offset: (%.1f,%.1f)",
src_n, src->Name, src->FontNo, src->OversampleH, src->OversampleV, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y))
{
const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader;
Text("Loader: '%s'", loader->Name ? loader->Name : "N/A");
@@ -16960,7 +17018,10 @@ void ImGui::DebugNodeFont(ImFont* font)
{
char utf8_buf[5];
for (unsigned int n = c; n < c_end; n++)
BulletText("Codepoint U+%04X (%s)", n, ImTextCharToUtf8(utf8_buf, n));
{
ImTextCharToUtf8(utf8_buf, n);
BulletText("Codepoint U+%04X (%s)", n, utf8_buf);
}
TreePop();
}
TableNextColumn();

76
imgui.h
View File

@@ -1,4 +1,4 @@
// dear imgui, v1.92.1
// dear imgui, v1.92.2
// (headers)
// Help:
@@ -28,8 +28,8 @@
// Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.92.1"
#define IMGUI_VERSION_NUM 19210
#define IMGUI_VERSION "1.92.2"
#define IMGUI_VERSION_NUM 19220
#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000
#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
@@ -317,7 +317,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE
// - When a Rendered Backend creates a texture, it store its native identifier into a ImTextureID value.
// (e.g. Used by DX11 backend to a `ID3D11ShaderResourceView*`; Used by OpenGL backends to store `GLuint`;
// Used by SDLGPU backend to store a `SDL_GPUTextureSamplerBinding*`, etc.).
// - User may submit their own textures to e.g. ImGui::Image() function by passing the same type.
// - User may submit their own textures to e.g. ImGui::Image() function by passing this value.
// - During the rendering loop, the Renderer Backend retrieve the ImTextureID, which stored inside a
// ImTextureRef, which is stored inside a ImDrawCmd.
// - Compile-time type configuration:
@@ -337,15 +337,17 @@ typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or
#define ImTextureID_Invalid ((ImTextureID)0)
#endif
// ImTextureRef = higher-level identifier for a texture.
// ImTextureRef = higher-level identifier for a texture. Store a ImTextureID _or_ a ImTextureData*.
// The identifier is valid even before the texture has been uploaded to the GPU/graphics system.
// This is what gets passed to functions such as `ImGui::Image()`, `ImDrawList::AddImage()`.
// This is what gets stored in draw commands (`ImDrawCmd`) to identify a texture during rendering.
// - When a texture is created by user code (e.g. custom images), we directly stores the low-level ImTextureID.
// Because of this, when displaying your own texture you are likely to ever only manage ImTextureID values on your side.
// - When a texture is created by the backend, we stores a ImTextureData* which becomes an indirection
// to extract the ImTextureID value during rendering, after texture upload has happened.
// - There is no constructor to create a ImTextureID from a ImTextureData* as we don't expect this
// to be useful to the end-user, and it would be erroneously called by many legacy code.
// - To create a ImTextureRef from a ImTextureData you can use ImTextureData::GetTexRef().
// We intentionally do not provide an ImTextureRef constructor for this: we don't expect this
// to be frequently useful to the end-user, and it would be erroneously called by many legacy code.
// - If you want to bind the current atlas when using custom rectangle, you can use io.Fonts->TexRef.
// - Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g.
// inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; }
@@ -914,7 +916,7 @@ namespace ImGui
IMGUI_API ImGuiTableSortSpecs* TableGetSortSpecs(); // get latest sort specs for the table (NULL if not sorting). Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable().
IMGUI_API int TableGetColumnCount(); // return number of columns (value passed to BeginTable)
IMGUI_API int TableGetColumnIndex(); // return current column index.
IMGUI_API int TableGetRowIndex(); // return current row index.
IMGUI_API int TableGetRowIndex(); // return current row index (header rows are accounted for)
IMGUI_API const char* TableGetColumnName(int column_n = -1); // return "" if column didn't have a name declared by TableSetupColumn(). Pass -1 to use current column.
IMGUI_API ImGuiTableColumnFlags TableGetColumnFlags(int column_n = -1); // return column flags so you can query their Enabled/Visible/Sorted/Hovered status flags. Pass -1 to use current column.
IMGUI_API void TableSetColumnEnabled(int column_n, bool v);// change user accessible enabled/disabled state of a column. Set to false to hide the column. User can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody)
@@ -1368,10 +1370,17 @@ enum ImGuiTabBarFlags_
ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, // Disable scrolling buttons (apply when fitting policy is ImGuiTabBarFlags_FittingPolicyScroll)
ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab
ImGuiTabBarFlags_DrawSelectedOverline = 1 << 6, // Draw selected overline markers over selected tab
ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 7, // Resize tabs when they don't fit
ImGuiTabBarFlags_FittingPolicyScroll = 1 << 8, // Add scroll buttons when tabs don't fit
ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll,
ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown,
// Fitting/Resize policy
ImGuiTabBarFlags_FittingPolicyMixed = 1 << 7, // Shrink down tabs when they don't fit, until width is style.TabMinWidthShrink, then enable scrolling buttons.
ImGuiTabBarFlags_FittingPolicyShrink = 1 << 8, // Shrink down tabs when they don't fit
ImGuiTabBarFlags_FittingPolicyScroll = 1 << 9, // Enable scrolling buttons when tabs don't fit
ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyMixed | ImGuiTabBarFlags_FittingPolicyShrink | ImGuiTabBarFlags_FittingPolicyScroll,
ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyMixed,
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGuiTabBarFlags_FittingPolicyResizeDown = ImGuiTabBarFlags_FittingPolicyShrink, // Renamed in 1.92.2
#endif
};
// Flags for ImGui::BeginTabItem()
@@ -1801,6 +1810,8 @@ enum ImGuiStyleVar_
ImGuiStyleVar_ImageBorderSize, // float ImageBorderSize
ImGuiStyleVar_TabRounding, // float TabRounding
ImGuiStyleVar_TabBorderSize, // float TabBorderSize
ImGuiStyleVar_TabMinWidthBase, // float TabMinWidthBase
ImGuiStyleVar_TabMinWidthShrink, // float TabMinWidthShrink
ImGuiStyleVar_TabBarBorderSize, // float TabBarBorderSize
ImGuiStyleVar_TabBarOverlineSize, // float TabBarOverlineSize
ImGuiStyleVar_TableAngledHeadersAngle, // float TableAngledHeadersAngle
@@ -2170,7 +2181,7 @@ struct ImVector
// Constructors, destructor
inline ImVector() { Size = Capacity = 0; Data = NULL; }
inline ImVector(const ImVector<T>& src) { Size = Capacity = 0; Data = NULL; operator=(src); }
inline ImVector<T>& operator=(const ImVector<T>& src) { clear(); resize(src.Size); if (src.Data) memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; }
inline ImVector<T>& operator=(const ImVector<T>& src) { clear(); resize(src.Size); if (Data && src.Data) memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; }
inline ~ImVector() { if (Data) IM_FREE(Data); } // Important: does not destruct anything
inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } // Important: does not destruct anything
@@ -2266,6 +2277,8 @@ struct ImGuiStyle
float ImageBorderSize; // Thickness of border around Image() calls.
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 TabMinWidthBase; // Minimum tab width, to make tabs larger than their contents. TabBar buttons are not affected.
float TabMinWidthShrink; // Minimum tab width after shrinking, when using ImGuiTabBarFlags_FittingPolicyMixed policy.
float TabCloseButtonMinWidthSelected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width.
float TabCloseButtonMinWidthUnselected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never show close button when unselected.
float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
@@ -2512,10 +2525,10 @@ struct ImGuiIO
float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold SHIFT to turn vertical scroll into horizontal scroll.
float MouseWheelH; // Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends.
ImGuiMouseSource MouseSource; // Mouse actual input peripheral (Mouse/TouchScreen/Pen).
bool KeyCtrl; // Keyboard modifier down: Control
bool KeyCtrl; // Keyboard modifier down: Ctrl (non-macOS), Cmd (macOS)
bool KeyShift; // Keyboard modifier down: Shift
bool KeyAlt; // Keyboard modifier down: Alt
bool KeySuper; // Keyboard modifier down: Cmd/Super/Windows
bool KeySuper; // Keyboard modifier down: Windows/Super (non-macOS), Ctrl (macOS)
// 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()
@@ -3359,7 +3372,7 @@ struct ImDrawList
struct ImDrawData
{
bool Valid; // Only valid after Render() is called and before the next NewFrame() is called.
int CmdListsCount; // Number of ImDrawList* to render. (== CmdLists.Size). Exists for legacy reason.
int CmdListsCount; // == CmdLists.Size. (OBSOLETE: exists for legacy reasons). Number of ImDrawList* to render.
int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size
int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size
ImVector<ImDrawList*> CmdLists; // Array of ImDrawList* to render. The ImDrawLists are owned by ImGuiContext and only pointed to from here.
@@ -3424,7 +3437,7 @@ struct ImTextureRect
struct ImTextureData
{
//------------------------------------------ core / backend ---------------------------------------
int UniqueID; // w - // Sequential index to facilitate identifying a texture when debugging/printing. Unique per atlas.
int UniqueID; // w - // [DEBUG] Sequential index to facilitate identifying a texture when debugging/printing. Unique per atlas.
ImTextureStatus Status; // rw rw // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy. Always use SetStatus() to modify!
void* BackendUserData; // - rw // Convenience storage for backend. Some backends may have enough with TexID.
ImTextureID TexID; // r w // Backend-specific texture identifier. Always use SetTexID() to modify! The identifier will stored in ImDrawCmd::GetTexID() and passed to backend's RenderDrawData function.
@@ -3442,7 +3455,7 @@ struct ImTextureData
bool WantDestroyNextFrame; // rw - // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame.
// Functions
ImTextureData() { memset(this, 0, sizeof(*this)); TexID = ImTextureID_Invalid; }
ImTextureData() { memset(this, 0, sizeof(*this)); Status = ImTextureStatus_Destroyed; TexID = ImTextureID_Invalid; }
~ImTextureData() { DestroyPixels(); }
IMGUI_API void Create(ImTextureFormat format, int w, int h);
IMGUI_API void DestroyPixels();
@@ -3744,9 +3757,10 @@ struct ImFontBaked
float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled)
unsigned int MetricsTotalSurface:26;// 3 // 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)
unsigned int WantDestroy:1; // 0 // // Queued for destroy
unsigned int LockLoadingFallback:1; // 0 // //
int LastUsedFrame; // 4 // // Record of that time this was bounds
ImGuiID BakedId; // 4 //
unsigned int LoadNoFallback:1; // 0 // // Disable loading fallback in lower-level calls.
unsigned int LoadNoRenderOnLayout:1;// 0 // // Enable a two-steps mode where CalcTextSize() calls will load AdvanceX *without* rendering/packing glyphs. Only advantagous if you know that the glyph is unlikely to actually be rendered, otherwise it is slower because we'd do one query on the first CalcTextSize and one query on the first Draw.
int LastUsedFrame; // 4 // // Record of that time this was bounds
ImGuiID BakedId; // 4 // // Unique ID for this baked storage
ImFont* ContainerFont; // 4-8 // in // Parent font
void* FontLoaderDatas; // 4-8 // // Font loader opaque storage (per baked font * sources): single contiguous buffer allocated by imgui, passed to loader.
@@ -3956,24 +3970,24 @@ struct ImGuiPlatformImeData
namespace ImGui
{
// OBSOLETED in 1.92.0 (from June 2025)
static inline void PushFont(ImFont* font) { PushFont(font, font ? font->LegacySize : 0.0f); }
inline void PushFont(ImFont* font) { PushFont(font, font ? font->LegacySize : 0.0f); }
IMGUI_API void SetWindowFontScale(float scale); // Set font scale factor for current window. Prefer using PushFont(NULL, style.FontSizeBase * factor) or use style.FontScaleMain to scale all windows.
// OBSOLETED in 1.91.9 (from February 2025)
IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- 'border_col' was removed in favor of ImGuiCol_ImageBorder. If you use 'tint_col', use ImageWithBg() instead.
// OBSOLETED in 1.91.0 (from July 2024)
static inline void PushButtonRepeat(bool repeat) { PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); }
static inline void PopButtonRepeat() { PopItemFlag(); }
static inline void PushTabStop(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); }
static inline void PopTabStop() { PopItemFlag(); }
inline void PushButtonRepeat(bool repeat) { PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); }
inline void PopButtonRepeat() { PopItemFlag(); }
inline void PushTabStop(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); }
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 void ShowStackToolWindow(bool* p_open = NULL) { ShowIDStackToolWindow(p_open); }
inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags window_flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, window_flags); }
inline void EndChildFrame() { EndChild(); }
//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
//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
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);
// OBSOLETED in 1.89.7 (from June 2023)

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.92.1
// dear imgui, v1.92.2
// (demo code)
// Help:
@@ -2170,7 +2170,7 @@ static void DemoWindowWidgetsQueryingStatuses()
);
ImGui::BulletText(
"with Hovering Delay or Stationary test:\n"
"IsItemHovered() = = %d\n"
"IsItemHovered() = %d\n"
"IsItemHovered(_Stationary) = %d\n"
"IsItemHovered(_DelayShort) = %d\n"
"IsItemHovered(_DelayNormal) = %d\n"
@@ -3379,6 +3379,18 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d
// [SECTION] DemoWindowWidgetsTabs()
//-----------------------------------------------------------------------------
static void EditTabBarFittingPolicyFlags(ImGuiTabBarFlags* p_flags)
{
if ((*p_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
*p_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyMixed", p_flags, ImGuiTabBarFlags_FittingPolicyMixed))
*p_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyMixed);
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyShrink", p_flags, ImGuiTabBarFlags_FittingPolicyShrink))
*p_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyShrink);
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", p_flags, ImGuiTabBarFlags_FittingPolicyScroll))
*p_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
}
static void DemoWindowWidgetsTabs()
{
IMGUI_DEMO_MARKER("Widgets/Tabs");
@@ -3421,12 +3433,7 @@ static void DemoWindowWidgetsTabs()
ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
ImGui::CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", &tab_bar_flags, ImGuiTabBarFlags_DrawSelectedOverline);
if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
EditTabBarFittingPolicyFlags(&tab_bar_flags);
// Tab Bar
ImGui::AlignTextToFramePadding();
@@ -3475,12 +3482,8 @@ static void DemoWindowWidgetsTabs()
ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button);
// Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown;
ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyShrink;
EditTabBarFittingPolicyFlags(&tab_bar_flags);
if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
{
@@ -7739,6 +7742,8 @@ static void DemoWindowColumns()
// [SECTION] DemoWindowInputs()
//-----------------------------------------------------------------------------
#include "imgui_internal.h" // FIXME Until the new key owner/routing system are in public API this section of the demo needs internal (and is kept in a branch).
static void DemoWindowInputs()
{
IMGUI_DEMO_MARKER("Inputs & Focus");
@@ -7920,7 +7925,355 @@ static void DemoWindowInputs()
}
ImGui::EndChild();
ImGui::PopStyleColor();
ImGui::TreePop();
}
// Ownership, Routings
IMGUI_DEMO_MARKER("Inputs & Focus/Key Ownership");
if (ImGui::TreeNode("Key Ownership"))
{
HelpMarker("See 'Tools->Metrics/Debugger->Inputs' to visualize ownership/routing data.");
// Demonstrate basic key ownership system
// Standard widgets all claim and test for key ownership
// (note that the ActiveId and HoveredId systems also generally prevents multiple items from interacting, but at a different level)
if (ImGui::TreeNode("1. Standard widgets taking input ownership"))
{
HelpMarker("Standard widgets claim and test for key ownership.\n\n\"Keys\" include mouse buttons, gamepad axises etc.");
const ImGuiKey key = ImGuiKey_MouseLeft; // Note how mouse and gamepad are also included in ImGuiKey: same data type for all.
const char* key_name = ImGui::GetKeyName(key);
ImGui::Text("Press '%s'", key_name);
ImGui::Text("1st read: (button)");
ImGui::Button("Click and Hold Me Tight!");
// Assume this is another piece of code running later.
// The *default* value for owner is ImGuiKeyOwner_Any, same as calling the simplified function:
// IsKeyDown(key) == IsKeyDown(key, ImGuiKeyOwner_Any)
// IsKeyPressed(key) == IsKeyPressed(key, ImGuiKeyOwner_Any)
// But notice the "bool repeat = true" parameter in old signature 'IsKeyPressed(key, repeat)'
// with the new signature becomes 'IsKeyPressed(key, owner, ImGuiInputFlags_Repeat)'
ImGui::Text("2nd read: (NOT owner-aware)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key) ? "PRESSED!" : "..");
ImGui::Text("3rd read: (owner-aware: ImGuiKeyOwner_NoOwner)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key, ImGuiKeyOwner_NoOwner) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, ImGuiInputFlags_Repeat, ImGuiKeyOwner_NoOwner) ? "PRESSED!" : "..");
ImGuiID another_owner = ImGui::GetID("AnotherItem");
ImGui::Text("4nd read: (owner-aware: different owner)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key, another_owner) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, ImGuiInputFlags_Repeat, another_owner) ? "PRESSED!" : "..");
ImGui::TreePop();
}
if (ImGui::TreeNode("2. Calling SetKeyOwner()"))
{
const ImGuiKey key = ImGuiKey_A;
const char* key_name = ImGui::GetKeyName(key);
ImGui::Text("Press '%s'", key_name);
ImGui::Text("1st read:");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, false) ? "PRESSED!" : "..");
ImGui::Text("...when pressed, call SetKeyOwner() with an owner ID.");
ImGuiID owner_1 = ImGui::GetID("MyItemID");
if (ImGui::IsKeyPressed(key, ImGuiInputFlags_Repeat, owner_1))
ImGui::SetKeyOwner(key, owner_1);
// Assume this is another piece of code running later.
// (same comments as in section 1)
ImGui::Text("2nd read: (NOT owner-aware)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key) ? "PRESSED!" : "..");
ImGui::Text("3rd read: (owner-aware: ImGuiKeyOwner_NoOwner)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key, ImGuiKeyOwner_NoOwner) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, ImGuiInputFlags_Repeat, ImGuiKeyOwner_NoOwner) ? "PRESSED!" : "..");
ImGuiID another_owner = ImGui::GetID("AnotherItem");
ImGui::Text("4th read: (owner-aware: different owner)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key, another_owner) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, ImGuiInputFlags_Repeat, another_owner) ? "PRESSED!" : "..");
ImGui::TreePop();
}
// Demonstrate using SetKeyOwner() with ImGuiInputFlags_LockThisFrame / ImGuiInputFlags_LockUntilRelease flags.
// - Using an owner id solves all/most cases as long as everyone is "owner-id-aware",
// meaning they call the long form of IsKeyXXX function. This is the preferred way to do things.
// - Using ImGuiInputFlags_LockXXXX flags is a way to prevent code that is NOT owner-id-aware from accessing the key.
// Think of it as "eating" a key completely: only same owner ID can access the key/button.
if (ImGui::TreeNode("3. Calling SetKeyOwner() with ImGuiInputFlags_LockXXX flags for non-owner-aware code"))
{
const ImGuiKey key = ImGuiKey_B;
const char* key_name = ImGui::GetKeyName(key);
ImGui::Text("Press '%s'", key_name);
static bool lock_this_frame = false;
static bool lock_until_release = false;
ImGui::Text("1st read:");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, false) ? "PRESSED!" : "..");
ImGui::Text("...when pressed, call SetKeyOwner() with:");
ImGui::Checkbox("ImGuiInputFlags_LockThisFrame", &lock_this_frame);
ImGui::Checkbox("ImGuiInputFlags_LockUntilRelease", &lock_until_release);
if (ImGui::IsKeyPressed(key, false) && (lock_this_frame || lock_until_release))
ImGui::SetKeyOwner(key, 0, (lock_this_frame ? ImGuiInputFlags_LockThisFrame : 0) | (lock_until_release ? ImGuiInputFlags_LockUntilRelease : 0));
// Assume this is another piece of code running later. The calls are not owner-aware,
// due to the lock they won't be able to see the key.
ImGui::Text("2nd read: (NOT owner-aware)");
ImGui::Text("- IsKeyDown(%s): %s", key_name, ImGui::IsKeyDown(key) ? "DOWN!" : "..");
ImGui::Text("- IsKeyPressed(%s): %s", key_name, ImGui::IsKeyPressed(key, false) ? "PRESSED!" : "..");
ImGui::TreePop();
}
// Miscellaneous examples
if (ImGui::TreeNode("Usage Scenarios"))
{
// We use colored buttons for the demo but this would generally apply to any widget.
const ImVec2 button_sz(60.0f, 60.0f);
const ImGuiColorEditFlags button_flags = ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop;
if (ImGui::TreeNode("1. Claiming Mouse Wheel"))
{
static float value1 = 0.0f;
ImGui::Text("%.2f", value1);
ImGui::SameLine();
HelpMarker("Hover button and use mouse wheel: window scrolling won't be activated.");
ImGui::ColorButton("Item1", ImVec4(0.4f, 0.4f, 0.8f, 1.0f), button_flags, button_sz);
ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY);
if (ImGui::IsItemHovered() || ImGui::IsItemActive())
value1 += io.MouseWheel;
static float value2 = 0.0f;
ImGui::Text("%.2f", value2);
ImGui::SameLine();
HelpMarker("Hold button and use mouse wheel: window scrolling won't be activated.");
ImGui::ColorButton("Item2", ImVec4(0.4f, 0.4f, 0.8f, 1.0f), button_flags, button_sz);
ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY, ImGuiInputFlags_CondActive);
if (ImGui::IsItemActive())
value2 += io.MouseWheel;
ImGui::TreePop();
}
if (ImGui::TreeNode("2. Claiming Alt key"))
{
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
static float spinner0 = 0.0f;
ImGui::Text("%.3f", spinner0);
ImGui::SameLine();
HelpMarker("Click, hold ALT drag to tweak value. Notice that Alt doesn't move focus to menu bar.");
ImGui::Button("Spin me", button_sz);
if (ImGui::IsItemActive())
{
ImGui::SetKeyOwner(ImGuiMod_Alt, ImGui::GetItemID());
if (ImGui::IsKeyDown(ImGuiMod_Alt)) // Poll on Active: we don't need to check for ownership of ImGuiMod_Alt since we know we unconditionally own it.
spinner0 += io.MouseDelta.x;
}
// When using of keys is conditioned by item being hovered or active,
// it creates a natural exclusivity, since only one item can be hovered or active.
// SetItemKeyOwner(...) is a shortcut for doing 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(..., GetItemID()); }'
static int value1 = 0;
ImGui::Text("%d", value1);
ImGui::SameLine();
HelpMarker("Item1 claims ALT key when Hovered or Active, counter increase when pressing ALT while Hovered.");
ImGui::Button("Item1", button_sz);
ImGui::SetItemKeyOwner(ImGuiMod_Alt); // Claim Alt on Hover and Active
if (ImGui::IsItemHovered() && ImGui::IsKeyPressed(ImGuiMod_Alt, false)) // Poll on Hover: we don't need to check for ownership of ImGuiMod_Alt since we know we unconditionally own it.
value1++;
ImGui::TreePop();
}
// Routing options are only available for Shortcuts (not Key)
// Using shortcut functions with only ImGuiMod_Alt means that other modifiers e.g. CTRL+ALT+S won't be affected, which is often desirable.
// Here we use ImGuiInputFlags_RouteFocused which will claim the Alt shortcut when the window is focused.
// Notice that opening this node will claim Alt, therefore change the behavior of the key checks in section (2) above.
if (ImGui::TreeNode("3. Claiming Alt shortcut"))
{
// Using Shortcut() with ImGuiInputFlags_RouteFocused means we react when parent window is focused.
// - Passing 0 (== ImGuiKeyOwner_Any) means current location will be used to identify.
// As both calls are from the same location, both items will receive the shortcut.
// - Passing GetItemID() here means they both have their unique id,
// - Item2 will only receive the shortcut when parent window is focused.
// - Item3 will only receive the shortcut when active.
// Not passing an item id would use current location as id so both items will always receive shortcut.
static bool use_shared_owner = false;
ImGui::Checkbox("Item2 and Item3 use same owner/location", &use_shared_owner);
static int value2 = 0;
ImGui::Text("%d", value2);
ImGui::SameLine();
HelpMarker("Item2 reads ALT shortcut when its parent window is focused.");
ImGui::Button("Item2", button_sz);
if (ImGui::Shortcut(ImGuiMod_Alt, 0, use_shared_owner ? 0 : ImGui::GetItemID()))
value2++;
static int value3 = 0;
ImGui::Text("%d", value3);
ImGui::SameLine();
HelpMarker("Item3 reads ALT shortcut when its parent window is focused AND it is active. Therefore, only active previous button will get the shortcut");
ImGui::Button("Item3", button_sz);
if (ImGui::Shortcut(ImGuiMod_Alt, 0, use_shared_owner ? 0 : ImGui::GetItemID()))
value3++;
ImGui::TreePop();
}
if (ImGui::TreeNode("4. Claiming Home key globally"))
{
static bool enable_home_robbery = false;
static int home_presses = 0;
ImGui::Checkbox("Global steal ImGuiKey_Home", &enable_home_robbery);
ImGui::Text("Home presses: %d", home_presses);
if (enable_home_robbery)
{
// Claim ownership is enough to keep Key away from main library behavior or any owner-aware code.
// - We optionally use the ImGuiInputFlags_LockUntilRelease to keep key away from code that is not owner-aware,
// but Dear ImGui itself is so that's not technically needed (unless you are stealing from another piece of code).
ImGuiID robber_id = ImGui::GetID("Some Identifier");
ImGui::SetKeyOwner(ImGuiKey_Home, robber_id, ImGuiInputFlags_LockUntilRelease);
if (ImGui::IsKeyPressed(ImGuiKey_Home, ImGuiInputFlags_Repeat, robber_id)) // We unconditionally own the key so no need to test for ownership
home_presses++;
}
ImGui::TreePop();
}
if (ImGui::TreeNode("5. Claiming CTRL+A shortcut globally"))
{
// Using a priority of ImGuiInputFlags_RouteGlobal + RouteOverActive means we takes away even from an active item (e.g. InputText)
// This is better covered in "Shortcut Routing basics" above.
static bool enable_ctrl_a_robbery = false;
static int ctrl_a_presses = 0;
ImGui::Checkbox("Global steal CTRL+A", &enable_ctrl_a_robbery);
ImGui::Text("CTRL+A presses: %d", ctrl_a_presses);
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_A, enable_ctrl_a_robbery ? ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive : ImGuiInputFlags_RouteAlways))
ctrl_a_presses++;
ImGui::TreePop();
}
if (ImGui::TreeNode("6. Disable ESC key from InputText()"))
{
static char buf[9];
ImGui::InputText("Text", buf, IM_ARRAYSIZE(buf));
// - If you don't need to use the key, you can use 'owner_id=0', 'flags=ImGuiInputFlags_LockXXX'
// as a convenience to hide the key from everyone.
// - If you need to use the key yourself, you need to use any arbitrary ID, and then use this ID to read the key.
// e.g. ImGui::SetKeyOwner(ImGuiKey_Escape, ImGui::GetID("robber")); + later use same ID to access the key.
if (ImGui::IsItemActive())
ImGui::SetKeyOwner(ImGuiKey_Escape, 0, ImGuiInputFlags_LockUntilRelease);
ImGui::TreePop();
}
if (ImGui::TreeNode("7. Claiming ESC key away from InputText()"))
{
static char buf[9];
ImGui::InputText("Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_EscapeClearsAll);
if (ImGui::IsItemActive())
{
// Using a route which is higher priority than one claimed the ActiveId
ImGuiID robber_id = ImGui::GetID("robber");
if (ImGui::Shortcut(ImGuiKey_Escape, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive, robber_id))
{
strcpy(buf, "Esc!");
ImGui::ClearActiveID();
}
}
ImGui::TreePop();
}
if (ImGui::TreeNode("8. Claiming ESC away from nav logic (e.g. exiting a child)"))
{
ImGui::BeginChild("child", ImVec2(-FLT_MIN, 50), true);
ImGui::Button("Button in child");
if (ImGui::IsWindowFocused())
ImGui::SetKeyOwner(ImGuiKey_Escape, ImGui::GetID("")); // any id
ImGui::EndChild();
ImGui::TreePop();
}
if (ImGui::TreeNode("9. Claiming Tab, CTRL+Tab"))
{
static int mode = 0;
static int counter = 0;
HelpMarker("Showcasing many variants as a recap.\nPlease read code and comments carefully!");
const char* mode_names[] = { "None", "Disable Tab key (item)", "Disable Tab key (global)", "Disable CTRL+Tab (global)", "Disable CTRL+Tab (if focused)", "Read CTRL+Tab (global)", "Replace CTRL+Tab (global)", "Replace CTRL+Tab (if focused)" };
ImGui::Combo("Operation Mode", &mode, mode_names, IM_ARRAYSIZE(mode_names));
ImGui::Text("Counter = %d", counter);
switch (mode)
{
case 1:
// Item take ownership of Tab key when hovered/active (meaning ALL uses of Tab will be disabled, not just CTRL+Tab)
ImGui::Button("This Button Steals The Tab Key");
ImGui::SetItemKeyOwner(ImGuiKey_Tab);
ImGui::SameLine();
HelpMarker("While hovering or activating this button, TAB key is stolen (e.g. won't tab out into other systems)");
break;
case 2:
// Take ownership of Tab key (meaning ALL uses of Tab will be disabled, not just CTRL+Tab)
ImGui::SetKeyOwner(ImGuiKey_Tab, ImGui::GetID("some-id"));
break;
case 3:
// Disable CTRL+Tab shortcuts (global): assign an owner to steal the route to our two shortcuts
ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiKey_Tab, 0, ImGui::GetID("some-id"));
ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, 0, ImGui::GetID("some-id"));
break;
case 4:
// Disable CTRL+Tab shortcuts (if focused): assign an owner to steal the route to our two shortcuts, applies focus testing so will only apply if window is in focus chain
ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiKey_Tab, ImGuiInputFlags_RouteFocused, ImGui::GetID("some-id"));
ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, ImGuiInputFlags_RouteFocused, ImGui::GetID("some-id"));
break;
case 5:
// Read CTRL+Tab (global): reading keys without interfering with any behaviors (need to specify ImGuiInputFlags_RouteAlways as other policies will interfere)
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_Tab, ImGuiInputFlags_RouteAlways, ImGuiKeyOwner_Any))
counter++;
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, ImGuiInputFlags_RouteAlways, ImGuiKeyOwner_Any))
counter--;
break;
case 6:
{
// Replace CTRL+Tab (global)
// - We steal the route and assign it to our ID (so core system won't access it). Our reading queries now need to specify that ID.
ImGuiID id = ImGui::GetID("My-Ctrl-Tab-Handler");
//ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiKey_Tab, id, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive);
//ImGui::SetShortcutRouting(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, id, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive);
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_Tab, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive, id))
counter++; // You could perform some other action here.
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive, id))
counter--;
break;
}
case 7:
// Replace CTRL+Tab (if focused)
// - Passing ImGuiInputFlags_RouteFocused will test for focus and assign a route using a default owner id based on location (so we can use 0 as id)
// - This would also work if we replaced 0 with ImGui::GetID("My-Ctrl-Tab-Handler")
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_Tab))
counter++; // You could perform some other action here.
if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab))
counter--;
break;
}
static char buf[8] = "";
ImGui::InputTextWithHint("Dummy", "(dummy input text to test effect of Tabbing)", buf, IM_ARRAYSIZE(buf));
ImGui::TreePop();
}
ImGui::TreePop();
}
ImGui::TreePop();
}
@@ -8096,6 +8449,9 @@ void ImGui::ShowAboutWindow(bool* p_open)
ImGui::Separator();
ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert));
ImGui::Text("define: __cplusplus=%d", (int)__cplusplus);
#ifdef IMGUI_ENABLE_TEST_ENGINE
ImGui::Text("define: IMGUI_ENABLE_TEST_ENGINE");
#endif
#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS");
#endif
@@ -8341,8 +8697,10 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f");
SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 3.0f, "%.0f");
SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.");
DragFloat("TabCloseButtonMinWidthSelected", &style.TabCloseButtonMinWidthSelected, 0.1f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthSelected < 0.0f) ? "%.0f (Always)" : "%.0f");
DragFloat("TabCloseButtonMinWidthUnselected", &style.TabCloseButtonMinWidthUnselected, 0.1f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthUnselected < 0.0f) ? "%.0f (Always)" : "%.0f");
DragFloat("TabMinWidthBase", &style.TabMinWidthBase, 0.5f, 1.0f, 500.0f, "%.0f");
DragFloat("TabMinWidthShrink", &style.TabMinWidthShrink, 0.5f, 1.0f, 500.0f, "%0.f");
DragFloat("TabCloseButtonMinWidthSelected", &style.TabCloseButtonMinWidthSelected, 0.5f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthSelected < 0.0f) ? "%.0f (Always)" : "%.0f");
DragFloat("TabCloseButtonMinWidthUnselected", &style.TabCloseButtonMinWidthUnselected, 0.5f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthUnselected < 0.0f) ? "%.0f (Always)" : "%.0f");
SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
SeparatorText("Tables");

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.92.1
// dear imgui, v1.92.2
// (drawing and font code)
/*
@@ -2312,17 +2312,16 @@ void ImDrawData::DeIndexAllBuffers()
{
ImVector<ImDrawVert> new_vtx_buffer;
TotalVtxCount = TotalIdxCount = 0;
for (int i = 0; i < CmdListsCount; i++)
for (ImDrawList* draw_list : CmdLists)
{
ImDrawList* cmd_list = CmdLists[i];
if (cmd_list->IdxBuffer.empty())
if (draw_list->IdxBuffer.empty())
continue;
new_vtx_buffer.resize(cmd_list->IdxBuffer.Size);
for (int j = 0; j < cmd_list->IdxBuffer.Size; j++)
new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]];
cmd_list->VtxBuffer.swap(new_vtx_buffer);
cmd_list->IdxBuffer.resize(0);
TotalVtxCount += cmd_list->VtxBuffer.Size;
new_vtx_buffer.resize(draw_list->IdxBuffer.Size);
for (int j = 0; j < draw_list->IdxBuffer.Size; j++)
new_vtx_buffer[j] = draw_list->VtxBuffer[draw_list->IdxBuffer[j]];
draw_list->VtxBuffer.swap(new_vtx_buffer);
draw_list->IdxBuffer.resize(0);
TotalVtxCount += draw_list->VtxBuffer.Size;
}
}
@@ -2457,8 +2456,10 @@ const char* ImTextureDataGetFormatName(ImTextureFormat format)
void ImTextureData::Create(ImTextureFormat format, int w, int h)
{
IM_ASSERT(Status == ImTextureStatus_Destroyed);
DestroyPixels();
Format = format;
Status = ImTextureStatus_WantCreate;
Width = w;
Height = h;
BytesPerPixel = ImTextureDataGetFormatBytesPerPixel(format);
@@ -2630,6 +2631,7 @@ ImFontAtlas::ImFontAtlas()
TexMinHeight = 128;
TexMaxWidth = 8192;
TexMaxHeight = 8192;
TexRef._TexID = ImTextureID_Invalid;
RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update.
TexNextUniqueID = 1;
FontNextUniqueID = 1;
@@ -2739,10 +2741,9 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool rendere
if (atlas->Builder == NULL) // This will only happen if fonts were not already loaded.
ImFontAtlasBuildMain(atlas);
}
else // Legacy backend
{
// Legacy backend
if (!atlas->RendererHasTextures)
IM_ASSERT_USER_ERROR(atlas->TexIsBuilt, "Backend does not support ImGuiBackendFlags_RendererHasTextures, and font atlas is not built! Update backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8().");
}
if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges)
IM_ASSERT_USER_ERROR(atlas->RendererHasTextures == false, "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With new backends: you don't need to call Build().");
@@ -2797,8 +2798,9 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool rendere
}
else if (tex->WantDestroyNextFrame && tex->Status != ImTextureStatus_WantDestroy)
{
// Request destroy. Keep bool as it allows us to keep track of things.
// We don't destroy pixels right away, as backend may have an in-flight copy from RAM.
// Request destroy.
// - Keep bool to true in order to differentiate a planned destroy vs a destroy decided by the backend.
// - We don't destroy pixels right away, as backend may have an in-flight copy from RAM.
IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates);
tex->Status = ImTextureStatus_WantDestroy;
}
@@ -2954,7 +2956,7 @@ void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex,
tex->UsedRect.h = (unsigned short)(ImMax(tex->UsedRect.y + tex->UsedRect.h, req.y + req.h) - tex->UsedRect.y);
atlas->TexIsBuilt = false;
// No need to queue if status is _WantCreate
// No need to queue if status is == ImTextureStatus_WantCreate
if (tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantUpdates)
{
tex->Status = ImTextureStatus_WantUpdates;
@@ -3361,11 +3363,7 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas)
{
IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!");
if (atlas->TexData && atlas->TexData->Format != atlas->TexDesiredFormat)
{
ImVec2i new_tex_size = ImFontAtlasTextureGetSizeEstimate(atlas);
ImFontAtlasBuildDestroy(atlas);
ImFontAtlasTextureAdd(atlas, new_tex_size.x, new_tex_size.y);
}
ImFontAtlasBuildClear(atlas);
if (atlas->Builder == NULL)
ImFontAtlasBuildInit(atlas);
@@ -3971,7 +3969,6 @@ ImTextureData* ImFontAtlasTextureAdd(ImFontAtlas* atlas, int w, int h)
}
new_tex->Create(atlas->TexDesiredFormat, w, h);
new_tex->Status = ImTextureStatus_WantCreate;
atlas->TexIsBuilt = false;
ImFontAtlasBuildSetTexture(atlas, new_tex);
@@ -4375,6 +4372,7 @@ ImTextureRect* ImFontAtlasPackGetRectSafe(ImFontAtlas* atlas, ImFontAtlasRectId
if (atlas->Builder == NULL)
ImFontAtlasBuildInit(atlas);
ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
IM_MSVC_WARNING_SUPPRESS(28182); // Static Analysis false positive "warning C28182: Dereferencing NULL pointer 'builder'"
if (index_idx >= builder->RectsIndex.Size)
return NULL;
ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx];
@@ -4417,7 +4415,7 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep
if (atlas->Locked || (font->Flags & ImFontFlags_NoLoadGlyphs))
{
// Lazily load fallback glyph
if (baked->FallbackGlyphIndex == -1 && baked->LockLoadingFallback == 0)
if (baked->FallbackGlyphIndex == -1 && baked->LoadNoFallback == 0)
ImFontAtlasBuildSetupFontBakedFallback(baked);
return NULL;
}
@@ -4469,7 +4467,7 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep
}
// Lazily load fallback glyph
if (baked->LockLoadingFallback)
if (baked->LoadNoFallback)
return NULL;
if (baked->FallbackGlyphIndex == -1)
ImFontAtlasBuildSetupFontBakedFallback(baked);
@@ -4483,7 +4481,7 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep
static float ImFontBaked_BuildLoadGlyphAdvanceX(ImFontBaked* baked, ImWchar codepoint)
{
if (baked->Size >= IMGUI_FONT_SIZE_THRESHOLD_FOR_LOADADVANCEXONLYMODE)
if (baked->Size >= IMGUI_FONT_SIZE_THRESHOLD_FOR_LOADADVANCEXONLYMODE || baked->LoadNoRenderOnLayout)
{
// First load AdvanceX value used by CalcTextSize() API then load the rest when loaded by drawing API.
float only_advance_x = 0.0f;
@@ -4572,15 +4570,16 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig*
}
src->FontLoaderData = bd_font_data;
const float ref_size = src->DstFont->Sources[0]->SizePixels;
if (src->MergeMode && src->SizePixels == 0.0f)
src->SizePixels = src->DstFont->Sources[0]->SizePixels;
src->SizePixels = ref_size;
if (src->SizePixels >= 0.0f)
bd_font_data->ScaleFactor = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f);
else
bd_font_data->ScaleFactor = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f);
if (src->MergeMode && src->SizePixels != 0.0f)
bd_font_data->ScaleFactor *= src->SizePixels / src->DstFont->Sources[0]->SizePixels; // FIXME-NEWATLAS: Should tidy up that a bit
if (src->MergeMode && src->SizePixels != 0.0f && ref_size != 0.0f)
bd_font_data->ScaleFactor *= src->SizePixels / ref_size; // FIXME-NEWATLAS: Should tidy up that a bit
return true;
}
@@ -4679,15 +4678,12 @@ static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontC
builder->TempBuffer.resize(w * h * 1);
unsigned char* bitmap_pixels = builder->TempBuffer.Data;
memset(bitmap_pixels, 0, w * h * 1);
stbtt_MakeGlyphBitmapSubpixel(&bd_font_data->FontInfo, bitmap_pixels, r->w - oversample_h + 1, r->h - oversample_v + 1, w,
scale_for_raster_x, scale_for_raster_y, 0, 0, glyph_index);
// Oversampling
// Render with oversampling
// (those functions conveniently assert if pixels are not cleared, which is another safety layer)
if (oversample_h > 1)
stbtt__h_prefilter(bitmap_pixels, r->w, r->h, r->w, oversample_h);
if (oversample_v > 1)
stbtt__v_prefilter(bitmap_pixels, r->w, r->h, r->w, oversample_v);
float sub_x, sub_y;
stbtt_MakeGlyphBitmapSubpixelPrefilter(&bd_font_data->FontInfo, bitmap_pixels, w, h, w,
scale_for_raster_x, scale_for_raster_y, 0, 0, oversample_h, oversample_v, &sub_x, &sub_y, glyph_index);
const float ref_size = baked->ContainerFont->Sources[0]->SizePixels;
const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f;
@@ -4697,8 +4693,8 @@ static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontC
font_off_x = IM_ROUND(font_off_x);
if (src->PixelSnapV)
font_off_y = IM_ROUND(font_off_y);
font_off_x += stbtt__oversample_shift(oversample_h);
font_off_y += stbtt__oversample_shift(oversample_v) + IM_ROUND(baked->Ascent);
font_off_x += sub_x;
font_off_y += sub_y + IM_ROUND(baked->Ascent);
float recip_h = 1.0f / (oversample_h * rasterizer_density);
float recip_v = 1.0f / (oversample_v * rasterizer_density);
@@ -5225,9 +5221,9 @@ ImFontGlyph* ImFontBaked::FindGlyphNoFallback(ImWchar c)
if (i != IM_FONTGLYPH_INDEX_UNUSED)
return &Glyphs.Data[i];
}
LockLoadingFallback = true; // This is actually a rare call, not done in hot-loop, so we prioritize not adding extra cruft to ImFontBaked_BuildLoadGlyph() call sites.
LoadNoFallback = true; // This is actually a rare call, not done in hot-loop, so we prioritize not adding extra cruft to ImFontBaked_BuildLoadGlyph() call sites.
ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c, NULL);
LockLoadingFallback = false;
LoadNoFallback = false;
return glyph;
}

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.92.1
// dear imgui, v1.92.2
// (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.
@@ -369,17 +369,17 @@ IMGUI_API ImGuiID ImHashStr(const char* data, size_t data_size = 0, ImGuiI
// Helpers: Sorting
#ifndef ImQsort
static inline void ImQsort(void* base, size_t count, size_t size_of_element, int(IMGUI_CDECL *compare_func)(void const*, void const*)) { if (count > 1) qsort(base, count, size_of_element, compare_func); }
inline void ImQsort(void* base, size_t count, size_t size_of_element, int(IMGUI_CDECL *compare_func)(void const*, void const*)) { if (count > 1) qsort(base, count, size_of_element, compare_func); }
#endif
// Helpers: Color Blending
IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b);
// Helpers: Bit manipulation
static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
static inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; }
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
static inline unsigned int ImCountSetBits(unsigned int v) { unsigned int count = 0; while (v > 0) { v = v & (v - 1); count++; } return count; }
inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; }
inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
inline unsigned int ImCountSetBits(unsigned int v) { unsigned int count = 0; while (v > 0) { v = v & (v - 1); count++; } return count; }
// Helpers: String
#define ImStrlen strlen
@@ -398,10 +398,10 @@ IMGUI_API const char* ImStrSkipBlank(const char* str);
IMGUI_API int ImStrlenW(const ImWchar* str); // Computer string length (ImWchar string)
IMGUI_API const char* ImStrbol(const char* buf_mid_line, const char* buf_begin); // Find beginning-of-line
IM_MSVC_RUNTIME_CHECKS_OFF
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'); }
inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; }
inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; }
inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; }
inline bool ImCharIsXdigitA(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); }
IM_MSVC_RUNTIME_CHECKS_RESTORE
// Helpers: Formatting
@@ -417,7 +417,7 @@ IMGUI_API const char* ImParseFormatSanitizeForScanning(const char* fmt_in, cha
IMGUI_API int ImParseFormatPrecision(const char* format, int default_value);
// Helpers: UTF-8 <> wchar conversions
IMGUI_API const char* ImTextCharToUtf8(char out_buf[5], unsigned int c); // return out_buf
IMGUI_API int ImTextCharToUtf8(char out_buf[5], unsigned int c); // return output UTF-8 bytes count
IMGUI_API int ImTextStrToUtf8(char* out_buf, int out_buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count
IMGUI_API int ImTextStrFromUtf8(ImWchar* out_buf, int out_buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count
@@ -431,11 +431,11 @@ IMGUI_API int ImTextCountLines(const char* in_text, const char* in_tex
#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
typedef void* ImFileHandle;
static inline ImFileHandle ImFileOpen(const char*, const char*) { return NULL; }
static inline bool ImFileClose(ImFileHandle) { return false; }
static inline ImU64 ImFileGetSize(ImFileHandle) { return (ImU64)-1; }
static inline ImU64 ImFileRead(void*, ImU64, ImU64, ImFileHandle) { return 0; }
static inline ImU64 ImFileWrite(const void*, ImU64, ImU64, ImFileHandle) { return 0; }
inline ImFileHandle ImFileOpen(const char*, const char*) { return NULL; }
inline bool ImFileClose(ImFileHandle) { return false; }
inline ImU64 ImFileGetSize(ImFileHandle) { return (ImU64)-1; }
inline ImU64 ImFileRead(void*, ImU64, ImU64, ImFileHandle) { return 0; }
inline ImU64 ImFileWrite(const void*, ImU64, ImU64, ImFileHandle) { return 0; }
#endif
#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
typedef FILE* ImFileHandle;
@@ -462,56 +462,56 @@ IM_MSVC_RUNTIME_CHECKS_OFF
#define ImAtan2(Y, X) atan2f((Y), (X))
#define ImAtof(STR) atof(STR)
#define ImCeil(X) ceilf(X)
static inline float ImPow(float x, float y) { return powf(x, y); } // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision
static inline double ImPow(double x, double y) { return pow(x, y); }
static inline float ImLog(float x) { return logf(x); } // DragBehaviorT/SliderBehaviorT uses ImLog with either float/double and need the precision
static inline double ImLog(double x) { return log(x); }
static inline int ImAbs(int x) { return x < 0 ? -x : x; }
static inline float ImAbs(float x) { return fabsf(x); }
static inline double ImAbs(double x) { return fabs(x); }
static inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : (x > 0.0f) ? 1.0f : 0.0f; } // Sign operator - returns -1, 0 or 1 based on sign of argument
static inline double ImSign(double x) { return (x < 0.0) ? -1.0 : (x > 0.0) ? 1.0 : 0.0; }
inline float ImPow(float x, float y) { return powf(x, y); } // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision
inline double ImPow(double x, double y) { return pow(x, y); }
inline float ImLog(float x) { return logf(x); } // DragBehaviorT/SliderBehaviorT uses ImLog with either float/double and need the precision
inline double ImLog(double x) { return log(x); }
inline int ImAbs(int x) { return x < 0 ? -x : x; }
inline float ImAbs(float x) { return fabsf(x); }
inline double ImAbs(double x) { return fabs(x); }
inline float ImSign(float x) { return (x < 0.0f) ? -1.0f : (x > 0.0f) ? 1.0f : 0.0f; } // Sign operator - returns -1, 0 or 1 based on sign of argument
inline double ImSign(double x) { return (x < 0.0) ? -1.0 : (x > 0.0) ? 1.0 : 0.0; }
#ifdef IMGUI_ENABLE_SSE
static inline float ImRsqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); }
inline float ImRsqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); }
#else
static inline float ImRsqrt(float x) { return 1.0f / sqrtf(x); }
inline float ImRsqrt(float x) { return 1.0f / sqrtf(x); }
#endif
static inline double ImRsqrt(double x) { return 1.0 / sqrt(x); }
inline double ImRsqrt(double x) { return 1.0 / sqrt(x); }
#endif
// - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support variety of types: signed/unsigned int/long long float/double
// (Exceptionally using templates here but we could also redefine them for those types)
template<typename T> static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; }
template<typename T> static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; }
template<typename T> static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; }
template<typename T> static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); }
template<typename T> static inline void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; }
template<typename T> static inline T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; }
template<typename T> static inline T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; }
template<typename T> T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; }
template<typename T> T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; }
template<typename T> T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; }
template<typename T> T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); }
template<typename T> void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; }
template<typename T> T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; }
template<typename T> T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; }
// - Misc maths helpers
static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); }
static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); }
static inline ImVec2 ImClamp(const ImVec2& v, const ImVec2&mn, const ImVec2&mx) { return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); }
static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); }
static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); }
static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); }
static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; }
static inline float ImLengthSqr(const ImVec2& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y); }
static inline float ImLengthSqr(const ImVec4& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y) + (lhs.z * lhs.z) + (lhs.w * lhs.w); }
static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return ImRsqrt(d); return fail_value; }
static inline float ImTrunc(float f) { return (float)(int)(f); }
static inline ImVec2 ImTrunc(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); }
static inline float ImFloor(float f) { return (float)((f >= 0 || (float)(int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf()
static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2(ImFloor(v.x), ImFloor(v.y)); }
static inline float ImTrunc64(float f) { return (float)(ImS64)(f); }
static inline float ImRound64(float f) { return (float)(ImS64)(f + 0.5f); }
static inline int ImModPositive(int a, int b) { return (a + b) % b; }
static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; }
static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); }
static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
static inline float ImLinearRemapClamp(float s0, float s1, float d0, float d1, float x) { return ImSaturate((x - s0) / (s1 - s0)) * (d1 - d0) + d0; }
static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
static inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; }
static inline float ImExponentialMovingAverage(float avg, float sample, int n) { avg -= avg / n; avg += sample / n; return avg; }
inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); }
inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); }
inline ImVec2 ImClamp(const ImVec2& v, const ImVec2&mn, const ImVec2&mx){ return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); }
inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); }
inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); }
inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); }
inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; }
inline float ImLengthSqr(const ImVec2& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y); }
inline float ImLengthSqr(const ImVec4& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y) + (lhs.z * lhs.z) + (lhs.w * lhs.w); }
inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return ImRsqrt(d); return fail_value; }
inline float ImTrunc(float f) { return (float)(int)(f); }
inline ImVec2 ImTrunc(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); }
inline float ImFloor(float f) { return (float)((f >= 0 || (float)(int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf()
inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2(ImFloor(v.x), ImFloor(v.y)); }
inline float ImTrunc64(float f) { return (float)(ImS64)(f); }
inline float ImRound64(float f) { return (float)(ImS64)(f + 0.5f); }
inline int ImModPositive(int a, int b) { return (a + b) % b; }
inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; }
inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); }
inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
inline float ImLinearRemapClamp(float s0, float s1, float d0, float d1, float x) { return ImSaturate((x - s0) / (s1 - s0)) * (d1 - d0) + d0; }
inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; }
inline float ImExponentialMovingAverage(float avg, float sample, int n){ avg -= avg / n; avg += sample / n; return avg; }
IM_MSVC_RUNTIME_CHECKS_RESTORE
// Helpers: Geometry
@@ -2328,8 +2328,8 @@ struct ImGuiContext
float NavWindowingTimer;
float NavWindowingHighlightAlpha;
ImGuiInputSource NavWindowingInputSource;
bool NavWindowingToggleLayer;
ImGuiKey NavWindowingToggleKey;
bool NavWindowingToggleLayer; // Set while Alt or GamepadMenu is held, may be cleared by other operations, and processed when releasing the key.
ImGuiKey NavWindowingToggleKey; // Keyboard/gamepad key used when toggling to menu layer.
ImVec2 NavWindowingAccumDeltaPos;
ImVec2 NavWindowingAccumDeltaSize;
@@ -2735,7 +2735,7 @@ struct ImGuiTabItem
int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance
float Offset; // Position relative to beginning of tab
float Width; // Width currently displayed
float ContentWidth; // Width of label, stored during BeginTabItem() call
float ContentWidth; // Width of label + padding, stored during BeginTabItem() call (misnamed as "Content" would normally imply width of label only)
float RequestedWidth; // Width optionally requested by caller, -1.0f is unused
ImS32 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames
ImS16 BeginOrder; // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable
@@ -2758,6 +2758,7 @@ struct IMGUI_API ImGuiTabBar
int CurrFrameVisible;
int PrevFrameVisible;
ImRect BarRect;
float BarRectPrevWidth; // Backup of previous width. When width change we enforce keep horizontal scroll on focused tab.
float CurrTabsContentsHeight;
float PrevTabsContentsHeight; // Record the height of contents submitted below the tab bar
float WidthAllTabs; // Actual width of all tabs (locked during layout)
@@ -2776,6 +2777,7 @@ struct IMGUI_API ImGuiTabBar
bool WantLayout;
bool VisibleTabWasSubmitted;
bool TabsAddedNew; // Set to true when a new tab item or button has been added to the tab bar during last frame
bool ScrollButtonEnabled;
ImS16 TabsActiveCount; // Number of tabs submitted this frame.
ImS16 LastTabItemIdx; // Index of last BeginTabItem() tab for use by EndTabItem()
float ItemSpacingY;
@@ -3124,7 +3126,7 @@ namespace ImGui
IMGUI_API void SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags);
// Fonts, drawing
IMGUI_API void RegisterUserTexture(ImTextureData* tex); // Register external texture
IMGUI_API void RegisterUserTexture(ImTextureData* tex); // Register external texture. EXPERIMENTAL: DO NOT USE YET.
IMGUI_API void UnregisterUserTexture(ImTextureData* tex);
IMGUI_API void RegisterFontAtlas(ImFontAtlas* atlas);
IMGUI_API void UnregisterFontAtlas(ImFontAtlas* atlas);
@@ -3150,6 +3152,7 @@ namespace ImGui
IMGUI_API void UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos);
IMGUI_API void FindHoveredWindowEx(const ImVec2& pos, bool find_first_and_in_any_viewport, ImGuiWindow** out_hovered_window, ImGuiWindow** out_hovered_window_under_moving_window);
IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window);
IMGUI_API void StopMouseMovingWindow();
IMGUI_API void UpdateMouseMovingWindowNewFrame();
IMGUI_API void UpdateMouseMovingWindowEndFrame();
@@ -3221,7 +3224,7 @@ namespace ImGui
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 void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess);
IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess, float width_min);
// Parameter stacks (shared)
IMGUI_API const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx);
@@ -3671,7 +3674,6 @@ namespace ImGui
//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():
// Refactored focus/nav/tabbing system in 1.82 and 1.84. If you have old/custom copy-and-pasted widgets which used FocusableItemRegister():
// (Old) IMGUI_VERSION_NUM < 18209: using 'ItemAdd(....)' and 'bool tab_focused = FocusableItemRegister(...)'
// (Old) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)' and 'bool tab_focused = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Focused) != 0'

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.92.1
// dear imgui, v1.92.2
// (tables and columns code)
/*
@@ -542,7 +542,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// Make table current
g.CurrentTable = table;
outer_window->DC.NavIsScrollPushableX = false; // Shortcut for NavUpdateCurrentWindowIsScrollPushableX();
inner_window->DC.NavIsScrollPushableX = false; // Shortcut for NavUpdateCurrentWindowIsScrollPushableX();
outer_window->DC.CurrentTableIdx = table_idx;
if (inner_window != outer_window) // So EndChild() within the inner window can restore the table properly.
inner_window->DC.CurrentTableIdx = table_idx;
@@ -1825,6 +1825,11 @@ void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n
ImGuiContext& g = *GImGui;
ImGuiTable* table = g.CurrentTable;
IM_ASSERT(target != ImGuiTableBgTarget_None);
if (table == NULL)
{
IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!");
return;
}
if (color == IM_COL32_DISABLE)
color = 0;
@@ -2876,9 +2881,7 @@ ImGuiTableSortSpecs* ImGui::TableGetSortSpecs()
{
ImGuiContext& g = *GImGui;
ImGuiTable* table = g.CurrentTable;
IM_ASSERT(table != NULL);
if (!(table->Flags & ImGuiTableFlags_Sortable))
if (table == NULL || !(table->Flags & ImGuiTableFlags_Sortable))
return NULL;
// Require layout (in case TableHeadersRow() hasn't been called) as it may alter IsSortSpecsDirty in some paths.

View File

@@ -1,4 +1,4 @@
// dear imgui, v1.92.1
// dear imgui, v1.92.2
// (widgets code)
/*
@@ -1830,27 +1830,31 @@ static int IMGUI_CDECL ShrinkWidthItemComparer(const void* lhs, const void* rhs)
// Shrink excess width from a set of item, by removing width from the larger items first.
// Set items Width to -1.0f to disable shrinking this item.
void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess)
void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess, float width_min)
{
if (count == 1)
{
if (items[0].Width >= 0.0f)
items[0].Width = ImMax(items[0].Width - width_excess, 1.0f);
items[0].Width = ImMax(items[0].Width - width_excess, width_min);
return;
}
ImQsort(items, (size_t)count, sizeof(ImGuiShrinkWidthItem), ShrinkWidthItemComparer);
ImQsort(items, (size_t)count, sizeof(ImGuiShrinkWidthItem), ShrinkWidthItemComparer); // Sort largest first, smallest last.
int count_same_width = 1;
while (width_excess > 0.0f && count_same_width < count)
while (width_excess > 0.001f && count_same_width < count)
{
while (count_same_width < count && items[0].Width <= items[count_same_width].Width)
count_same_width++;
float max_width_to_remove_per_item = (count_same_width < count && items[count_same_width].Width >= 0.0f) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f);
max_width_to_remove_per_item = ImMin(items[0].Width - width_min, max_width_to_remove_per_item);
if (max_width_to_remove_per_item <= 0.0f)
break;
float width_to_remove_per_item = ImMin(width_excess / count_same_width, max_width_to_remove_per_item);
float base_width_to_remove_per_item = ImMin(width_excess / count_same_width, max_width_to_remove_per_item);
for (int item_n = 0; item_n < count_same_width; item_n++)
items[item_n].Width -= width_to_remove_per_item;
width_excess -= width_to_remove_per_item * count_same_width;
{
float width_to_remove_for_this_item = ImMin(base_width_to_remove_per_item, items[item_n].Width - width_min);
items[item_n].Width -= width_to_remove_for_this_item;
width_excess -= width_to_remove_for_this_item;
}
}
// Round width and redistribute remainder
@@ -4940,7 +4944,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
{
// Determine if we turn Enter into a \n character
bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
if (!is_multiline || is_gamepad_validate || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))
if (!is_multiline || is_gamepad_validate || (ctrl_enter_for_new_line != io.KeyCtrl))
{
validated = true;
if (io.ConfigInputTextEnterKeepActive && !is_multiline)
@@ -8879,6 +8883,7 @@ void ImGui::EndMenuBar()
PopClipRect();
PopID();
IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'"
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.
// FIXME: Extremely confusing, cleanup by (a) working on WorkRect stack system (b) not using a Group confusingly here.
@@ -9358,6 +9363,7 @@ struct ImGuiTabBarSection
{
int TabCount; // Number of tabs in this section.
float Width; // Sum of width of tabs in this section (after shrinking down)
float WidthAfterShrinkMinWidth;
float Spacing; // Horizontal spacing at the end of the section.
ImGuiTabBarSection() { memset(this, 0, sizeof(*this)); }
@@ -9429,8 +9435,8 @@ bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags)
ImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id);
ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->WorkRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2);
tab_bar->ID = id;
tab_bar->SeparatorMinX = tab_bar->BarRect.Min.x - IM_TRUNC(window->WindowPadding.x * 0.5f);
tab_bar->SeparatorMaxX = tab_bar->BarRect.Max.x + IM_TRUNC(window->WindowPadding.x * 0.5f);
tab_bar->SeparatorMinX = tab_bar_bb.Min.x - IM_TRUNC(window->WindowPadding.x * 0.5f);
tab_bar->SeparatorMaxX = tab_bar_bb.Max.x + IM_TRUNC(window->WindowPadding.x * 0.5f);
//if (g.NavWindow && IsWindowChildOf(g.NavWindow, window, false, false))
flags |= ImGuiTabBarFlags_IsFocused;
return BeginTabBarEx(tab_bar, tab_bar_bb, flags);
@@ -9550,6 +9556,10 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
ImGuiContext& g = *GImGui;
tab_bar->WantLayout = false;
// Track selected tab when resizing our parent down
const bool scroll_to_selected_tab = (tab_bar->BarRectPrevWidth > tab_bar->BarRect.GetWidth());
tab_bar->BarRectPrevWidth = tab_bar->BarRect.GetWidth();
// Garbage collect by compacting list
// Detect if we need to sort out tab list (e.g. in rare case where a tab changed section)
int tab_dst_n = 0;
@@ -9626,6 +9636,9 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
int shrink_buffer_indexes[3] = { 0, sections[0].TabCount + sections[2].TabCount, sections[0].TabCount };
g.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size);
// Minimum shrink width
const float shrink_min_width = (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyMixed) ? g.Style.TabMinWidthShrink : 1.0f;
// Compute ideal tabs widths + store them into shrink buffer
ImGuiTabItem* most_recently_selected_tab = NULL;
int curr_section_n = -1;
@@ -9648,10 +9661,13 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
const char* tab_name = TabBarGetTabName(tab_bar, tab);
const bool has_close_button_or_unsaved_marker = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0 || (tab->Flags & ImGuiTabItemFlags_UnsavedDocument);
tab->ContentWidth = (tab->RequestedWidth >= 0.0f) ? tab->RequestedWidth : TabItemCalcSize(tab_name, has_close_button_or_unsaved_marker).x;
if ((tab->Flags & ImGuiTabItemFlags_Button) == 0)
tab->ContentWidth = ImMax(tab->ContentWidth, g.Style.TabMinWidthBase);
int section_n = TabItemGetSectionIdx(tab);
ImGuiTabBarSection* section = &sections[section_n];
section->Width += tab->ContentWidth + (section_n == curr_section_n ? g.Style.ItemInnerSpacing.x : 0.0f);
section->WidthAfterShrinkMinWidth += ImMin(tab->ContentWidth, shrink_min_width) + (section_n == curr_section_n ? g.Style.ItemInnerSpacing.x : 0.0f);
curr_section_n = section_n;
// Store data so we can build an array sorted by width if we need to shrink tabs down
@@ -9663,19 +9679,28 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
}
// Compute total ideal width (used for e.g. auto-resizing a window)
float width_all_tabs_after_min_width_shrink = 0.0f;
tab_bar->WidthAllTabsIdeal = 0.0f;
for (int section_n = 0; section_n < 3; section_n++)
{
tab_bar->WidthAllTabsIdeal += sections[section_n].Width + sections[section_n].Spacing;
width_all_tabs_after_min_width_shrink += sections[section_n].WidthAfterShrinkMinWidth + sections[section_n].Spacing;
}
// Horizontal scrolling buttons
// (note that TabBarScrollButtons() will alter BarRect.Max.x)
if ((tab_bar->WidthAllTabsIdeal > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll))
// Important: note that TabBarScrollButtons() will alter BarRect.Max.x.
const bool can_scroll = (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) || (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyMixed);
const float width_all_tabs_to_use_for_scroll = (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) ? tab_bar->WidthAllTabs : width_all_tabs_after_min_width_shrink;
tab_bar->ScrollButtonEnabled = ((width_all_tabs_to_use_for_scroll > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && can_scroll);
if (tab_bar->ScrollButtonEnabled)
if (ImGuiTabItem* scroll_and_select_tab = TabBarScrollingButtons(tab_bar))
{
scroll_to_tab_id = scroll_and_select_tab->ID;
if ((scroll_and_select_tab->Flags & ImGuiTabItemFlags_Button) == 0)
tab_bar->SelectedTabId = scroll_to_tab_id;
}
if (scroll_to_tab_id == 0 && scroll_to_selected_tab)
scroll_to_tab_id = tab_bar->SelectedTabId;
// Shrink widths if full tabs don't fit in their allocated space
float section_0_w = sections[0].Width + sections[0].Spacing;
@@ -9689,11 +9714,12 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
width_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); // Excess used to shrink leading/trailing section
// With ImGuiTabBarFlags_FittingPolicyScroll policy, we will only shrink leading/trailing if the central section is not visible anymore
if (width_excess >= 1.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible))
const bool can_shrink = (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyShrink) || (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyMixed);
if (width_excess >= 1.0f && (can_shrink || !central_section_is_visible))
{
int shrink_data_count = (central_section_is_visible ? sections[1].TabCount : sections[0].TabCount + sections[2].TabCount);
int shrink_data_offset = (central_section_is_visible ? sections[0].TabCount + sections[2].TabCount : 0);
ShrinkWidths(g.ShrinkWidthBuffer.Data + shrink_data_offset, shrink_data_count, width_excess);
ShrinkWidths(g.ShrinkWidthBuffer.Data + shrink_data_offset, shrink_data_count, width_excess, shrink_min_width);
// Apply shrunk values into tabs and sections
for (int tab_n = shrink_data_offset; tab_n < shrink_data_offset + shrink_data_count; tab_n++)
@@ -9748,7 +9774,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
// Apply request requests
if (scroll_to_tab_id != 0)
TabBarScrollToTab(tab_bar, scroll_to_tab_id, sections);
else if ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) && IsMouseHoveringRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, true) && IsWindowContentHoverable(g.CurrentWindow))
else if (tab_bar->ScrollButtonEnabled && IsMouseHoveringRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, true) && IsWindowContentHoverable(g.CurrentWindow))
{
const float wheel = g.IO.MouseWheelRequestAxisSwap ? g.IO.MouseWheel : g.IO.MouseWheelH;
const ImGuiKey wheel_key = g.IO.MouseWheelRequestAxisSwap ? ImGuiKey_MouseWheelY : ImGuiKey_MouseWheelX;
@@ -10022,7 +10048,7 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)
PushStyleColor(ImGuiCol_Text, arrow_col);
PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
PushItemFlag(ImGuiItemFlags_ButtonRepeat, true);
PushItemFlag(ImGuiItemFlags_ButtonRepeat | ImGuiItemFlags_NoNav, true);
const float backup_repeat_delay = g.IO.KeyRepeatDelay;
const float backup_repeat_rate = g.IO.KeyRepeatRate;
g.IO.KeyRepeatDelay = 0.250f;