Merge branch 'master' into docking

# Conflicts:
#	backends/imgui_impl_glfw.cpp
#	imgui.h
This commit is contained in:
ocornut
2026-03-31 21:48:34 +02:00
18 changed files with 450 additions and 166 deletions
+4
View File
@@ -32,6 +32,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)
// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2026-03-25: Mouse cursor is properly restored if changed by user app/code while using glfwSetInputMode(..., GLFW_CURSOR_DISABLED) or ImGuiConfigFlags_NoMouseCursorChange. Amend change from 2025-12-10.
// 2026-02-10: Try to set IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND automatically if corresponding headers are not accessible. (#9225) // 2026-02-10: Try to set IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND automatically if corresponding headers are not accessible. (#9225)
// 2026-01-25: [Docking] Improve workarounds for cases where GLFW is unable to provide any reliable monitor info. Preserve existing monitor list when none of the new one is valid. (#9195, #7902, #5683) // 2026-01-25: [Docking] Improve workarounds for cases where GLFW is unable to provide any reliable monitor info. Preserve existing monitor list when none of the new one is valid. (#9195, #7902, #5683)
// 2026-01-18: [Docking] Dynamically load X11 functions to avoid -lx11 linking requirement introduced on 2025-09-10. // 2026-01-18: [Docking] Dynamically load X11 functions to avoid -lx11 linking requirement introduced on 2025-09-10.
@@ -993,7 +994,10 @@ static void ImGui_ImplGlfw_UpdateMouseCursor()
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
{
bd->LastMouseCursor = nullptr; // Invalidate so that if user changes underlying cursor we will update it next time we can.
return; return;
}
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+6 -9
View File
@@ -538,14 +538,12 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline
// Setup scale and translation: // Setup scale and translation:
// Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. // Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
{ {
float scale[2]; float constants[4];
scale[0] = 2.0f / draw_data->DisplaySize.x; constants[0] = 2.0f / draw_data->DisplaySize.x; // Scale
scale[1] = 2.0f / draw_data->DisplaySize.y; constants[1] = 2.0f / draw_data->DisplaySize.y;
float translate[2]; constants[2] = -1.0f - draw_data->DisplayPos.x * constants[0]; // Translate
translate[0] = -1.0f - draw_data->DisplayPos.x * scale[0]; constants[3] = -1.0f - draw_data->DisplayPos.y * constants[1];
translate[1] = -1.0f - draw_data->DisplayPos.y * scale[1]; vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 4, constants);
vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale);
vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate);
} }
} }
@@ -1842,7 +1840,6 @@ void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevic
VkCommandPoolCreateInfo pool_info = {}; VkCommandPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_info.queueFamilyIndex = queue_family; pool_info.queueFamilyIndex = queue_family;
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
VkResult err = vkCreateCommandPool(device, &pool_info, allocator, &command_pool); VkResult err = vkCreateCommandPool(device, &pool_info, allocator, &command_pool);
check_vk_result(err); check_vk_result(err);
+89 -11
View File
@@ -22,6 +22,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)
// 2026-03-25: Added support for WGVK native backend via IMGUI_IMPL_WEBGPU_BACKEND_WGVK define, with SPIRV shaders if WGSL is not available. (#9316, #9246, #9257)
// 2026-03-09: Removed support for Emscripten < 4.0.10. (#9281) // 2026-03-09: Removed support for Emscripten < 4.0.10. (#9281)
// 2025-10-16: Update to compile with Dawn and Emscripten's 4.0.10+ '--use-port=emdawnwebgpu' ports. (#8381, #8898) // 2025-10-16: Update to compile with Dawn and Emscripten's 4.0.10+ '--use-port=emdawnwebgpu' ports. (#8381, #8898)
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
@@ -58,14 +59,14 @@
#include <stdio.h> #include <stdio.h>
// One of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be provided. See imgui_impl_wgpu.h for more details. // One of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be provided. See imgui_impl_wgpu.h for more details.
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) == defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) #if !defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
#error Exactly one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be defined! #error Exactly one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN, IMGUI_IMPL_WEBGPU_BACKEND_WGPU or IMGUI_IMPL_WEBGPU_BACKEND_WGVK must be defined!
#endif #endif
#if defined(__EMSCRIPTEN__) && defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) #if defined(__EMSCRIPTEN__) && defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
#error Emscripten <4.0.10 with '-sUSE_WEBGPU=1' is not supported anymore. #error Emscripten <4.0.10 with '-sUSE_WEBGPU=1' is not supported anymore.
#endif #endif
#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN #if defined IMGUI_IMPL_WEBGPU_BACKEND_DAWN || defined IMGUI_IMPL_WEBGPU_BACKEND_WGVK
// Dawn renamed WGPUProgrammableStageDescriptor to WGPUComputeState (see: https://github.com/webgpu-native/webgpu-headers/pull/413) // Dawn renamed WGPUProgrammableStageDescriptor to WGPUComputeState (see: https://github.com/webgpu-native/webgpu-headers/pull/413)
// Using type alias until WGPU adopts the same naming convention (#8369) // Using type alias until WGPU adopts the same naming convention (#8369)
using WGPUProgrammableStageDescriptor = WGPUComputeState; using WGPUProgrammableStageDescriptor = WGPUComputeState;
@@ -187,6 +188,60 @@ fn main(in: VertexOutput) -> @location(0) vec4<f32> {
} }
)"; )";
// Same shader as __shader_vert_wgsl[] but compiled as SPIRV.
// 'wgslc -o vert.spv vert.wgsl' + 'binary_to_compressed_c -u8 -nocompress vert.spv'
static const unsigned char __shader_vert_spirv[1996] =
{
3,2,35,7,0,3,1,0,1,0,23,0,90,0,0,0,0,0,0,0,17,0,2,0,1,0,0,0,14,0,3,0,0,0,0,0,1,0,0,0,15,0,12,0,0,0,0,0,78,0,0,0,109,97,105,110,0,0,0,0,8,0,0,0,12,0,0,0,13,0,0,0,16,0,0,0,18,0,0,0,19,
0,0,0,21,0,0,0,71,0,4,0,4,0,0,0,6,0,0,0,16,0,0,0,72,0,5,0,3,0,0,0,0,0,0,0,35,0,0,0,0,0,0,0,71,0,3,0,3,0,0,0,2,0,0,0,71,0,4,0,1,0,0,0,34,0,0,0,0,0,0,0,71,0,4,0,1,0,0,0,33,0,0,0,0,0,
0,0,71,0,3,0,1,0,0,0,24,0,0,0,71,0,4,0,8,0,0,0,30,0,0,0,0,0,0,0,71,0,4,0,12,0,0,0,30,0,0,0,1,0,0,0,71,0,4,0,13,0,0,0,30,0,0,0,2,0,0,0,71,0,4,0,16,0,0,0,11,0,0,0,0,0,0,0,71,0,4,0,18,
0,0,0,30,0,0,0,0,0,0,0,71,0,4,0,19,0,0,0,30,0,0,0,1,0,0,0,71,0,4,0,21,0,0,0,11,0,0,0,1,0,0,0,21,0,4,0,6,0,0,0,32,0,0,0,0,0,0,0,23,0,4,0,5,0,0,0,6,0,0,0,4,0,0,0,43,0,4,0,6,0,0,0,7,0,
0,0,5,0,0,0,28,0,4,0,4,0,0,0,5,0,0,0,7,0,0,0,30,0,3,0,3,0,0,0,4,0,0,0,32,0,4,0,2,0,0,0,2,0,0,0,3,0,0,0,59,0,4,0,2,0,0,0,1,0,0,0,2,0,0,0,22,0,3,0,11,0,0,0,32,0,0,0,23,0,4,0,10,0,0,0,
11,0,0,0,2,0,0,0,32,0,4,0,9,0,0,0,1,0,0,0,10,0,0,0,59,0,4,0,9,0,0,0,8,0,0,0,1,0,0,0,59,0,4,0,9,0,0,0,12,0,0,0,1,0,0,0,23,0,4,0,15,0,0,0,11,0,0,0,4,0,0,0,32,0,4,0,14,0,0,0,1,0,0,0,15,
0,0,0,59,0,4,0,14,0,0,0,13,0,0,0,1,0,0,0,32,0,4,0,17,0,0,0,3,0,0,0,15,0,0,0,59,0,4,0,17,0,0,0,16,0,0,0,3,0,0,0,59,0,4,0,17,0,0,0,18,0,0,0,3,0,0,0,32,0,4,0,20,0,0,0,3,0,0,0,10,0,0,0,
59,0,4,0,20,0,0,0,19,0,0,0,3,0,0,0,32,0,4,0,22,0,0,0,3,0,0,0,11,0,0,0,59,0,4,0,22,0,0,0,21,0,0,0,3,0,0,0,30,0,5,0,24,0,0,0,15,0,0,0,15,0,0,0,10,0,0,0,30,0,5,0,25,0,0,0,10,0,0,0,10,
0,0,0,15,0,0,0,33,0,4,0,27,0,0,0,24,0,0,0,25,0,0,0,32,0,4,0,30,0,0,0,7,0,0,0,24,0,0,0,46,0,3,0,24,0,0,0,31,0,0,0,32,0,4,0,33,0,0,0,7,0,0,0,15,0,0,0,43,0,4,0,6,0,0,0,34,0,0,0,0,0,0,
0,24,0,4,0,36,0,0,0,15,0,0,0,4,0,0,0,43,0,4,0,11,0,0,0,40,0,0,0,0,0,0,0,43,0,4,0,11,0,0,0,41,0,0,0,0,0,128,63,43,0,4,0,6,0,0,0,44,0,0,0,1,0,0,0,32,0,4,0,47,0,0,0,7,0,0,0,10,0,0,0,43,
0,4,0,6,0,0,0,48,0,0,0,2,0,0,0,33,0,4,0,52,0,0,0,36,0,0,0,6,0,0,0,43,0,4,0,6,0,0,0,55,0,0,0,16,0,0,0,32,0,4,0,57,0,0,0,2,0,0,0,5,0,0,0,43,0,4,0,6,0,0,0,66,0,0,0,32,0,0,0,43,0,4,0,6,
0,0,0,72,0,0,0,48,0,0,0,19,0,2,0,79,0,0,0,33,0,3,0,80,0,0,0,79,0,0,0,54,0,5,0,24,0,0,0,23,0,0,0,0,0,0,0,27,0,0,0,55,0,3,0,25,0,0,0,26,0,0,0,248,0,2,0,28,0,0,0,59,0,5,0,30,0,0,0,29,
0,0,0,7,0,0,0,31,0,0,0,65,0,5,0,33,0,0,0,32,0,0,0,29,0,0,0,34,0,0,0,57,0,5,0,36,0,0,0,35,0,0,0,37,0,0,0,34,0,0,0,81,0,5,0,10,0,0,0,38,0,0,0,26,0,0,0,0,0,0,0,80,0,6,0,15,0,0,0,39,0,
0,0,38,0,0,0,40,0,0,0,41,0,0,0,145,0,5,0,15,0,0,0,42,0,0,0,35,0,0,0,39,0,0,0,62,0,4,0,32,0,0,0,42,0,0,0,0,0,0,0,65,0,5,0,33,0,0,0,43,0,0,0,29,0,0,0,44,0,0,0,81,0,5,0,15,0,0,0,45,0,
0,0,26,0,0,0,2,0,0,0,62,0,4,0,43,0,0,0,45,0,0,0,0,0,0,0,65,0,5,0,47,0,0,0,46,0,0,0,29,0,0,0,48,0,0,0,81,0,5,0,10,0,0,0,49,0,0,0,26,0,0,0,1,0,0,0,62,0,4,0,46,0,0,0,49,0,0,0,0,0,0,0,
61,0,5,0,24,0,0,0,50,0,0,0,29,0,0,0,0,0,0,0,254,0,2,0,50,0,0,0,56,0,1,0,54,0,5,0,36,0,0,0,37,0,0,0,0,0,0,0,52,0,0,0,55,0,3,0,6,0,0,0,51,0,0,0,248,0,2,0,53,0,0,0,134,0,5,0,6,0,0,0,54,
0,0,0,51,0,0,0,55,0,0,0,65,0,6,0,57,0,0,0,56,0,0,0,1,0,0,0,34,0,0,0,54,0,0,0,61,0,5,0,5,0,0,0,58,0,0,0,56,0,0,0,0,0,0,0,124,0,4,0,15,0,0,0,59,0,0,0,58,0,0,0,128,0,5,0,6,0,0,0,60,0,
0,0,55,0,0,0,51,0,0,0,134,0,5,0,6,0,0,0,61,0,0,0,60,0,0,0,55,0,0,0,65,0,6,0,57,0,0,0,62,0,0,0,1,0,0,0,34,0,0,0,61,0,0,0,61,0,5,0,5,0,0,0,63,0,0,0,62,0,0,0,0,0,0,0,124,0,4,0,15,0,0,
0,64,0,0,0,63,0,0,0,128,0,5,0,6,0,0,0,65,0,0,0,66,0,0,0,51,0,0,0,134,0,5,0,6,0,0,0,67,0,0,0,65,0,0,0,55,0,0,0,65,0,6,0,57,0,0,0,68,0,0,0,1,0,0,0,34,0,0,0,67,0,0,0,61,0,5,0,5,0,0,0,
69,0,0,0,68,0,0,0,0,0,0,0,124,0,4,0,15,0,0,0,70,0,0,0,69,0,0,0,128,0,5,0,6,0,0,0,71,0,0,0,72,0,0,0,51,0,0,0,134,0,5,0,6,0,0,0,73,0,0,0,71,0,0,0,55,0,0,0,65,0,6,0,57,0,0,0,74,0,0,0,
1,0,0,0,34,0,0,0,73,0,0,0,61,0,5,0,5,0,0,0,75,0,0,0,74,0,0,0,0,0,0,0,124,0,4,0,15,0,0,0,76,0,0,0,75,0,0,0,80,0,7,0,36,0,0,0,77,0,0,0,59,0,0,0,64,0,0,0,70,0,0,0,76,0,0,0,254,0,2,0,77,
0,0,0,56,0,1,0,54,0,5,0,79,0,0,0,78,0,0,0,0,0,0,0,80,0,0,0,248,0,2,0,81,0,0,0,61,0,5,0,10,0,0,0,82,0,0,0,8,0,0,0,0,0,0,0,61,0,5,0,10,0,0,0,83,0,0,0,12,0,0,0,0,0,0,0,61,0,5,0,15,0,0,
0,84,0,0,0,13,0,0,0,0,0,0,0,80,0,6,0,25,0,0,0,85,0,0,0,82,0,0,0,83,0,0,0,84,0,0,0,57,0,5,0,24,0,0,0,86,0,0,0,23,0,0,0,85,0,0,0,81,0,5,0,15,0,0,0,87,0,0,0,86,0,0,0,0,0,0,0,62,0,4,0,
16,0,0,0,87,0,0,0,0,0,0,0,81,0,5,0,15,0,0,0,88,0,0,0,86,0,0,0,1,0,0,0,62,0,4,0,18,0,0,0,88,0,0,0,0,0,0,0,81,0,5,0,10,0,0,0,89,0,0,0,86,0,0,0,2,0,0,0,62,0,4,0,19,0,0,0,89,0,0,0,0,0,
0,0,62,0,4,0,21,0,0,0,41,0,0,0,0,0,0,0,253,0,1,0,56,0,1,0,
};
// Same shader as __shader_frag_wgsl[] but compiled as SPIRV.
// 'wgslc -o frag.spv frag.wgsl' + 'binary_to_compressed_c -u8 -nocompress frag.spv'
static const unsigned char __shader_frag_spirv[1392] =
{
3,2,35,7,0,3,1,0,1,0,23,0,60,0,0,0,0,0,0,0,17,0,2,0,1,0,0,0,11,0,6,0,48,0,0,0,71,76,83,76,46,115,116,100,46,52,53,48,0,0,0,0,14,0,3,0,0,0,0,0,1,0,0,0,15,0,9,0,4,0,0,0,51,0,0,0,109,
97,105,110,0,0,0,0,15,0,0,0,18,0,0,0,19,0,0,0,22,0,0,0,16,0,3,0,51,0,0,0,7,0,0,0,71,0,4,0,4,0,0,0,6,0,0,0,16,0,0,0,72,0,5,0,3,0,0,0,0,0,0,0,35,0,0,0,0,0,0,0,71,0,3,0,3,0,0,0,2,0,0,
0,71,0,4,0,1,0,0,0,34,0,0,0,0,0,0,0,71,0,4,0,1,0,0,0,33,0,0,0,0,0,0,0,71,0,3,0,1,0,0,0,24,0,0,0,71,0,4,0,8,0,0,0,34,0,0,0,0,0,0,0,71,0,4,0,8,0,0,0,33,0,0,0,1,0,0,0,71,0,4,0,11,0,0,
0,34,0,0,0,1,0,0,0,71,0,4,0,11,0,0,0,33,0,0,0,0,0,0,0,71,0,4,0,15,0,0,0,11,0,0,0,15,0,0,0,71,0,4,0,18,0,0,0,30,0,0,0,0,0,0,0,71,0,4,0,19,0,0,0,30,0,0,0,1,0,0,0,71,0,4,0,22,0,0,0,30,
0,0,0,0,0,0,0,21,0,4,0,6,0,0,0,32,0,0,0,0,0,0,0,23,0,4,0,5,0,0,0,6,0,0,0,4,0,0,0,43,0,4,0,6,0,0,0,7,0,0,0,5,0,0,0,28,0,4,0,4,0,0,0,5,0,0,0,7,0,0,0,30,0,3,0,3,0,0,0,4,0,0,0,32,0,4,0,
2,0,0,0,2,0,0,0,3,0,0,0,59,0,4,0,2,0,0,0,1,0,0,0,2,0,0,0,26,0,2,0,10,0,0,0,32,0,4,0,9,0,0,0,0,0,0,0,10,0,0,0,59,0,4,0,9,0,0,0,8,0,0,0,0,0,0,0,22,0,3,0,14,0,0,0,32,0,0,0,25,0,9,0,13,
0,0,0,14,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,32,0,4,0,12,0,0,0,0,0,0,0,13,0,0,0,59,0,4,0,12,0,0,0,11,0,0,0,0,0,0,0,23,0,4,0,17,0,0,0,14,0,0,0,4,0,0,0,32,0,4,0,16,
0,0,0,1,0,0,0,17,0,0,0,59,0,4,0,16,0,0,0,15,0,0,0,1,0,0,0,59,0,4,0,16,0,0,0,18,0,0,0,1,0,0,0,23,0,4,0,21,0,0,0,14,0,0,0,2,0,0,0,32,0,4,0,20,0,0,0,1,0,0,0,21,0,0,0,59,0,4,0,20,0,0,0,
19,0,0,0,1,0,0,0,32,0,4,0,23,0,0,0,3,0,0,0,17,0,0,0,59,0,4,0,23,0,0,0,22,0,0,0,3,0,0,0,30,0,5,0,25,0,0,0,17,0,0,0,17,0,0,0,21,0,0,0,33,0,4,0,27,0,0,0,17,0,0,0,25,0,0,0,27,0,3,0,34,
0,0,0,13,0,0,0,23,0,4,0,38,0,0,0,14,0,0,0,3,0,0,0,32,0,4,0,40,0,0,0,2,0,0,0,5,0,0,0,43,0,4,0,6,0,0,0,41,0,0,0,0,0,0,0,43,0,4,0,6,0,0,0,42,0,0,0,4,0,0,0,19,0,2,0,52,0,0,0,33,0,3,0,53,
0,0,0,52,0,0,0,54,0,5,0,17,0,0,0,24,0,0,0,0,0,0,0,27,0,0,0,55,0,3,0,25,0,0,0,26,0,0,0,248,0,2,0,28,0,0,0,81,0,5,0,17,0,0,0,29,0,0,0,26,0,0,0,1,0,0,0,61,0,5,0,13,0,0,0,30,0,0,0,11,0,
0,0,0,0,0,0,61,0,5,0,10,0,0,0,31,0,0,0,8,0,0,0,0,0,0,0,81,0,5,0,21,0,0,0,32,0,0,0,26,0,0,0,2,0,0,0,86,0,5,0,34,0,0,0,33,0,0,0,30,0,0,0,31,0,0,0,87,0,6,0,17,0,0,0,35,0,0,0,33,0,0,0,
32,0,0,0,0,0,0,0,133,0,5,0,17,0,0,0,36,0,0,0,29,0,0,0,35,0,0,0,79,0,8,0,38,0,0,0,37,0,0,0,36,0,0,0,36,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,65,0,6,0,40,0,0,0,39,0,0,0,1,0,0,0,41,0,0,0,42,0,
0,0,61,0,5,0,5,0,0,0,43,0,0,0,39,0,0,0,0,0,0,0,81,0,5,0,6,0,0,0,44,0,0,0,43,0,0,0,0,0,0,0,124,0,4,0,14,0,0,0,45,0,0,0,44,0,0,0,80,0,6,0,38,0,0,0,46,0,0,0,45,0,0,0,45,0,0,0,45,0,0,0,
12,0,7,0,38,0,0,0,47,0,0,0,48,0,0,0,26,0,0,0,37,0,0,0,46,0,0,0,81,0,5,0,14,0,0,0,49,0,0,0,36,0,0,0,3,0,0,0,80,0,5,0,17,0,0,0,50,0,0,0,47,0,0,0,49,0,0,0,254,0,2,0,50,0,0,0,56,0,1,0,
54,0,5,0,52,0,0,0,51,0,0,0,0,0,0,0,53,0,0,0,248,0,2,0,54,0,0,0,61,0,5,0,17,0,0,0,55,0,0,0,15,0,0,0,0,0,0,0,61,0,5,0,17,0,0,0,56,0,0,0,18,0,0,0,0,0,0,0,61,0,5,0,21,0,0,0,57,0,0,0,19,
0,0,0,0,0,0,0,80,0,6,0,25,0,0,0,58,0,0,0,55,0,0,0,56,0,0,0,57,0,0,0,57,0,5,0,17,0,0,0,59,0,0,0,24,0,0,0,58,0,0,0,62,0,4,0,22,0,0,0,59,0,0,0,0,0,0,0,253,0,1,0,56,0,1,0,
};
static void SafeRelease(ImDrawIdx*& res) static void SafeRelease(ImDrawIdx*& res)
{ {
if (res) if (res)
@@ -257,7 +312,7 @@ static void SafeRelease(FrameResources& res)
SafeRelease(res.VertexBufferHost); SafeRelease(res.VertexBufferHost);
} }
static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const char* wgsl_source) static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModuleWGSL(const char* wgsl_source)
{ {
ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData();
@@ -275,6 +330,25 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const c
return stage_desc; return stage_desc;
} }
static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModuleSPIRV(const void* spirv_binary, size_t spirv_length)
{
ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData();
WGPUShaderSourceSPIRV spirv_desc = {};
spirv_desc.chain.sType = WGPUSType_ShaderSourceSPIRV;
spirv_desc.code = (const uint32_t *)spirv_binary;
spirv_desc.codeSize = ((uint32_t)(spirv_length / 4));
WGPUShaderModuleDescriptor desc = {};
desc.nextInChain = (WGPUChainedStruct*)&spirv_desc;
WGPUProgrammableStageDescriptor stage_desc = {};
stage_desc.module = wgpuDeviceCreateShaderModule(bd->wgpuDevice, &desc);
stage_desc.entryPoint = { "main", WGPU_STRLEN };
return stage_desc;
}
static WGPUBindGroup ImGui_ImplWGPU_CreateImageBindGroup(WGPUBindGroupLayout layout, WGPUTextureView texture) static WGPUBindGroup ImGui_ImplWGPU_CreateImageBindGroup(WGPUBindGroupLayout layout, WGPUTextureView texture)
{ {
ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData();
@@ -438,8 +512,8 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
} }
int64_t vb_write_size = MEMALIGN((char*)vtx_dst - (char*)fr->VertexBufferHost, 4); int64_t vb_write_size = MEMALIGN((char*)vtx_dst - (char*)fr->VertexBufferHost, 4);
int64_t ib_write_size = MEMALIGN((char*)idx_dst - (char*)fr->IndexBufferHost, 4); int64_t ib_write_size = MEMALIGN((char*)idx_dst - (char*)fr->IndexBufferHost, 4);
wgpuQueueWriteBuffer(bd->defaultQueue, fr->VertexBuffer, 0, fr->VertexBufferHost, vb_write_size); wgpuQueueWriteBuffer(bd->defaultQueue, fr->VertexBuffer, 0, fr->VertexBufferHost, (size_t)vb_write_size);
wgpuQueueWriteBuffer(bd->defaultQueue, fr->IndexBuffer, 0, fr->IndexBufferHost, ib_write_size); wgpuQueueWriteBuffer(bd->defaultQueue, fr->IndexBuffer, 0, fr->IndexBufferHost, (size_t)ib_write_size);
// Setup desired render state // Setup desired render state
ImGui_ImplWGPU_SetupRenderState(draw_data, pass_encoder, fr); ImGui_ImplWGPU_SetupRenderState(draw_data, pass_encoder, fr);
@@ -667,14 +741,15 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
graphics_pipeline_desc.layout = wgpuDeviceCreatePipelineLayout(bd->wgpuDevice, &layout_desc); graphics_pipeline_desc.layout = wgpuDeviceCreatePipelineLayout(bd->wgpuDevice, &layout_desc);
// Create the vertex shader // Create the vertex shader
WGPUProgrammableStageDescriptor vertex_shader_desc = ImGui_ImplWGPU_CreateShaderModule(__shader_vert_wgsl); WGPUProgrammableStageDescriptor vertex_shader_desc = ImGui_ImplWGPU_CreateShaderModuleWGSL(__shader_vert_wgsl);
if (!vertex_shader_desc.module) vertex_shader_desc = ImGui_ImplWGPU_CreateShaderModuleSPIRV(__shader_vert_spirv, sizeof(__shader_vert_spirv));
graphics_pipeline_desc.vertex.module = vertex_shader_desc.module; graphics_pipeline_desc.vertex.module = vertex_shader_desc.module;
graphics_pipeline_desc.vertex.entryPoint = vertex_shader_desc.entryPoint; graphics_pipeline_desc.vertex.entryPoint = vertex_shader_desc.entryPoint;
// Vertex input configuration // Vertex input configuration
WGPUVertexAttribute attribute_desc[] = WGPUVertexAttribute attribute_desc[] =
{ {
#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN #if defined IMGUI_IMPL_WEBGPU_BACKEND_DAWN || defined IMGUI_IMPL_WEBGPU_BACKEND_WGVK
{ nullptr, WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, pos), 0 }, { nullptr, WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, pos), 0 },
{ nullptr, WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, uv), 1 }, { nullptr, WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, uv), 1 },
{ nullptr, WGPUVertexFormat_Unorm8x4, (uint64_t)offsetof(ImDrawVert, col), 2 }, { nullptr, WGPUVertexFormat_Unorm8x4, (uint64_t)offsetof(ImDrawVert, col), 2 },
@@ -695,7 +770,8 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
graphics_pipeline_desc.vertex.buffers = buffer_layouts; graphics_pipeline_desc.vertex.buffers = buffer_layouts;
// Create the pixel shader // Create the pixel shader
WGPUProgrammableStageDescriptor pixel_shader_desc = ImGui_ImplWGPU_CreateShaderModule(__shader_frag_wgsl); WGPUProgrammableStageDescriptor pixel_shader_desc = ImGui_ImplWGPU_CreateShaderModuleWGSL(__shader_frag_wgsl);
if (!pixel_shader_desc.module) pixel_shader_desc = ImGui_ImplWGPU_CreateShaderModuleSPIRV(__shader_frag_spirv, sizeof(__shader_frag_spirv));
// Create the blending setup // Create the blending setup
WGPUBlendState blend_state = {}; WGPUBlendState blend_state = {};
@@ -808,6 +884,8 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info)
#endif #endif
#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
io.BackendRendererName = "imgui_impl_wgpu (WGPU, Native)"; io.BackendRendererName = "imgui_impl_wgpu (WGPU, Native)";
#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
io.BackendRendererName = "imgui_impl_wgpu (WGVK, Native)";
#endif #endif
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
@@ -879,7 +957,7 @@ void ImGui_ImplWGPU_NewFrame()
bool ImGui_ImplWGPU_IsSurfaceStatusError(WGPUSurfaceGetCurrentTextureStatus status) bool ImGui_ImplWGPU_IsSurfaceStatusError(WGPUSurfaceGetCurrentTextureStatus status)
{ {
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
return (status == WGPUSurfaceGetCurrentTextureStatus_Error); return (status == WGPUSurfaceGetCurrentTextureStatus_Error);
#else #else
return (status == WGPUSurfaceGetCurrentTextureStatus_OutOfMemory || status == WGPUSurfaceGetCurrentTextureStatus_DeviceLost); return (status == WGPUSurfaceGetCurrentTextureStatus_OutOfMemory || status == WGPUSurfaceGetCurrentTextureStatus_DeviceLost);
@@ -896,7 +974,7 @@ bool ImGui_ImplWGPU_IsSurfaceStatusSubOptimal(WGPUSurfaceGetCurrentTextureStatus
} }
// Helpers to obtain a string // Helpers to obtain a string
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
const char* ImGui_ImplWGPU_GetErrorTypeName(WGPUErrorType type) const char* ImGui_ImplWGPU_GetErrorTypeName(WGPUErrorType type)
{ {
switch (type) switch (type)
+2 -1
View File
@@ -3,7 +3,7 @@
// (Please note that WebGPU is a recent API, may not be supported by all browser, and its ecosystem is generally a mess) // (Please note that WebGPU is a recent API, may not be supported by all browser, and its ecosystem is generally a mess)
// When targeting native platforms: // When targeting native platforms:
// - One of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU *must* be provided. // - One of IMGUI_IMPL_WEBGPU_BACKEND_DAWN, IMGUI_IMPL_WEBGPU_BACKEND_WGPU or IMGUI_IMPL_WEBGPU_BACKEND_WGVK *must* be provided.
// When targeting Emscripten: // When targeting Emscripten:
// - We now defaults to IMGUI_IMPL_WEBGPU_BACKEND_DAWN and requires Emscripten 4.0.10+, which correspond to using Emscripten '--use-port=emdawnwebgpu'. // - We now defaults to IMGUI_IMPL_WEBGPU_BACKEND_DAWN and requires Emscripten 4.0.10+, which correspond to using Emscripten '--use-port=emdawnwebgpu'.
// - Emscripten < 4.0.10 is not supported anymore (old '-sUSE_WEBGPU=1' option). // - Emscripten < 4.0.10 is not supported anymore (old '-sUSE_WEBGPU=1' option).
@@ -12,6 +12,7 @@
// This requirement may be removed once WebGPU stabilizes and backends converge on a unified interface. // This requirement may be removed once WebGPU stabilizes and backends converge on a unified interface.
//#define IMGUI_IMPL_WEBGPU_BACKEND_DAWN //#define IMGUI_IMPL_WEBGPU_BACKEND_DAWN
//#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU //#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU
//#define IMGUI_IMPL_WEBGPU_BACKEND_WGVK
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID/ImTextureRef!
+20 -1
View File
@@ -120,6 +120,8 @@ Other Changes:
- Clear `DisplayStart`/`DisplayEnd` fields when `Step()` returns false. - Clear `DisplayStart`/`DisplayEnd` fields when `Step()` returns false.
- Added `UserIndex` helper storage. This is solely a convenience for cases where - Added `UserIndex` helper storage. This is solely a convenience for cases where
you may want to carry an index around. you may want to carry an index around.
- Always pulls current context on `ImGuiListClipper::Begin()`, consistent with public
API design, and avoids issues with clipper instances outliving contexts. (#9324, #5856)
- Scrollbar: - Scrollbar:
- Implemented a custom tweak to extend hit-testing bounding box when window is sitting - Implemented a custom tweak to extend hit-testing bounding box when window is sitting
at the edge of a viewport (e.g. fullscreen or docked window), so that e.g. mouse the at the edge of a viewport (e.g. fullscreen or docked window), so that e.g. mouse the
@@ -130,6 +132,9 @@ Other Changes:
as a convenience for when using e.g. InvisibleButton(). as a convenience for when using e.g. InvisibleButton().
- Focus: fixed fallback "Debug" window temporarily taking focus and setting io.WantCaptureKeyboard - Focus: fixed fallback "Debug" window temporarily taking focus and setting io.WantCaptureKeyboard
for one frame on e.g. application boot if no other windows are submitted. (#9243) for one frame on e.g. application boot if no other windows are submitted. (#9243)
- DrawList:
- PathArcTo(): fixed erroneous segment count for pathologically small arcs on large
circles. (#9331, #9313) [@thedmd, @epajarre]
- Memory: - Memory:
- Discard/GC of ImDrawList buffers for unused windows favor restoring them to - Discard/GC of ImDrawList buffers for unused windows favor restoring them to
~Size*1.05 instead of Capacity when awakening again. Facilitate releasing ImDrawList ~Size*1.05 instead of Capacity when awakening again. Facilitate releasing ImDrawList
@@ -137,13 +142,26 @@ Other Changes:
- Fixed GetForegroundDrawList()/GetBackgroundDrawList() per-viewport buffers not being - Fixed GetForegroundDrawList()/GetBackgroundDrawList() per-viewport buffers not being
collected when unused for io.ConfigMemoryCompactTimer amount of time. (#9303) collected when unused for io.ConfigMemoryCompactTimer amount of time. (#9303)
- Demo: fixed IMGUI_DEMO_MARKER locations for examples applets. (#9261, #3689) [@pthom] - Demo: fixed IMGUI_DEMO_MARKER locations for examples applets. (#9261, #3689) [@pthom]
- Misc: added missing ImVec2/ImVec4 operators. (#9339, #8258) [@dkosmari, @ArashPartow]
- Internals:
- ButtonBehavior: fixed internal/low-level ImGuiButtonFlags_PressedOnRelease
(as well as equivalent ImGuiSelectableFlags_SelectOnRelease for Selectable) from
not taking current active id. ImGuiButtonFlags_NoHoldingActiveID allows that.
This was pretty sure only used internally by MenuItem().
- Backends: - Backends:
- DirectX9, OpenGL2, OpenGL3, Metal, SDLGPU3, SDLRenderer2, SDLRenderer3: fixed easy-to-fix - DirectX9, OpenGL2, OpenGL3, Metal, SDLGPU3, SDLRenderer2, SDLRenderer3: fixed easy-to-fix
issues in code assuming ImTextureID_Invalid is always defined to 0. (#9295, #9310) issues in code assuming ImTextureID_Invalid is always defined to 0. (#9295, #9310)
- GLFW: mouse cursor is properly restored if changed by user app/code while using
glfwSetInputMode(..., GLFW_CURSOR_DISABLED) or ImGuiConfigFlags_NoMouseCursorChange.
Amend optimization done in 1.92.6.
- SDLGPU3: removed unnecessary call to SDL_WaitForGPUIdle when releasing - SDLGPU3: removed unnecessary call to SDL_WaitForGPUIdle when releasing
vertex/index buffers. (#9262) [@jaenis] vertex/index buffers. (#9262) [@jaenis]
- WebGPU: fixed version check for Emscripten 5.0.0+. - WebGPU: fixed version check for Emscripten 5.0.0+.
- WebGPU: removed support for Emscripten <4.0.10. (#9281) [@ypujante] - WebGPU: removed support for Emscripten <4.0.10. (#9281) [@ypujante]
- WebGPU: added support for WGVK native backend via IMGUI_IMPL_WEBGPU_BACKEND_WGVK,
using SPIRV shaders if WGSL is not available. (#9316, #9246, #9257) [@r-lyeh]
(WGVK is a lightweight alternative to Dawn or WGPU for native applications,
which is easier to build/setup, see: https://github.com/manuel5975p/WGVK)
- Examples: - Examples:
- Emscripten: added `tabindex=-1` to canvas in our shell_minimal.htm. Without it, - Emscripten: added `tabindex=-1` to canvas in our shell_minimal.htm. Without it,
the canvas was not focusable in the DOM, which in turn make some backends the canvas was not focusable in the DOM, which in turn make some backends
@@ -158,7 +176,8 @@ Other Changes:
- WebGPU: fixed undefined behaviors in example code for requesting adapter - WebGPU: fixed undefined behaviors in example code for requesting adapter
and device. (#9246, #9256) [@r-lyeh] and device. (#9246, #9256) [@r-lyeh]
- SDL2+WebGPU: fixed hi-dpi handling. (#9300) [@ypujante] - SDL2+WebGPU: fixed hi-dpi handling. (#9300) [@ypujante]
- GLFW/SDL2/SDL3+WebGPU: removed suport for Emscripten <4.0.10. (#9281) [@ypujante] - GLFW/SDL2/SDL3+WebGPU: added support for WGVK. (#9316, #9246, #9257) [@r-lyeh, @ocornut]
- GLFW/SDL2/SDL3+WebGPU: removed support for Emscripten <4.0.10. (#9281) [@ypujante]
Docking+Viewports Branch: Docking+Viewports Branch:
+98 -24
View File
@@ -25,7 +25,7 @@ or view this file with any Markdown viewer.
| [I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-clipping-or-disappearing-when-i-move-windows-around) | | [I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-clipping-or-disappearing-when-i-move-windows-around) |
| [I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-displaying-outside-their-expected-windows-boundaries) | | [I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-displaying-outside-their-expected-windows-boundaries) |
| **Q&A: Usage** | | **Q&A: Usage** |
| **[About the ID Stack system..<br>Why is my widget not reacting when I click on it?<br>Why is the wrong widget reacting when I click on one?<br>How can I have widgets with an empty label?<br>How can I have multiple widgets with the same label?<br>How can I have multiple windows with the same label?](#q-about-the-id-stack-system)** | | **[About the ID Stack system...](#q-about-the-id-stack-system)**<br>**[How can I have multiple widgets with the same label?](#q-how-can-i-have-multiple-widgets-with-the-same-label) (using `##` or `PushID()`)**<br>**[How can I have widgets with an empty label?](#q-how-can-i-have-widgets-with-an-empty-label) (using `##`)**<br>**[How can I animate the label of an existing widget?](#q-how-can-i-change-the-label-of-an-existing-widget) (using `###`)**<br>**[General description of the label and ID Stack system.](#general-description-of-the-label-and-id-stack-system)** |
| [How can I display an image?](#q-how-can-i-display-an-image)<br>[What are ImTextureID/ImTextureRef?](#q-what-are-imtextureidimtextureref)| | [How can I display an image?](#q-how-can-i-display-an-image)<br>[What are ImTextureID/ImTextureRef?](#q-what-are-imtextureidimtextureref)|
| [How can I use maths operators with ImVec2?](#q-how-can-i-use-maths-operators-with-imvec2) | | [How can I use maths operators with ImVec2?](#q-how-can-i-use-maths-operators-with-imvec2) |
| [How can I use my own maths types instead of ImVec2/ImVec4?](#q-how-can-i-use-my-own-maths-types-instead-of-imvec2imvec4) | | [How can I use my own maths types instead of ImVec2/ImVec4?](#q-how-can-i-use-my-own-maths-types-instead-of-imvec2imvec4) |
@@ -263,15 +263,19 @@ ctx->RSSetScissorRects(1, &r);
# Q&A: Usage # Q&A: Usage
### Q: About the ID Stack system... ## Q: About the ID Stack system...
### Q: Why is my widget not reacting when I click on it?
### Q: Why is the wrong widget reacting when I click on one?
### Q: How can I have widgets with an empty label?
### Q: How can I have multiple widgets with the same label?
### Q: How can I have multiple windows with the same label?
**USING THE SAME LABEL+ID IS THE MOST COMMON USER MISTAKE!** **USING THE SAME LABEL+ID IS THE MOST COMMON USER MISTAKE!**
<br>**USING AN EMPTY LABEL IS THE SAME AS USING THE SAME LABEL AS YOUR PARENT WIDGET!** <br>**USING AN EMPTY LABEL IS THE SAME AS USING THE SAME LABEL AS YOUR PARENT WIDGET!**
<br>Read the questions in this section for a more general understand of how labels and ID works in Dear ImGui.
TL;DR;
- Widgets labels are also used to compute Widgets unique identifiers.
- Unique identifiers are hashes of the label + of the parent scope (e.g. parent window or parent tree node labels).
- You can use `PushID()` to append to the identifier without making it visible.
- You can use `"##something"` in a label to append to the identifier without making it visible.
- You can use `"###something"` in a label to make the identifier ignore the visible part.
<table> <table>
<tr> <tr>
<td><img src="https://github.com/user-attachments/assets/776a8315-1164-4178-9a8c-df52e0ff28aa"></td> <td><img src="https://github.com/user-attachments/assets/776a8315-1164-4178-9a8c-df52e0ff28aa"></td>
@@ -302,16 +306,99 @@ ImGui::End();
</tr> </tr>
</table> </table>
A primer on labels and the ID Stack... ### Q: How can I have multiple widgets with the same label?
A. When widgets are in a same scope and finite, you can use a `"##something"` suffix which will be part of the identifier but not visible as a label.
```cpp
Button("Play"); // Label = "Play", ID = hash of ("MyWindow", "Play")
Button("Play##foo1"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo1") // Different from other buttons
Button("Play##foo2"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo2") // Different from other buttons
```
B. More generally, e.g. in loops, you can use `PushID()/PopID()` to push a prefix which will be part of the identifier.
```cpp
// Using PushID() with a string
for (int i = 0; i < 100; i++)
{
MyObject* obj = Objects[i];
PushID(obj->Name);
Button("Click"); // Label = "Click", ID = hash of ("Window", obj->Name, "Click")
PopID();
}
```
```cpp
// Using PushID() with an index
for (int i = 0; i < 100; i++)
{
PushID(i);
Button("Click"); // Label = "Click", ID = hash of ("Window", i, "Click")
PopID();
}
```
### Q: How can I have widgets with an empty label?
If you want to completely hide the label, but still need an ID:
```cpp
Checkbox("##On", &b); // Label = "", ID = hash of (..., "##On") // No visible label, just a checkbox!
```
##### [Return to Index](#index)
### Q: How can I make a label dynamic?
Dear ImGui is very dynamic so you can submit different widgets every frame.
However, in order to preserve widget state (eg. which tree node is open; which button is focused) the library internaly refers to their unique ID.
Occasionally you might want to change a label while preserving a constant ID. This allows you to change/animate labels while persisting associated state.
For example, you may want to include varying information in a window title bar or button label.
Using "###" exclude the preceeding part from ID computation:
```cpp
Button("Hello###ID"); // Label = "Enable", ID = hash of (..., "ID")
Button("World###ID"); // Label = "Disable", ID = hash of (..., "ID") // Same ID, different label
```
Using a same ID ensure that associated related e.g. weither the widget is focused, won't be lost when the label changes.
<table>
<tr>
<td><img src="https://github.com/user-attachments/assets/2bf18756-e122-498d-bbd4-5c44bb1018d5"></td>
<td>
<pre lang="cpp">
// Window label has animating FPS counter
// Window ID stays the same = hash of "MyGame"
char buf[128];
sprintf(buf, "My game (%.1f FPS)###MyGame", io.Framerate);
ImGui::Begin(buf);
&nbsp;
// Label changes between "Enable" and "Disable"
// ID stays the same = hash of ("MyGame", "MyButton")
if (ImGui::Button(enabled ? "Disable###MyButton" : "Enable###MyButton", { -FLT_MIN, 0.0f }))
enabled = !enabled;
&nbsp;
ImGui::End();
</pre>
</td>
</tr>
</table>
(Hint: I'd suggest wrapping sprintf in something more compact to use, e.g. [ocornut/Str](https://github.com/ocornut/Str) for what I personally use).
##### [Return to Index](#index)
### General description of the label and ID Stack system
Dear ImGui internally needs to uniquely identify UI elements. Dear ImGui internally needs to uniquely identify UI elements.
Elements that are typically not clickable (such as calls to the Text functions) don't need an ID. Elements that are typically not clickable (such as calls to Text() functions) don't need an ID.
Interactive widgets (such as calls to Button buttons) need a unique ID. Interactive widgets (such as calls to Button() functions) need a unique ID.
**Unique IDs are used internally to track active widgets and occasionally associate state to widgets.<BR> **Unique IDs are used internally to track active widgets and occasionally associate state to widgets.<BR>
Unique IDs are implicitly built from the hash of multiple elements that identify the "path" to the UI element.** Unique IDs are implicitly built from the hash of multiple elements that identify the "path" to the UI element.**
Since Dear ImGui 1.85, you can use `Demo>Tools>ID Stack Tool` or call `ImGui::ShowIDStackToolWindow()`. The tool display intermediate values leading to the creation of a unique ID, making things easier to debug and understand. You can use `Demo>Tools>ID Stack Tool` or call `ImGui::ShowIDStackToolWindow()`. The tool display intermediate values leading to the creation of a unique ID, making things easier to debug and understand.
![Stack tool](https://user-images.githubusercontent.com/8225057/136235657-a0ea5665-dcd1-423f-9be6-dc3f8ced8f12.png) ![Stack tool](https://user-images.githubusercontent.com/8225057/136235657-a0ea5665-dcd1-423f-9be6-dc3f8ced8f12.png)
@@ -365,20 +452,7 @@ Button("Play##foo2"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo
Button("##foo"); // Label = "", ID = hash of ("MyWindow", "##foo") // Different from window Button("##foo"); // Label = "", ID = hash of ("MyWindow", "##foo") // Different from window
End(); End();
``` ```
- If you want to completely hide the label, but still need an ID:
```cpp
Checkbox("##On", &b); // Label = "", ID = hash of (..., "##On") // No visible label, just a checkbox!
```
- Occasionally/rarely you might want to change a label while preserving a constant ID. This allows
you to animate labels. For example, you may want to include varying information in a window title bar,
but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID:
```cpp
Button("Hello###ID"); // Label = "Hello", ID = hash of (..., "###ID")
Button("World###ID"); // Label = "World", ID = hash of (..., "###ID") // Same ID, different label
sprintf(buf, "My game (%f FPS)###MyGame", fps);
Begin(buf); // Variable title, ID = hash of "MyGame"
```
- Solving ID conflict in a more general manner: - Solving ID conflict in a more general manner:
Use `PushID()` / `PopID()` to create scopes and manipulate the ID stack, as to avoid ID conflicts Use `PushID()` / `PopID()` to create scopes and manipulate the ID stack, as to avoid ID conflicts
within the same window. This is the most convenient way of distinguishing ID when iterating and within the same window. This is the most convenient way of distinguishing ID when iterating and
+36 -15
View File
@@ -1,19 +1,24 @@
# Building for desktop (WebGPU-native) with Dawn: # Building for desktop with Dawn:
# 1. git clone https://github.com/google/dawn dawn # 1. git clone https://github.com/google/dawn dawn
# 2. cmake -B build -DIMGUI_DAWN_DIR=dawn # 2. cmake -B build -DIMGUI_DAWN_DIR=dawn
# 3. cmake --build build # 3. cmake --build build
# The resulting binary will be found at one of the following locations: # The resulting binary will be found at one of the following locations:
# * build/Debug/example_glfw_wgpu[.exe] # * build/example_glfw_wgpu[.exe] or build/Debug/example_glfw_wgpu[.exe]
# * build/example_glfw_wgpu[.exe]
# Building for desktop (WGPU-Native) with WGPU-Native: # Building for desktop with WGPU-Native:
# 1. download WGPU-Native autogenerated binary modules for your platform/compiler from: https://github.com/gfx-rs/wgpu-native/releases # 1. download WGPU-Native autogenerated binary modules for your platform/compiler from: https://github.com/gfx-rs/wgpu-native/releases
# 2. unzip the downloaded file in your_preferred_folder # 2. unzip the downloaded file in your_preferred_folder
# 3. cmake -B build -DIMGUI_WGPU_DIR=your_preferred_folder ("full path" or "relative" starting from current directory) # 3. cmake -B build -DIMGUI_WGPU_DIR=your_preferred_folder ("full path" or "relative" starting from current directory)
# 4. cmake --build build # 4. cmake --build build
# The resulting binary will be found at one of the following locations: # The resulting binary will be found at one of the following locations:
# * build/Debug/example_glfw_wgpu[.exe] # * build/example_glfw_wgpu[.exe] or build/Debug/example_glfw_wgpu[.exe]
# * build/example_glfw_wgpu[.exe]
# Building for desktop with WGVK (MUCH EASIER)
# 1. git clone https://github.com/manuel5975p/WGVK dawn
# 2. cmake -B build -DIMGUI_WGVK_DIR=wgvk
# 3. cmake --build build
# The resulting binary will be found at one of the following locations:
# * build/example_glfw_wgpu[.exe] or build/Debug/example_glfw_wgpu[.exe]
# Building for Emscripten: # Building for Emscripten:
# 1. Install Emscripten SDK following the instructions: https://emscripten.org/docs/getting_started/downloads.html # 1. Install Emscripten SDK following the instructions: https://emscripten.org/docs/getting_started/downloads.html
@@ -66,13 +71,14 @@ if(EMSCRIPTEN)
set(LIBRARIES glfw) set(LIBRARIES glfw)
add_compile_options(-sDISABLE_EXCEPTION_CATCHING=1 -DIMGUI_DISABLE_FILE_FUNCTIONS=1) add_compile_options(-sDISABLE_EXCEPTION_CATCHING=1 -DIMGUI_DISABLE_FILE_FUNCTIONS=1)
else() # Native/Desktop build else() # Native/Desktop build
# Check DAWN/WGPU directory
if(NOT IMGUI_DAWN_DIR AND NOT IMGUI_WGPU_DIR) # if it's Native/Desktop build, IMGUI_DAWN_DIR or IMGUI_WGPU_DIR must be specified
message(FATAL_ERROR "Please specify the Dawn or WGPU base directory")
endif()
if(IMGUI_DAWN_DIR AND IMGUI_WGPU_DIR) # both IMGUI_DAWN_DIR and IMGUI_WGPU_DIR cannot be set # Check DAWN/WGPU/WGVK directory
message(FATAL_ERROR "Please specify only one between Dawn / WGPU base directory") # If it's Native/Desktop build, IMGUI_DAWN_DIR or IMGUI_WGPU_DIR or IMGUI_WGVK_DIR must be specified
if(NOT IMGUI_DAWN_DIR AND NOT IMGUI_WGPU_DIR AND NOT IMGUI_WGVK_DIR)
message(FATAL_ERROR "Please specify one of IMGUI_DAWN_DIR/IMGUI_WGPU_DIR/IMGUI_WGVK_DIR base directory.")
endif()
if((IMGUI_DAWN_DIR AND (IMGUI_WGPU_DIR OR IMGUI_WGVK_DIR)) OR (IMGUI_WGPU_DIR AND IMGUI_WGVK_DIR))
message(FATAL_ERROR "Please specify only one of IMGUI_DAWN_DIR/IMGUI_WGPU_DIR/IMGUI_WGVK_DIR base directory.")
endif() endif()
if(APPLE) # Add SDL2 module to get Surface, with libs and file property for MacOS build if(APPLE) # Add SDL2 module to get Surface, with libs and file property for MacOS build
@@ -82,7 +88,7 @@ else() # Native/Desktop build
find_package(glfw3 REQUIRED) find_package(glfw3 REQUIRED)
if(IMGUI_DAWN_DIR) # DAWN-Native build options if(IMGUI_DAWN_DIR)
list(APPEND CMAKE_PREFIX_PATH ${IMGUI_DAWN_DIR}) list(APPEND CMAKE_PREFIX_PATH ${IMGUI_DAWN_DIR})
find_package(Dawn) # Search for a Dawn installation using IMGUI_DAWN_DIR in CMAKE_PREFIX_PATH find_package(Dawn) # Search for a Dawn installation using IMGUI_DAWN_DIR in CMAKE_PREFIX_PATH
if(Dawn_FOUND) if(Dawn_FOUND)
@@ -125,7 +131,9 @@ else() # Native/Desktop build
set(LIBRARIES webgpu_dawn glfw) set(LIBRARIES webgpu_dawn glfw)
endif() endif()
else() # WGPU-Native build options endif()
if(IMGUI_WGPU_DIR)
set(WGPU_NATIVE_LIB_DIR ${IMGUI_WGPU_DIR}/lib) set(WGPU_NATIVE_LIB_DIR ${IMGUI_WGPU_DIR}/lib)
find_library(WGPU_LIBRARY NAMES libwgpu_native.a wgpu_native.lib wgpu_native HINTS ${WGPU_NATIVE_LIB_DIR} REQUIRED) find_library(WGPU_LIBRARY NAMES libwgpu_native.a wgpu_native.lib wgpu_native HINTS ${WGPU_NATIVE_LIB_DIR} REQUIRED)
if(WIN32) if(WIN32)
@@ -136,6 +144,9 @@ else() # Native/Desktop build
set(LIBRARIES glfw ${WGPU_LIBRARY} ${OS_LIBRARIES}) set(LIBRARIES glfw ${WGPU_LIBRARY} ${OS_LIBRARIES})
endif() endif()
if(IMGUI_WGVK_DIR)
endif()
endif() endif()
add_executable(${IMGUI_EXECUTABLE} ${IMGUI_EXAMPLE_SOURCE_FILES}) add_executable(${IMGUI_EXECUTABLE} ${IMGUI_EXAMPLE_SOURCE_FILES})
@@ -168,10 +179,20 @@ if(NOT EMSCRIPTEN) # WegGPU-Native settings
if(NOT Dawn_FOUND) if(NOT Dawn_FOUND)
target_link_libraries(${IMGUI_EXECUTABLE} INTERFACE webgpu_cpp) target_link_libraries(${IMGUI_EXECUTABLE} INTERFACE webgpu_cpp)
endif() endif()
else() endif()
if(IMGUI_WGPU_DIR)
target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGPU") target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGPU")
target_include_directories(${IMGUI_EXECUTABLE} PUBLIC ${IMGUI_WGPU_DIR}/include) target_include_directories(${IMGUI_EXECUTABLE} PUBLIC ${IMGUI_WGPU_DIR}/include)
endif() endif()
if(IMGUI_WGVK_DIR)
target_sources(${IMGUI_EXECUTABLE} PRIVATE ${IMGUI_WGVK_DIR}/src/wgvk.c)
target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGVK")
target_include_directories(${IMGUI_EXECUTABLE} PUBLIC ${IMGUI_WGVK_DIR}/include)
if (MSVC)
target_compile_options(${IMGUI_EXECUTABLE} PUBLIC /std:clatest /experimental:c11atomics)
endif()
endif()
target_link_libraries(${IMGUI_EXECUTABLE} PUBLIC ${LIBRARIES}) target_link_libraries(${IMGUI_EXECUTABLE} PUBLIC ${LIBRARIES})
else() # Emscripten settings else() # Emscripten settings
+9 -5
View File
@@ -65,8 +65,8 @@ int main(int, char**)
// Create window // Create window
float main_scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor()); // Valid on GLFW 3.3+ only float main_scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor()); // Valid on GLFW 3.3+ only
wgpu_surface_width *= main_scale; wgpu_surface_width = (int)(wgpu_surface_width * main_scale);
wgpu_surface_height *= main_scale; wgpu_surface_height = (int)(wgpu_surface_height * main_scale);
GLFWwindow* window = glfwCreateWindow(wgpu_surface_width, wgpu_surface_height, "Dear ImGui GLFW+WebGPU example", nullptr, nullptr); GLFWwindow* window = glfwCreateWindow(wgpu_surface_width, wgpu_surface_height, "Dear ImGui GLFW+WebGPU example", nullptr, nullptr);
if (window == nullptr) if (window == nullptr)
return 1; return 1;
@@ -341,9 +341,10 @@ static WGPUDevice RequestDevice(wgpu::Instance& instance, wgpu::Adapter& adapter
IM_ASSERT(acquired_device != nullptr && waitStatusDevice == wgpu::WaitStatus::Success && "Error on Device request"); IM_ASSERT(acquired_device != nullptr && waitStatusDevice == wgpu::WaitStatus::Success && "Error on Device request");
return acquired_device.MoveToCHandle(); return acquired_device.MoveToCHandle();
} }
#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2)
{ {
IM_UNUSED(userdata2);
if (status == WGPURequestAdapterStatus_Success) if (status == WGPURequestAdapterStatus_Success)
{ {
WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1; WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1;
@@ -357,6 +358,7 @@ static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter
static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2) static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2)
{ {
IM_UNUSED(userdata2);
if (status == WGPURequestDeviceStatus_Success) if (status == WGPURequestDeviceStatus_Success)
{ {
WGPUDevice* extDevice = (WGPUDevice*)userdata1; WGPUDevice* extDevice = (WGPUDevice*)userdata1;
@@ -440,17 +442,19 @@ bool InitWGPU(GLFWwindow* window)
preferred_fmt = surface_capabilities.formats[0]; preferred_fmt = surface_capabilities.formats[0];
// WGPU backend: Adapter and Device acquisition, Surface creation // WGPU backend: Adapter and Device acquisition, Surface creation
#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
WGPUInstanceDescriptor instanceDesc = {}; WGPUInstanceDescriptor instanceDesc = {};
WGPUInstanceFeatureName timedWaitAny = WGPUInstanceFeatureName_TimedWaitAny; WGPUInstanceFeatureName timedWaitAny = WGPUInstanceFeatureName_TimedWaitAny;
instanceDesc.requiredFeatureCount = 1; instanceDesc.requiredFeatureCount = 1;
instanceDesc.requiredFeatures = &timedWaitAny; instanceDesc.requiredFeatures = &timedWaitAny;
wgpu_instance = wgpuCreateInstance(&instanceDesc); wgpu_instance = wgpuCreateInstance(&instanceDesc);
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
wgpuSetLogCallback( wgpuSetLogCallback(
[](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr [](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr
); );
wgpuSetLogLevel(WGPULogLevel_Warn); wgpuSetLogLevel(WGPULogLevel_Warn);
#endif
WGPUAdapter adapter = RequestAdapter(wgpu_instance); WGPUAdapter adapter = RequestAdapter(wgpu_instance);
ImGui_ImplWGPU_DebugPrintAdapterInfo(adapter); ImGui_ImplWGPU_DebugPrintAdapterInfo(adapter);
@@ -550,7 +554,7 @@ WGPUSurface CreateWGPUSurface(const WGPUInstance& instance, GLFWwindow* window)
} }
#else #else
#error "Unsupported WebGPU native platform!" #error "Unsupported WebGPU native platform!"
#endif
return nullptr; return nullptr;
#endif
} }
#endif // #ifndef __EMSCRIPTEN__ #endif // #ifndef __EMSCRIPTEN__
+35 -14
View File
@@ -1,19 +1,24 @@
# Building for desktop (WebGPU-native) with Dawn: # Building for desktop with Dawn:
# 1. git clone https://github.com/google/dawn dawn # 1. git clone https://github.com/google/dawn dawn
# 2. cmake -B build -DIMGUI_DAWN_DIR=dawn # 2. cmake -B build -DIMGUI_DAWN_DIR=dawn
# 3. cmake --build build # 3. cmake --build build
# The resulting binary will be found at one of the following locations: # The resulting binary will be found at one of the following locations:
# * build/Debug/example_sdl2_wgpu[.exe] # * build/example_sdl2_wgpu[.exe] or build/Debug/example_sdl2_wgpu[.exe]
# * build/example_sdl2_wgpu[.exe]
# Building for desktop (WGPU-Native) with WGPU-Native: # Building for desktop with WGPU-Native:
# 1. download WGPU-Native autogenerated binary modules for your platform/compiler from: https://github.com/gfx-rs/wgpu-native/releases # 1. download WGPU-Native autogenerated binary modules for your platform/compiler from: https://github.com/gfx-rs/wgpu-native/releases
# 2. unzip the downloaded file in your_preferred_folder # 2. unzip the downloaded file in your_preferred_folder
# 3. cmake -B build -DIMGUI_WGPU_DIR=your_preferred_folder ("full path" or "relative" starting from current directory) # 3. cmake -B build -DIMGUI_WGPU_DIR=your_preferred_folder ("full path" or "relative" starting from current directory)
# 4. cmake --build build # 4. cmake --build build
# The resulting binary will be found at one of the following locations: # The resulting binary will be found at one of the following locations:
# * build/Debug/example_sdl2_wgpu[.exe] # * build/example_sdl2_wgpu[.exe] or build/Debug/example_sdl2_wgpu[.exe]
# * build/example_sdl2_wgpu[.exe]
# Building for desktop with WGVK (MUCH EASIER)
# 1. git clone https://github.com/manuel5975p/WGVK dawn
# 2. cmake -B build -DIMGUI_WGVK_DIR=wgvk
# 3. cmake --build build
# The resulting binary will be found at one of the following locations:
# * build/example_sdl2_wgpu[.exe] or build/Debug/example_sdl2_wgpu[.exe]
# Building for Emscripten: # Building for Emscripten:
# 1. Install Emscripten SDK following the instructions: https://emscripten.org/docs/getting_started/downloads.html # 1. Install Emscripten SDK following the instructions: https://emscripten.org/docs/getting_started/downloads.html
@@ -60,12 +65,14 @@ if(EMSCRIPTEN)
add_compile_options(-sDISABLE_EXCEPTION_CATCHING=1 -DIMGUI_DISABLE_FILE_FUNCTIONS=1) add_compile_options(-sDISABLE_EXCEPTION_CATCHING=1 -DIMGUI_DISABLE_FILE_FUNCTIONS=1)
else() # Native/Desktop build else() # Native/Desktop build
if(NOT IMGUI_DAWN_DIR AND NOT IMGUI_WGPU_DIR) # if it's Native/Desktop build, IMGUI_DAWN_DIR or IMGUI_WGPU_DIR must be specified
message(FATAL_ERROR "Please specify the Dawn or WGPU base directory")
endif()
if(IMGUI_DAWN_DIR AND IMGUI_WGPU_DIR) # both IMGUI_DAWN_DIR and IMGUI_WGPU_DIR cannot be set # Check DAWN/WGPU/WGVK directory
message(FATAL_ERROR "Please specify only one between Dawn / WGPU base directory") # If it's Native/Desktop build, IMGUI_DAWN_DIR or IMGUI_WGPU_DIR or IMGUI_WGVK_DIR must be specified
if(NOT IMGUI_DAWN_DIR AND NOT IMGUI_WGPU_DIR AND NOT IMGUI_WGVK_DIR)
message(FATAL_ERROR "Please specify one of IMGUI_DAWN_DIR/IMGUI_WGPU_DIR/IMGUI_WGVK_DIR base directory.")
endif()
if((IMGUI_DAWN_DIR AND (IMGUI_WGPU_DIR OR IMGUI_WGVK_DIR)) OR (IMGUI_WGPU_DIR AND IMGUI_WGVK_DIR))
message(FATAL_ERROR "Please specify only one of IMGUI_DAWN_DIR/IMGUI_WGPU_DIR/IMGUI_WGVK_DIR base directory.")
endif() endif()
if(APPLE) # Add SDL2 module to get Surface, with libs and file property for MacOS build if(APPLE) # Add SDL2 module to get Surface, with libs and file property for MacOS build
@@ -75,7 +82,7 @@ else() # Native/Desktop build
find_package(SDL2 REQUIRED) # SDL_MAIN_HANDLED find_package(SDL2 REQUIRED) # SDL_MAIN_HANDLED
if(IMGUI_DAWN_DIR) # DAWN-Native build options if(IMGUI_DAWN_DIR)
list(APPEND CMAKE_PREFIX_PATH ${IMGUI_DAWN_DIR}) list(APPEND CMAKE_PREFIX_PATH ${IMGUI_DAWN_DIR})
find_package(Threads) # required from Dawn installation find_package(Threads) # required from Dawn installation
find_package(Dawn) # Search for a Dawn installation using IMGUI_DAWN_DIR in CMAKE_PREFIX_PATH find_package(Dawn) # Search for a Dawn installation using IMGUI_DAWN_DIR in CMAKE_PREFIX_PATH
@@ -119,8 +126,9 @@ else() # Native/Desktop build
set(LIBRARIES webgpu_dawn ${OS_LIBRARIES}) set(LIBRARIES webgpu_dawn ${OS_LIBRARIES})
endif() endif()
else() # WGPU-Native build options endif()
if(IMGUI_WGPU_DIR)
set(WGPU_NATIVE_LIB_DIR ${IMGUI_WGPU_DIR}/lib) set(WGPU_NATIVE_LIB_DIR ${IMGUI_WGPU_DIR}/lib)
find_library(WGPU_LIBRARY NAMES libwgpu_native.a wgpu_native.lib wgpu_native HINTS ${WGPU_NATIVE_LIB_DIR} REQUIRED) find_library(WGPU_LIBRARY NAMES libwgpu_native.a wgpu_native.lib wgpu_native HINTS ${WGPU_NATIVE_LIB_DIR} REQUIRED)
if(WIN32) if(WIN32)
@@ -131,6 +139,10 @@ else() # Native/Desktop build
set(LIBRARIES ${WGPU_LIBRARY} ${OS_LIBRARIES}) set(LIBRARIES ${WGPU_LIBRARY} ${OS_LIBRARIES})
endif() endif()
if(IMGUI_WGVK_DIR)
endif()
endif() endif()
add_executable(${IMGUI_EXECUTABLE} ${IMGUI_EXAMPLE_SOURCE_FILES}) add_executable(${IMGUI_EXECUTABLE} ${IMGUI_EXAMPLE_SOURCE_FILES})
@@ -163,10 +175,19 @@ if(NOT EMSCRIPTEN) # WegGPU-Native settings
if(NOT Dawn_FOUND) if(NOT Dawn_FOUND)
target_link_libraries(${IMGUI_EXECUTABLE} INTERFACE webgpu_cpp) target_link_libraries(${IMGUI_EXECUTABLE} INTERFACE webgpu_cpp)
endif() endif()
else() endif()
if(IMGUI_WGPU_DIR)
target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGPU") target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGPU")
target_include_directories(${IMGUI_EXECUTABLE} PUBLIC ${IMGUI_WGPU_DIR}/include) target_include_directories(${IMGUI_EXECUTABLE} PUBLIC ${IMGUI_WGPU_DIR}/include)
endif() endif()
if(IMGUI_WGVK_DIR)
target_sources(${IMGUI_EXECUTABLE} PRIVATE ${IMGUI_WGVK_DIR}/src/wgvk.c)
target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGVK")
target_include_directories(${IMGUI_EXECUTABLE} PUBLIC ${IMGUI_WGVK_DIR}/include)
if (MSVC)
target_compile_options(${IMGUI_EXECUTABLE} PUBLIC /std:clatest /experimental:c11atomics)
endif()
endif()
target_link_libraries(${IMGUI_EXECUTABLE} PUBLIC ${LIBRARIES} ${SDL2_LIBRARIES}) target_link_libraries(${IMGUI_EXECUTABLE} PUBLIC ${LIBRARIES} ${SDL2_LIBRARIES})
else() # Emscripten settings else() # Emscripten settings
+9 -3
View File
@@ -53,6 +53,8 @@ int main(int, char**)
// Create window with graphics context // Create window with graphics context
float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0); float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0);
wgpu_surface_width = (int)(wgpu_surface_width * main_scale);
wgpu_surface_height = (int)(wgpu_surface_height * main_scale);
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+WebGPU example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, wgpu_surface_width, wgpu_surface_height, window_flags); SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+WebGPU example", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, wgpu_surface_width, wgpu_surface_height, window_flags);
if (window == nullptr) if (window == nullptr)
@@ -324,9 +326,10 @@ static WGPUDevice RequestDevice(wgpu::Instance& instance, wgpu::Adapter& adapter
IM_ASSERT(acquired_device != nullptr && waitStatusDevice == wgpu::WaitStatus::Success && "Error on Device request"); IM_ASSERT(acquired_device != nullptr && waitStatusDevice == wgpu::WaitStatus::Success && "Error on Device request");
return acquired_device.MoveToCHandle(); return acquired_device.MoveToCHandle();
} }
#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2)
{ {
IM_UNUSED(userdata2);
if (status == WGPURequestAdapterStatus_Success) if (status == WGPURequestAdapterStatus_Success)
{ {
WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1; WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1;
@@ -340,6 +343,7 @@ static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter
static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2) static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2)
{ {
IM_UNUSED(userdata2);
if (status == WGPURequestDeviceStatus_Success) if (status == WGPURequestDeviceStatus_Success)
{ {
WGPUDevice* extDevice = (WGPUDevice*)userdata1; WGPUDevice* extDevice = (WGPUDevice*)userdata1;
@@ -424,17 +428,19 @@ static bool InitWGPU(SDL_Window* window)
preferred_fmt = surface_capabilities.formats[0]; preferred_fmt = surface_capabilities.formats[0];
// WGPU backend: Adapter and Device acquisition, Surface creation // WGPU backend: Adapter and Device acquisition, Surface creation
#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
WGPUInstanceDescriptor instanceDesc = {}; WGPUInstanceDescriptor instanceDesc = {};
WGPUInstanceFeatureName timedWaitAny = WGPUInstanceFeatureName_TimedWaitAny; WGPUInstanceFeatureName timedWaitAny = WGPUInstanceFeatureName_TimedWaitAny;
instanceDesc.requiredFeatureCount = 1; instanceDesc.requiredFeatureCount = 1;
instanceDesc.requiredFeatures = &timedWaitAny; instanceDesc.requiredFeatures = &timedWaitAny;
wgpu_instance = wgpuCreateInstance(&instanceDesc); wgpu_instance = wgpuCreateInstance(&instanceDesc);
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
wgpuSetLogCallback( wgpuSetLogCallback(
[](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr [](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr
); );
wgpuSetLogLevel(WGPULogLevel_Warn); wgpuSetLogLevel(WGPULogLevel_Warn);
#endif
WGPUAdapter adapter = RequestAdapter(wgpu_instance); WGPUAdapter adapter = RequestAdapter(wgpu_instance);
ImGui_ImplWGPU_DebugPrintAdapterInfo(adapter); ImGui_ImplWGPU_DebugPrintAdapterInfo(adapter);
@@ -514,7 +520,7 @@ WGPUSurface CreateWGPUSurface(const WGPUInstance& instance, SDL_Window* window)
} }
#else #else
#error "Unsupported WebGPU native platform!" #error "Unsupported WebGPU native platform!"
#endif
return nullptr; return nullptr;
#endif
} }
#endif // #ifndef __EMSCRIPTEN__ #endif // #ifndef __EMSCRIPTEN__
+35 -14
View File
@@ -1,19 +1,24 @@
# Building for desktop (WebGPU-native) with Dawn: # Building for desktop with Dawn:
# 1. git clone https://github.com/google/dawn dawn # 1. git clone https://github.com/google/dawn dawn
# 2. cmake -B build -DIMGUI_DAWN_DIR=dawn # 2. cmake -B build -DIMGUI_DAWN_DIR=dawn
# 3. cmake --build build # 3. cmake --build build
# The resulting binary will be found at one of the following locations: # The resulting binary will be found at one of the following locations:
# * build/Debug/example_sdl3_wgpu[.exe] # * build/example_sdl3_wgpu[.exe] or build/Debug/example_sdl3_wgpu[.exe]
# * build/example_sdl3_wgpu[.exe]
# Building for desktop (WGPU-Native) with WGPU-Native: # Building for desktop with WGPU-Native:
# 1. download WGPU-Native autogenerated binary modules for your platform/compiler from: https://github.com/gfx-rs/wgpu-native/releases # 1. download WGPU-Native autogenerated binary modules for your platform/compiler from: https://github.com/gfx-rs/wgpu-native/releases
# 2. unzip the downloaded file in your_preferred_folder # 2. unzip the downloaded file in your_preferred_folder
# 3. cmake -B build -DIMGUI_WGPU_DIR=your_preferred_folder ("full path" or "relative" starting from current directory) # 3. cmake -B build -DIMGUI_WGPU_DIR=your_preferred_folder ("full path" or "relative" starting from current directory)
# 4. cmake --build build # 4. cmake --build build
# The resulting binary will be found at one of the following locations: # The resulting binary will be found at one of the following locations:
# * build/Debug/example_sdl3_wgpu[.exe] # * build/example_sdl3_wgpu[.exe] or build/Debug/example_sdl3_wgpu[.exe]
# * build/example_sdl3_wgpu[.exe]
# Building for desktop with WGVK (MUCH EASIER)
# 1. git clone https://github.com/manuel5975p/WGVK dawn
# 2. cmake -B build -DIMGUI_WGVK_DIR=wgvk
# 3. cmake --build build
# The resulting binary will be found at one of the following locations:
# * build/example_sdl3_wgpu[.exe] or build/Debug/example_sdl3_wgpu[.exe]
# Building for Emscripten: # Building for Emscripten:
# 1. Install Emscripten SDK following the instructions: https://emscripten.org/docs/getting_started/downloads.html # 1. Install Emscripten SDK following the instructions: https://emscripten.org/docs/getting_started/downloads.html
@@ -60,12 +65,14 @@ if(EMSCRIPTEN)
add_compile_options(-sDISABLE_EXCEPTION_CATCHING=1 -DIMGUI_DISABLE_FILE_FUNCTIONS=1) add_compile_options(-sDISABLE_EXCEPTION_CATCHING=1 -DIMGUI_DISABLE_FILE_FUNCTIONS=1)
else() # Native/Desktop build else() # Native/Desktop build
if(NOT IMGUI_DAWN_DIR AND NOT IMGUI_WGPU_DIR) # if it's Native/Desktop build, IMGUI_DAWN_DIR or IMGUI_WGPU_DIR must be specified
message(FATAL_ERROR "Please specify the Dawn or WGPU base directory")
endif()
if(IMGUI_DAWN_DIR AND IMGUI_WGPU_DIR) # both IMGUI_DAWN_DIR and IMGUI_WGPU_DIR cannot be set # Check DAWN/WGPU/WGVK directory
message(FATAL_ERROR "Please specify only one between Dawn / WGPU base directory") # If it's Native/Desktop build, IMGUI_DAWN_DIR or IMGUI_WGPU_DIR or IMGUI_WGVK_DIR must be specified
if(NOT IMGUI_DAWN_DIR AND NOT IMGUI_WGPU_DIR AND NOT IMGUI_WGVK_DIR)
message(FATAL_ERROR "Please specify one of IMGUI_DAWN_DIR/IMGUI_WGPU_DIR/IMGUI_WGVK_DIR base directory.")
endif()
if((IMGUI_DAWN_DIR AND (IMGUI_WGPU_DIR OR IMGUI_WGVK_DIR)) OR (IMGUI_WGPU_DIR AND IMGUI_WGVK_DIR))
message(FATAL_ERROR "Please specify only one of IMGUI_DAWN_DIR/IMGUI_WGPU_DIR/IMGUI_WGVK_DIR base directory.")
endif() endif()
if(APPLE) # Add SDL3 module to get Surface, with libs and file property for MacOS build if(APPLE) # Add SDL3 module to get Surface, with libs and file property for MacOS build
@@ -75,7 +82,7 @@ else() # Native/Desktop build
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3) find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3)
if(IMGUI_DAWN_DIR) # DAWN-Native build options if(IMGUI_DAWN_DIR)
list(APPEND CMAKE_PREFIX_PATH ${IMGUI_DAWN_DIR}) list(APPEND CMAKE_PREFIX_PATH ${IMGUI_DAWN_DIR})
find_package(Threads) # required from Dawn installation find_package(Threads) # required from Dawn installation
find_package(Dawn) # Search for a Dawn installation using IMGUI_DAWN_DIR in CMAKE_PREFIX_PATH find_package(Dawn) # Search for a Dawn installation using IMGUI_DAWN_DIR in CMAKE_PREFIX_PATH
@@ -119,7 +126,9 @@ else() # Native/Desktop build
set(LIBRARIES webgpu_dawn ${OS_LIBRARIES}) set(LIBRARIES webgpu_dawn ${OS_LIBRARIES})
endif() endif()
else() # WGPU-Native build options endif()
if(IMGUI_WGPU_DIR)
set(WGPU_NATIVE_LIB_DIR ${IMGUI_WGPU_DIR}/lib) set(WGPU_NATIVE_LIB_DIR ${IMGUI_WGPU_DIR}/lib)
find_library(WGPU_LIBRARY NAMES libwgpu_native.a wgpu_native.lib wgpu_native HINTS ${WGPU_NATIVE_LIB_DIR} REQUIRED) find_library(WGPU_LIBRARY NAMES libwgpu_native.a wgpu_native.lib wgpu_native HINTS ${WGPU_NATIVE_LIB_DIR} REQUIRED)
if(WIN32) if(WIN32)
@@ -130,6 +139,9 @@ else() # Native/Desktop build
set(LIBRARIES ${WGPU_LIBRARY} ${OS_LIBRARIES}) set(LIBRARIES ${WGPU_LIBRARY} ${OS_LIBRARIES})
endif() endif()
if(IMGUI_WGVK_DIR)
endif()
endif() endif()
add_executable(${IMGUI_EXECUTABLE} ${IMGUI_EXAMPLE_SOURCE_FILES}) add_executable(${IMGUI_EXECUTABLE} ${IMGUI_EXAMPLE_SOURCE_FILES})
@@ -162,10 +174,19 @@ if(NOT EMSCRIPTEN) # WegGPU-Native settings
if(NOT Dawn_FOUND) if(NOT Dawn_FOUND)
target_link_libraries(${IMGUI_EXECUTABLE} INTERFACE webgpu_cpp) target_link_libraries(${IMGUI_EXECUTABLE} INTERFACE webgpu_cpp)
endif() endif()
else() endif()
if(IMGUI_WGPU_DIR)
target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGPU") target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGPU")
target_include_directories(${IMGUI_EXECUTABLE} PUBLIC ${IMGUI_WGPU_DIR}/include) target_include_directories(${IMGUI_EXECUTABLE} PUBLIC ${IMGUI_WGPU_DIR}/include)
endif() endif()
if(IMGUI_WGVK_DIR)
target_sources(${IMGUI_EXECUTABLE} PRIVATE ${IMGUI_WGVK_DIR}/src/wgvk.c)
target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGVK")
target_include_directories(${IMGUI_EXECUTABLE} PUBLIC ${IMGUI_WGVK_DIR}/include)
if (MSVC)
target_compile_options(${IMGUI_EXECUTABLE} PUBLIC /std:clatest /experimental:c11atomics)
endif()
endif()
target_link_libraries(${IMGUI_EXECUTABLE} PUBLIC ${LIBRARIES} SDL3::SDL3) target_link_libraries(${IMGUI_EXECUTABLE} PUBLIC ${LIBRARIES} SDL3::SDL3)
else() # Emscripten settings else() # Emscripten settings
+9 -3
View File
@@ -61,6 +61,8 @@ int main(int, char**)
// Create SDL window graphics context // Create SDL window graphics context
float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE; SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE;
wgpu_surface_width = (int)(wgpu_surface_width * main_scale);
wgpu_surface_height = (int)(wgpu_surface_height * main_scale);
SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+WebGPU example", wgpu_surface_width, wgpu_surface_height, window_flags); SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+WebGPU example", wgpu_surface_width, wgpu_surface_height, window_flags);
if (window == nullptr) if (window == nullptr)
{ {
@@ -335,9 +337,10 @@ static WGPUDevice RequestDevice(wgpu::Instance& instance, wgpu::Adapter& adapter
IM_ASSERT(acquired_device != nullptr && waitStatusDevice == wgpu::WaitStatus::Success && "Error on Device request"); IM_ASSERT(acquired_device != nullptr && waitStatusDevice == wgpu::WaitStatus::Success && "Error on Device request");
return acquired_device.MoveToCHandle(); return acquired_device.MoveToCHandle();
} }
#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2)
{ {
IM_UNUSED(userdata2);
if (status == WGPURequestAdapterStatus_Success) if (status == WGPURequestAdapterStatus_Success)
{ {
WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1; WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1;
@@ -351,6 +354,7 @@ static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter
static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2) static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2)
{ {
IM_UNUSED(userdata2);
if (status == WGPURequestDeviceStatus_Success) if (status == WGPURequestDeviceStatus_Success)
{ {
WGPUDevice* extDevice = (WGPUDevice*)userdata1; WGPUDevice* extDevice = (WGPUDevice*)userdata1;
@@ -435,17 +439,19 @@ static bool InitWGPU(SDL_Window* window)
preferred_fmt = surface_capabilities.formats[0]; preferred_fmt = surface_capabilities.formats[0];
// WGPU backend: Adapter and Device acquisition, Surface creation // WGPU backend: Adapter and Device acquisition, Surface creation
#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
WGPUInstanceDescriptor instanceDesc = {}; WGPUInstanceDescriptor instanceDesc = {};
WGPUInstanceFeatureName timedWaitAny = WGPUInstanceFeatureName_TimedWaitAny; WGPUInstanceFeatureName timedWaitAny = WGPUInstanceFeatureName_TimedWaitAny;
instanceDesc.requiredFeatureCount = 1; instanceDesc.requiredFeatureCount = 1;
instanceDesc.requiredFeatures = &timedWaitAny; instanceDesc.requiredFeatures = &timedWaitAny;
wgpu_instance = wgpuCreateInstance(&instanceDesc); wgpu_instance = wgpuCreateInstance(&instanceDesc);
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
wgpuSetLogCallback( wgpuSetLogCallback(
[](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr [](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr
); );
wgpuSetLogLevel(WGPULogLevel_Warn); wgpuSetLogLevel(WGPULogLevel_Warn);
#endif
WGPUAdapter adapter = RequestAdapter(wgpu_instance); WGPUAdapter adapter = RequestAdapter(wgpu_instance);
ImGui_ImplWGPU_DebugPrintAdapterInfo(adapter); ImGui_ImplWGPU_DebugPrintAdapterInfo(adapter);
@@ -526,7 +532,7 @@ WGPUSurface CreateWGPUSurface(const WGPUInstance& instance, SDL_Window* window)
} }
#else #else
#error "Unsupported WebGPU native platform!" #error "Unsupported WebGPU native platform!"
#endif
return nullptr; return nullptr;
#endif
} }
#endif // #ifndef __EMSCRIPTEN__ #endif // #ifndef __EMSCRIPTEN__
+12 -10
View File
@@ -1165,10 +1165,10 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
---------- ----------
Q: About the ID Stack system.. Q: About the ID Stack system..
- Why is my widget not reacting when I click on it? - How can I have multiple widgets with the same label? (using ## or PushID)
- How can I have widgets with an empty label? - How can I have widgets with an empty label? (using ##)
- How can I have multiple widgets with the same label? - How can I make a label dynamic? (using ###)
- How can I have multiple windows with the same label? - General description of the label and ID Stack system.
Q: How can I display an image? What is ImTextureID, how does it work? Q: How can I display an image? What is ImTextureID, how does it work?
Q: How can I use my own math types instead of ImVec2? Q: How can I use my own math types instead of ImVec2?
Q: How can I interact with standard C++ types (such as std::string and std::vector)? Q: How can I interact with standard C++ types (such as std::string and std::vector)?
@@ -3337,8 +3337,7 @@ ImGuiListClipper::~ImGuiListClipper()
void ImGuiListClipper::Begin(int items_count, float items_height) void ImGuiListClipper::Begin(int items_count, float items_height)
{ {
if (Ctx == NULL) Ctx = ImGui::GetCurrentContext();
Ctx = ImGui::GetCurrentContext();
ImGuiContext& g = *Ctx; ImGuiContext& g = *Ctx;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
@@ -10709,11 +10708,12 @@ static void UpdateAliasKey(ImGuiKey key, bool v, float analog_value)
// [Internal] Do not use directly // [Internal] Do not use directly
static ImGuiKeyChord GetMergedModsFromKeys() static ImGuiKeyChord GetMergedModsFromKeys()
{ {
// Bypass IsKeyDown() for the unlikely case where user used a ImGuiInputFlags_LockXXXX on those.
ImGuiKeyChord mods = 0; ImGuiKeyChord mods = 0;
if (ImGui::IsKeyDown(ImGuiMod_Ctrl)) { mods |= ImGuiMod_Ctrl; } if (ImGui::GetKeyData(ImGuiMod_Ctrl)->Down) { mods |= ImGuiMod_Ctrl; }
if (ImGui::IsKeyDown(ImGuiMod_Shift)) { mods |= ImGuiMod_Shift; } if (ImGui::GetKeyData(ImGuiMod_Shift)->Down) { mods |= ImGuiMod_Shift; }
if (ImGui::IsKeyDown(ImGuiMod_Alt)) { mods |= ImGuiMod_Alt; } if (ImGui::GetKeyData(ImGuiMod_Alt)->Down) { mods |= ImGuiMod_Alt; }
if (ImGui::IsKeyDown(ImGuiMod_Super)) { mods |= ImGuiMod_Super; } if (ImGui::GetKeyData(ImGuiMod_Super)->Down) { mods |= ImGuiMod_Super; }
return mods; return mods;
} }
@@ -11796,6 +11796,8 @@ bool ImGui::ErrorLog(const char* msg)
return g.IO.ConfigErrorRecoveryEnableAssert; return g.IO.ConfigErrorRecoveryEnableAssert;
} }
// Display an error tooltip when same ID as HoveredId was submitted multiple times.
// See code in ItemHoverable() for an explanation of why we associate this error to HoveredId + code drawing of rectangles over individual items instances.
void ImGui::ErrorCheckEndFrameFinalizeErrorTooltip() void ImGui::ErrorCheckEndFrameFinalizeErrorTooltip()
{ {
#ifndef IMGUI_DISABLE_DEBUG_TOOLS #ifndef IMGUI_DISABLE_DEBUG_TOOLS
+16 -7
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.7 WIP" #define IMGUI_VERSION "1.92.7 WIP"
#define IMGUI_VERSION_NUM 19266 #define IMGUI_VERSION_NUM 19268
#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.
@@ -922,7 +922,7 @@ namespace ImGui
// The context menu can also be made available in columns body using ImGuiTableFlags_ContextMenuInBody. // The context menu can also be made available in columns body using ImGuiTableFlags_ContextMenuInBody.
// - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in // - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in
// some advanced use cases (e.g. adding custom widgets in header row). // some advanced use cases (e.g. adding custom widgets in header row).
// - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled. // - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled. When freezing columns you would usually also use ImGuiTableColumnFlags_NoHide on them.
IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_id = 0); IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_id = 0);
IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled. IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled.
IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used) IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used)
@@ -1771,6 +1771,7 @@ enum ImGuiInputFlags_
}; };
// Configuration flags stored in io.ConfigFlags. Set by user/application. // Configuration flags stored in io.ConfigFlags. Set by user/application.
// Note that nowadays most of our configuration options are in other ImGuiIO fields, e.g. io.ConfigWindowsMoveFromTitleBarOnly.
enum ImGuiConfigFlags_ enum ImGuiConfigFlags_
{ {
ImGuiConfigFlags_None = 0, ImGuiConfigFlags_None = 0,
@@ -1787,10 +1788,9 @@ enum ImGuiConfigFlags_
// When using viewports it is recommended that your default value for ImGuiCol_WindowBg is opaque (Alpha=1.0) so transition to a viewport won't be noticeable. // When using viewports it is recommended that your default value for ImGuiCol_WindowBg is opaque (Alpha=1.0) so transition to a viewport won't be noticeable.
ImGuiConfigFlags_ViewportsEnable = 1 << 10, // Viewport enable flags (require both ImGuiBackendFlags_PlatformHasViewports + ImGuiBackendFlags_RendererHasViewports set by the respective backends) ImGuiConfigFlags_ViewportsEnable = 1 << 10, // Viewport enable flags (require both ImGuiBackendFlags_PlatformHasViewports + ImGuiBackendFlags_RendererHasViewports set by the respective backends)
// User storage (to allow your backend/engine to communicate to code that may be shared between multiple projects. Those flags are NOT used by core Dear ImGui) // [Unused] User storage (to allow your backend/engine to communicate to code that may be shared between multiple projects. Those flags are NOT used by core Dear ImGui)
ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware. ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware.
ImGuiConfigFlags_IsTouchScreen = 1 << 21, // Application is using a touch screen instead of a mouse. ImGuiConfigFlags_IsTouchScreen = 1 << 21, // Application is using a touch screen instead of a mouse.
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavMoveSetMousePos ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavMoveSetMousePos
ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavCaptureKeyboard ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavCaptureKeyboard
@@ -2988,16 +2988,16 @@ enum ImGuiListClipperFlags_
// - The clipper also handles various subtleties related to keyboard/gamepad navigation, wrapping etc. // - The clipper also handles various subtleties related to keyboard/gamepad navigation, wrapping etc.
struct ImGuiListClipper struct ImGuiListClipper
{ {
ImGuiContext* Ctx; // Parent UI context
int DisplayStart; // First item to display, updated by each call to Step() int DisplayStart; // First item to display, updated by each call to Step()
int DisplayEnd; // End of items to display (exclusive) int DisplayEnd; // End of items to display (exclusive)
int UserIndex; // Helper storage for user convenience/code. Optional, and otherwise unused if you don't use it. int UserIndex; // Helper storage for user convenience/code. Optional, and otherwise unused if you don't use it.
int ItemsCount; // [Internal] Number of items int ItemsCount; // [Internal] Number of items
float ItemsHeight; // [Internal] Height of item after a first step and item submission can calculate it float ItemsHeight; // [Internal] Height of item after a first step and item submission can calculate it
ImGuiListClipperFlags Flags; // [Internal] Flags, currently not yet well exposed.
double StartPosY; // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed double StartPosY; // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed
double StartSeekOffsetY; // [Internal] Account for frozen rows in a table and initial loss of precision in very large windows. double StartSeekOffsetY; // [Internal] Account for frozen rows in a table and initial loss of precision in very large windows.
ImGuiContext* Ctx; // [Internal] Parent UI context
void* TempData; // [Internal] Internal data void* TempData; // [Internal] Internal data
ImGuiListClipperFlags Flags; // [Internal] Flags, currently not yet well exposed.
// items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step, and you can call SeekCursorForItem() manually if you need) // items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step, and you can call SeekCursorForItem() manually if you need)
// items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing(). // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing().
@@ -3028,17 +3028,18 @@ struct ImGuiListClipper
// - It is important that we are keeping those disabled by default so they don't leak in user space. // - It is important that we are keeping those disabled by default so they don't leak in user space.
// - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h) // - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h)
// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4. // - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4.
// - We intentionally provide ImVec2*float but not float*ImVec2: this is rare enough and we want to reduce the surface for possible user mistake.
#ifdef IMGUI_DEFINE_MATH_OPERATORS #ifdef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED #define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED
IM_MSVC_RUNTIME_CHECKS_OFF IM_MSVC_RUNTIME_CHECKS_OFF
// ImVec2 operators // ImVec2 operators
inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); }
inline ImVec2 operator*(const float lhs, const ImVec2& rhs) { return ImVec2(lhs * rhs.x, lhs * rhs.y); }
inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); }
inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); }
inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); }
inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); }
inline ImVec2 operator+(const ImVec2& lhs) { return lhs; }
inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); }
inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; }
inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; }
@@ -3050,12 +3051,20 @@ inline bool operator==(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x =
inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; }
// ImVec4 operators // ImVec4 operators
inline ImVec4 operator*(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); } inline ImVec4 operator*(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); }
inline ImVec4 operator*(const float lhs, const ImVec4& rhs) { return ImVec4(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w); }
inline ImVec4 operator/(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs); } inline ImVec4 operator/(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs); }
inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); }
inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); }
inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); }
inline ImVec4 operator/(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w); } inline ImVec4 operator/(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w); }
inline ImVec4 operator+(const ImVec4& lhs) { return lhs; }
inline ImVec4 operator-(const ImVec4& lhs) { return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); } inline ImVec4 operator-(const ImVec4& lhs) { return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); }
inline ImVec4& operator*=(ImVec4& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; lhs.z *= rhs; lhs.w *= rhs; return lhs; }
inline ImVec4& operator/=(ImVec4& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; lhs.z /= rhs; lhs.w /= rhs; return lhs; }
inline ImVec4& operator+=(ImVec4& lhs, const ImVec4& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; lhs.z += rhs.z; lhs.w += rhs.w; return lhs; }
inline ImVec4& operator-=(ImVec4& lhs, const ImVec4& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; lhs.z -= rhs.z; lhs.w -= rhs.w; return lhs; }
inline ImVec4& operator*=(ImVec4& lhs, const ImVec4& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; lhs.z *= rhs.z; lhs.w *= rhs.w; return lhs; }
inline ImVec4& operator/=(ImVec4& lhs, const ImVec4& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; lhs.z /= rhs.z; lhs.w /= rhs.w; return lhs; }
inline bool operator==(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; } inline bool operator==(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; }
inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; } inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; }
IM_MSVC_RUNTIME_CHECKS_RESTORE IM_MSVC_RUNTIME_CHECKS_RESTORE
+1 -1
View File
@@ -1318,7 +1318,7 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa
{ {
const float arc_length = ImAbs(a_max - a_min); const float arc_length = ImAbs(a_max - a_min);
const int circle_segment_count = _CalcCircleAutoSegmentCount(radius); const int circle_segment_count = _CalcCircleAutoSegmentCount(radius);
const int arc_segment_count = ImMax((int)ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0f)), (int)(2.0f * IM_PI / arc_length)); const int arc_segment_count = ImMax((int)ImCeil(circle_segment_count * arc_length / (IM_PI * 2.0f)), 1);
_PathArcToN(center, radius, a_min, a_max, arc_segment_count); _PathArcToN(center, radius, a_min, a_max, arc_segment_count);
} }
} }
+5 -4
View File
@@ -1034,7 +1034,7 @@ enum ImGuiInputTextFlagsPrivate_
{ {
// [Internal] // [Internal]
ImGuiInputTextFlags_Multiline = 1 << 26, // For internal use by InputTextMultiline() ImGuiInputTextFlags_Multiline = 1 << 26, // For internal use by InputTextMultiline()
ImGuiInputTextFlags_MergedItem = 1 << 27, // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match. ImGuiInputTextFlags_TempInput = 1 << 27, // For internal use by TempInputText(), will skip calling ItemAdd(). Require bounding-box to strictly match.
ImGuiInputTextFlags_LocalizeDecimalPoint= 1 << 28, // For internal use by InputScalar() and TempInputScalar() ImGuiInputTextFlags_LocalizeDecimalPoint= 1 << 28, // For internal use by InputScalar() and TempInputScalar()
}; };
@@ -1044,7 +1044,7 @@ enum ImGuiButtonFlagsPrivate_
ImGuiButtonFlags_PressedOnClick = 1 << 4, // return true on click (mouse down event) ImGuiButtonFlags_PressedOnClick = 1 << 4, // return true on click (mouse down event)
ImGuiButtonFlags_PressedOnClickRelease = 1 << 5, // [Default] return true on click + release on same item <-- this is what the majority of Button are using ImGuiButtonFlags_PressedOnClickRelease = 1 << 5, // [Default] return true on click + release on same item <-- this is what the majority of Button are using
ImGuiButtonFlags_PressedOnClickReleaseAnywhere = 1 << 6, // return true on click + release even if the release event is not done while hovering the item ImGuiButtonFlags_PressedOnClickReleaseAnywhere = 1 << 6, // return true on click + release even if the release event is not done while hovering the item
ImGuiButtonFlags_PressedOnRelease = 1 << 7, // return true on release (default requires click+release) ImGuiButtonFlags_PressedOnRelease = 1 << 7, // return true on release (default requires click+release). Prior to 2026/03/20 this implied ImGuiButtonFlags_NoHoldingActiveId but they are separate now.
ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8, // return true on double-click (default requires click+release) ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8, // return true on double-click (default requires click+release)
ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers)
//ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat -> use ImGuiItemFlags_ButtonRepeat instead. //ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat -> use ImGuiItemFlags_ButtonRepeat instead.
@@ -3279,7 +3279,7 @@ struct IMGUI_API ImGuiTable
ImGuiTableColumnIdx LastResizedColumn; // Index of column being resized from previous frame. ImGuiTableColumnIdx LastResizedColumn; // Index of column being resized from previous frame.
ImGuiTableColumnIdx HeldHeaderColumn; // Index of column header being held. ImGuiTableColumnIdx HeldHeaderColumn; // Index of column header being held.
ImGuiTableColumnIdx ReorderColumn; // Index of column being reordered. (not cleared) ImGuiTableColumnIdx ReorderColumn; // Index of column being reordered. (not cleared)
ImGuiTableColumnIdx ReorderColumnDir; // -1 or +1 ImGuiTableColumnIdx ReorderColumnDstOrder; // Requested display order of column being reordered.
ImGuiTableColumnIdx LeftMostEnabledColumn; // Index of left-most non-hidden column. ImGuiTableColumnIdx LeftMostEnabledColumn; // Index of left-most non-hidden column.
ImGuiTableColumnIdx RightMostEnabledColumn; // Index of right-most non-hidden column. ImGuiTableColumnIdx RightMostEnabledColumn; // Index of right-most non-hidden column.
ImGuiTableColumnIdx LeftMostStretchedColumn; // Index of left-most stretched column. ImGuiTableColumnIdx LeftMostStretchedColumn; // Index of left-most stretched column.
@@ -3852,6 +3852,7 @@ namespace ImGui
IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n);
IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table);
IMGUI_API void TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order); IMGUI_API void TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order);
IMGUI_API void TableQueueSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order);
IMGUI_API void TableRemove(ImGuiTable* table); IMGUI_API void TableRemove(ImGuiTable* table);
IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table); IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table);
IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table); IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table);
@@ -3982,7 +3983,7 @@ namespace ImGui
// InputText // InputText
IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
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, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = 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); 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
+32 -26
View File
@@ -702,21 +702,11 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table)
// Note: we don't clear ReorderColumn after handling the request (FIXME: clarify why or add a test). // Note: we don't clear ReorderColumn after handling the request (FIXME: clarify why or add a test).
if (table->InstanceCurrent == 0) if (table->InstanceCurrent == 0)
{ {
if (table->HeldHeaderColumn == -1 && table->ReorderColumn != -1)
table->ReorderColumn = -1;
table->HeldHeaderColumn = -1; table->HeldHeaderColumn = -1;
if (table->ReorderColumn != -1 && table->ReorderColumnDir != 0) if (table->ReorderColumn != -1 && table->ReorderColumnDstOrder != -1)
{ {
// We need to handle reordering across hidden columns. TableSetColumnDisplayOrder(table, table->ReorderColumn, table->ReorderColumnDstOrder);
// In the configuration below, moving C to the right of E will lead to: table->ReorderColumnDstOrder = -1;
// ... C [D] E ---> ... [D] E C (Column name/index)
// ... 2 3 4 ... 2 3 4 (Display order)
IM_ASSERT(table->ReorderColumnDir == -1 || table->ReorderColumnDir == +1);
IM_ASSERT(table->Flags & ImGuiTableFlags_Reorderable);
ImGuiTableColumn* src_column = &table->Columns[table->ReorderColumn];
ImGuiTableColumn* dst_column = &table->Columns[(table->ReorderColumnDir < 0) ? src_column->PrevEnabledColumn : src_column->NextEnabledColumn];
TableSetColumnDisplayOrder(table, table->ReorderColumn, dst_column->DisplayOrder);
table->ReorderColumnDir = 0;
} }
} }
@@ -730,8 +720,7 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table)
} }
} }
// Note that TableSetupScrollFreeze() enforce a display order range for frozen columns. // Apply immediately. See TableQueueSetColumnDisplayOrder() for additional checks/constraints.
// So reordering a column across the frozen column barrier is illegal and will be undone.
void ImGui::TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order) void ImGui::TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order)
{ {
IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount);
@@ -755,6 +744,25 @@ void ImGui::TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_
table->IsSettingsDirty = true; table->IsSettingsDirty = true;
} }
// Reorder requested by user indirection needs to verify
// - That we don't reorder columns with the ImGuiTableColumnFlags_NoReorder flag.
// - That we don't cross the frozen column limit.
// (that TableSetupScrollFreeze() enforce a display order range for frozen columns.
// so reordering a column across the frozen column barrier is illegal and will be undone.)
void ImGui::TableQueueSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order)
{
ImGuiTableColumn* src_column = &table->Columns[column_n];
ImGuiTableColumn* dst_column = &table->Columns[table->DisplayOrderToIndex[dst_order]];
if ((src_column->Flags | dst_column->Flags) & ImGuiTableColumnFlags_NoReorder) // FIXME: Perform a sweep test?
return;
int src_i = (src_column->IndexWithinEnabledSet != -1) ? src_column->IndexWithinEnabledSet : table->Columns.index_from_ptr(src_column); // FIXME: Hidden columns don't count into the FreezeColumns count, so what to do here is ill-defined. For now we use regular index.
int dst_i = (dst_column->IndexWithinEnabledSet != -1) ? dst_column->IndexWithinEnabledSet : table->Columns.index_from_ptr(dst_column);
if ((src_i < table->FreezeColumnsRequest) != (dst_i < table->FreezeColumnsRequest))
return;
table->ReorderColumn = (ImGuiTableColumnIdx)column_n;
table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)dst_order;
}
// Adjust flags: default width mode + stretch columns are not allowed when auto extending // Adjust flags: default width mode + stretch columns are not allowed when auto extending
static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in) static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in)
{ {
@@ -3224,21 +3232,19 @@ void ImGui::TableHeader(const char* label)
// FIXME-TABLE: Scroll request while reordering a column and it lands out of the scrolling zone. // FIXME-TABLE: Scroll request while reordering a column and it lands out of the scrolling zone.
if (held && (table->Flags & ImGuiTableFlags_Reorderable) && IsMouseDragging(0) && !g.DragDropActive) if (held && (table->Flags & ImGuiTableFlags_Reorderable) && IsMouseDragging(0) && !g.DragDropActive)
{ {
// While moving a column it will jump on the other side of the mouse, so we also test for MouseDelta.x // - While moving a column it will jump on the other side of the mouse, so we also test for MouseDelta.x
table->ReorderColumn = (ImGuiTableColumnIdx)column_n; // - We need to handle reordering across hidden columns.
// In the configuration below, moving C to the right of E will lead to:
// ... C [D] E ---> ... [D] E C (Column name/index)
// ... 2 3 4 ... 2 3 4 (Display order)
// - The other constraints are enforced by TableQueueSetColumnDisplayOrder() which might early out.
table->InstanceInteracted = table->InstanceCurrent; table->InstanceInteracted = table->InstanceCurrent;
// We don't reorder: through the frozen<>unfrozen line, or through a column that is marked with ImGuiTableColumnFlags_NoReorder.
if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < cell_r.Min.x) if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < cell_r.Min.x)
if (ImGuiTableColumn* prev_column = (column->PrevEnabledColumn != -1) ? &table->Columns[column->PrevEnabledColumn] : NULL) if (ImGuiTableColumn* prev_column = (column->PrevEnabledColumn != -1) ? &table->Columns[column->PrevEnabledColumn] : NULL)
if (!((column->Flags | prev_column->Flags) & ImGuiTableColumnFlags_NoReorder)) TableQueueSetColumnDisplayOrder(table, column_n, prev_column->DisplayOrder);
if ((column->IndexWithinEnabledSet < table->FreezeColumnsRequest) == (prev_column->IndexWithinEnabledSet < table->FreezeColumnsRequest))
table->ReorderColumnDir = -1;
if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > cell_r.Max.x) if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > cell_r.Max.x)
if (ImGuiTableColumn* next_column = (column->NextEnabledColumn != -1) ? &table->Columns[column->NextEnabledColumn] : NULL) if (ImGuiTableColumn* next_column = (column->NextEnabledColumn != -1) ? &table->Columns[column->NextEnabledColumn] : NULL)
if (!((column->Flags | next_column->Flags) & ImGuiTableColumnFlags_NoReorder)) TableQueueSetColumnDisplayOrder(table, column_n, next_column->DisplayOrder);
if ((column->IndexWithinEnabledSet < table->FreezeColumnsRequest) == (next_column->IndexWithinEnabledSet < table->FreezeColumnsRequest))
table->ReorderColumnDir = +1;
} }
// Sort order arrow // Sort order arrow
@@ -3277,7 +3283,7 @@ void ImGui::TableHeader(const char* label)
SetItemTooltip("%.*s", (int)(label_end - label), label); SetItemTooltip("%.*s", (int)(label_end - label), label);
// We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden // We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden
if (IsMouseReleased(1) && IsItemHovered()) if (IsPopupOpenRequestForItem(ImGuiPopupFlags_None, id))
TableOpenContextMenu(column_n); TableOpenContextMenu(column_n);
} }
+32 -18
View File
@@ -653,6 +653,14 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
FocusWindow(window, ImGuiFocusRequestFlags_RestoreFocusedChild); // Still need to focus and bring to front, but try to avoid losing NavId when navigating a child FocusWindow(window, ImGuiFocusRequestFlags_RestoreFocusedChild); // Still need to focus and bring to front, but try to avoid losing NavId when navigating a child
} }
} }
if (flags & ImGuiButtonFlags_PressedOnRelease)
{
// FIXME: Traditionally ImGuiButtonFlags_PressedOnRelease never took ActiveId. Adding it in 2026-03-20 since ImGuiButtonFlags_NoHoldingActiveId can always be added.
// We don't yet perform an explicit ClearActiveID() to reduce scope of change, but this possibility could be investigated.
if (!(flags & ImGuiButtonFlags_NoHoldingActiveId))
SetActiveID(id, window); // Hold on ID
g.ActiveIdMouseButton = (ImS8)mouse_button_clicked;
}
} }
if (flags & ImGuiButtonFlags_PressedOnRelease) if (flags & ImGuiButtonFlags_PressedOnRelease)
{ {
@@ -3693,27 +3701,33 @@ int ImParseFormatPrecision(const char* fmt, int default_precision)
} }
// Create text input in place of another active widget (e.g. used when doing a Ctrl+Click on drag/slider widgets) // Create text input in place of another active widget (e.g. used when doing a Ctrl+Click on drag/slider widgets)
// - This must be submitted right after the item it is overlaying.
// FIXME: Facilitate using this in variety of other situations. // FIXME: Facilitate using this in variety of other situations.
// FIXME: Among other things, setting ImGuiItemFlags_AllowDuplicateId in LastItemData is currently correct but bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
// the expected relationship between TempInputXXX functions and LastItemData is a little fishy.
bool ImGui::TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags)
{ {
// On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id. // On the first frame, g.TempInputTextId == 0, then on subsequent frames it becomes == id.
// We clear ActiveID on the first frame to allow the InputText() taking it back. // We clear ActiveID on the first frame to allow the InputText() taking it back.
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
const bool init = (g.TempInputId != id); const bool init = (g.TempInputId != id);
if (init) if (init)
ClearActiveID(); ClearActiveID();
g.CurrentWindow->DC.CursorPos = bb.Min; ImVec2 backup_pos = window->DC.CursorPos;
g.LastItemData.ItemFlags |= ImGuiItemFlags_AllowDuplicateId; window->DC.CursorPos = bb.Min;
bool value_changed = InputTextEx(label, NULL, buf, buf_size, bb.GetSize(), flags | ImGuiInputTextFlags_MergedItem); g.LastItemData.ItemFlags |= ImGuiItemFlags_AllowDuplicateId; // Using ImGuiInputTextFlags_MergedItem above will skip ItemAdd() so we poke here.
bool value_changed = InputTextEx(label, NULL, buf, (int)buf_size, bb.GetSize(), flags | ImGuiInputTextFlags_TempInput | ImGuiInputTextFlags_AutoSelectAll, callback, user_data);
KeepAliveID(id); // Not done because of ImGuiInputTextFlags_TempInput
if (init) if (init)
{ {
// First frame we started displaying the InputText widget, we expect it to take the active id. // First frame we started displaying the InputText widget, we expect it to take the active id.
IM_ASSERT(g.ActiveId == id); IM_ASSERT(g.ActiveId == id);
g.TempInputId = g.ActiveId; g.TempInputId = g.ActiveId;
} }
if (g.ActiveId != id)
g.TempInputId = 0;
window->DC.CursorPos = backup_pos;
return value_changed; return value_changed;
} }
@@ -4748,7 +4762,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
{ {
// Support for internal ImGuiInputTextFlags_MergedItem flag, which could be redesigned as an ItemFlags if needed (with test performed in ItemAdd) // Support for internal ImGuiInputTextFlags_MergedItem flag, which could be redesigned as an ItemFlags if needed (with test performed in ItemAdd)
ItemSize(total_bb, style.FramePadding.y); ItemSize(total_bb, style.FramePadding.y);
if (!(flags & ImGuiInputTextFlags_MergedItem)) if (!(flags & ImGuiInputTextFlags_TempInput))
if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable)) if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable))
return false; return false;
} }
@@ -4779,9 +4793,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (is_wordwrap) if (is_wordwrap)
wrap_width = ImMax(1.0f, GetContentRegionAvail().x + (draw_window->ScrollbarY ? 0.0f : -g.Style.ScrollbarSize)); wrap_width = ImMax(1.0f, GetContentRegionAvail().x + (draw_window->ScrollbarY ? 0.0f : -g.Style.ScrollbarSize));
const bool user_clicked = hovered && io.MouseClicked[0];
const bool input_requested_by_nav = (g.ActiveId != id) && (g.NavActivateId == id); const bool input_requested_by_nav = (g.ActiveId != id) && (g.NavActivateId == id);
const bool input_requested_by_reactivate = (g.InputTextReactivateId == id); // for io.ConfigInputTextEnterKeepActive const bool input_requested_by_reactivate = (g.InputTextReactivateId == id); // for io.ConfigInputTextEnterKeepActive
const bool user_clicked = hovered && io.MouseClicked[0]; const bool input_requested_by_user = (user_clicked) || (g.ActiveId == 0 && (flags & ImGuiInputTextFlags_TempInput));
const ImGuiID scrollbar_id = (is_multiline && state != NULL) ? GetWindowScrollbarID(draw_window, ImGuiAxis_Y) : 0; const ImGuiID scrollbar_id = (is_multiline && state != NULL) ? GetWindowScrollbarID(draw_window, ImGuiAxis_Y) : 0;
const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == scrollbar_id; const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == scrollbar_id;
const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == scrollbar_id; const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == scrollbar_id;
@@ -4792,7 +4807,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
const bool init_reload_from_user_buf = (state != NULL && state->WantReloadUserBuf); const bool init_reload_from_user_buf = (state != NULL && state->WantReloadUserBuf);
const bool init_changed_specs = (state != NULL && state->Stb->single_line != !is_multiline); // state != NULL means its our state. const bool init_changed_specs = (state != NULL && state->Stb->single_line != !is_multiline); // state != NULL means its our state.
const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav || input_requested_by_reactivate); const bool init_make_active = (input_requested_by_user || input_requested_by_nav || input_requested_by_reactivate || user_scroll_finish);
if (init_reload_from_user_buf) if (init_reload_from_user_buf)
{ {
int new_len = (int)ImStrlen(buf); int new_len = (int)ImStrlen(buf);
@@ -9257,11 +9272,12 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
PushID(label); PushID(label);
if (!enabled) if (!enabled)
BeginDisabled(); BeginDisabled();
const ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
bool pressed; bool pressed;
// We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another. // We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another.
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_NoAutoClosePopups; const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_NoAutoClosePopups;
ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
{ {
// Menu inside a horizontal menu bar // Menu inside a horizontal menu bar
@@ -9269,9 +9285,8 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
// For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin()
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;
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, pos.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, label_size);
LogSetNextTextDecoration("[", "]"); LogSetNextTextDecoration("[", "]");
RenderText(text_pos, label); RenderText(text_pos, label);
PopStyleVar(); PopStyleVar();
@@ -9285,7 +9300,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
// 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.)
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 = offsets->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, pos.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));
@@ -9470,17 +9485,16 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
BeginDisabled(); BeginDisabled();
// We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another. // We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another.
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SetNavIdOnHover; const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SetNavIdOnHover;
const ImGuiMenuColumns* offsets = &window->DC.MenuColumns; ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
{ {
// Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful
// Note that in this situation: we don't render the shortcut, we render a highlight instead of the selected tick mark. // Note that in this situation: we don't render the shortcut, we render a highlight instead of the selected tick mark.
float w = label_size.x;
window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f); window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f);
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
PushStyleVarX(ImGuiStyleVar_ItemSpacing, style.ItemSpacing.x * 2.0f); PushStyleVarX(ImGuiStyleVar_ItemSpacing, style.ItemSpacing.x * 2.0f);
pressed = Selectable("", selected, selectable_flags, ImVec2(w, 0.0f)); pressed = Selectable("", selected, selectable_flags, ImVec2(label_size.x, 0.0f));
PopStyleVar(); PopStyleVar();
if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)
RenderText(text_pos, label); RenderText(text_pos, label);
@@ -9494,7 +9508,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
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 shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, NULL).x : 0.0f; float shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, 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, shortcut_w, checkmark_w); // Feedback for next frame float min_w = offsets->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); 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));