Merge branch 'master' into docking

# Conflicts:
#	backends/imgui_impl_sdlgpu3.cpp
#	backends/imgui_impl_win32.cpp
This commit is contained in:
ocornut
2025-12-03 13:35:35 +01:00
15 changed files with 211 additions and 71 deletions

View File

@@ -24,6 +24,7 @@
// CHANGELOG // CHANGELOG
// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2025-11-26: macOS version can use MSL shaders in order to support macOS 10.14+ (vs Metallib shaders requiring macOS 14+). Requires calling SDL_CreateGPUDevice() with SDL_GPU_SHADERFORMAT_MSL.
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
// 2025-08-20: Added ImGui_ImplSDLGPU3_InitInfo::SwapchainComposition and ImGui_ImplSDLGPU3_InitInfo::PresentMode to configure how secondary viewports are created. // 2025-08-20: Added ImGui_ImplSDLGPU3_InitInfo::SwapchainComposition and ImGui_ImplSDLGPU3_InitInfo::PresentMode to configure how secondary viewports are created.
// 2025-08-08: *BREAKING* Changed ImTextureID type from SDL_GPUTextureSamplerBinding* to SDL_GPUTexture*, which is more natural and easier for user to manage. If you need to change the current sampler, you can access the ImGui_ImplSDLGPU3_RenderState struct. (#8866, #8163, #7998, #7988) // 2025-08-08: *BREAKING* Changed ImTextureID type from SDL_GPUTextureSamplerBinding* to SDL_GPUTexture*, which is more natural and easier for user to manage. If you need to change the current sampler, you can access the ImGui_ImplSDLGPU3_RenderState struct. (#8866, #8163, #7998, #7988)
@@ -454,14 +455,31 @@ static void ImGui_ImplSDLGPU3_CreateShaders()
#ifdef __APPLE__ #ifdef __APPLE__
else else
{ {
vertex_shader_info.entrypoint = "main0"; SDL_GPUShaderFormat supported_formats = SDL_GetGPUShaderFormats(v->Device);
vertex_shader_info.format = SDL_GPU_SHADERFORMAT_METALLIB; if (supported_formats & SDL_GPU_SHADERFORMAT_METALLIB)
vertex_shader_info.code = metallib_vertex; {
vertex_shader_info.code_size = sizeof(metallib_vertex); // Using metallib blobs (macOS 14+, iOS)
fragment_shader_info.entrypoint = "main0"; vertex_shader_info.entrypoint = "main0";
fragment_shader_info.format = SDL_GPU_SHADERFORMAT_METALLIB; vertex_shader_info.format = SDL_GPU_SHADERFORMAT_METALLIB;
fragment_shader_info.code = metallib_fragment; vertex_shader_info.code = metallib_vertex;
fragment_shader_info.code_size = sizeof(metallib_fragment); vertex_shader_info.code_size = sizeof(metallib_vertex);
fragment_shader_info.entrypoint = "main0";
fragment_shader_info.format = SDL_GPU_SHADERFORMAT_METALLIB;
fragment_shader_info.code = metallib_fragment;
fragment_shader_info.code_size = sizeof(metallib_fragment);
}
else if (supported_formats & SDL_GPU_SHADERFORMAT_MSL)
{
// macOS: using MSL source
vertex_shader_info.entrypoint = "main0";
vertex_shader_info.format = SDL_GPU_SHADERFORMAT_MSL;
vertex_shader_info.code = msl_vertex;
vertex_shader_info.code_size = sizeof(msl_vertex);
fragment_shader_info.entrypoint = "main0";
fragment_shader_info.format = SDL_GPU_SHADERFORMAT_MSL;
fragment_shader_info.code = msl_fragment;
fragment_shader_info.code_size = sizeof(msl_fragment);
}
} }
#endif #endif
bd->VertexShader = SDL_CreateGPUShader(v->Device, &vertex_shader_info); bd->VertexShader = SDL_CreateGPUShader(v->Device, &vertex_shader_info);

View File

@@ -221,6 +221,40 @@ const uint8_t metallib_fragment[3787] = {
148,161,0,0,0,0,109,97,105,110,48,97,105,114,46,115,97,109,112,108,101,95,116,101,120,116,117,114,101,95,50,100,46,118,52,102,51,50,51,50,48,50,51,46,51,54,56,97,105,114,54,52,45,97, 148,161,0,0,0,0,109,97,105,110,48,97,105,114,46,115,97,109,112,108,101,95,116,101,120,116,117,114,101,95,50,100,46,118,52,102,51,50,51,50,48,50,51,46,51,54,56,97,105,114,54,52,45,97,
112,112,108,101,45,109,97,99,111,115,120,49,52,46,48,46,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 112,112,108,101,45,109,97,99,111,115,120,49,52,46,48,46,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
}; };
static uint8_t msl_vertex[800] =
{
35,105,110,99,108,117,100,101,32,60,109,101,116,97,108,95,115,116,100,108,105,98,62,10,35,105,110,99,108,117,100,101,32,60,115,105,109,100,47,115,105,109,100,46,104,62,10,10,117,115,
105,110,103,32,110,97,109,101,115,112,97,99,101,32,109,101,116,97,108,59,10,10,115,116,114,117,99,116,32,95,57,10,123,10,32,32,32,32,102,108,111,97,116,52,32,67,111,108,111,114,59,
10,32,32,32,32,102,108,111,97,116,50,32,85,86,59,10,125,59,10,10,115,116,114,117,99,116,32,85,66,79,10,123,10,32,32,32,32,102,108,111,97,116,50,32,117,83,99,97,108,101,59,10,32,32,
32,32,102,108,111,97,116,50,32,117,84,114,97,110,115,108,97,116,101,59,10,125,59,10,10,115,116,114,117,99,116,32,109,97,105,110,48,95,111,117,116,10,123,10,32,32,32,32,102,108,111,
97,116,52,32,79,117,116,95,67,111,108,111,114,32,91,91,117,115,101,114,40,108,111,99,110,48,41,93,93,59,10,32,32,32,32,102,108,111,97,116,50,32,79,117,116,95,85,86,32,91,91,117,115,
101,114,40,108,111,99,110,49,41,93,93,59,10,32,32,32,32,102,108,111,97,116,52,32,103,108,95,80,111,115,105,116,105,111,110,32,91,91,112,111,115,105,116,105,111,110,93,93,59,10,125,
59,10,10,115,116,114,117,99,116,32,109,97,105,110,48,95,105,110,10,123,10,32,32,32,32,102,108,111,97,116,50,32,97,80,111,115,32,91,91,97,116,116,114,105,98,117,116,101,40,48,41,93,
93,59,10,32,32,32,32,102,108,111,97,116,50,32,97,85,86,32,91,91,97,116,116,114,105,98,117,116,101,40,49,41,93,93,59,10,32,32,32,32,102,108,111,97,116,52,32,97,67,111,108,111,114,32,
91,91,97,116,116,114,105,98,117,116,101,40,50,41,93,93,59,10,125,59,10,10,118,101,114,116,101,120,32,109,97,105,110,48,95,111,117,116,32,109,97,105,110,48,40,109,97,105,110,48,95,105,
110,32,105,110,32,91,91,115,116,97,103,101,95,105,110,93,93,44,32,99,111,110,115,116,97,110,116,32,85,66,79,38,32,117,98,111,32,91,91,98,117,102,102,101,114,40,48,41,93,93,41,10,123,
10,32,32,32,32,109,97,105,110,48,95,111,117,116,32,111,117,116,32,61,32,123,125,59,10,32,32,32,32,95,57,32,79,117,116,32,61,32,123,125,59,10,32,32,32,32,79,117,116,46,67,111,108,111,
114,32,61,32,105,110,46,97,67,111,108,111,114,59,10,32,32,32,32,79,117,116,46,85,86,32,61,32,105,110,46,97,85,86,59,10,32,32,32,32,111,117,116,46,103,108,95,80,111,115,105,116,105,
111,110,32,61,32,102,108,111,97,116,52,40,40,105,110,46,97,80,111,115,32,42,32,117,98,111,46,117,83,99,97,108,101,41,32,43,32,117,98,111,46,117,84,114,97,110,115,108,97,116,101,44,
32,48,46,48,44,32,49,46,48,41,59,10,32,32,32,32,111,117,116,46,103,108,95,80,111,115,105,116,105,111,110,46,121,32,42,61,32,40,45,49,46,48,41,59,10,32,32,32,32,111,117,116,46,79,117,
116,95,67,111,108,111,114,32,61,32,79,117,116,46,67,111,108,111,114,59,10,32,32,32,32,111,117,116,46,79,117,116,95,85,86,32,61,32,79,117,116,46,85,86,59,10,32,32,32,32,114,101,116,
117,114,110,32,111,117,116,59,10,125,10,10,
};
static uint8_t msl_fragment[580] =
{
35,105,110,99,108,117,100,101,32,60,109,101,116,97,108,95,115,116,100,108,105,98,62,10,35,105,110,99,108,117,100,101,32,60,115,105,109,100,47,115,105,109,100,46,104,62,10,10,117,115,
105,110,103,32,110,97,109,101,115,112,97,99,101,32,109,101,116,97,108,59,10,10,115,116,114,117,99,116,32,95,49,49,10,123,10,32,32,32,32,102,108,111,97,116,52,32,67,111,108,111,114,
59,10,32,32,32,32,102,108,111,97,116,50,32,85,86,59,10,125,59,10,10,115,116,114,117,99,116,32,109,97,105,110,48,95,111,117,116,10,123,10,32,32,32,32,102,108,111,97,116,52,32,102,67,
111,108,111,114,32,91,91,99,111,108,111,114,40,48,41,93,93,59,10,125,59,10,10,115,116,114,117,99,116,32,109,97,105,110,48,95,105,110,10,123,10,32,32,32,32,102,108,111,97,116,52,32,
73,110,95,67,111,108,111,114,32,91,91,117,115,101,114,40,108,111,99,110,48,41,93,93,59,10,32,32,32,32,102,108,111,97,116,50,32,73,110,95,85,86,32,91,91,117,115,101,114,40,108,111,99,
110,49,41,93,93,59,10,125,59,10,10,102,114,97,103,109,101,110,116,32,109,97,105,110,48,95,111,117,116,32,109,97,105,110,48,40,109,97,105,110,48,95,105,110,32,105,110,32,91,91,115,116,
97,103,101,95,105,110,93,93,44,32,116,101,120,116,117,114,101,50,100,60,102,108,111,97,116,62,32,115,84,101,120,116,117,114,101,32,91,91,116,101,120,116,117,114,101,40,48,41,93,93,
44,32,115,97,109,112,108,101,114,32,115,84,101,120,116,117,114,101,83,109,112,108,114,32,91,91,115,97,109,112,108,101,114,40,48,41,93,93,41,10,123,10,32,32,32,32,109,97,105,110,48,
95,111,117,116,32,111,117,116,32,61,32,123,125,59,10,32,32,32,32,95,49,49,32,73,110,32,61,32,123,125,59,10,32,32,32,32,73,110,46,67,111,108,111,114,32,61,32,105,110,46,73,110,95,67,
111,108,111,114,59,10,32,32,32,32,73,110,46,85,86,32,61,32,105,110,46,73,110,95,85,86,59,10,32,32,32,32,111,117,116,46,102,67,111,108,111,114,32,61,32,73,110,46,67,111,108,111,114,
32,42,32,115,84,101,120,116,117,114,101,46,115,97,109,112,108,101,40,115,84,101,120,116,117,114,101,83,109,112,108,114,44,32,73,110,46,85,86,41,59,10,32,32,32,32,114,101,116,117,114,
110,32,111,117,116,59,10,125,10,10,
};
#elif TARGET_OS_IPHONE #elif TARGET_OS_IPHONE
const uint8_t metallib_vertex[3876] = { const uint8_t metallib_vertex[3876] = {
77,84,76,66,1,0,2,0,7,0,0,130,18,0,1,0,36,15,0,0,0,0,0,0,88,0,0,0,0,0,0,0,123,0,0,0,0,0,0,0,219,0,0,0,0,0,0,0,49,0,0,0,0,0,0,0,12,1,0,0,0,0,0,0,8,0,0,0,0,0,0,0,20,1,0,0,0,0,0,0,16, 77,84,76,66,1,0,2,0,7,0,0,130,18,0,1,0,36,15,0,0,0,0,0,0,88,0,0,0,0,0,0,0,123,0,0,0,0,0,0,0,219,0,0,0,0,0,0,0,49,0,0,0,0,0,0,0,12,1,0,0,0,0,0,0,8,0,0,0,0,0,0,0,20,1,0,0,0,0,0,0,16,

View File

@@ -23,6 +23,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2025-12-03: Inputs: handle WM_IME_CHAR/WM_IME_COMPOSITION messages to support Unicode inputs on MBCS (non-Unicode) Windows. (#9099, #3653, #5961)
// 2025-10-19: Inputs: Revert previous change to allow for io.ClearInputKeys() on focus-out not losing gamepad state. // 2025-10-19: Inputs: Revert previous change to allow for io.ClearInputKeys() on focus-out not losing gamepad state.
// 2025-09-23: Inputs: Minor optimization not submitting gamepad input if packet number has not changed. // 2025-09-23: Inputs: Minor optimization not submitting gamepad input if packet number has not changed.
// 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown.
@@ -889,10 +890,28 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA
else else
{ {
wchar_t wch = 0; wchar_t wch = 0;
::MultiByteToWideChar(bd->KeyboardCodePage, MB_PRECOMPOSED, (char*)&wParam, 1, &wch, 1); ::MultiByteToWideChar(bd->KeyboardCodePage, MB_PRECOMPOSED, (char*)&wParam, 2, &wch, 1);
io.AddInputCharacter(wch); io.AddInputCharacter(wch);
} }
return 0; return 0;
case WM_IME_COMPOSITION:
{
// Handling WM_IME_COMPOSITION ensure that WM_IME_CHAR value is correct even for MBCS apps.
// (see #9099, #3653 and https://stackoverflow.com/questions/77450354 topics)
LRESULT result = ::DefWindowProcW(hwnd, msg, wParam, lParam);
return (lParam & GCS_RESULTSTR) ? 1 : result;
}
case WM_IME_CHAR:
if (::IsWindowUnicode(hwnd) == FALSE)
{
if (::IsDBCSLeadByte(HIBYTE(wParam)))
wParam = (WPARAM)MAKEWORD(HIBYTE(wParam), LOBYTE(wParam));
wchar_t wch = 0;
::MultiByteToWideChar(bd->KeyboardCodePage, MB_PRECOMPOSED, (char*)&wParam, 2, &wch, 1);
io.AddInputCharacterUTF16(wch);
return 1;
}
return 0;
case WM_SETCURSOR: case WM_SETCURSOR:
// This is required to restore cursor when transitioning from e.g resize borders to client area. // This is required to restore cursor when transitioning from e.g resize borders to client area.
if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor(io, bd->LastMouseCursor)) if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor(io, bd->LastMouseCursor))

View File

@@ -34,6 +34,8 @@ Instructions to rebuild imgui_impl_sdlgpu3_shaders.h
xcrun -sdk macosx metallib -o vertex.metallib -c vertex.ir xcrun -sdk macosx metallib -o vertex.metallib -c vertex.ir
xcrun -sdk macosx metallib -o fragment.metallib -c fragment.ir xcrun -sdk macosx metallib -o fragment.metallib -c fragment.ir
note: use .metal outputs for updating msl_vertex / msl_fragment variables, and use .metallib outputs for metallib_vertex / metallib_fragment variables
Proceed to step 4 Proceed to step 4

View File

@@ -51,12 +51,37 @@ Other Changes:
- Textures: - Textures:
- Fixed a building issue when ImTextureID is defined as a struct. - Fixed a building issue when ImTextureID is defined as a struct.
- Fixed displaying texture # in Metrics/Debugger window. - Fixed displaying texture # in Metrics/Debugger window.
- Menus:
- Fixed MenuItem() label position and BeginMenu() arrow/icon/popup positions,
when used inside a line with a baseline offset.
- TreeNode:
- Fixed highlight position when used inside a line with a large text baseline offset.
(never quite worked in this situation; but then most of the time the text
baseline offset ends up being zero or FramePadding.y for a given line).
- Tables:
- Fixed an issue where a very thin scrolling table would advance parent layout
slightly differently depending on its visibility (caused by a mismatch
between hard minimum window size and table minimum size).
- Fixed an issue where submitting non-integer row heights would eventually
advance table parent layout by +0/+1 depending on its visibility.
- Scrollbar: fixed a codepath leading to a divide-by-zero (which would not be - Scrollbar: fixed a codepath leading to a divide-by-zero (which would not be
noticeable by user but detected by sanitizers). (#9089) [@judicaelclair] noticeable by user but detected by sanitizers). (#9089) [@judicaelclair]
- Debug Tools:
- Debug Log: fixed incorrectly printing characters in IO log when submitting
non-ASCII values to io.AddInputCharacter(). (#9099)
- Backends: - Backends:
- SDL_GPU3: macOS version can use MSL shaders in order to support macOS 10.14+
(vs Metallib shaders requiring macOS 14+). Requires application calling
SDL_CreateGPUDevice() with SDL_GPU_SHADERFORMAT_MSL. (#9076) [@Niminem]
- Vulkan: helper for creating a swapchain (used by examples and multi-viewports) - Vulkan: helper for creating a swapchain (used by examples and multi-viewports)
selects `VkSwapchainCreateInfoKHR`'s `compositeAlpha` value based on selects `VkSwapchainCreateInfoKHR`'s `compositeAlpha` value based on
`cap.supportedCompositeAlpha`. (#8784) [@FelixStach] `cap.supportedCompositeAlpha`, which seems to be required on some Android
devices. (#8784) [@FelixStach]
- Win32: handle WM_IME_CHAR/WM_IME_COMPOSITION to support Unicode inputs on
MBCS (non-Unicode) Windows. (#9099, #3653, #5961) [@ulhc, @ocornut, @Othereum]
- Examples:
- Win32+DirectX12: ignore seemingly incorrect D3D12_MESSAGE_ID_FENCE_ZERO_WAIT
warning on startups on some setups. (#9084, #9093) [@RT2Code, @LeoGautheron]
Docking+Viewports Branch: Docking+Viewports Branch:

View File

@@ -39,10 +39,12 @@ Dear ImGui is particularly suited to integration in game engines (for tooling),
### Usage ### Usage
**The core of Dear ImGui is self-contained within a few platform-agnostic files** which you can easily compile in your application/engine. They are all the files in the root folder of the repository (imgui*.cpp, imgui*.h). **No specific build process is required**. You can add the .cpp files into your existing project. **The core of Dear ImGui is self-contained within a few platform-agnostic files** which you can easily compile in your application/engine. They are all the files in the root folder of the repository (`imgui*.cpp`, `imgui*.h`). **No specific build process is required**: you can add all files into your existing project.
**Backends for a variety of graphics API and rendering platforms** are provided in the [backends/](https://github.com/ocornut/imgui/tree/master/backends) folder, along with example applications in the [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder. You may also create your own backend. Anywhere where you can render textured triangles, you can render Dear ImGui. **Backends for a variety of graphics API and rendering platforms** are provided in the [backends/](https://github.com/ocornut/imgui/tree/master/backends) folder, along with example applications in the [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder. You may also create your own backend. Anywhere where you can render textured triangles, you can render Dear ImGui.
C++20 users wishing to use a module may the use [stripe2933/imgui-module](https://github.com/stripe2933/imgui-module) third-party extension.
See the [Getting Started & Integration](#getting-started--integration) section of this document for more details. See the [Getting Started & Integration](#getting-started--integration) section of this document for more details.
After Dear ImGui is set up in your application, you can use it from \_anywhere\_ in your program loop: After Dear ImGui is set up in your application, you can use it from \_anywhere\_ in your program loop:

View File

@@ -188,7 +188,7 @@
-(NSWindow*)window -(NSWindow*)window
{ {
if (_window != nil) if (_window != nil)
return (_window); return _window;
NSRect viewRect = NSMakeRect(100.0, 100.0, 100.0 + 1280.0, 100 + 800.0); NSRect viewRect = NSMakeRect(100.0, 100.0, 100.0 + 1280.0, 100 + 800.0);
@@ -198,7 +198,7 @@
[_window setOpaque:YES]; [_window setOpaque:YES];
[_window makeKeyAndOrderFront:NSApp]; [_window makeKeyAndOrderFront:NSApp];
return (_window); return _window;
} }
-(void)setupMenu -(void)setupMenu

View File

@@ -47,7 +47,7 @@ int main(int, char**)
SDL_ShowWindow(window); SDL_ShowWindow(window);
// Create GPU Device // Create GPU Device
SDL_GPUDevice* gpu_device = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_METALLIB,true,nullptr); SDL_GPUDevice* gpu_device = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL | SDL_GPU_SHADERFORMAT_METALLIB, true, nullptr);
if (gpu_device == nullptr) if (gpu_device == nullptr)
{ {
printf("Error: SDL_CreateGPUDevice(): %s\n", SDL_GetError()); printf("Error: SDL_CreateGPUDevice(): %s\n", SDL_GetError());

View File

@@ -371,6 +371,15 @@ bool CreateDeviceD3D(HWND hWnd)
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true); pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true); pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, true); pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, true);
// Disable breaking on this warning because of a suspected bug in the D3D12 SDK layer, see #9084 for details.
const int D3D12_MESSAGE_ID_FENCE_ZERO_WAIT_ = 1424; // not in all copies of d3d12sdklayers.h
D3D12_MESSAGE_ID disabledMessages[] = { (D3D12_MESSAGE_ID)D3D12_MESSAGE_ID_FENCE_ZERO_WAIT_ };
D3D12_INFO_QUEUE_FILTER filter = {};
filter.DenyList.NumIDs = 1;
filter.DenyList.pIDList = disabledMessages;
pInfoQueue->AddStorageFilterEntries(&filter);
pInfoQueue->Release(); pInfoQueue->Release();
pdx12Debug->Release(); pdx12Debug->Release();
} }

View File

@@ -2096,7 +2096,7 @@ bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c,
bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f; bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f; bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f; bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
return ((b1 == b2) && (b2 == b3)); return (b1 == b2) && (b2 == b3);
} }
void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w) void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
@@ -3196,7 +3196,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE
static bool GetSkipItemForListClipping() static bool GetSkipItemForListClipping()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
return (g.CurrentTable ? g.CurrentTable->HostSkipItems : g.CurrentWindow->SkipItems); return g.CurrentTable ? g.CurrentTable->HostSkipItems : g.CurrentWindow->SkipItems;
} }
static void ImGuiListClipper_SortAndFuseRanges(ImVector<ImGuiListClipperRange>& ranges, int offset = 0) static void ImGuiListClipper_SortAndFuseRanges(ImVector<ImGuiListClipperRange>& ranges, int offset = 0)
@@ -4421,7 +4421,7 @@ void ImGui::Initialize()
g.ViewportCreatedCount++; g.ViewportCreatedCount++;
g.PlatformIO.Viewports.push_back(g.Viewports[0]); g.PlatformIO.Viewports.push_back(g.Viewports[0]);
// Build KeysMayBeCharInput[] lookup table (1 bool per named key) // Build KeysMayBeCharInput[] lookup table (1 bit per named key)
for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
if ((key >= ImGuiKey_0 && key <= ImGuiKey_9) || (key >= ImGuiKey_A && key <= ImGuiKey_Z) || (key >= ImGuiKey_Keypad0 && key <= ImGuiKey_Keypad9) if ((key >= ImGuiKey_0 && key <= ImGuiKey_9) || (key >= ImGuiKey_A && key <= ImGuiKey_Z) || (key >= ImGuiKey_Keypad0 && key <= ImGuiKey_Keypad9)
|| key == ImGuiKey_Tab || key == ImGuiKey_Space || key == ImGuiKey_Apostrophe || key == ImGuiKey_Comma || key == ImGuiKey_Minus || key == ImGuiKey_Period || key == ImGuiKey_Tab || key == ImGuiKey_Space || key == ImGuiKey_Apostrophe || key == ImGuiKey_Comma || key == ImGuiKey_Minus || key == ImGuiKey_Period
@@ -4547,6 +4547,13 @@ void ImGui::Shutdown()
g.Initialized = false; g.Initialized = false;
} }
// When using multiple context it can be helpful to give name a name.
// (A) Will be visible in debugger, (B) Will be included in all IMGUI_DEBUG_LOG() calls, (C) Should be <= 15 characters long.
void ImGui::SetContextName(ImGuiContext* ctx, const char* name)
{
ImStrncpy(ctx->ContextName, name, IM_ARRAYSIZE(ctx->ContextName));
}
// No specific ordering/dependency support, will see as needed // No specific ordering/dependency support, will see as needed
ImGuiID ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook) ImGuiID ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook)
{ {
@@ -5472,7 +5479,7 @@ static void ScaleWindow(ImGuiWindow* window, float scale)
static bool IsWindowActiveAndVisible(ImGuiWindow* window) static bool IsWindowActiveAndVisible(ImGuiWindow* window)
{ {
return (window->Active) && (!window->Hidden); return window->Active && !window->Hidden;
} }
// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app) // The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app)
@@ -5887,7 +5894,7 @@ static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs)
return d; return d;
if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip)) if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))
return d; return d;
return (a->BeginOrderWithinParent - b->BeginOrderWithinParent); return a->BeginOrderWithinParent - b->BeginOrderWithinParent;
} }
static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window) static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)
@@ -6434,7 +6441,7 @@ bool ImGui::IsItemDeactivated()
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDeactivated) if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDeactivated)
return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Deactivated) != 0; return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
return (g.DeactivatedItemData.ID == g.LastItemData.ID && g.LastItemData.ID != 0 && g.DeactivatedItemData.ElapseFrame >= g.FrameCount); return g.DeactivatedItemData.ID == g.LastItemData.ID && g.LastItemData.ID != 0 && g.DeactivatedItemData.ElapseFrame >= g.FrameCount;
} }
bool ImGui::IsItemDeactivatedAfterEdit() bool ImGui::IsItemDeactivatedAfterEdit()
@@ -6880,13 +6887,13 @@ static inline ImVec2 CalcWindowMinSize(ImGuiWindow* window)
ImVec2 size_min; ImVec2 size_min;
if ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Popup)) if ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Popup))
{ {
size_min.x = (window->ChildFlags & ImGuiChildFlags_ResizeX) ? g.Style.WindowMinSize.x : 4.0f; size_min.x = (window->ChildFlags & ImGuiChildFlags_ResizeX) ? g.Style.WindowMinSize.x : IMGUI_WINDOW_HARD_MIN_SIZE;
size_min.y = (window->ChildFlags & ImGuiChildFlags_ResizeY) ? g.Style.WindowMinSize.y : 4.0f; size_min.y = (window->ChildFlags & ImGuiChildFlags_ResizeY) ? g.Style.WindowMinSize.y : IMGUI_WINDOW_HARD_MIN_SIZE;
} }
else else
{ {
size_min.x = ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) == 0) ? g.Style.WindowMinSize.x : 4.0f; size_min.x = ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) == 0) ? g.Style.WindowMinSize.x : IMGUI_WINDOW_HARD_MIN_SIZE;
size_min.y = ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) == 0) ? g.Style.WindowMinSize.y : 4.0f; size_min.y = ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) == 0) ? g.Style.WindowMinSize.y : IMGUI_WINDOW_HARD_MIN_SIZE;
} }
// Reduce artifacts with very small windows // Reduce artifacts with very small windows
@@ -10008,7 +10015,7 @@ int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, flo
if (t0 >= t1) if (t0 >= t1)
return 0; return 0;
if (repeat_rate <= 0.0f) if (repeat_rate <= 0.0f)
return (t0 < repeat_delay) && (t1 >= repeat_delay); return t0 < repeat_delay && t1 >= repeat_delay;
const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate); const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate);
const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate); const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate);
const int count = count_t1 - count_t0; const int count = count_t1 - count_t0;
@@ -10951,12 +10958,13 @@ static const char* GetMouseSourceName(ImGuiMouseSource source)
static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e) static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
char buf[5];
if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (%.1f, %.1f) (%s)\n", prefix, e->MousePos.PosX, e->MousePos.PosY, GetMouseSourceName(e->MousePos.MouseSource)); return; } if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (%.1f, %.1f) (%s)\n", prefix, e->MousePos.PosX, e->MousePos.PosY, GetMouseSourceName(e->MousePos.MouseSource)); return; }
if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseButton %d %s (%s)\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up", GetMouseSourceName(e->MouseButton.MouseSource)); return; } if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseButton %d %s (%s)\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up", GetMouseSourceName(e->MouseButton.MouseSource)); return; }
if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseWheel (%.3f, %.3f) (%s)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; } if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseWheel (%.3f, %.3f) (%s)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; }
if (e->Type == ImGuiInputEventType_MouseViewport){IMGUI_DEBUG_LOG_IO("[io] %s: MouseViewport (0x%08X)\n", prefix, e->MouseViewport.HoveredViewportID); return; } if (e->Type == ImGuiInputEventType_MouseViewport){IMGUI_DEBUG_LOG_IO("[io] %s: MouseViewport (0x%08X)\n", prefix, e->MouseViewport.HoveredViewportID); return; }
if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("[io] %s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; } if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("[io] %s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; }
if (e->Type == ImGuiInputEventType_Text) { IMGUI_DEBUG_LOG_IO("[io] %s: Text: %c (U+%08X)\n", prefix, e->Text.Char, e->Text.Char); return; } if (e->Type == ImGuiInputEventType_Text) { ImTextCharToUtf8(buf, e->Text.Char); IMGUI_DEBUG_LOG_IO("[io] %s: Text: '%s' (U+%08X)\n", prefix, buf, e->Text.Char); return; }
if (e->Type == ImGuiInputEventType_Focus) { IMGUI_DEBUG_LOG_IO("[io] %s: AppFocused %d\n", prefix, e->AppFocused.Focused); return; } if (e->Type == ImGuiInputEventType_Focus) { IMGUI_DEBUG_LOG_IO("[io] %s: AppFocused %d\n", prefix, e->AppFocused.Focused); return; }
} }
#endif #endif
@@ -11137,7 +11145,7 @@ bool ImGui::TestKeyOwner(ImGuiKey key, ImGuiID owner_id)
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key); ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
if (owner_id == ImGuiKeyOwner_Any) if (owner_id == ImGuiKeyOwner_Any)
return (owner_data->LockThisFrame == false); return owner_data->LockThisFrame == false;
// Note: SetKeyOwner() sets OwnerCurr. It is not strictly required for most mouse routing overlap (because of ActiveId/HoveredId // Note: SetKeyOwner() sets OwnerCurr. It is not strictly required for most mouse routing overlap (because of ActiveId/HoveredId
// are acting as filter before this has a chance to filter), but sane as soon as user tries to look into things. // are acting as filter before this has a chance to filter), but sane as soon as user tries to look into things.
@@ -13378,7 +13386,7 @@ bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags)
if (flags & ImGuiFocusedFlags_ChildWindows) if (flags & ImGuiFocusedFlags_ChildWindows)
return IsWindowChildOf(ref_window, cur_window, popup_hierarchy, dock_hierarchy); return IsWindowChildOf(ref_window, cur_window, popup_hierarchy, dock_hierarchy);
else else
return (ref_window == cur_window); return ref_window == cur_window;
} }
static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) static int ImGui::FindWindowFocusIndex(ImGuiWindow* window)

View File

@@ -30,7 +30,7 @@
// Library Version // Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.92.6 WIP" #define IMGUI_VERSION "1.92.6 WIP"
#define IMGUI_VERSION_NUM 19251 #define IMGUI_VERSION_NUM 19252
#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000
#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
#define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch. #define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch.
@@ -905,7 +905,7 @@ namespace ImGui
// - 5. Call EndTable() // - 5. Call EndTable()
IMGUI_API bool BeginTable(const char* str_id, int columns, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f); IMGUI_API bool BeginTable(const char* str_id, int columns, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f);
IMGUI_API void EndTable(); // only call EndTable() if BeginTable() returns true! 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. IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); // append into the first cell of a new row. 'min_row_height' include the minimum top and bottom padding aka CellPadding.y * 2.0f.
IMGUI_API bool TableNextColumn(); // append into the next column (or first column of next row if currently in last column). Return true when column is visible. IMGUI_API bool TableNextColumn(); // append into the next column (or first column of next row if currently in last column). Return true when column is visible.
IMGUI_API bool TableSetColumnIndex(int column_n); // append into the specified column. Return true when column is visible. IMGUI_API bool TableSetColumnIndex(int column_n); // append into the specified column. Return true when column is visible.

View File

@@ -2616,7 +2616,7 @@ struct ExampleDualListBox
{ {
const int* a = (const int*)lhs; const int* a = (const int*)lhs;
const int* b = (const int*)rhs; const int* b = (const int*)rhs;
return (*a - *b); return *a - *b;
} }
void SortItems(int n) void SortItems(int n)
{ {
@@ -2949,7 +2949,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d
const int ITEMS_COUNT = 10000; const int ITEMS_COUNT = 10000;
ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT); ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
if (ImGui::BeginTable("##Basket", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter)) if (ImGui::BeginTable("##Basket", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter, ImVec2(0.0f, ImGui::GetFontSize() * 20)))
{ {
ImGui::TableSetupColumn("Object"); ImGui::TableSetupColumn("Object");
ImGui::TableSetupColumn("Action"); ImGui::TableSetupColumn("Action");
@@ -2970,6 +2970,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d
{ {
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::PushID(n);
char label[64]; char label[64];
sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]); sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
bool item_is_selected = selection.Contains((ImGuiID)n); bool item_is_selected = selection.Contains((ImGuiID)n);
@@ -2977,6 +2978,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d
ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap); ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap);
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::SmallButton("hello"); ImGui::SmallButton("hello");
ImGui::PopID();
} }
} }
@@ -4170,6 +4172,7 @@ static void DemoWindowWidgetsTreeNodes()
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only."); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only.");
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap);
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)"); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)");
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_FramePadding", &base_flags, ImGuiTreeNodeFlags_FramePadding);
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsToParent", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsToParent); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsToParent", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsToParent);
HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags"); HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags");
@@ -4834,7 +4837,7 @@ static void DemoWindowLayout()
// Tree // Tree
// (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags_DrawLinesNone to disable hierarchy outline) // (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags_DrawLinesNone to disable hierarchy outline)
const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
ImGui::Button("Button##1"); ImGui::Button("Button##1"); // Will make line higher
ImGui::SameLine(0.0f, spacing); ImGui::SameLine(0.0f, spacing);
if (ImGui::TreeNodeEx("Node##1", ImGuiTreeNodeFlags_DrawLinesNone)) if (ImGui::TreeNodeEx("Node##1", ImGuiTreeNodeFlags_DrawLinesNone))
{ {
@@ -4844,14 +4847,22 @@ static void DemoWindowLayout()
ImGui::TreePop(); ImGui::TreePop();
} }
const float padding = (float)(int)(ImGui::GetFontSize() * 1.20f); // Large padding
ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, padding);
ImGui::Button("Button##2");
ImGui::PopStyleVar();
ImGui::SameLine(0.0f, spacing);
if (ImGui::TreeNodeEx("Node##2", ImGuiTreeNodeFlags_DrawLinesNone))
ImGui::TreePop();
// Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget.
// Otherwise you can use SmallButton() (smaller fit). // Otherwise you can use SmallButton() (smaller fit).
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
// Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add
// other contents below the node. // other contents "inside" the node.
bool node_open = ImGui::TreeNode("Node##2"); bool node_open = ImGui::TreeNode("Node##3");
ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2"); ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##3");
if (node_open) if (node_open)
{ {
// Placeholder tree data // Placeholder tree data
@@ -4861,13 +4872,13 @@ static void DemoWindowLayout()
} }
// Bullet // Bullet
ImGui::Button("Button##3"); ImGui::Button("Button##4");
ImGui::SameLine(0.0f, spacing); ImGui::SameLine(0.0f, spacing);
ImGui::BulletText("Bullet text"); ImGui::BulletText("Bullet text");
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
ImGui::BulletText("Node"); ImGui::BulletText("Node");
ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4"); ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##5");
ImGui::Unindent(); ImGui::Unindent();
} }
@@ -5631,7 +5642,7 @@ struct MyItem
// qsort() is instable so always return a way to differentiate items. // qsort() is instable so always return a way to differentiate items.
// Your own compare function may want to avoid fallback on implicit sort specs. // Your own compare function may want to avoid fallback on implicit sort specs.
// e.g. a Name compare if it wasn't already part of the sort specs. // e.g. a Name compare if it wasn't already part of the sort specs.
return (a->ID - b->ID); return a->ID - b->ID;
} }
}; };
const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL; const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL;
@@ -6595,7 +6606,7 @@ static void DemoWindowTables()
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("A0 Row 0"); ImGui::Text("A0 Row 0");
{ {
float rows_height = TEXT_BASE_HEIGHT * 2; float rows_height = (TEXT_BASE_HEIGHT * 2.0f) + (ImGui::GetStyle().CellPadding.y * 2.0f);
if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) if (ImGui::BeginTable("table_nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
{ {
ImGui::TableSetupColumn("B0"); ImGui::TableSetupColumn("B0");
@@ -6637,7 +6648,7 @@ static void DemoWindowTables()
{ {
for (int row = 0; row < 8; row++) for (int row = 0; row < 8; row++)
{ {
float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row); float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row + ImGui::GetStyle().CellPadding.y * 2.0f);
ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height); ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height);
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("min_row_height = %.2f", min_row_height); ImGui::Text("min_row_height = %.2f", min_row_height);
@@ -6741,9 +6752,10 @@ static void DemoWindowTables()
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f))) if (ImGui::BeginTable("table3", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
{ {
const float rows_height = TEXT_BASE_HEIGHT * 1.5f + ImGui::GetStyle().CellPadding.y * 2.0f;
for (int row = 0; row < 3; row++) for (int row = 0; row < 3; row++)
{ {
ImGui::TableNextRow(0, TEXT_BASE_HEIGHT * 1.5f); ImGui::TableNextRow(0, rows_height);
for (int column = 0; column < 3; column++) for (int column = 0; column < 3; column++)
{ {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
@@ -10828,7 +10840,7 @@ struct ExampleAsset
if (delta < 0) if (delta < 0)
return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1; return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
} }
return ((int)a->ID - (int)b->ID); return (int)a->ID - (int)b->ID;
} }
}; };
const ImGuiTableSortSpecs* ExampleAsset::s_current_sort_specs = NULL; const ImGuiTableSortSpecs* ExampleAsset::s_current_sort_specs = NULL;

View File

@@ -2770,6 +2770,8 @@ struct ImGuiContext
// [SECTION] ImGuiWindowTempData, ImGuiWindow // [SECTION] ImGuiWindowTempData, ImGuiWindow
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#define IMGUI_WINDOW_HARD_MIN_SIZE 4.0f
// Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow. // Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow.
// (That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered..) // (That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered..)
// (This doesn't need a constructor because we zero-clear it as part of ImGuiWindow and all frame-temporary data are setup on Begin) // (This doesn't need a constructor because we zero-clear it as part of ImGuiWindow and all frame-temporary data are setup on Begin)
@@ -3425,6 +3427,12 @@ namespace ImGui
IMGUI_API void Initialize(); IMGUI_API void Initialize();
IMGUI_API void Shutdown(); // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext(). IMGUI_API void Shutdown(); // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext().
// Context name & generic context hooks
IMGUI_API void SetContextName(ImGuiContext* ctx, const char* name);
IMGUI_API ImGuiID AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook);
IMGUI_API void RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_to_remove);
IMGUI_API void CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType type);
// NewFrame // NewFrame
IMGUI_API void UpdateInputEvents(bool trickle_fast_inputs); IMGUI_API void UpdateInputEvents(bool trickle_fast_inputs);
IMGUI_API void UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos); IMGUI_API void UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos);
@@ -3435,11 +3443,6 @@ namespace ImGui
IMGUI_API void UpdateMouseMovingWindowNewFrame(); IMGUI_API void UpdateMouseMovingWindowNewFrame();
IMGUI_API void UpdateMouseMovingWindowEndFrame(); IMGUI_API void UpdateMouseMovingWindowEndFrame();
// Generic context hooks
IMGUI_API ImGuiID AddContextHook(ImGuiContext* context, const ImGuiContextHook* hook);
IMGUI_API void RemoveContextHook(ImGuiContext* context, ImGuiID hook_to_remove);
IMGUI_API void CallContextHooks(ImGuiContext* context, ImGuiContextHookType type);
// Viewports // Viewports
IMGUI_API void TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos, const ImVec2& old_size, const ImVec2& new_size); IMGUI_API void TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos, const ImVec2& old_size, const ImVec2& new_size);
IMGUI_API void ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale); IMGUI_API void ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale);
@@ -3947,7 +3950,7 @@ namespace ImGui
IMGUI_API void InputTextDeactivateHook(ImGuiID id); IMGUI_API void InputTextDeactivateHook(ImGuiID id);
IMGUI_API bool TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags); IMGUI_API bool TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags);
IMGUI_API bool TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL); IMGUI_API bool TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL);
inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); } inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return g.ActiveId == id && g.TempInputId == id; }
inline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active inline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active
IMGUI_API void SetNextItemRefVal(ImGuiDataType data_type, void* p_data); IMGUI_API void SetNextItemRefVal(ImGuiDataType data_type, void* p_data);
inline bool IsItemActiveAsInputText() { ImGuiContext& g = *GImGui; return g.ActiveId != 0 && g.ActiveId == g.LastItemData.ID && g.InputTextState.ID == g.LastItemData.ID; } // This may be useful to apply workaround that a based on distinguish whenever an item is active as a text input field. inline bool IsItemActiveAsInputText() { ImGuiContext& g = *GImGui; return g.ActiveId != 0 && g.ActiveId == g.LastItemData.ID && g.InputTextState.ID == g.LastItemData.ID; } // This may be useful to apply workaround that a based on distinguish whenever an item is active as a text input field.

View File

@@ -335,7 +335,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// - always performing the GetOrAddByKey() O(log N) query in g.Tables.Map[]. // - always performing the GetOrAddByKey() O(log N) query in g.Tables.Map[].
const bool use_child_window = (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) != 0; const bool use_child_window = (flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) != 0;
const ImVec2 avail_size = GetContentRegionAvail(); const ImVec2 avail_size = GetContentRegionAvail();
const ImVec2 actual_outer_size = ImTrunc(CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f)); const ImVec2 actual_outer_size = ImTrunc(CalcItemSize(outer_size, ImMax(avail_size.x, IMGUI_WINDOW_HARD_MIN_SIZE), use_child_window ? ImMax(avail_size.y, IMGUI_WINDOW_HARD_MIN_SIZE) : 0.0f));
const ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size); const ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size);
const bool outer_window_is_measuring_size = (outer_window->AutoFitFramesX > 0) || (outer_window->AutoFitFramesY > 0); // Doesn't apply to AlwaysAutoResize windows! const bool outer_window_is_measuring_size = (outer_window->AutoFitFramesX > 0) || (outer_window->AutoFitFramesY > 0); // Doesn't apply to AlwaysAutoResize windows!
if (use_child_window && IsClippedEx(outer_rect, 0) && !outer_window_is_measuring_size) if (use_child_window && IsClippedEx(outer_rect, 0) && !outer_window_is_measuring_size)
@@ -1383,7 +1383,7 @@ void ImGui::EndTable()
inner_window->DC.PrevLineSize = temp_data->HostBackupPrevLineSize; inner_window->DC.PrevLineSize = temp_data->HostBackupPrevLineSize;
inner_window->DC.CurrLineSize = temp_data->HostBackupCurrLineSize; inner_window->DC.CurrLineSize = temp_data->HostBackupCurrLineSize;
inner_window->DC.CursorMaxPos = temp_data->HostBackupCursorMaxPos; inner_window->DC.CursorMaxPos = temp_data->HostBackupCursorMaxPos;
const float inner_content_max_y = table->RowPosY2; const float inner_content_max_y = ImCeil(table->RowPosY2); // Rounding final position is important as we currently don't round row height ('Demo->Tables->Outer Size' demo uses non-integer heights)
IM_ASSERT(table->RowPosY2 == inner_window->DC.CursorPos.y); IM_ASSERT(table->RowPosY2 == inner_window->DC.CursorPos.y);
if (inner_window != outer_window) if (inner_window != outer_window)
inner_window->DC.CursorMaxPos.y = inner_content_max_y; inner_window->DC.CursorMaxPos.y = inner_content_max_y;
@@ -2458,6 +2458,11 @@ void ImGui::TableUpdateColumnsWeightFromWidth(ImGuiTable* table)
// - TableDrawBorders() [Internal] // - TableDrawBorders() [Internal]
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// FIXME: This could be abstracted and merged with PushColumnsBackground(), by creating a generic struct
// with storage for backup cliprect + backup channel + storage for splitter pointer, new clip rect.
// This would slightly simplify caller code.
// Bg2 is used by Selectable (and possibly other widgets) to render to the background. // Bg2 is used by Selectable (and possibly other widgets) to render to the background.
// Unlike our Bg0/1 channel which we uses for RowBg/CellBg/Borders and where we guarantee all shapes to be CPU-clipped, the Bg2 channel being widgets-facing will rely on regular ClipRect. // Unlike our Bg0/1 channel which we uses for RowBg/CellBg/Borders and where we guarantee all shapes to be CPU-clipped, the Bg2 channel being widgets-facing will rely on regular ClipRect.
void ImGui::TablePushBackgroundChannel() void ImGui::TablePushBackgroundChannel()

View File

@@ -1840,7 +1840,7 @@ static int IMGUI_CDECL ShrinkWidthItemComparer(const void* lhs, const void* rhs)
const ImGuiShrinkWidthItem* b = (const ImGuiShrinkWidthItem*)rhs; const ImGuiShrinkWidthItem* b = (const ImGuiShrinkWidthItem*)rhs;
if (int d = (int)(b->Width - a->Width)) if (int d = (int)(b->Width - a->Width))
return d; return d;
return (b->Index - a->Index); return b->Index - a->Index;
} }
// Shrink excess width from a set of item, by removing width from the larger items first. // Shrink excess width from a set of item, by removing width from the larger items first.
@@ -6782,7 +6782,6 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags, float x1)
window->DC.TreeRecordsClippedNodesY2Mask |= (1 << window->DC.TreeDepth); window->DC.TreeRecordsClippedNodesY2Mask |= (1 << window->DC.TreeDepth);
} }
// When using public API, currently 'id == storage_id' is always true, but we separate the values to facilitate advanced user code doing storage queries outside of UI loop.
bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end) bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
@@ -6791,26 +6790,28 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
// When not framed, we vertically increase height up to typical framed widget height
const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0; const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0;
const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, ImMin(window->DC.CurrLineTextBaseOffset, style.FramePadding.y)); const bool use_frame_padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding));
const ImVec2 padding = use_frame_padding ? style.FramePadding : ImVec2(style.FramePadding.x, ImMin(window->DC.CurrLineTextBaseOffset, style.FramePadding.y));
if (!label_end) if (!label_end)
label_end = FindRenderedTextEnd(label); label_end = FindRenderedTextEnd(label);
const ImVec2 label_size = CalcTextSize(label, label_end, false); const ImVec2 label_size = CalcTextSize(label, label_end, false);
const float text_offset_x = g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2); // Collapsing arrow width + Spacing const float text_offset_x = g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2); // Collapsing arrow width + Spacing
const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it const float text_offset_y = use_frame_padding ? ImMax(style.FramePadding.y, window->DC.CurrLineTextBaseOffset) : window->DC.CurrLineTextBaseOffset; // Latch before ItemSize changes it
const float text_width = g.FontSize + label_size.x + padding.x * 2; // Include collapsing arrow const float text_width = g.FontSize + label_size.x + padding.x * 2; // Include collapsing arrow
// We vertically grow up to current line height up the typical widget height. const float frame_height = label_size.y + padding.y * 2;
const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2);
const bool span_all_columns = (flags & ImGuiTreeNodeFlags_SpanAllColumns) != 0 && (g.CurrentTable != NULL); const bool span_all_columns = (flags & ImGuiTreeNodeFlags_SpanAllColumns) != 0 && (g.CurrentTable != NULL);
const bool span_all_columns_label = (flags & ImGuiTreeNodeFlags_LabelSpanAllColumns) != 0 && (g.CurrentTable != NULL); const bool span_all_columns_label = (flags & ImGuiTreeNodeFlags_LabelSpanAllColumns) != 0 && (g.CurrentTable != NULL);
ImRect frame_bb; ImRect frame_bb;
frame_bb.Min.x = span_all_columns ? window->ParentWorkRect.Min.x : (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x; frame_bb.Min.x = span_all_columns ? window->ParentWorkRect.Min.x : (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x;
frame_bb.Min.y = window->DC.CursorPos.y; frame_bb.Min.y = window->DC.CursorPos.y + (text_offset_y - padding.y);
frame_bb.Max.x = span_all_columns ? window->ParentWorkRect.Max.x : (flags & ImGuiTreeNodeFlags_SpanLabelWidth) ? window->DC.CursorPos.x + text_width + padding.x : window->WorkRect.Max.x; frame_bb.Max.x = span_all_columns ? window->ParentWorkRect.Max.x : (flags & ImGuiTreeNodeFlags_SpanLabelWidth) ? window->DC.CursorPos.x + text_width + padding.x : window->WorkRect.Max.x;
frame_bb.Max.y = window->DC.CursorPos.y + frame_height; frame_bb.Max.y = window->DC.CursorPos.y + (text_offset_y - padding.y) + frame_height;
if (display_frame) if (display_frame)
{ {
const float outer_extend = IM_TRUNC(window->WindowPadding.x * 0.5f); // Framed header expand a little outside of current limits const float outer_extend = IM_TRUNC(window->WindowPadding.x * 0.5f); // Framed header expand a little outside of current limits
@@ -9203,7 +9204,8 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
// The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu, // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu,
// However the final position is going to be different! It is chosen by FindBestWindowPosForPopup(). // However the final position is going to be different! It is chosen by FindBestWindowPosForPopup().
// e.g. Menus tend to overlap each other horizontally to amplify relative Z-ordering. // e.g. Menus tend to overlap each other horizontally to amplify relative Z-ordering.
ImVec2 popup_pos, pos = window->DC.CursorPos; ImVec2 popup_pos;
ImVec2 pos = window->DC.CursorPos;
PushID(label); PushID(label);
if (!enabled) if (!enabled)
BeginDisabled(); BeginDisabled();
@@ -9217,34 +9219,34 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
// Menu inside a horizontal menu bar // Menu inside a horizontal menu bar
// Selectable extend their highlight by half ItemSpacing in each direction. // Selectable extend their highlight by half ItemSpacing in each direction.
// For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin()
popup_pos = ImVec2(pos.x - 1.0f - IM_TRUNC(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight);
window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f); window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f);
PushStyleVarX(ImGuiStyleVar_ItemSpacing, style.ItemSpacing.x * 2.0f); PushStyleVarX(ImGuiStyleVar_ItemSpacing, style.ItemSpacing.x * 2.0f);
float w = label_size.x; float w = label_size.x;
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, pos.y + window->DC.CurrLineTextBaseOffset);
pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, label_size.y)); pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, label_size.y));
LogSetNextTextDecoration("[", "]"); LogSetNextTextDecoration("[", "]");
RenderText(text_pos, label); RenderText(text_pos, label);
PopStyleVar(); PopStyleVar();
window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
popup_pos = ImVec2(pos.x - 1.0f - IM_TRUNC(style.ItemSpacing.x * 0.5f), text_pos.y - style.FramePadding.y + window->MenuBarHeight);
} }
else else
{ {
// Menu inside a regular/vertical menu // Menu inside a regular/vertical menu
// (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f. // (In a typical menu window where all items are BeginMenu() or MenuItem() calls, extra_w will always be 0.0f.
// Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.) // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.)
popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);
float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f;
float checkmark_w = IM_TRUNC(g.FontSize * 1.20f); float checkmark_w = IM_TRUNC(g.FontSize * 1.20f);
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame
float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); ImVec2 text_pos(window->DC.CursorPos.x, pos.y + window->DC.CurrLineTextBaseOffset);
pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));
LogSetNextTextDecoration("", ">"); LogSetNextTextDecoration("", ">");
RenderText(text_pos, label); RenderText(ImVec2(text_pos.x + offsets->OffsetLabel, text_pos.y), label);
if (icon_w > 0.0f) if (icon_w > 0.0f)
RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); RenderText(ImVec2(text_pos.x + offsets->OffsetIcon, text_pos.y), icon);
RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w + g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right); RenderArrow(window->DrawList, ImVec2(text_pos.x + offsets->OffsetMark + extra_w + g.FontSize * 0.30f, text_pos.y), GetColorU32(ImGuiCol_Text), ImGuiDir_Right);
popup_pos = ImVec2(pos.x, text_pos.y - style.WindowPadding.y);
} }
if (!enabled) if (!enabled)
EndDisabled(); EndDisabled();
@@ -9445,21 +9447,22 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
float checkmark_w = IM_TRUNC(g.FontSize * 1.20f); float checkmark_w = IM_TRUNC(g.FontSize * 1.20f);
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame
float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
ImVec2 text_pos(pos.x, pos.y + window->DC.CurrLineTextBaseOffset);
pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));
if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)
{ {
RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label); RenderText(text_pos + ImVec2(offsets->OffsetLabel, 0.0f), label);
if (icon_w > 0.0f) if (icon_w > 0.0f)
RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); RenderText(text_pos + ImVec2(offsets->OffsetIcon, 0.0f), icon);
if (shortcut_w > 0.0f) if (shortcut_w > 0.0f)
{ {
PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]);
LogSetNextTextDecoration("(", ")"); LogSetNextTextDecoration("(", ")");
RenderText(pos + ImVec2(offsets->OffsetShortcut + stretch_w, 0.0f), shortcut, NULL, false); RenderText(text_pos + ImVec2(offsets->OffsetShortcut + stretch_w, 0.0f), shortcut, NULL, false);
PopStyleColor(); PopStyleColor();
} }
if (selected) if (selected)
RenderCheckMark(window->DrawList, pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f); RenderCheckMark(window->DrawList, text_pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f);
} }
} }
IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0)); IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0));