Merge branch 'master' into docking # Conflicts: # imgui.h # imgui_internal.h
diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 8810b60..2443ef1 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp
@@ -9,7 +9,7 @@ // Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'. // This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*. -// This define is done in the example .vcxproj file and need to be replicated in your app (by e.g. editing imconfig.h) +// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index 4a2adaf..6565466 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h
@@ -8,7 +8,7 @@ // Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'. // This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*. -// This define is done in the example .vcxproj file and need to be replicated in your app (by e.g. editing imconfig.h) +// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4e4fbbf..8618820 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt
@@ -180,6 +180,7 @@ - Examples: Apple+Metal: Consolidated/simplified to get closer to other examples. (#3543) [@warrenm] - Examples: Apple+Metal: Forward events down so OS key combination like Cmd+Q can work. (#3554) [@rokups] - Examples: Emscripten: Renamed example_emscripten/ to example_emscripten_opengl3/. (#3632) +- Examples: DirectX12: Move ImGui::Render() call above the first barrier to clarify its lack of effect on the graphics pipe. - CI: Fix testing for Windows DLL builds. (#3603, #3601) [@iboB] - Docs: Split examples/README.txt into docs/BACKENDS.md and docs/EXAMPLES.md improved them. - Docs: Consistently renamed all occurences of "binding" and "back-end" to "backend" in comments and docs.
diff --git a/docs/FAQ.md b/docs/FAQ.md index f47015d..7ed9b06 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md
@@ -214,8 +214,6 @@ End(); ``` -We used "..." above to signify whatever was already pushed to the ID stack previously: - - If you have a same ID twice in the same location, you'll have a conflict: ```cpp Button("OK");
diff --git a/docs/README.md b/docs/README.md index a555588..b21ddae 100644 --- a/docs/README.md +++ b/docs/README.md
@@ -132,7 +132,7 @@ ### Upcoming Changes Some of the goals for 2020 are: -- Work on new Tables API (to replace Columns). (see [#2957](https://github.com/ocornut/imgui/issues/2957), in public [tables](https://github.com/ocornut/imgui/tree/tables) branch looking for feedback) +- Work on Tables (see [#2957](https://github.com/ocornut/imgui/issues/2957), now merged in master. - Work on Docking (see [#2109](https://github.com/ocornut/imgui/issues/2109), in public [docking](https://github.com/ocornut/imgui/tree/docking) branch) - Work on Multi-Viewport / Multiple OS windows. (see [#1542](https://github.com/ocornut/imgui/issues/1542), in public [docking](https://github.com/ocornut/imgui/tree/docking) branch looking for feedback) - Work on gamepad/keyboard controls. (see [#787](https://github.com/ocornut/imgui/issues/787))
diff --git a/docs/TODO.txt b/docs/TODO.txt index 84fac88..9efcc5b 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt
@@ -129,18 +129,6 @@ - group: IsHovered() after EndGroup() covers whole aabb rather than the intersection of individual items. Is that desirable? - group: merge deactivation/activation within same group (fwd WasEdited flag). (#2550) - - columns: sizing policy (e.g. for each column: fixed size, %, fill, distribute default size among fills) (#513, #125) - - columns: add a conditional parameter to SetColumnOffset() (#513, #125) - - columns: headers. re-orderable. (#513, #125) - - columns: optional sorting modifiers (up/down), sort list so sorting can be done multi-criteria. notify user when sort order changed. - - columns: option to alternate background colors on odd/even scanlines. - - columns: allow columns to recurse. - - columns: allow a same columns set to be interrupted by e.g. CollapsingHeader and resume with columns in sync when moving them. - - columns: sizing is lossy when columns width is very small (default width may turn negative etc.) - - columns: separator function or parameter that works within the column (currently Separator() bypass all columns) (#125) - - columns: flag to add horizontal separator above/below) - - columns/layout: setup minimum line height (equivalent of automatically calling AlignFirstTextHeightToWidgets) - !- color: the color conversion helpers/types are a mess and needs sorting out. - color: (api breaking) ImGui::ColorConvertXXX functions should be loose ImColorConvertXX to match imgui_internals.h
diff --git a/examples/example_glfw_opengl2/build_win32.bat b/examples/example_glfw_opengl2/build_win32.bat index ce08445..a0a75f9 100644 --- a/examples/example_glfw_opengl2/build_win32.bat +++ b/examples/example_glfw_opengl2/build_win32.bat
@@ -1,3 +1,8 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. -mkdir Debug -cl /nologo /Zi /MD /I .. /I ..\.. /I ..\libs\glfw\include *.cpp ..\..\backends\imgui_impl_opengl2.cpp ..\..\backends\imgui_impl_glfw.cpp ..\..\imgui*.cpp /FeDebug/example_glfw_opengl2.exe /FoDebug/ /link /LIBPATH:..\libs\glfw\lib-vc2010-32 glfw3.lib opengl32.lib gdi32.lib shell32.lib +@set OUT_DIR=Debug +@set OUT_EXE=example_glfw_opengl2 +@set INCLUDES=/I..\.. /I..\..\backends /I..\libs\glfw\include +@set SOURCES=main.cpp ..\..\backends\imgui_impl_opengl2.cpp ..\..\backends\imgui_impl_glfw.cpp ..\..\imgui*.cpp +@set LIBS=/LIBPATH:..\libs\glfw\lib-vc2010-32 glfw3.lib opengl32.lib gdi32.lib shell32.lib +mkdir %OUT_DIR% +cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
diff --git a/examples/example_glfw_opengl3/build_win32.bat b/examples/example_glfw_opengl3/build_win32.bat index eb755d6..83a0ef8 100644 --- a/examples/example_glfw_opengl3/build_win32.bat +++ b/examples/example_glfw_opengl3/build_win32.bat
@@ -1,3 +1,8 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. -mkdir Debug -cl /nologo /Zi /MD /I .. /I ..\.. /I ..\libs\glfw\include /I ..\libs\gl3w *.cpp ..\..\backends\imgui_impl_glfw.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp ..\libs\gl3w\GL\gl3w.c /FeDebug/example_glfw_opengl3.exe /FoDebug/ /link /LIBPATH:..\libs\glfw\lib-vc2010-32 glfw3.lib opengl32.lib gdi32.lib shell32.lib +@set OUT_DIR=Debug +@set OUT_EXE=example_glfw_opengl3 +@set INCLUDES=/I..\.. /I..\..\backends /I..\libs\glfw\include /I..\libs\gl3w +@set SOURCES=main.cpp ..\..\backends\imgui_impl_glfw.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp ..\libs\gl3w\GL\gl3w.c +@set LIBS=/LIBPATH:..\libs\glfw\lib-vc2010-32 glfw3.lib opengl32.lib gdi32.lib shell32.lib +mkdir %OUT_DIR% +cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
diff --git a/examples/example_glfw_vulkan/build_win32.bat b/examples/example_glfw_vulkan/build_win32.bat index ad53cb0..f49cbd7 100644 --- a/examples/example_glfw_vulkan/build_win32.bat +++ b/examples/example_glfw_vulkan/build_win32.bat
@@ -1,7 +1,14 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. -mkdir Debug -cl /nologo /Zi /MD /I .. /I ..\.. /I ..\libs\glfw\include /I %VULKAN_SDK%\include *.cpp ..\..\backends\imgui_impl_vulkan.cpp ..\..\backends\imgui_impl_glfw.cpp ..\..\imgui*.cpp /FeDebug/example_glfw_vulkan.exe /FoDebug/ /link /LIBPATH:..\libs\glfw\lib-vc2010-32 /libpath:%VULKAN_SDK%\lib32 glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib +@set OUT_EXE=example_glfw_vulkan +@set INCLUDES=/I..\.. /I..\..\backends /I..\libs\glfw\include /I %VULKAN_SDK%\include +@set SOURCES=main.cpp ..\..\backends\imgui_impl_vulkan.cpp ..\..\backends\imgui_impl_glfw.cpp ..\..\imgui*.cpp +@set LIBS=/LIBPATH:..\libs\glfw\lib-vc2010-32 /libpath:%VULKAN_SDK%\lib32 glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib -mkdir Release -cl /nologo /Zi /MD /Ox /Oi /I .. /I ..\.. /I ..\libs\glfw\include /I %VULKAN_SDK%\include *.cpp ..\..\backends\imgui_impl_vulkan.cpp ..\..\backends\imgui_impl_glfw.cpp ..\..\imgui*.cpp /FeRelease/example_glfw_vulkan.exe /FoRelease/ /link /LIBPATH:..\libs\glfw\lib-vc2010-32 /libpath:%VULKAN_SDK%\lib32 glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib +@set OUT_DIR=Debug +mkdir %OUT_DIR% +cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% + +@set OUT_DIR=Release +mkdir %OUT_DIR% +cl /nologo /Zi /MD /Ox /Oi %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
diff --git a/examples/example_glfw_vulkan/build_win64.bat b/examples/example_glfw_vulkan/build_win64.bat index d6b24b5..893f296 100644 --- a/examples/example_glfw_vulkan/build_win64.bat +++ b/examples/example_glfw_vulkan/build_win64.bat
@@ -1,7 +1,13 @@ @REM Build for Visual Studio compiler. Run your copy of amd64/vcvars32.bat to setup 64-bit command-line compiler. -mkdir Debug -cl /nologo /Zi /MD /I .. /I ..\.. /I ..\libs\glfw\include /I %VULKAN_SDK%\include *.cpp ..\..\backends\imgui_impl_vulkan.cpp ..\..\backends\imgui_impl_glfw.cpp ..\..\imgui*.cpp /FeDebug/example_glfw_vulkan.exe /FoDebug/ /link /LIBPATH:..\libs\glfw\lib-vc2010-64 /libpath:%VULKAN_SDK%\lib glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib +@set INCLUDES=/I..\.. /I..\..\backends /I..\libs\glfw\include /I %VULKAN_SDK%\include +@set SOURCES=main.cpp ..\..\backends\imgui_impl_vulkan.cpp ..\..\backends\imgui_impl_glfw.cpp ..\..\imgui*.cpp +@set LIBS=/LIBPATH:..\libs\glfw\lib-vc2010-64 /libpath:%VULKAN_SDK%\lib glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib -mkdir Release -cl /nologo /Zi /MD /Ox /Oi /I .. /I ..\.. /I ..\libs\glfw\include /I %VULKAN_SDK%\include *.cpp ..\..\backends\imgui_impl_vulkan.cpp ..\..\backends\imgui_impl_glfw.cpp ..\..\imgui*.cpp /FeRelease/example_glfw_vulkan.exe /FoRelease/ /link /LIBPATH:..\libs\glfw\lib-vc2010-64 /libpath:%VULKAN_SDK%\lib glfw3.lib opengl32.lib gdi32.lib shell32.lib vulkan-1.lib +@set OUT_DIR=Debug +mkdir %OUT_DIR% +cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% + +@set OUT_DIR=Release +mkdir %OUT_DIR% +cl /nologo /Zi /MD /Ox /Oi %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
diff --git a/examples/example_sdl_directx11/build_win32.bat b/examples/example_sdl_directx11/build_win32.bat index b0b4d88..7433c74 100644 --- a/examples/example_sdl_directx11/build_win32.bat +++ b/examples/example_sdl_directx11/build_win32.bat
@@ -1,8 +1,8 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. -set OUT_DIR=Debug -set OUT_EXE=example_sdl_directx11 -set INCLUDES=/I.. /I..\.. /I%SDL2_DIR%\include /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" /I "%DXSDK_DIR%Include" -set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl.cpp ..\..\backends\imgui_impl_dx11.cpp ..\..\imgui*.cpp -set LIBS=/libpath:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib /LIBPATH:"%DXSDK_DIR%/Lib/x86" d3d11.lib d3dcompiler.lib +@set OUT_DIR=Debug +@set OUT_EXE=example_sdl_directx11 +@set INCLUDES=/I..\.. /I..\..\backends /I%SDL2_DIR%\include /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" /I "%DXSDK_DIR%Include" +@set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl.cpp ..\..\backends\imgui_impl_dx11.cpp ..\..\imgui*.cpp +@set LIBS=/LIBPATH:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib /LIBPATH:"%DXSDK_DIR%/Lib/x86" d3d11.lib d3dcompiler.lib mkdir %OUT_DIR% cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console
diff --git a/examples/example_sdl_opengl2/build_win32.bat b/examples/example_sdl_opengl2/build_win32.bat index 71157f5..d7fb003 100644 --- a/examples/example_sdl_opengl2/build_win32.bat +++ b/examples/example_sdl_opengl2/build_win32.bat
@@ -1,8 +1,8 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. -set OUT_DIR=Debug -set OUT_EXE=example_sdl_opengl2 -set INCLUDES=/I.. /I..\.. /I%SDL2_DIR%\include -set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl.cpp ..\..\backends\imgui_impl_opengl2.cpp ..\..\imgui*.cpp -set LIBS=/libpath:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib +@set OUT_DIR=Debug +@set OUT_EXE=example_sdl_opengl2 +@set INCLUDES=/I..\.. /I..\..\backends /I%SDL2_DIR%\include +@set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl.cpp ..\..\backends\imgui_impl_opengl2.cpp ..\..\imgui*.cpp +@set LIBS=/LIBPATH:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib mkdir %OUT_DIR% cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console
diff --git a/examples/example_sdl_opengl3/build_win32.bat b/examples/example_sdl_opengl3/build_win32.bat index d13cc94..8f54960 100644 --- a/examples/example_sdl_opengl3/build_win32.bat +++ b/examples/example_sdl_opengl3/build_win32.bat
@@ -1,8 +1,8 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. -set OUT_DIR=Debug -set OUT_EXE=example_sdl_opengl3 -set INCLUDES=/I.. /I..\.. /I%SDL2_DIR%\include /I..\libs\gl3w -set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp ..\libs\gl3w\GL\gl3w.c -set LIBS=/libpath:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib +@set OUT_DIR=Debug +@set OUT_EXE=example_sdl_opengl3 +@set INCLUDES=/I..\.. /I..\..\backends /I%SDL2_DIR%\include /I..\libs\gl3w +@set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl.cpp ..\..\backends\imgui_impl_opengl3.cpp ..\..\imgui*.cpp ..\libs\gl3w\GL\gl3w.c +@set LIBS=/LIBPATH:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib opengl32.lib mkdir %OUT_DIR% cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console
diff --git a/examples/example_win32_directx10/build_win32.bat b/examples/example_win32_directx10/build_win32.bat index 75cb837..fd74223 100644 --- a/examples/example_win32_directx10/build_win32.bat +++ b/examples/example_win32_directx10/build_win32.bat
@@ -1,4 +1,8 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. -mkdir Debug -cl /nologo /Zi /MD /I .. /I ..\.. /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" /I "%DXSDK_DIR%Include" /D UNICODE /D _UNICODE *.cpp ..\..\backends\imgui_impl_win32.cpp ..\..\backends\imgui_impl_dx10.cpp ..\..\imgui*.cpp /FeDebug/example_win32_directx10.exe /FoDebug/ /link /LIBPATH:"%DXSDK_DIR%/Lib/x86" d3d10.lib d3dcompiler.lib - +@set OUT_DIR=Debug +@set OUT_EXE=example_win32_directx10 +@set INCLUDES=/I..\.. /I..\..\backends /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" /I "%DXSDK_DIR%Include" +@set SOURCES=main.cpp ..\..\backends\imgui_impl_win32.cpp ..\..\backends\imgui_impl_dx10.cpp ..\..\imgui*.cpp +@set LIBS=/LIBPATH:"%DXSDK_DIR%/Lib/x86" d3d10.lib d3dcompiler.lib +mkdir %OUT_DIR% +cl /nologo /Zi /MD %INCLUDES% /D UNICODE /D _UNICODE %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
diff --git a/examples/example_win32_directx11/build_win32.bat b/examples/example_win32_directx11/build_win32.bat index cbe96b0..b1cf7d1 100644 --- a/examples/example_win32_directx11/build_win32.bat +++ b/examples/example_win32_directx11/build_win32.bat
@@ -1,4 +1,9 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. -mkdir Debug -cl /nologo /Zi /MD /I .. /I ..\.. /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" /I "%DXSDK_DIR%Include" /D UNICODE /D _UNICODE *.cpp ..\..\backends\imgui_impl_dx11.cpp ..\..\backends\imgui_impl_win32.cpp ..\..\imgui*.cpp /FeDebug/example_win32_directx11.exe /FoDebug/ /link /LIBPATH:"%DXSDK_DIR%/Lib/x86" d3d11.lib d3dcompiler.lib +@set OUT_DIR=Debug +@set OUT_EXE=example_win32_directx11 +@set INCLUDES=/I..\.. /I..\..\backends /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" /I "%DXSDK_DIR%Include" +@set SOURCES=main.cpp ..\..\backends\imgui_impl_dx11.cpp ..\..\backends\imgui_impl_win32.cpp ..\..\imgui*.cpp +@set LIBS=/LIBPATH:"%DXSDK_DIR%/Lib/x86" d3d11.lib d3dcompiler.lib +mkdir %OUT_DIR% +cl /nologo /Zi /MD %INCLUDES% /D UNICODE /D _UNICODE %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
diff --git a/examples/example_win32_directx12/build_win32.bat b/examples/example_win32_directx12/build_win32.bat index 5556dfe..48dadb2 100644 --- a/examples/example_win32_directx12/build_win32.bat +++ b/examples/example_win32_directx12/build_win32.bat
@@ -1,5 +1,9 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. @REM Important: to build on 32-bit systems, the DX12 backends needs '#define ImTextureID ImU64', so we pass it here. +@set OUT_DIR=Debug +@set OUT_EXE=example_win32_directx12 +@set INCLUDES=/I..\.. /I..\..\backends /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" +@set SOURCES=main.cpp ..\..\backends\imgui_impl_dx12.cpp ..\..\backends\imgui_impl_win32.cpp ..\..\imgui*.cpp +@set LIBS=d3d12.lib d3dcompiler.lib dxgi.lib mkdir Debug -cl /nologo /Zi /MD /I .. /I ..\.. /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" /D ImTextureID=ImU64 /D UNICODE /D _UNICODE *.cpp ..\..\backends\imgui_impl_dx12.cpp ..\..\backends\imgui_impl_win32.cpp ..\..\imgui*.cpp /FeDebug/example_win32_directx12.exe /FoDebug/ /link d3d12.lib d3dcompiler.lib dxgi.lib - +cl /nologo /Zi /MD %INCLUDES% /D ImTextureID=ImU64 /D UNICODE /D _UNICODE %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index f711602..5cec361 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp
@@ -1,7 +1,10 @@ // Dear ImGui: standalone example application for DirectX 12 // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. // Read online: https://github.com/ocornut/imgui/tree/master/docs -// FIXME: 64-bit only for now! (Because sizeof(ImTextureId) == sizeof(void*)) + +// Important: to compile on 32-bit systems, the DirectX12 backend requires code to be compiled with '#define ImTextureID ImU64'. +// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*. +// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file. #include "imgui.h" #include "imgui_impl_win32.h" @@ -185,9 +188,11 @@ } // Rendering - FrameContext* frameCtxt = WaitForNextFrameResources(); + ImGui::Render(); + + FrameContext* frameCtx = WaitForNextFrameResources(); UINT backBufferIdx = g_pSwapChain->GetCurrentBackBufferIndex(); - frameCtxt->CommandAllocator->Reset(); + frameCtx->CommandAllocator->Reset(); D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; @@ -196,13 +201,13 @@ barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; - - g_pd3dCommandList->Reset(frameCtxt->CommandAllocator, NULL); + g_pd3dCommandList->Reset(frameCtx->CommandAllocator, NULL); g_pd3dCommandList->ResourceBarrier(1, &barrier); + + // Render Dear ImGui graphics g_pd3dCommandList->ClearRenderTargetView(g_mainRenderTargetDescriptor[backBufferIdx], (float*)&clear_color, 0, NULL); g_pd3dCommandList->OMSetRenderTargets(1, &g_mainRenderTargetDescriptor[backBufferIdx], FALSE, NULL); g_pd3dCommandList->SetDescriptorHeaps(1, &g_pd3dSrvDescHeap); - ImGui::Render(); ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), g_pd3dCommandList); barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; @@ -224,10 +229,12 @@ UINT64 fenceValue = g_fenceLastSignaledValue + 1; g_pd3dCommandQueue->Signal(g_fence, fenceValue); g_fenceLastSignaledValue = fenceValue; - frameCtxt->FenceValue = fenceValue; + frameCtx->FenceValue = fenceValue; } WaitForLastSubmittedFrame(); + + // Cleanup ImGui_ImplDX12_Shutdown(); ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); @@ -401,13 +408,13 @@ void WaitForLastSubmittedFrame() { - FrameContext* frameCtxt = &g_frameContext[g_frameIndex % NUM_FRAMES_IN_FLIGHT]; + FrameContext* frameCtx = &g_frameContext[g_frameIndex % NUM_FRAMES_IN_FLIGHT]; - UINT64 fenceValue = frameCtxt->FenceValue; + UINT64 fenceValue = frameCtx->FenceValue; if (fenceValue == 0) return; // No fence was signaled - frameCtxt->FenceValue = 0; + frameCtx->FenceValue = 0; if (g_fence->GetCompletedValue() >= fenceValue) return; @@ -423,11 +430,11 @@ HANDLE waitableObjects[] = { g_hSwapChainWaitableObject, NULL }; DWORD numWaitableObjects = 1; - FrameContext* frameCtxt = &g_frameContext[nextFrameIndex % NUM_FRAMES_IN_FLIGHT]; - UINT64 fenceValue = frameCtxt->FenceValue; + FrameContext* frameCtx = &g_frameContext[nextFrameIndex % NUM_FRAMES_IN_FLIGHT]; + UINT64 fenceValue = frameCtx->FenceValue; if (fenceValue != 0) // means no fence was signaled { - frameCtxt->FenceValue = 0; + frameCtx->FenceValue = 0; g_fence->SetEventOnCompletion(fenceValue, g_fenceEvent); waitableObjects[1] = g_fenceEvent; numWaitableObjects = 2; @@ -435,7 +442,7 @@ WaitForMultipleObjects(numWaitableObjects, waitableObjects, TRUE, INFINITE); - return frameCtxt; + return frameCtx; } void ResizeSwapChain(HWND hWnd, int width, int height)
diff --git a/examples/example_win32_directx9/build_win32.bat b/examples/example_win32_directx9/build_win32.bat index 1378103..bbd4b13 100644 --- a/examples/example_win32_directx9/build_win32.bat +++ b/examples/example_win32_directx9/build_win32.bat
@@ -1,3 +1,8 @@ @REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. -mkdir Debug -cl /nologo /Zi /MD /I .. /I ..\.. /I "%DXSDK_DIR%/Include" /D UNICODE /D _UNICODE *.cpp ..\..\backends\imgui_impl_dx9.cpp ..\..\backends\imgui_impl_win32.cpp ..\..\imgui*.cpp /FeDebug/example_win32_directx9.exe /FoDebug/ /link /LIBPATH:"%DXSDK_DIR%/Lib/x86" d3d9.lib +@set OUT_DIR=Debug +@set OUT_EXE=example_win32_directx9 +@set INCLUDES=/I..\.. /I..\..\backends /I "%DXSDK_DIR%/Include" +@set SOURCES=main.cpp ..\..\backends\imgui_impl_dx9.cpp ..\..\backends\imgui_impl_win32.cpp ..\..\imgui*.cpp +@set LIBS=/LIBPATH:"%DXSDK_DIR%/Lib/x86" d3d9.lib +mkdir %OUT_DIR% +cl /nologo /Zi /MD %INCLUDES% /D UNICODE /D _UNICODE %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
diff --git a/imgui.cpp b/imgui.cpp index 34b7634..a03c5d0 100644 --- a/imgui.cpp +++ b/imgui.cpp
@@ -6089,6 +6089,8 @@ window->HiddenFramesCanSkipItems--; if (window->HiddenFramesCannotSkipItems > 0) window->HiddenFramesCannotSkipItems--; + if (window->HiddenFramesForRenderOnly > 0) + window->HiddenFramesForRenderOnly--; // Hide new windows for one frame until they calculate their size if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api)) @@ -6730,7 +6732,7 @@ window->HiddenFramesCanSkipItems = 1; // Update the Hidden flag - window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0); + window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0) || (window->HiddenFramesForRenderOnly > 0); // Update the SkipItems flag, used to early out of all items functions (no layout required) bool skip_items = false; @@ -8505,7 +8507,7 @@ { // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one. window->Hidden = true; - window->HiddenFramesCanSkipItems = 1; + window->HiddenFramesCanSkipItems = 1; // FIXME: This may not be necessary? ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount); } ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking;
diff --git a/imgui.h b/imgui.h index 52110b8..83cc6ea 100644 --- a/imgui.h +++ b/imgui.h
@@ -27,15 +27,13 @@ // ImVector<> // ImGuiStyle // ImGuiIO -// Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiWindowClass, ImGuiPayload) +// Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiWindowClass, ImGuiPayload, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) // Obsolete functions // Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) // Draw List API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData) // Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) // Platform interface for multi-viewport support (ImGuiPlatformIO, ImGuiPlatformMonitor, ImGuiViewportFlags, ImGuiViewport) -// FIXME-TABLE: Add ImGuiTableSortSpecs and ImGuiTableColumnSortSpecs in "Misc data structures" section above (we don't do it right now to facilitate merging various branches) - */ #pragma once @@ -65,8 +63,9 @@ #define IMGUI_VERSION "1.80 WIP" #define IMGUI_VERSION_NUM 17906 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) -#define IMGUI_HAS_VIEWPORT 1 // Viewport WIP branch -#define IMGUI_HAS_DOCK 1 // Docking WIP branch +#define IMGUI_HAS_TABLE +#define IMGUI_HAS_VIEWPORT // Viewport WIP branch +#define IMGUI_HAS_DOCK // Docking WIP branch // Define attributes of all API symbols declarations (e.g. for DLL under Windows) // IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default backends files (imgui_impl_xxx.h) @@ -692,7 +691,6 @@ // TableNextRow() -> Text("Hello 0") // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear! // ---------------------------------------------------------------------------------------------------------- // - 5. Call EndTable() - #define IMGUI_HAS_TABLE 1 IMGUI_API bool BeginTable(const char* str_id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f); IMGUI_API void EndTable(); // only call EndTable() if BeginTable() returns true! IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); // append into the first cell of a new row. @@ -1101,38 +1099,40 @@ ImGuiTableFlags_Reorderable = 1 << 1, // Allow reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers) ImGuiTableFlags_Hideable = 1 << 2, // Allow hiding/disabling columns in context menu. ImGuiTableFlags_Sortable = 1 << 3, // Allow sorting on one column (sort_specs_count will always be == 1). Call TableGetSortSpecs() to obtain sort specs. - ImGuiTableFlags_MultiSortable = 1 << 4, // Allow sorting on multiple columns by holding Shift (sort_specs_count may be > 1). Call TableGetSortSpecs() to obtain sort specs. - ImGuiTableFlags_NoSavedSettings = 1 << 5, // Disable persisting columns order, width and sort settings in the .ini file. - ImGuiTableFlags_ContextMenuInBody = 1 << 6, // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow(). + ImGuiTableFlags_NoSavedSettings = 1 << 4, // Disable persisting columns order, width and sort settings in the .ini file. + ImGuiTableFlags_ContextMenuInBody = 1 << 5, // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow(). // Decorations - ImGuiTableFlags_RowBg = 1 << 7, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually) - ImGuiTableFlags_BordersInnerH = 1 << 8, // Draw horizontal borders between rows. - ImGuiTableFlags_BordersOuterH = 1 << 9, // Draw horizontal borders at the top and bottom. - ImGuiTableFlags_BordersInnerV = 1 << 10, // Draw vertical borders between columns. - ImGuiTableFlags_BordersOuterV = 1 << 11, // Draw vertical borders on the left and right sides. + ImGuiTableFlags_RowBg = 1 << 6, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually) + ImGuiTableFlags_BordersInnerH = 1 << 7, // Draw horizontal borders between rows. + ImGuiTableFlags_BordersOuterH = 1 << 8, // Draw horizontal borders at the top and bottom. + ImGuiTableFlags_BordersInnerV = 1 << 9, // Draw vertical borders between columns. + ImGuiTableFlags_BordersOuterV = 1 << 10, // Draw vertical borders on the left and right sides. ImGuiTableFlags_BordersH = ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH, // Draw horizontal borders. ImGuiTableFlags_BordersV = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV, // Draw vertical borders. ImGuiTableFlags_BordersInner = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersInnerH, // Draw inner borders. ImGuiTableFlags_BordersOuter = ImGuiTableFlags_BordersOuterV | ImGuiTableFlags_BordersOuterH, // Draw outer borders. ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, // Draw all borders. - ImGuiTableFlags_NoBordersInBody = 1 << 12, // Disable vertical borders in columns Body (borders will always appears in Headers). - ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 13, // Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers). + ImGuiTableFlags_NoBordersInBody = 1 << 11, // Disable vertical borders in columns Body (borders will always appears in Headers). + ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12, // Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers). // Sizing - ImGuiTableFlags_ColumnsWidthStretch = 1 << 14, // Default if ScrollX is off. Columns will default to use _WidthStretch. Read description above for more details. - ImGuiTableFlags_ColumnsWidthFixed = 1 << 15, // Default if ScrollX is on. Columns will default to use _WidthFixed or _WidthAutoResize policy (if Resizable is off). Read description above for more details. - ImGuiTableFlags_SameWidths = 1 << 16, // Make all columns the same widths which is useful with Fixed columns policy (but granted by default with Stretch policy + no resize). Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible and disable ImGuiTableFlags_Resizable. - ImGuiTableFlags_NoHeadersWidth = 1 << 17, // Disable headers' contribution to automatic width calculation. - ImGuiTableFlags_NoHostExtendY = 1 << 18, // Disable extending past the limit set by outer_size.y, only meaningful when neither of ScrollX|ScrollY are set (data below the limit will be clipped and not visible) - ImGuiTableFlags_NoKeepColumnsVisible = 1 << 19, // Disable keeping column always minimally visible when ScrollX is off and table gets too small. - ImGuiTableFlags_PreciseWidths = 1 << 20, // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth. - ImGuiTableFlags_NoClip = 1 << 21, // Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze(). + ImGuiTableFlags_ColumnsWidthStretch = 1 << 13, // Default if ScrollX is off. Columns will default to use _WidthStretch. Read description above for more details. + ImGuiTableFlags_ColumnsWidthFixed = 1 << 14, // Default if ScrollX is on. Columns will default to use _WidthFixed or _WidthAutoResize policy (if Resizable is off). Read description above for more details. + ImGuiTableFlags_SameWidths = 1 << 15, // Make all columns the same widths which is useful with Fixed columns policy (but granted by default with Stretch policy + no resize). Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible and disable ImGuiTableFlags_Resizable. + ImGuiTableFlags_NoHeadersWidth = 1 << 16, // Disable headers' contribution to automatic width calculation. + ImGuiTableFlags_NoHostExtendY = 1 << 17, // Disable extending past the limit set by outer_size.y, only meaningful when neither of ScrollX|ScrollY are set (data below the limit will be clipped and not visible) + ImGuiTableFlags_NoKeepColumnsVisible = 1 << 18, // Disable keeping column always minimally visible when ScrollX is off and table gets too small. + ImGuiTableFlags_PreciseWidths = 1 << 19, // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth. + ImGuiTableFlags_NoClip = 1 << 20, // Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze(). // Padding - ImGuiTableFlags_PadOuterX = 1 << 22, // Default if BordersOuterV is on. Enable outer-most padding. - ImGuiTableFlags_NoPadOuterX = 1 << 23, // Default if BordersOuterV is off. Disable outer-most padding. - ImGuiTableFlags_NoPadInnerX = 1 << 24, // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off). + ImGuiTableFlags_PadOuterX = 1 << 21, // Default if BordersOuterV is on. Enable outer-most padding. + ImGuiTableFlags_NoPadOuterX = 1 << 22, // Default if BordersOuterV is off. Disable outer-most padding. + ImGuiTableFlags_NoPadInnerX = 1 << 23, // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off). // Scrolling - ImGuiTableFlags_ScrollX = 1 << 25, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this create a child window, ScrollY is currently generally recommended when using ScrollX. - ImGuiTableFlags_ScrollY = 1 << 26 // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. + ImGuiTableFlags_ScrollX = 1 << 24, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this create a child window, ScrollY is currently generally recommended when using ScrollX. + ImGuiTableFlags_ScrollY = 1 << 25, // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. + // Sorting + ImGuiTableFlags_SortMulti = 1 << 26, // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1). + ImGuiTableFlags_SortTristate = 1 << 27 // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0). }; // Flags for ImGui::TableSetupColumn() @@ -1152,7 +1152,7 @@ ImGuiTableColumnFlags_NoSort = 1 << 9, // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table). ImGuiTableColumnFlags_NoSortAscending = 1 << 10, // Disable ability to sort in the ascending direction. ImGuiTableColumnFlags_NoSortDescending = 1 << 11, // Disable ability to sort in the descending direction. - ImGuiTableColumnFlags_NoHeaderWidth = 1 << 12, // Header width don't contribute to automatic column width. + ImGuiTableColumnFlags_NoHeaderWidth = 1 << 12, // Disable header text width contribution to automatic column width. ImGuiTableColumnFlags_PreferSortAscending = 1 << 13, // Make the initial sort direction Ascending when first sorting on this column (default). ImGuiTableColumnFlags_PreferSortDescending = 1 << 14, // Make the initial sort direction Descending when first sorting on this column. ImGuiTableColumnFlags_IndentEnable = 1 << 15, // Use current Indent value when entering cell (default for column 0). @@ -1190,11 +1190,9 @@ enum ImGuiTableBgTarget_ { ImGuiTableBgTarget_None = 0, - //ImGuiTableBgTarget_ColumnBg0 = 1, // FIXME-TABLE: Todo. Set column background color 0 (generally used for background - //ImGuiTableBgTarget_ColumnBg1 = 2, // FIXME-TABLE: Todo. Set column background color 1 (generally used for selection marking) - ImGuiTableBgTarget_RowBg0 = 3, // Set row background color 0 (generally used for background, automatically set when ImGuiTableFlags_RowBg is used) - ImGuiTableBgTarget_RowBg1 = 4, // Set row background color 1 (generally used for selection marking) - ImGuiTableBgTarget_CellBg = 5 // Set cell background color (top-most color) + ImGuiTableBgTarget_RowBg0 = 1, // Set row background color 0 (generally used for background, automatically set when ImGuiTableFlags_RowBg is used) + ImGuiTableBgTarget_RowBg1 = 2, // Set row background color 1 (generally used for selection marking) + ImGuiTableBgTarget_CellBg = 3 // Set cell background color (top-most color) }; // Flags for ImGui::IsWindowFocused() @@ -2023,7 +2021,7 @@ struct ImGuiTableSortSpecs { const ImGuiTableColumnSortSpecs* Specs; // Pointer to sort spec array. - int SpecsCount; // Sort spec count. Most often 1 unless e.g. ImGuiTableFlags_MultiSortable is enabled. + int SpecsCount; // Sort spec count. Most often 1. May be > 1 when ImGuiTableFlags_SortMulti is enabled. May be == 0 when ImGuiTableFlags_SortTristate is enabled. bool SpecsDirty; // Set to true when specs have changed since last time! Use this to sort again, then clear the flag. ImGuiTableSortSpecs() { memset(this, 0, sizeof(*this)); }
diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 4df021c..5a5665f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp
@@ -3652,7 +3652,7 @@ // If there is not enough available width to fit all columns, they will however be resized down. // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings HelpMarker( - "Using _Resizable + _ColumnsWidthFixedX flags.\n" + "Using _Resizable + _ColumnsWidthFixed flags.\n" "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n" "Double-click a column border to auto-fit the column to its contents."); static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_ColumnsWidthFixed | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; @@ -3785,7 +3785,8 @@ "e.g.:\n" "- BorderOuterV\n" "- any form of row selection\n" - "Because of this, activating BorderOuterV sets the default to PadOuterX. Using PadOuterX or NoPadOuterX you can override the default.\n"); + "Because of this, activating BorderOuterV sets the default to PadOuterX. Using PadOuterX or NoPadOuterX you can override the default.\n\n" + "Actual padding values are using style.CellPadding."); PushStyleCompact(); ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags, ImGuiTableFlags_PadOuterX); @@ -4087,7 +4088,7 @@ HelpMarker("This section allows you to interact and see the effect of StretchX vs FixedX sizing policies depending on whether Scroll is enabled and the contents of your columns."); enum ContentsType { CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText }; static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg; - static int contents_type = CT_Button; + static int contents_type = CT_LongText; static int column_count = 3; PushStyleCompact(); @@ -4633,8 +4634,6 @@ ImGui::SetNextItemOpen(open_action != 0); if (ImGui::TreeNode("Sorting")) { - HelpMarker("Use Shift+Click to sort on multiple columns"); - // Create item list static ImVector<MyItem> items; if (items.Size == 0) @@ -4650,10 +4649,16 @@ } } - ImGuiTableFlags flags = - ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_MultiSortable + // Options + static ImGuiTableFlags flags = + ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_ScrollY; + ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti); + ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1)."); + ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate); + ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0)."); + if (ImGui::BeginTable("##table", 4, flags, ImVec2(0, TEXT_BASE_HEIGHT * 15), 0.0f)) { // Declare columns @@ -4712,11 +4717,11 @@ if (ImGui::TreeNode("Advanced")) { static ImGuiTableFlags flags = - ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_MultiSortable + ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable + | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY - | ImGuiTableFlags_ColumnsWidthFixed - ; + | ImGuiTableFlags_ColumnsWidthFixed; enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow }; static int contents_type = CT_Button; @@ -4744,7 +4749,6 @@ ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable); ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable); ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable); - ImGui::CheckboxFlags("ImGuiTableFlags_MultiSortable", &flags, ImGuiTableFlags_MultiSortable); ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings); ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody); ImGui::TreePop(); @@ -4805,6 +4809,15 @@ ImGui::TreePop(); } + if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti); + ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1)."); + ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate); + ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0)."); + ImGui::TreePop(); + } + if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::Checkbox("show_headers", &show_headers); @@ -4860,13 +4873,13 @@ // Declare columns // We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications. // This is so our sort function can identify a column given our own identifier. We could also identify them based on their index! - ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows); ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, -1.0f, MyItemColumnID_ID); ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, -1.0f, MyItemColumnID_Name); ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, -1.0f, MyItemColumnID_Action); ImGui::TableSetupColumn("Quantity (Long Label)", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 1.0f, MyItemColumnID_Quantity);// , ImGuiTableColumnFlags_WidthAutoResize); ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_WidthStretch, 1.0f, MyItemColumnID_Description); ImGui::TableSetupColumn("Hidden", ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort); + ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows); // Sort our data if sort specs have been changed! ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs();
diff --git a/imgui_internal.h b/imgui_internal.h index bb8ea5c..87c40e4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h
@@ -1912,12 +1912,13 @@ ImS8 AutoFitChildAxises; bool AutoFitOnlyGrows; ImGuiDir AutoPosLastDirection; - int HiddenFramesCanSkipItems; // Hide the window for N frames - int HiddenFramesCannotSkipItems; // Hide the window for N frames while allowing items to be submitted so we can measure their size - ImGuiCond SetWindowPosAllowFlags; // store acceptable condition flags for SetNextWindowPos() use. - ImGuiCond SetWindowSizeAllowFlags; // store acceptable condition flags for SetNextWindowSize() use. - ImGuiCond SetWindowCollapsedAllowFlags; // store acceptable condition flags for SetNextWindowCollapsed() use. - ImGuiCond SetWindowDockAllowFlags; // store acceptable condition flags for SetNextWindowDock() use. + ImS8 HiddenFramesCanSkipItems; // Hide the window for N frames + ImS8 HiddenFramesCannotSkipItems; // Hide the window for N frames while allowing items to be submitted so we can measure their size + ImS8 HiddenFramesForRenderOnly; // Hide the window until frame N at Render() time only + ImGuiCond SetWindowPosAllowFlags : 8; // store acceptable condition flags for SetNextWindowPos() use. + ImGuiCond SetWindowSizeAllowFlags : 8; // store acceptable condition flags for SetNextWindowSize() use. + ImGuiCond SetWindowCollapsedAllowFlags : 8; // store acceptable condition flags for SetNextWindowCollapsed() use. + ImGuiCond SetWindowDockAllowFlags : 8; // store acceptable condition flags for SetNextWindowDock() use. ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size) ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0, 0) when positioning from top-left corner; ImVec2(0.5f, 0.5f) for centering; ImVec2(1, 1) for bottom right. @@ -2115,8 +2116,7 @@ { ImRect ClipRect; // Clipping rectangle for the column ImGuiID UserID; // Optional, value passed to TableSetupColumn() - ImGuiTableColumnFlags FlagsIn; // Flags as they were provided by user. See ImGuiTableColumnFlags_ - ImGuiTableColumnFlags Flags; // Effective flags. See ImGuiTableColumnFlags_ + ImGuiTableColumnFlags Flags; // Flags after some patching (not directly same as provided by user). See ImGuiTableColumnFlags_ float MinX; // Absolute positions float MaxX; float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_). @@ -2148,9 +2148,12 @@ bool IsSkipItems; // Do we want item submissions to this column to be completely ignored (no layout will happen). bool IsPreserveWidthAuto; ImS8 NavLayerCurrent; // ImGuiNavLayer in 1 byte - ImS8 SortDirection; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending ImU8 AutoFitQueue; // Queue of 8 values for the next 8 frames to request auto-fit ImU8 CannotSkipItemsQueue; // Queue of 8 values for the next 8 frames to disable Clipped/SkipItem + ImU8 SortDirection : 2; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending + ImU8 SortDirectionsAvailCount : 2; // Number of available sort directions (0 to 3) + ImU8 SortDirectionsAvailMask : 4; // Mask of available sort directions (1-bit each) + ImU8 SortDirectionsAvailList; // Ordered of available sort directions (2-bits each) ImGuiTableColumn() { @@ -2173,7 +2176,7 @@ ImGuiTableColumnIdx Column; // Column number }; -// FIXME-TABLES: transient data could be stored in a per-stacked table structure: DrawSplitter, SortSpecs, incoming RowData +// FIXME-TABLE: transient data could be stored in a per-stacked table structure: DrawSplitter, SortSpecs, incoming RowData struct ImGuiTable { ImGuiID ID; @@ -2280,8 +2283,8 @@ bool MemoryCompacted; bool HostSkipItems; // Backup of InnerWindow->SkipItem at the end of BeginTable(), because we will overwrite InnerWindow->SkipItem on a per-column basis - IMGUI_API ImGuiTable(); - IMGUI_API ~ImGuiTable(); + IMGUI_API ImGuiTable() { memset(this, 0, sizeof(*this)); LastFrameActive = -1; } + IMGUI_API ~ImGuiTable() { IM_FREE(RawData); } }; // sizeof() ~ 12 @@ -2550,7 +2553,6 @@ // Tables: Candidates for public API IMGUI_API void TableOpenContextMenu(int column_n = -1); IMGUI_API void TableSetColumnWidth(int column_n, float width); - IMGUI_API void TableSetColumnIsEnabled(int column_n, bool enabled); IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs); IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. IMGUI_API float TableGetHeaderRowHeight(); @@ -2565,12 +2567,14 @@ IMGUI_API void TableSetupDrawChannels(ImGuiTable* table); IMGUI_API void TableUpdateLayout(ImGuiTable* table); IMGUI_API void TableUpdateBorders(ImGuiTable* table); + IMGUI_API void TableUpdateColumnsWeightFromWidth(ImGuiTable* table); IMGUI_API void TableDrawBorders(ImGuiTable* table); IMGUI_API void TableDrawContextMenu(ImGuiTable* table); IMGUI_API void TableMergeDrawChannels(ImGuiTable* table); IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); IMGUI_API void TableSortSpecsBuild(ImGuiTable* table); - IMGUI_API void TableFixColumnSortDirection(ImGuiTableColumn* column); + IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column); + IMGUI_API void TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column); IMGUI_API void TableBeginRow(ImGuiTable* table); IMGUI_API void TableEndRow(ImGuiTable* table); IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n); @@ -2578,6 +2582,7 @@ IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n); IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n); IMGUI_API ImGuiID TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no = 0); + IMGUI_API float TableGetMinColumnWidth(); IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); IMGUI_API void TableRemove(ImGuiTable* table);
diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 24653cd..7a488b9 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp
@@ -6,6 +6,9 @@ Index of this file: // [SECTION] Tables: Main code +// [SECTION] Tables: Row changes +// [SECTION] Tables: Columns changes +// [SECTION] Tables: Columns width management // [SECTION] Tables: Drawing // [SECTION] Tables: Sorting // [SECTION] Tables: Headers @@ -17,17 +20,25 @@ */ +// Navigating this file: +// - In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. +// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. + //----------------------------------------------------------------------------- // Typical tables call flow: (root level is generally public API): //----------------------------------------------------------------------------- // - BeginTable() user begin into a table // | BeginChild() - (if ScrollX/ScrollY is set) +// | TableBeginInitMemory() - first time table is used +// | TableResetSettings() - on settings reset +// | TableLoadSettings() - on settings load // | TableBeginApplyRequests() - apply queued resizing/reordering/hiding requests // | - TableSetColumnWidth() - apply resizing width (for mouse resize, often requested by previous frame) // | - TableUpdateColumnsWeightFromWidth()- recompute columns weights (of stretch columns) from their respective width // - TableSetupColumn() user submit columns details (optional) // - TableSetupScrollFreeze() user submit scroll freeze information (optional) -// - TableUpdateLayout() [Internal] automatically called by the FIRST call to TableNextRow() or TableHeadersRow(): lock all widths, columns positions, clipping rectangles +//----------------------------------------------------------------------------- +// - TableUpdateLayout() [Internal] setup everything, lock all widths, columns positions, clipping rectangles. Automatically called by the FIRST call to TableNextRow() or TableHeadersRow(). // | TableSetupDrawChannels() - setup ImDrawList channels // | TableUpdateBorders() - detect hovering columns for resize, ahead of contents submission // | TableDrawContextMenu() - draw right-click context menu @@ -167,7 +178,7 @@ // Configuration static const int TABLE_DRAW_CHANNEL_BG0 = 0; static const int TABLE_DRAW_CHANNEL_BG1_FROZEN = 1; -static const int TABLE_DRAW_CHANNEL_UNCLIPPED = 2; // When using ImGuiTableFlags_NoClip +static const int TABLE_DRAW_CHANNEL_NOCLIP = 2; // When using ImGuiTableFlags_NoClip static const float TABLE_BORDER_SIZE = 1.0f; // FIXME-TABLE: Currently hard-coded because of clipping assumptions with outer borders rendering. static const float TABLE_RESIZE_SEPARATOR_HALF_THICKNESS = 4.0f; // Extend outside inner borders. static const float TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER = 0.06f; // Delay/timer before making the hover feedback (color+cursor) visible because tables/columns tends to be more cramped. @@ -179,10 +190,6 @@ if ((flags & (ImGuiTableFlags_ColumnsWidthStretch | ImGuiTableFlags_ColumnsWidthFixed)) == 0) flags |= (flags & ImGuiTableFlags_ScrollX) ? ImGuiTableFlags_ColumnsWidthFixed : ImGuiTableFlags_ColumnsWidthStretch; - // Adjust flags: MultiSortable automatically enable Sortable - if (flags & ImGuiTableFlags_MultiSortable) - flags |= ImGuiTableFlags_Sortable; - // Adjust flags: disable Resizable when using SameWidths (done above enforcing BordersInnerV) if (flags & ImGuiTableFlags_SameWidths) flags = (flags & ~ImGuiTableFlags_Resizable) | ImGuiTableFlags_NoKeepColumnsVisible; @@ -215,25 +222,6 @@ return flags; } -ImGuiTable::ImGuiTable() -{ - memset(this, 0, sizeof(*this)); - SettingsOffset = -1; - InstanceInteracted = -1; - LastFrameActive = -1; - LastResizedColumn = -1; - ContextPopupColumn = -1; - ReorderColumn = -1; - ResizedColumn = -1; - AutoFitSingleStretchColumn = -1; - HoveredColumnBody = HoveredColumnBorder = -1; -} - -ImGuiTable::~ImGuiTable() -{ - IM_FREE(RawData); -} - ImGuiTable* ImGui::TableFindByID(ImGuiID id) { ImGuiContext& g = *GImGui; @@ -350,9 +338,8 @@ const float inner_spacing_for_border = (flags & ImGuiTableFlags_BordersInnerV) ? TABLE_BORDER_SIZE : 0.0f; const float inner_spacing_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) == 0) ? g.Style.CellPadding.x : 0.0f; const float inner_padding_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) != 0) ? g.Style.CellPadding.x : 0.0f; - const float inner_spacing = inner_spacing_for_border + inner_spacing_explicit; - table->CellSpacingX1 = ImCeil(inner_spacing * 0.5f); - table->CellSpacingX2 = inner_spacing - table->CellSpacingX1; + table->CellSpacingX1 = inner_spacing_explicit + inner_spacing_for_border; + table->CellSpacingX2 = inner_spacing_explicit; table->CellPaddingX = inner_padding_explicit; table->CellPaddingY = g.Style.CellPadding.y; @@ -423,9 +410,14 @@ TableResetSettings(table); if (table->IsInitializing) { - // Initialize for new settings + // Initialize table->SettingsOffset = -1; table->IsSortSpecsDirty = true; + table->InstanceInteracted = -1; + table->ContextPopupColumn = -1; + table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1; + table->AutoFitSingleStretchColumn = -1; + table->HoveredColumnBody = table->HoveredColumnBorder = -1; for (int n = 0; n < columns_count; n++) { ImGuiTableColumn* column = &table->Columns[n]; @@ -463,16 +455,9 @@ inner_window->SkipItems = true; // Clear names - // FIXME-TABLES: probably could be done differently... + // At this point the ->NameOffset field of each column will be invalid until TableUpdateLayout() or the first call to TableSetupColumn() if (table->ColumnsNames.Buf.Size > 0) - { table->ColumnsNames.Buf.resize(0); - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - { - ImGuiTableColumn* column = &table->Columns[column_n]; - column->NameOffset = -1; - } - } // Apply queued resizing/reordering/hiding requests TableBeginApplyRequests(table); @@ -573,8 +558,10 @@ } // Adjust flags: default width mode + stretch columns are not allowed when auto extending -static ImGuiTableColumnFlags TableFixColumnFlags(ImGuiTable* table, ImGuiTableColumnFlags flags) +static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in) { + ImGuiTableColumnFlags flags = flags_in; + // Sizing Policy if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0) { @@ -592,20 +579,33 @@ if ((flags & ImGuiTableColumnFlags_NoSortAscending) && (flags & ImGuiTableColumnFlags_NoSortDescending)) flags |= ImGuiTableColumnFlags_NoSort; + // Indentation + if ((flags & ImGuiTableColumnFlags_IndentMask_) == 0) + flags |= (table->Columns.index_from_ptr(column) == 0) ? ImGuiTableColumnFlags_IndentEnable : ImGuiTableColumnFlags_IndentDisable; + // Alignment //if ((flags & ImGuiTableColumnFlags_AlignMask_) == 0) // flags |= ImGuiTableColumnFlags_AlignCenter; //IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_AlignMask_)); // Check that only 1 of each set is used. - return flags; -} + // Preserve status flags + column->Flags = flags | (column->Flags & ImGuiTableColumnFlags_StatusMask_); -// Minimum column content width (without padding) -static float TableGetMinColumnWidth() -{ - ImGuiContext& g = *GImGui; - //return g.Style.ColumnsMinSpacing; // FIXME-TABLE - return g.Style.FramePadding.x * 1.0f; + // Build an ordered list of available sort directions + column->SortDirectionsAvailCount = column->SortDirectionsAvailMask = column->SortDirectionsAvailList = 0; + if (table->Flags & ImGuiTableFlags_Sortable) + { + int count = 0, mask = 0, list = 0; + if ((flags & ImGuiTableColumnFlags_PreferSortAscending) != 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending; list |= ImGuiSortDirection_Ascending << (count << 1); count++; } + if ((flags & ImGuiTableColumnFlags_PreferSortDescending) != 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; } + if ((flags & ImGuiTableColumnFlags_PreferSortAscending) == 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending; list |= ImGuiSortDirection_Ascending << (count << 1); count++; } + if ((flags & ImGuiTableColumnFlags_PreferSortDescending) == 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; } + if ((table->Flags & ImGuiTableFlags_SortTristate) || count == 0) { mask |= 1 << ImGuiSortDirection_None; count++; } + column->SortDirectionsAvailList = (ImU8)list; + column->SortDirectionsAvailMask = (ImU8)mask; + column->SortDirectionsAvailCount = (ImU8)count; + ImGui::TableFixColumnSortDirection(table, column); + } } // Layout columns for the frame. This is in essence the followup to BeginTable(). @@ -632,6 +632,19 @@ if (column_n != order_n) table->IsDefaultDisplayOrder = false; ImGuiTableColumn* column = &table->Columns[column_n]; + + // Clear column settings if not submitted by user. + // Currently we make it mandatory to call TableSetupColumn() every frame. + // It would easily work without but we're ready to guarantee it since e.g. names need resubmission anyway. + // In theory we could be calling TableSetupColumn() here with dummy values it should yield the same effect. + if (column_n >= table->DeclColumnsCount) + { + TableSetupColumnFlags(table, column, ImGuiTableColumnFlags_None); + column->NameOffset = -1; + column->UserID = 0; + column->InitStretchWeightOrWidth = -1.0f; + } + if (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide)) column->IsEnabledNextFrame = true; if (column->IsEnabled != column->IsEnabledNextFrame) @@ -641,7 +654,7 @@ if (!column->IsEnabled && column->SortOrder != -1) table->IsSortSpecsDirty = true; } - if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_MultiSortable)) + if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti)) table->IsSortSpecsDirty = true; bool start_auto_fit = false; @@ -659,6 +672,7 @@ ImU64 display_order_mask = (ImU64)1 << column->DisplayOrder; if (column->IsEnabled) { + // Mark as enabled and link to previous/next enabled column column->PrevEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx; column->NextEnabledColumn = -1; if (last_visible_column_idx != -1) @@ -675,6 +689,8 @@ } IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); } + if ((table->Flags & ImGuiTableFlags_Sortable) && table->SortSpecsCount == 0 && !(table->Flags & ImGuiTableFlags_SortTristate)) + table->IsSortSpecsDirty = true; table->RightMostEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx; // [Part 2] Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible @@ -700,25 +716,16 @@ continue; ImGuiTableColumn* column = &table->Columns[column_n]; - // Adjust flags: default width mode + weighted columns are not allowed when auto extending - // FIXME-TABLE: Clarify why we need to do this again here and not just in TableSetupColumn() - column->Flags = TableFixColumnFlags(table, column->FlagsIn) | (column->Flags & ImGuiTableColumnFlags_StatusMask_); - if ((column->Flags & ImGuiTableColumnFlags_IndentMask_) == 0) - column->Flags |= (column_n == 0) ? ImGuiTableColumnFlags_IndentEnable : ImGuiTableColumnFlags_IndentDisable; + // Count resizable columns if ((column->Flags & ImGuiTableColumnFlags_NoResize) == 0) count_resizable++; - // We have a unusual edge case where if the user doesn't call TableGetSortSpecs() but has sorting enabled - // or varying sorting flags, we still want the sorting arrows to honor those flags. - if (table->Flags & ImGuiTableFlags_Sortable) - TableFixColumnSortDirection(column); - // Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping) // Combine width from regular rows + width from headers unless requested not to. if (!column->IsPreserveWidthAuto) { - const float content_width_body = (float)ImMax(column->ContentMaxXFrozen, column->ContentMaxXUnfrozen) - column->WorkMinX; - const float content_width_headers = (float)column->ContentMaxXHeadersIdeal - column->WorkMinX; + const float content_width_body = ImMax(column->ContentMaxXFrozen, column->ContentMaxXUnfrozen) - column->WorkMinX; + const float content_width_headers = column->ContentMaxXHeadersIdeal - column->WorkMinX; float width_auto = content_width_body; if (!(table->Flags & ImGuiTableFlags_NoHeadersWidth) && !(column->Flags & ImGuiTableColumnFlags_NoHeaderWidth)) width_auto = ImMax(width_auto, content_width_headers); @@ -784,7 +791,7 @@ { sum_weights_stretched += 1.0f - column->StretchWeight; // Update old sum column->StretchWeight = 1.0f; - if (count_fixed > 0) + if (mixed_same_widths) column->WidthRequest = max_width_auto; } } @@ -808,7 +815,7 @@ if (column->Flags & ImGuiTableColumnFlags_WidthStretch) { // StretchWeight gets converted into WidthRequest - if (!mixed_same_widths) + if (!mixed_same_widths) { float weight_ratio = column->StretchWeight / sum_weights_stretched; column->WidthRequest = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, min_column_width) + 0.01f); @@ -925,7 +932,8 @@ // Lock all our positions // - ClipRect.Min.x: Because merging draw commands doesn't compare min boundaries, we make ClipRect.Min.x match left bounds to be consistent regardless of merging. - // - ClipRect.Max.x: using WorkMaxX instead of MaxX (aka including padding) is detrimental to visibility in very-small column. + // - ClipRect.Max.x: using WorkMaxX instead of MaxX (aka including padding) makes things more consistent when resizing down, tho slightly detrimental to visibility in very-small column. + // - ClipRect.Max.x: using MaxX makes it easier for header to receive hover highlight with no discontinuity and display sorting arrow. // - FIXME-TABLE: We want equal width columns to have equal (ClipRect.Max.x - WorkMinX) width, which means ClipRect.max.x cannot stray off host_clip_rect.Max.x else right-most column may appear shorter. column->MinX = offset_x; column->MaxX = offset_x + column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f; @@ -934,7 +942,7 @@ column->ItemWidth = ImFloor(column->WidthGiven * 0.65f); column->ClipRect.Min.x = column->MinX; column->ClipRect.Min.y = work_rect.Min.y; - column->ClipRect.Max.x = column->MaxX; // column->WorkMaxX; + column->ClipRect.Max.x = column->MaxX; //column->WorkMaxX; column->ClipRect.Max.y = FLT_MAX; column->ClipRect.ClipWithFull(host_clip_rect); @@ -942,7 +950,7 @@ // Note that scrolling tables (where inner_window != outer_window) handle Y clipped earlier in BeginTable() so IsVisibleY really only applies to non-scrolling tables. // FIXME-TABLE: Because InnerClipRect.Max.y is conservatively ==outer_window->ClipRect.Max.y, we never can mark columns _Above_ the scroll line as not IsVisibleY. // Taking advantage of LastOuterHeight would yield good results there... - // FIXME-TABLE: IsVisible == false is disabled because it effectively means not submitting will reduces contents width which is fed to outer_window->DC.CursorMaxPos.x, + // FIXME-TABLE: Y clipping is disabled because it effectively means not submitting will reduce contents width which is fed to outer_window->DC.CursorMaxPos.x, // and this may be used (e.g. typically by outer_window using AlwaysAutoResize or outer_window's horizontal scrollbar, but could be something else). // Possible solution to preserve last known content width for clipped column. Test 'table_reported_size' fails when enabling Y clipping and window is resized small. column->IsVisibleX = (column->ClipRect.Max.x > column->ClipRect.Min.x); @@ -958,9 +966,6 @@ // Mark column as SkipItems (ignoring all items/layout) column->IsSkipItems = !column->IsEnabled || table->HostSkipItems; - //if (!is_visible && (column->Flags & ImGuiTableColumnFlags_AutoCull)) - // if ((column->AutoFitQueue & 1) == 0 && (column->CannotSkipItemsQueue & 1) == 0) - // column->IsSkipItems = true; if (column->IsSkipItems) IM_ASSERT(!is_visible); @@ -1047,7 +1052,7 @@ // Initial state ImGuiWindow* inner_window = table->InnerWindow; if (table->Flags & ImGuiTableFlags_NoClip) - table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_UNCLIPPED); + table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); else inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false); } @@ -1177,7 +1182,8 @@ #if 0 // Strip out dummy channel draw calls // We have no way to prevent user submitting direct ImDrawList calls into a hidden column (but ImGui:: calls will be clipped out) - // (The problem with this approach is we are effectively making it harder for users watching metrics to spot wasted vertices) + // Pros: remove draw calls which will have no effect. since they'll have zero-size cliprect they may be early out anyway. + // Cons: making it harder for users watching metrics/debugger to spot the wasted vertices. if (table->DummyDrawChannel != (ImGuiTableColumnIdx)-1) { ImDrawChannel* dummy_channel = &table->DrawSplitter._Channels[table->DummyDrawChannel]; @@ -1261,124 +1267,6 @@ outer_window->DC.CurrentTableIdx = g.CurrentTable ? g.Tables.GetIndex(g.CurrentTable) : -1; } -static void TableUpdateColumnsWeightFromWidth(ImGuiTable* table) -{ - IM_ASSERT(table->LeftMostStretchedColumnDisplayOrder != -1); - - // Measure existing quantity - float visible_weight = 0.0f; - float visible_width = 0.0f; - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - { - ImGuiTableColumn* column = &table->Columns[column_n]; - if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) - continue; - IM_ASSERT(column->StretchWeight > 0.0f); - visible_weight += column->StretchWeight; - visible_width += column->WidthRequest; - } - IM_ASSERT(visible_weight > 0.0f && visible_width > 0.0f); - - // Apply new weights - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - { - ImGuiTableColumn* column = &table->Columns[column_n]; - if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) - continue; - column->StretchWeight = ((column->WidthRequest + 0.0f) / visible_width) * visible_weight; - } -} - -// 'width' = inner column width, without padding -void ImGui::TableSetColumnWidth(int column_n, float width) -{ - ImGuiContext& g = *GImGui; - ImGuiTable* table = g.CurrentTable; - IM_ASSERT(table != NULL && table->IsLayoutLocked == false); - IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); - ImGuiTableColumn* column_0 = &table->Columns[column_n]; - float column_0_width = width; - - // Constraints - const float min_width = TableGetMinColumnWidth(); - float max_width_0 = FLT_MAX; - if (!(table->Flags & ImGuiTableFlags_ScrollX)) - max_width_0 = (table->WorkRect.Max.x - column_0->MinX) - (table->ColumnsEnabledCount - (column_0->IndexWithinEnabledSet + 1)) * min_width; - column_0_width = ImClamp(column_0_width, min_width, max_width_0); - - // Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded) - if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width) - return; - - ImGuiTableColumn* column_1 = (column_0->NextEnabledColumn != -1) ? &table->Columns[column_0->NextEnabledColumn] : NULL; - - // In this surprisingly not simple because of how we support mixing Fixed and Stretch columns. - // When forwarding resize from Wn| to Fn+1| we need to be considerate of the _NoResize flag on Fn+1. - // FIXME-TABLE: Find a way to rewrite all of this so interactions feel more consistent for the user. - // Scenarios: - // - F1 F2 F3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. Subsequent columns will be offset. - // - F1 F2 F3 resize from F3| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered. - // - F1 F2 W3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered, but it doesn't make much sense as the Stretch column will always be minimal size. - // - F1 F2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1) - // - W1 W2 W3 resize from W1| or W2| --> FIXME - // - W1 W2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1) - // - W1 F2 F3 resize from F3| --> ok: no-op (disabled by Resize Rule 1) - // - W1 F2 resize from F2| --> ok: no-op (disabled by Resize Rule 1) - // - W1 W2 F3 resize from W1| or W2| --> ok - // - W1 F2 W3 resize from W1| or F2| --> FIXME - // - F1 W2 F3 resize from W2| --> ok - // - W1 F2 F3 resize from W1| --> ok: equivalent to resizing |F2. F3 will not move. (forwarded by Resize Rule 2) - // - W1 F2 F3 resize from F2| --> FIXME should resize F2, F3 and not have effect on W1 (Stretch columns are _before_ the Fixed column). - - // Rules: - // - [Resize Rule 1] Can't resize from right of right-most visible column if there is any Stretch column. Implemented in TableUpdateLayout(). - // - [Resize Rule 2] Resizing from right-side of a Stretch column before a fixed column forward sizing to left-side of fixed column. - // - [Resize Rule 3] If we are are followed by a fixed column and we have a Stretch column before, we need to ensure that our left border won't move. - table->IsSettingsDirty = true; - if (column_0->Flags & ImGuiTableColumnFlags_WidthFixed) - { - // [Resize Rule 3] If we are are followed by a fixed column and we have a Stretch column before, we need to ensure - // that our left border won't move, which we can do by making sure column_a/column_b resizes cancels each others. - if (column_1 && (column_1->Flags & ImGuiTableColumnFlags_WidthFixed)) - if (table->LeftMostStretchedColumnDisplayOrder != -1 && table->LeftMostStretchedColumnDisplayOrder < column_0->DisplayOrder) - { - // (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b) - float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width); - column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width; - column_1->WidthRequest = column_1_width; - } - - // Apply - //IMGUI_DEBUG_LOG("TableSetColumnWidth(%d, %.1f->%.1f)\n", column_0_idx, column_0->WidthRequested, column_0_width); - column_0->WidthRequest = column_0_width; - } - else if (column_0->Flags & ImGuiTableColumnFlags_WidthStretch) - { - // We can also use previous column if there's no next one - if (column_1 == NULL) - column_1 = (column_0->PrevEnabledColumn != -1) ? &table->Columns[column_0->PrevEnabledColumn] : NULL; - if (column_1 == NULL) - return; - - if (column_1->Flags & ImGuiTableColumnFlags_WidthFixed) - { - // [Resize Rule 2] - float off = (column_0->WidthGiven - column_0_width); - float column_1_width = column_1->WidthGiven + off; - column_1->WidthRequest = ImMax(min_width, column_1_width); - } - else - { - // (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b) - float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width); - column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width; - column_1->WidthRequest = column_1_width; - column_0->WidthRequest = column_0_width; - TableUpdateColumnsWeightFromWidth(table); - } - } -} - // We use a default parameter of 'init_width_or_weight == -1', // - with ImGuiTableColumnFlags_WidthFixed, width <= 0 --> init width == auto // - with ImGuiTableColumnFlags_WidthFixed, width > 0 --> init width == manual @@ -1399,14 +1287,12 @@ // When passing a width automatically enforce WidthFixed policy // (vs TableFixColumnFlags would default to WidthAutoResize) - // (we write to FlagsIn which is a little misleading, another solution would be to pass init_width_or_weight to TableFixColumnFlags) if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0) if ((table->Flags & ImGuiTableFlags_ColumnsWidthFixed) && (init_width_or_weight > 0.0f)) flags |= ImGuiTableColumnFlags_WidthFixed; + TableSetupColumnFlags(table, column, flags); column->UserID = user_id; - column->FlagsIn = flags; - column->Flags = TableFixColumnFlags(table, column->FlagsIn) | (column->Flags & ImGuiTableColumnFlags_StatusMask_); flags = column->Flags; // Initialize defaults @@ -1432,13 +1318,13 @@ column->IsEnabled = column->IsEnabledNextFrame = false; if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0) { - column->SortOrder = 0; // Multiple columns using _DefaultSort will be reordered when building the sort specs. + column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs. column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending); } } // Store name (append with zero-terminator in contiguous buffer) - IM_ASSERT(column->NameOffset == -1); + column->NameOffset = -1; if (label != NULL && label[0] != 0) { column->NameOffset = (ImS16)table->ColumnsNames.size(); @@ -1463,6 +1349,143 @@ table->IsUnfrozen = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b } +int ImGui::TableGetColumnCount() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + return table ? table->ColumnsCount : 0; +} + +const char* ImGui::TableGetColumnName(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return NULL; + if (column_n < 0) + column_n = table->CurrentColumn; + return TableGetColumnName(table, column_n); +} + +const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n) +{ + IM_ASSERT(table->IsLayoutLocked == true || column_n <= table->DeclColumnsCount); // NameOffset is invalid otherwise + const ImGuiTableColumn* column = &table->Columns[column_n]; + if (column->NameOffset == -1) + return ""; + return &table->ColumnsNames.Buf[column->NameOffset]; +} + +// We allow querying for an extra column in order to poll the IsHovered state of the right-most section +ImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return ImGuiTableColumnFlags_None; + if (column_n < 0) + column_n = table->CurrentColumn; + if (column_n == table->ColumnsCount) + return (table->HoveredColumnBody == column_n) ? ImGuiTableColumnFlags_IsHovered : ImGuiTableColumnFlags_None; + return table->Columns[column_n].Flags; +} + +// Return the cell rectangle based on currently known height. +// - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations. +// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it. +// - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right +// columns report a small offset so their CellBgRect can extend up to the outer border. +ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n) +{ + const ImGuiTableColumn* column = &table->Columns[column_n]; + float x1 = column->MinX; + float x2 = column->MaxX; + if (column->PrevEnabledColumn == -1) + x1 -= table->CellSpacingX1; + if (column->NextEnabledColumn == -1) + x2 += table->CellSpacingX2; + return ImRect(x1, table->RowPosY1, x2, table->RowPosY2); +} + +// Return the resizing ID for the right-side of the given column. +ImGuiID ImGui::TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no) +{ + IM_ASSERT(column_n < table->ColumnsCount); + ImGuiID id = table->ID + 1 + (instance_no * table->ColumnsCount) + column_n; + return id; +} + +// Return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. +int ImGui::TableGetHoveredColumn() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return -1; + return (int)table->HoveredColumnBody; +} + +void ImGui::TableSetBgColor(ImGuiTableBgTarget bg_target, ImU32 color, int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(bg_target != ImGuiTableBgTarget_None); + + if (color == IM_COL32_DISABLE) + color = 0; + + // We cannot draw neither the cell or row background immediately as we don't know the row height at this point in time. + switch (bg_target) + { + case ImGuiTableBgTarget_CellBg: + { + if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard + return; + if (column_n == -1) + column_n = table->CurrentColumn; + if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0) + return; + if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n) + table->RowCellDataCurrent++; + ImGuiTableCellData* cell_data = &table->RowCellData[table->RowCellDataCurrent]; + cell_data->BgColor = color; + cell_data->Column = (ImGuiTableColumnIdx)column_n; + break; + } + case ImGuiTableBgTarget_RowBg0: + case ImGuiTableBgTarget_RowBg1: + { + if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard + return; + IM_ASSERT(column_n == -1); + int bg_idx = (bg_target == ImGuiTableBgTarget_RowBg1) ? 1 : 0; + table->RowBgColor[bg_idx] = color; + break; + } + default: + IM_ASSERT(0); + } +} + +//------------------------------------------------------------------------- +// [SECTION] Tables: Row changes +//------------------------------------------------------------------------- +// - TableGetRowIndex() +// - TableNextRow() +// - TableBeginRow() [Internal] +// - TableEndRow() [Internal] +//------------------------------------------------------------------------- + +// [Public] Note: for row coloring we use ->RowBgColorCounter which is the same value without counting header rows +int ImGui::TableGetRowIndex() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return 0; + return table->CurrentRow; +} + // [Public] Starts into the first cell of a new row void ImGui::TableNextRow(ImGuiTableRowFlags row_flags, float row_min_height) { @@ -1488,7 +1511,7 @@ table->InnerWindow->SkipItems = true; } -// [Internal] Called by TableNextRow()! +// [Internal] Called by TableNextRow() void ImGui::TableBeginRow(ImGuiTable* table) { ImGuiWindow* window = table->InnerWindow; @@ -1521,7 +1544,7 @@ } } -// [Internal] Called by TableNextRow()! +// [Internal] Called by TableNextRow() void ImGui::TableEndRow(ImGuiTable* table) { ImGuiContext& g = *GImGui; @@ -1653,7 +1676,74 @@ table->IsInsideRow = false; } -// [Internal] Called by TableNextColumn()! +//------------------------------------------------------------------------- +// [SECTION] Tables: Columns changes +//------------------------------------------------------------------------- +// - TableGetColumnIndex() +// - TableSetColumnIndex() +// - TableNextColumn() +// - TableBeginCell() [Internal] +// - TableEndCell() [Internal] +//------------------------------------------------------------------------- + +int ImGui::TableGetColumnIndex() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return 0; + return table->CurrentColumn; +} + +// [Public] Append into a specific column +bool ImGui::TableSetColumnIndex(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return false; + + if (table->CurrentColumn != column_n) + { + if (table->CurrentColumn != -1) + TableEndCell(table); + IM_ASSERT(column_n >= 0 && table->ColumnsCount); + TableBeginCell(table, column_n); + } + + // Return whether the column is visible. User may choose to skip submitting items based on this return value, + // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. + return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0; +} + +// [Public] Append into the next column, wrap and create a new row when already on last column +bool ImGui::TableNextColumn() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + if (!table) + return false; + + if (table->IsInsideRow && table->CurrentColumn + 1 < table->ColumnsCount) + { + if (table->CurrentColumn != -1) + TableEndCell(table); + TableBeginCell(table, table->CurrentColumn + 1); + } + else + { + TableNextRow(); + TableBeginCell(table, 0); + } + + // Return whether the column is visible. User may choose to skip submitting items based on this return value, + // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. + int column_n = table->CurrentColumn; + return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0; +} + + +// [Internal] Called by TableSetColumnIndex()/TableNextColumn() // This is called very frequently, so we need to be mindful of unnecessary overhead. // FIXME-TABLE FIXME-OPT: Could probably shortcut some things for non-active or clipped columns. void ImGui::TableBeginCell(ImGuiTable* table, int column_n) @@ -1688,8 +1778,8 @@ if (table->Flags & ImGuiTableFlags_NoClip) { // FIXME: if we end up drawing all borders/bg in EndTable, could remove this and just assert that channel hasn't changed. - table->DrawSplitter.SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_UNCLIPPED); - //IM_ASSERT(table->DrawSplitter._Current == TABLE_DRAW_CHANNEL_UNCLIPPED); + table->DrawSplitter.SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP); + //IM_ASSERT(table->DrawSplitter._Current == TABLE_DRAW_CHANNEL_NOCLIP); } else { @@ -1699,7 +1789,7 @@ } } -// [Internal] Called by TableNextRow()/TableNextColumn()! +// [Internal] Called by TableNextRow()/TableSetColumnIndex()/TableNextColumn() void ImGui::TableEndCell(ImGuiTable* table) { ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; @@ -1720,146 +1810,112 @@ table->RowTextBaseline = ImMax(table->RowTextBaseline, window->DC.PrevLineTextBaseOffset); } -// [Public] Append into the next column/cell -bool ImGui::TableNextColumn() +//------------------------------------------------------------------------- +// [SECTION] Tables: Columns width management +//------------------------------------------------------------------------- +// - TableGetMinColumnWidth() [Internal] +// - TableSetColumnWidth() +// - TableSetColumnWidthAutoSingle() [Internal] +// - TableSetColumnWidthAutoAll() [Internal] +// - TableUpdateColumnsWeightFromWidth() [Internal] +//------------------------------------------------------------------------- + +// Minimum column content width (without padding) +float ImGui::TableGetMinColumnWidth() { ImGuiContext& g = *GImGui; - ImGuiTable* table = g.CurrentTable; - if (!table) - return false; - - if (table->IsInsideRow && table->CurrentColumn + 1 < table->ColumnsCount) - { - if (table->CurrentColumn != -1) - TableEndCell(table); - TableBeginCell(table, table->CurrentColumn + 1); - } - else - { - TableNextRow(); - TableBeginCell(table, 0); - } - - // Return whether the column is visible. User may choose to skip submitting items based on this return value, - // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. - int column_n = table->CurrentColumn; - return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0; + //return g.Style.ColumnsMinSpacing; // FIXME-TABLE + return g.Style.FramePadding.x * 1.0f; } -// [Public] Append into a specific column -bool ImGui::TableSetColumnIndex(int column_n) -{ - ImGuiContext& g = *GImGui; - ImGuiTable* table = g.CurrentTable; - if (!table) - return false; - - if (table->CurrentColumn != column_n) - { - if (table->CurrentColumn != -1) - TableEndCell(table); - IM_ASSERT(column_n >= 0 && table->ColumnsCount); - TableBeginCell(table, column_n); - } - - // Return whether the column is visible. User may choose to skip submitting items based on this return value, - // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. - return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0; -} - -int ImGui::TableGetColumnCount() -{ - ImGuiContext& g = *GImGui; - ImGuiTable* table = g.CurrentTable; - return table ? table->ColumnsCount : 0; -} - -const char* ImGui::TableGetColumnName(int column_n) -{ - ImGuiContext& g = *GImGui; - ImGuiTable* table = g.CurrentTable; - if (!table) - return NULL; - if (column_n < 0) - column_n = table->CurrentColumn; - return TableGetColumnName(table, column_n); -} - -// We allow querying for an extra column in order to poll the IsHovered state of the right-most section -ImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n) -{ - ImGuiContext& g = *GImGui; - ImGuiTable* table = g.CurrentTable; - if (!table) - return ImGuiTableColumnFlags_None; - if (column_n < 0) - column_n = table->CurrentColumn; - if (column_n == table->ColumnsCount) - return (table->HoveredColumnBody == column_n) ? ImGuiTableColumnFlags_IsHovered : ImGuiTableColumnFlags_None; - return table->Columns[column_n].Flags; -} - -void ImGui::TableSetColumnIsEnabled(int column_n, bool hidden) +// 'width' = inner column width, without padding +void ImGui::TableSetColumnWidth(int column_n, float width) { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; IM_ASSERT(table != NULL && table->IsLayoutLocked == false); - if (column_n < 0) - column_n = table->CurrentColumn; IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); - table->Columns[column_n].IsEnabledNextFrame = !hidden; -} + ImGuiTableColumn* column_0 = &table->Columns[column_n]; + float column_0_width = width; -int ImGui::TableGetColumnIndex() -{ - ImGuiContext& g = *GImGui; - ImGuiTable* table = g.CurrentTable; - if (!table) - return 0; - return table->CurrentColumn; -} + // Constraints + const float min_width = TableGetMinColumnWidth(); + float max_width_0 = FLT_MAX; + if (!(table->Flags & ImGuiTableFlags_ScrollX)) + max_width_0 = (table->WorkRect.Max.x - column_0->MinX) - (table->ColumnsEnabledCount - (column_0->IndexWithinEnabledSet + 1)) * min_width; + column_0_width = ImClamp(column_0_width, min_width, max_width_0); -// Note: for row coloring we use ->RowBgColorCounter which is the same value without counting header rows -int ImGui::TableGetRowIndex() -{ - ImGuiContext& g = *GImGui; - ImGuiTable* table = g.CurrentTable; - if (!table) - return 0; - return table->CurrentRow; -} + // Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded) + if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width) + return; -// Return the cell rectangle based on currently known height. -// - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations. -// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it. -// - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right -// columns report a small offset so their CellBgRect can extend up to the outer border. -ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n) -{ - const ImGuiTableColumn* column = &table->Columns[column_n]; - float x1 = column->MinX; - float x2 = column->MaxX; - if (column->PrevEnabledColumn == -1) - x1 -= table->CellSpacingX1; - if (column->NextEnabledColumn == -1) - x2 += table->CellSpacingX2; - return ImRect(x1, table->RowPosY1, x2, table->RowPosY2); -} + ImGuiTableColumn* column_1 = (column_0->NextEnabledColumn != -1) ? &table->Columns[column_0->NextEnabledColumn] : NULL; -const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n) -{ - const ImGuiTableColumn* column = &table->Columns[column_n]; - if (column->NameOffset == -1) - return ""; - return &table->ColumnsNames.Buf[column->NameOffset]; -} + // In this surprisingly not simple because of how we support mixing Fixed and Stretch columns. + // When forwarding resize from Wn| to Fn+1| we need to be considerate of the _NoResize flag on Fn+1. + // FIXME-TABLE: Find a way to rewrite all of this so interactions feel more consistent for the user. + // Scenarios: + // - F1 F2 F3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. Subsequent columns will be offset. + // - F1 F2 F3 resize from F3| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered. + // - F1 F2 W3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered, but it doesn't make much sense as the Stretch column will always be minimal size. + // - F1 F2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1) + // - W1 W2 W3 resize from W1| or W2| --> FIXME + // - W1 W2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1) + // - W1 F2 F3 resize from F3| --> ok: no-op (disabled by Resize Rule 1) + // - W1 F2 resize from F2| --> ok: no-op (disabled by Resize Rule 1) + // - W1 W2 F3 resize from W1| or W2| --> ok + // - W1 F2 W3 resize from W1| or F2| --> FIXME + // - F1 W2 F3 resize from W2| --> ok + // - W1 F2 F3 resize from W1| --> ok: equivalent to resizing |F2. F3 will not move. (forwarded by Resize Rule 2) + // - W1 F2 F3 resize from F2| --> FIXME should resize F2, F3 and not have effect on W1 (Stretch columns are _before_ the Fixed column). -// Return the resizing ID for the right-side of the given column. -ImGuiID ImGui::TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no) -{ - IM_ASSERT(column_n < table->ColumnsCount); - ImGuiID id = table->ID + 1 + (instance_no * table->ColumnsCount) + column_n; - return id; + // Rules: + // - [Resize Rule 1] Can't resize from right of right-most visible column if there is any Stretch column. Implemented in TableUpdateLayout(). + // - [Resize Rule 2] Resizing from right-side of a Stretch column before a fixed column forward sizing to left-side of fixed column. + // - [Resize Rule 3] If we are are followed by a fixed column and we have a Stretch column before, we need to ensure that our left border won't move. + table->IsSettingsDirty = true; + if (column_0->Flags & ImGuiTableColumnFlags_WidthFixed) + { + // [Resize Rule 3] If we are are followed by a fixed column and we have a Stretch column before, we need to ensure + // that our left border won't move, which we can do by making sure column_a/column_b resizes cancels each others. + if (column_1 && (column_1->Flags & ImGuiTableColumnFlags_WidthFixed)) + if (table->LeftMostStretchedColumnDisplayOrder != -1 && table->LeftMostStretchedColumnDisplayOrder < column_0->DisplayOrder) + { + // (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b) + float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width); + column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width; + column_1->WidthRequest = column_1_width; + } + + // Apply + //IMGUI_DEBUG_LOG("TableSetColumnWidth(%d, %.1f->%.1f)\n", column_0_idx, column_0->WidthRequested, column_0_width); + column_0->WidthRequest = column_0_width; + } + else if (column_0->Flags & ImGuiTableColumnFlags_WidthStretch) + { + // We can also use previous column if there's no next one + if (column_1 == NULL) + column_1 = (column_0->PrevEnabledColumn != -1) ? &table->Columns[column_0->PrevEnabledColumn] : NULL; + if (column_1 == NULL) + return; + + if (column_1->Flags & ImGuiTableColumnFlags_WidthFixed) + { + // [Resize Rule 2] + float off = (column_0->WidthGiven - column_0_width); + float column_1_width = column_1->WidthGiven + off; + column_1->WidthRequest = ImMax(min_width, column_1_width); + } + else + { + // (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b) + float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width); + column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width; + column_1->WidthRequest = column_1_width; + column_0->WidthRequest = column_0_width; + TableUpdateColumnsWeightFromWidth(table); + } + } } // Disable clipping then auto-fit, will take 2 frames @@ -1888,55 +1944,31 @@ } } -// Return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. -int ImGui::TableGetHoveredColumn() +void ImGui::TableUpdateColumnsWeightFromWidth(ImGuiTable* table) { - ImGuiContext& g = *GImGui; - ImGuiTable* table = g.CurrentTable; - if (!table) - return -1; - return (int)table->HoveredColumnBody; -} + IM_ASSERT(table->LeftMostStretchedColumnDisplayOrder != -1); -void ImGui::TableSetBgColor(ImGuiTableBgTarget bg_target, ImU32 color, int column_n) -{ - ImGuiContext& g = *GImGui; - ImGuiTable* table = g.CurrentTable; - IM_ASSERT(bg_target != ImGuiTableBgTarget_None); - - if (color == IM_COL32_DISABLE) - color = 0; - - // We cannot draw neither the cell or row background immediately as we don't know the row height at this point in time. - switch (bg_target) + // Measure existing quantity + float visible_weight = 0.0f; + float visible_width = 0.0f; + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { - case ImGuiTableBgTarget_CellBg: - { - if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard - return; - if (column_n == -1) - column_n = table->CurrentColumn; - if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0) - return; - if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n) - table->RowCellDataCurrent++; - ImGuiTableCellData* cell_data = &table->RowCellData[table->RowCellDataCurrent]; - cell_data->BgColor = color; - cell_data->Column = (ImGuiTableColumnIdx)column_n; - break; + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) + continue; + IM_ASSERT(column->StretchWeight > 0.0f); + visible_weight += column->StretchWeight; + visible_width += column->WidthRequest; } - case ImGuiTableBgTarget_RowBg0: - case ImGuiTableBgTarget_RowBg1: + IM_ASSERT(visible_weight > 0.0f && visible_width > 0.0f); + + // Apply new weights + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { - if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard - return; - IM_ASSERT(column_n == -1); - int bg_idx = (bg_target == ImGuiTableBgTarget_RowBg1) ? 1 : 0; - table->RowBgColor[bg_idx] = color; - break; - } - default: - IM_ASSERT(0); + ImGuiTableColumn* column = &table->Columns[column_n]; + if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) + continue; + column->StretchWeight = ((column->WidthRequest + 0.0f) / visible_width) * visible_weight; } } @@ -2248,7 +2280,8 @@ if (column->MaxX > table->InnerClipRect.Max.x && !is_resized)// && is_hovered) continue; if (column->NextEnabledColumn == -1 && !is_resizable) - continue; + if ((table->Flags & ImGuiTableFlags_SameWidths) == 0) + continue; if (column->MaxX <= column->ClipRect.Min.x) // FIXME-TABLE FIXME-STYLE: Assume BorderSize==1, this is problematic if we want to increase the border size.. continue; @@ -2314,6 +2347,7 @@ //------------------------------------------------------------------------- // - TableGetSortSpecs() // - TableFixColumnSortDirection() [Internal] +// - TableGetColumnNextSortDirection() [Internal] // - TableSetColumnSortDirection() [Internal] // - TableSortSpecsSanitize() [Internal] // - TableSortSpecsBuild() [Internal] @@ -2339,22 +2373,39 @@ if (table->IsSortSpecsDirty) TableSortSpecsBuild(table); - return table->SortSpecs.SpecsCount ? &table->SortSpecs : NULL; + return &table->SortSpecs; } -void ImGui::TableFixColumnSortDirection(ImGuiTableColumn* column) +static inline ImGuiSortDirection TableGetColumnAvailSortDirection(ImGuiTableColumn* column, int n) { - // Initial sort state - if (column->SortDirection == ImGuiSortDirection_None) - column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImS8)(ImGuiSortDirection_Ascending); - - // Handle NoSortAscending/NoSortDescending - if (column->SortDirection == ImGuiSortDirection_Ascending && (column->Flags & ImGuiTableColumnFlags_NoSortAscending)) - column->SortDirection = ImGuiSortDirection_Descending; - else if (column->SortDirection == ImGuiSortDirection_Descending && (column->Flags & ImGuiTableColumnFlags_NoSortDescending)) - column->SortDirection = ImGuiSortDirection_Ascending; + IM_ASSERT(n < column->SortDirectionsAvailCount); + return (column->SortDirectionsAvailList >> (n << 1)) & 0x03; } +// Fix sort direction if currently set on a value which is unavailable (e.g. activating NoSortAscending/NoSortDescending) +void ImGui::TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column) +{ + if (column->SortOrder == -1 || (column->SortDirectionsAvailMask & (1 << column->SortDirection)) != 0) + return; + column->SortDirection = (ImU8)TableGetColumnAvailSortDirection(column, 0); + table->IsSortSpecsDirty = true; +} + +// Calculate next sort direction that would be set after clicking the column +// - If the PreferSortDescending flag is set, we will default to a Descending direction on the first click. +// - Note that the PreferSortAscending flag is never checked, it is essentially the default and therefore a no-op. +IM_STATIC_ASSERT(ImGuiSortDirection_None == 0 && ImGuiSortDirection_Ascending == 1 && ImGuiSortDirection_Descending == 2); +ImGuiSortDirection ImGui::TableGetColumnNextSortDirection(ImGuiTableColumn* column) +{ + IM_ASSERT(column->SortDirectionsAvailCount > 0); + if (column->SortOrder == -1) + return TableGetColumnAvailSortDirection(column, 0); + for (int n = 0; n < 3; n++) + if (column->SortDirection == TableGetColumnAvailSortDirection(column, n)) + return TableGetColumnAvailSortDirection(column, (n + 1) % column->SortDirectionsAvailCount); + IM_ASSERT(0); + return ImGuiSortDirection_None; +} // Note that the NoSortAscending/NoSortDescending flags are processed in TableSortSpecsSanitize(), and they may change/revert // the value of SortDirection. We could technically also do it here but it would be unnecessary and duplicate code. @@ -2363,8 +2414,10 @@ ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - if (!(table->Flags & ImGuiTableFlags_MultiSortable)) + if (!(table->Flags & ImGuiTableFlags_SortMulti)) append_to_sort_specs = false; + if (!(table->Flags & ImGuiTableFlags_SortTristate)) + IM_ASSERT(sort_direction != ImGuiSortDirection_None); ImGuiTableColumnIdx sort_order_max = 0; if (append_to_sort_specs) @@ -2372,8 +2425,10 @@ sort_order_max = ImMax(sort_order_max, table->Columns[other_column_n].SortOrder); ImGuiTableColumn* column = &table->Columns[column_n]; - column->SortDirection = (ImS8)sort_direction; - if (column->SortOrder == -1 || !append_to_sort_specs) + column->SortDirection = (ImU8)sort_direction; + if (column->SortDirection == ImGuiSortDirection_None) + column->SortOrder = -1; + else if (column->SortOrder == -1 || !append_to_sort_specs) column->SortOrder = append_to_sort_specs ? sort_order_max + 1 : 0; for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++) @@ -2381,7 +2436,7 @@ ImGuiTableColumn* other_column = &table->Columns[other_column_n]; if (other_column != column && !append_to_sort_specs) other_column->SortOrder = -1; - TableFixColumnSortDirection(other_column); + TableFixColumnSortDirection(table, other_column); } table->IsSettingsDirty = true; table->IsSortSpecsDirty = true; @@ -2407,7 +2462,7 @@ } const bool need_fix_linearize = ((ImU64)1 << sort_order_count) != (sort_order_mask + 1); - const bool need_fix_single_sort_order = (sort_order_count > 1) && !(table->Flags & ImGuiTableFlags_MultiSortable); + const bool need_fix_single_sort_order = (sort_order_count > 1) && !(table->Flags & ImGuiTableFlags_SortMulti); if (need_fix_linearize || need_fix_single_sort_order) { ImU64 fixed_mask = 0x00; @@ -2437,7 +2492,7 @@ } // Fallback default sort order (if no column had the ImGuiTableColumnFlags_DefaultSort flag) - if (sort_order_count == 0) + if (sort_order_count == 0 && !(table->Flags & ImGuiTableFlags_SortTristate)) for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { ImGuiTableColumn* column = &table->Columns[column_n]; @@ -2445,7 +2500,7 @@ { sort_order_count = 1; column->SortOrder = 0; - TableFixColumnSortDirection(column); + column->SortDirection = TableGetColumnAvailSortDirection(column, 0); break; } } @@ -2459,9 +2514,8 @@ TableSortSpecsSanitize(table); // Write output - const bool single_sort_specs = (table->SortSpecsCount <= 1); - table->SortSpecsMulti.resize(single_sort_specs ? 0 : table->SortSpecsCount); - ImGuiTableColumnSortSpecs* sort_specs = single_sort_specs ? &table->SortSpecsSingle : table->SortSpecsMulti.Data; + table->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount); + ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &table->SortSpecsSingle : table->SortSpecsMulti.Data; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { ImGuiTableColumn* column = &table->Columns[column_n]; @@ -2593,6 +2647,12 @@ TableSetBgColor(ImGuiTableBgTarget_CellBg, col, table->CurrentColumn); RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); } + else + { + // Submit single cell bg color in the case we didn't submit a full header row + if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0) + TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn); + } if (held) table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n; window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f; @@ -2654,14 +2714,7 @@ // Handle clicking on column header to adjust Sort Order if (pressed && table->ReorderColumn != column_n) { - // Set new sort direction - // - If the PreferSortDescending flag is set, we will default to a Descending direction on the first click. - // - Note that the PreferSortAscending flag is never checked, it is essentially the default and therefore a no-op. - ImGuiSortDirection sort_direction; - if (column->SortOrder == -1) - sort_direction = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending; - else - sort_direction = (column->SortDirection == ImGuiSortDirection_Ascending) ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending; + ImGuiSortDirection sort_direction = TableGetColumnNextSortDirection(column); TableSetColumnSortDirection(column_n, sort_direction, g.IO.KeyShift); } } @@ -3269,6 +3322,8 @@ // [SECTION] Columns, BeginColumns, EndColumns, etc. // (This is a legacy API, prefer using BeginTable/EndTable!) //------------------------------------------------------------------------- +// FIXME: sizing is lossy when columns width is very small (default width may turn negative etc.) +//------------------------------------------------------------------------- // - SetWindowClipRectBeforeSetChannel() [Internal] // - GetColumnIndex() // - GetColumnsCount()