diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 0e4fb484b..8ac7b8858 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -29,6 +29,7 @@ // CHANGELOG // (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-03-11: Vulkan: Added ImGui_ImplVulkan_PipelineInfo::ExtraDynamicStates[] to allow specifying extra dynamic states to add when creating the VkPipeline. (#9211) // 2025-09-26: [Helpers] *BREAKING CHANGE*: Vulkan: Helper ImGui_ImplVulkanH_DestroyWindow() does not call vkDestroySurfaceKHR(): as surface is created by caller of ImGui_ImplVulkanH_CreateOrResizeWindow(), it is more consistent that we don't destroy it. (#9163) // 2026-01-05: [Helpers] *BREAKING CHANGE*: Vulkan: Helper for creating render pass uses ImGui_ImplVulkanH_Window::AttachmentDesc to create render pass. Removed ClearEnabled. (#9152) // 2025-11-24: [Helpers] Vulkan: Helper for creating a swap-chain (used by examples and multi-viewports) selects VkSwapchainCreateInfoKHR's compositeAlpha based on cap.supportedCompositeAlpha. (#8784) @@ -1040,11 +1041,13 @@ static VkPipeline ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAlloc blend_info.attachmentCount = 1; blend_info.pAttachments = color_attachment; - VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + ImVector dynamic_states = info->ExtraDynamicStates; + dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); + dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR); VkPipelineDynamicStateCreateInfo dynamic_state = {}; dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamic_state.dynamicStateCount = (uint32_t)IM_COUNTOF(dynamic_states); - dynamic_state.pDynamicStates = dynamic_states; + dynamic_state.dynamicStateCount = dynamic_states.Size; + dynamic_state.pDynamicStates = dynamic_states.Data; VkGraphicsPipelineCreateInfo create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index f84080097..503643130 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -90,6 +90,7 @@ struct ImGui_ImplVulkan_PipelineInfo // For Main and Secondary viewports uint32_t Subpass; // VkSampleCountFlagBits MSAASamples = {}; // 0 defaults to VK_SAMPLE_COUNT_1_BIT + ImVector ExtraDynamicStates; // Optional, allows to insert more dynamic states into our VkPipeline #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; // Optional, valid if .sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR #endif diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index a8d39245d..09d8db6a8 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -22,6 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 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-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-12: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. (#8465) @@ -60,11 +61,8 @@ #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) == defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) #error Exactly one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be defined! #endif - -// This condition is true when it's built with EMSCRIPTEN using -sUSE_WEBGPU=1 flag (deprecated from 4.0.10) -// This condition is false for all other 3 cases: WGPU-Native, DAWN-Native or DAWN-EMSCRIPTEN (using --use-port=emdawnwebgpu flag) #if defined(__EMSCRIPTEN__) && defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN +#error Emscripten <4.0.10 with '-sUSE_WEBGPU=1' is not supported anymore. #endif #ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN @@ -263,15 +261,9 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const c { ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) WGPUShaderSourceWGSL wgsl_desc = {}; wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL; wgsl_desc.code = { wgsl_source, WGPU_STRLEN }; -#else - WGPUShaderModuleWGSLDescriptor wgsl_desc = {}; - wgsl_desc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor; - wgsl_desc.code = wgsl_source; -#endif WGPUShaderModuleDescriptor desc = {}; desc.nextInChain = (WGPUChainedStruct*)&wgsl_desc; @@ -279,11 +271,7 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const c WGPUProgrammableStageDescriptor stage_desc = {}; stage_desc.module = wgpuDeviceCreateShaderModule(bd->wgpuDevice, &desc); -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) stage_desc.entryPoint = { "main", WGPU_STRLEN }; -#else - stage_desc.entryPoint = "main"; -#endif return stage_desc; } @@ -402,11 +390,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder WGPUBufferDescriptor vb_desc = { nullptr, -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) { "Dear ImGui Vertex buffer", WGPU_STRLEN, }, -#else - "Dear ImGui Vertex buffer", -#endif WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex, MEMALIGN(fr->VertexBufferSize * sizeof(ImDrawVert), 4), false @@ -430,11 +414,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder WGPUBufferDescriptor ib_desc = { nullptr, -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) { "Dear ImGui Index buffer", WGPU_STRLEN, }, -#else - "Dear ImGui Index buffer", -#endif WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index, MEMALIGN(fr->IndexBufferSize * sizeof(ImDrawIdx), 4), false @@ -566,11 +546,7 @@ void ImGui_ImplWGPU_UpdateTexture(ImTextureData* tex) // Create texture WGPUTextureDescriptor tex_desc = {}; -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) tex_desc.label = { "Dear ImGui Texture", WGPU_STRLEN }; -#else - tex_desc.label = "Dear ImGui Texture"; -#endif tex_desc.dimension = WGPUTextureDimension_2D; tex_desc.size.width = tex->Width; tex_desc.size.height = tex->Height; @@ -611,20 +587,12 @@ void ImGui_ImplWGPU_UpdateTexture(ImTextureData* tex) // Update full texture or selected blocks. We only ever write to textures regions which have never been used before! // This backend choose to use tex->UpdateRect but you can use tex->Updates[] to upload individual regions. -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) WGPUTexelCopyTextureInfo dst_view = {}; -#else - WGPUImageCopyTexture dst_view = {}; -#endif dst_view.texture = backend_tex->Texture; dst_view.mipLevel = 0; dst_view.origin = { (uint32_t)upload_x, (uint32_t)upload_y, 0 }; dst_view.aspect = WGPUTextureAspect_All; -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) WGPUTexelCopyBufferLayout layout = {}; -#else - WGPUTextureDataLayout layout = {}; -#endif layout.offset = 0; layout.bytesPerRow = tex->Width * tex->BytesPerPixel; layout.rowsPerImage = upload_h; @@ -642,11 +610,7 @@ static void ImGui_ImplWGPU_CreateUniformBuffer() WGPUBufferDescriptor ub_desc = { nullptr, -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) { "Dear ImGui Uniform buffer", WGPU_STRLEN, }, -#else - "Dear ImGui Uniform buffer", -#endif WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform, MEMALIGN(sizeof(Uniforms), 16), false @@ -758,11 +722,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() // Create depth-stencil State WGPUDepthStencilState depth_stencil_state = {}; depth_stencil_state.format = bd->depthStencilFormat; -#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU_EMSCRIPTEN) depth_stencil_state.depthWriteEnabled = WGPUOptionalBool_False; -#else - depth_stencil_state.depthWriteEnabled = false; -#endif depth_stencil_state.depthCompare = WGPUCompareFunction_Always; depth_stencil_state.stencilFront.compare = WGPUCompareFunction_Always; depth_stencil_state.stencilFront.failOp = WGPUStencilOperation_Keep; @@ -847,11 +807,7 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info) io.BackendRendererName = "imgui_impl_wgpu (Dawn, Native)"; #endif #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#if defined(__EMSCRIPTEN__) - io.BackendRendererName = "imgui_impl_wgpu (WGPU, Emscripten)"; // linked using EMSCRIPTEN with "-sUSE_WEBGPU=1" flag, deprecated from EMSCRIPTEN 4.0.10 -#else io.BackendRendererName = "imgui_impl_wgpu (WGPU, Native)"; -#endif #endif 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. diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index 4e616a311..39797f035 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -5,7 +5,8 @@ // When targeting native platforms: // - One of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU *must* be provided. // When targeting Emscripten: -// - We now defaults to IMGUI_IMPL_WEBGPU_BACKEND_DAWN is Emscripten version is 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). // - We can still define IMGUI_IMPL_WEBGPU_BACKEND_WGPU to use Emscripten '-s USE_WEBGPU=1' which is marked as obsolete by Emscripten. // Add #define to your imconfig.h file, or as a compilation flag in your build system. // This requirement may be removed once WebGPU stabilizes and backends converge on a unified interface. @@ -35,20 +36,7 @@ // Setup Emscripten default if not specified. #if defined(__EMSCRIPTEN__) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) #include - -#ifdef __EMSCRIPTEN_MAJOR__ -#if (__EMSCRIPTEN_MAJOR__ >= 5) || ((__EMSCRIPTEN_MAJOR__ >= 4) && (__EMSCRIPTEN_MINOR__ >= 0) && (__EMSCRIPTEN_TINY__ >= 10)) #define IMGUI_IMPL_WEBGPU_BACKEND_DAWN -#else -#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU -#endif -#else -#if (__EMSCRIPTEN_major__ >= 4) && (__EMSCRIPTEN_minor__ >= 0) && (__EMSCRIPTEN_tiny__ >= 10) -#define IMGUI_IMPL_WEBGPU_BACKEND_DAWN -#else -#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU -#endif -#endif #endif #include @@ -111,7 +99,7 @@ const char* ImGui_ImplWGPU_GetAdapterTypeName(WGPUAdapterType type); #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) const char* ImGui_ImplWGPU_GetDeviceLostReasonName(WGPUDeviceLostReason type); const char* ImGui_ImplWGPU_GetErrorTypeName(WGPUErrorType type); -#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(__EMSCRIPTEN__) +#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) const char* ImGui_ImplWGPU_GetLogLevelName(WGPULogLevel level); #endif diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7bcbca8a7..6c93252f5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,18 @@ HOW TO UPDATE? Breaking Changes: + - Separator(): fixed a legacy quirk where Separator() was submitting a zero-height + item for layout purpose, even though it draws a 1-pixel separator. + The fix could affect code e.g. computing height from multiple widgets in order to + allocate vertical space for a footer or multi-line status bar. (#2657, #9263) + The "Console" example had such a bug: + float footer_height = style.ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + BeginChild("ScrollingRegion", { 0, -footer_height }); + Should be: + float footer_height = style.ItemSpacing.y + style.SeparatorSize + ImGui::GetFrameHeightWithSpacing(); + BeginChild("ScrollingRegion", { 0, -footer_height }); + When such idiom was used and assuming zero-height Separator, it is likely that + in 1.92.7 the resulting window will have unexpected 1 pixel scrolling range. - Combo(), ListBox(): commented out legacy signatures which were obsoleted in 1.90 (Nov 2023), when the getter callback type was changed from: getter type: bool (*getter)(void* user_data, int idx, const char** out_text) @@ -60,22 +72,44 @@ Other Changes: - InputText: - Shift+Enter in multi-line editor always adds a new line, regardless of ImGuiInputTextFlags_CtrlEnterForNewLine being set or not. (#9239) -- Style: border sizes are now scaled (and rounded) by ScaleAllSizes(). -- Demo: fixed IMGUI_DEMO_MARKER locations for examples applets. (#9261, #3689) [@pthom] + - Reworked io.ConfigInputTextEnterKeepActive mode so that pressing Enter will + deactivate/reactivate the item in order for e.g. IsItemDeactivatedAfterEdit() + signals to be emitted the same way regardless of that setting. (#9001, #9115) +- Style: + - Border sizes are now scaled (and rounded) by ScaleAllSizes(). + - When using large values with ScallAllSizes(), the following items thickness + are scaled to integer amounts: + - InputText Caret/cursor thickness. (#7031) + - CloseButton() thickness. + - TextLink() underline thickness. + - ColorButton() border thickness. + - Separator() thickness, via scaling newly added style.SeparatorSize. (#2657, #9263) - Clipper: - Clear `DisplayStart`/`DisplayEnd` fields when `Step()` returns false. - Added `UserIndex` helper storage. This is solely a convenience for cases where you may want to carry an index around. +- Scrollbar: + - 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 + mouse at the extreme of the screen will reach the scrollbar. (#9276) +- Demo: fixed IMGUI_DEMO_MARKER locations for examples applets. (#9261, #3689) [@pthom] - Backends: - SDLGPU3: removed unnecessary call to SDL_WaitForGPUIdle when releasing vertex/index buffers. (#9262) [@jaenis] - WebGPU: fixed version check for Emscripten 5.0.0+. + - WebGPU: removed support for Emscripten <4.0.10. (#9281) [@ypujante] - Examples: - 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 (e.g. pongasoft/emscripten-glfw) not receive focus loss events. (#9259) [@pthom] - - WGPU: fixed undefined behaviors in example code for requesting adapter + - Emscripten: fixed minor rendering issues with our HTML shell. (#9281) [@ypujante] + - hidden small blue outline when canvas is focused on Chrome. + - hidden scrollbar in Firefox. + - Vulkan: added ImGui_ImplVulkan_PipelineInfo::ExtraDynamicStates[] to allow specifying + extra dynamic states to add when creating the VkPipeline. (#9211) [@DziubanMaciej] + - WebGPU: fixed undefined behaviors in example code for requesting adapter and device. (#9246, #9256) [@r-lyeh] + - GLFW/SDL2/SDL3+WebGPU: removed suport for Emscripten <4.0.10. (#9281) [@ypujante] Docking+Viewports Branch: diff --git a/docs/FAQ.md b/docs/FAQ.md index 6c9526aa7..05dd777b3 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -55,6 +55,7 @@ or view this file with any Markdown viewer. - Handy [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide to integrate Dear ImGui in an existing application. - 20+ standalone example applications using e.g. OpenGL/DirectX are provided in the [examples/](https://github.com/ocornut/imgui/blob/master/examples/) folder to explain how to integrate Dear ImGui with your own engine/application. You can run those applications and explore them. - See demo code in [imgui_demo.cpp](https://github.com/ocornut/imgui/blob/master/imgui_demo.cpp) and particularly the `ImGui::ShowDemoWindow()` function. The demo covers most features of Dear ImGui, so you can read the code and see its output. +- See pthom's online [imgui_explorer](https://pthom.github.io/imgui_explorer) which is a web version of the demo with a source code browser. - See documentation: [Backends](https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md), [Examples](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md), [Fonts](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md). - See documentation and comments at the top of [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) + general API comments in [imgui.h](https://github.com/ocornut/imgui/blob/master/imgui.h). - The [Glossary](https://github.com/ocornut/imgui/wiki/Glossary) page may be useful. diff --git a/docs/README.md b/docs/README.md index 4f090545a..a409b9301 100644 --- a/docs/README.md +++ b/docs/README.md @@ -110,11 +110,10 @@ Reading the changelogs is a good way to keep up to date with the things Dear ImG ### Demo Calling the `ImGui::ShowDemoWindow()` function will create a demo window showcasing a variety of features and examples. The code is always available for reference in `imgui_demo.cpp`. -- [Web version of the demo](https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html) courtesy of [@pthom](https://github.com/pthom). -- [Screenshot of the demo](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/v167-misc.png). +- [imgui_explorer](https://pthom.github.io/imgui_explorer): Web version of the demo w/ source code browser, courtesy of [@pthom](https://github.com/pthom). You should be able to build the examples from sources. If you don't, let us know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here: -- [imgui-demo-binaries-20250625.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20250625.zip) (Windows, 1.92.0, built 2025/06/25, master) or [older binaries](https://www.dearimgui.com/binaries). +- [imgui-demo-binaries-20260225.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20260225.zip) (Windows, 1.92.6, built 2026/02/25, master) or [older binaries](https://www.dearimgui.com/binaries). ### Gallery diff --git a/examples/example_glfw_wgpu/CMakeLists.txt b/examples/example_glfw_wgpu/CMakeLists.txt index 86291f9e2..f1951cb5d 100644 --- a/examples/example_glfw_wgpu/CMakeLists.txt +++ b/examples/example_glfw_wgpu/CMakeLists.txt @@ -52,23 +52,15 @@ set(IMGUI_EXAMPLE_SOURCE_FILES ) if(EMSCRIPTEN) - if(NOT IMGUI_EMSCRIPTEN_WEBGPU_FLAG) # if IMGUI_EMSCRIPTEN_WEBGPU_FLAG not used, set by current EMSCRIPTEN version - if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "4.0.10") - set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "--use-port=emdawnwebgpu" CACHE STRING "Choose between --use-port=emdawnwebgpu (Dawn implementation of EMSCRIPTEN) and -sUSE_WEBGPU=1 (WGPU implementation of EMSCRIPTEN, deprecated in 4.0.10): default to --use-port=emdawnwebgpu for EMSCRIPTEN >= 4.0.10") - else() - set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "-sUSE_WEBGPU=1" CACHE STRING "Use -sUSE_WEBGPU=1 for EMSCRIPTEN WGPU implementation") - endif() - else() # if IMGUI_EMSCRIPTEN_WEBGPU_FLAG used, check correct version - if(EMSCRIPTEN_VERSION VERSION_LESS "4.0.10" AND "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}" MATCHES "emdawnwebgpu") - # it's necessary EMSCRIPTEN >= v4.0.10 (although "--use-port=path/to/emdawnwebgpu.port.py" is supported/tested from v4.0.8) - message(FATAL_ERROR "emdawnwebgpu needs EMSCRIPTEN version >= 4.0.10") - endif() + if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "4.0.10") + set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "--use-port=emdawnwebgpu" CACHE STRING "Default to --use-port=emdawnwebgpu. You can override to provide your own local port.") + else() + message(FATAL_ERROR "emdawnwebgpu needs EMSCRIPTEN version >= 4.0.10") endif() - if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "3.1.57") + if(NOT IMGUI_EMSCRIPTEN_GLFW3) + # Defaults to contrib.glfw3 because Emscripten version is > 3.1.57 set(IMGUI_EMSCRIPTEN_GLFW3 "--use-port=contrib.glfw3" CACHE STRING "Choose between --use-port=contrib.glfw3 and -sUSE_GLFW=3 for GLFW implementation (default to --use-port=contrib.glfw3)") - else() # cannot use contrib.glfw3 prior to 3.1.57 - set(IMGUI_EMSCRIPTEN_GLFW3 "-sUSE_GLFW=3" CACHE STRING "Use -sUSE_GLFW=3 for GLFW implementation" FORCE) endif() set(LIBRARIES glfw) @@ -165,7 +157,6 @@ endif() # In this example IMGUI_IMPL_WEBGPU_BACKEND_DAWN / IMGUI_IMPL_WEBGPU_BACKEND_WGPU internal define is set according to: # EMSCRIPTEN: by used FLAG # --use-port=emdawnwebgpu --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN defined -# -sUSE_WEBGPU=1 --> IMGUI_IMPL_WEBGPU_BACKEND_WGPU defined # NATIVE: by used SDK installation directory # if IMGUI_DAWN_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN defined # if IMGUI_WGPU_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_WGPU defined @@ -191,12 +182,8 @@ else() # Emscripten settings endif() message(STATUS "Using ${IMGUI_EMSCRIPTEN_GLFW3} GLFW implementation") - if("${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}" MATCHES "emdawnwebgpu") - target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}") - target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN") - else() - target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGPU") - endif() + target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}") + target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN") message(STATUS "Using ${IMGUI_EMSCRIPTEN_WEBGPU_FLAG} WebGPU implementation") target_link_options(${IMGUI_EXECUTABLE} PRIVATE diff --git a/examples/example_glfw_wgpu/Makefile.emscripten b/examples/example_glfw_wgpu/Makefile.emscripten index 8fee2fc7c..ff386fec5 100644 --- a/examples/example_glfw_wgpu/Makefile.emscripten +++ b/examples/example_glfw_wgpu/Makefile.emscripten @@ -19,8 +19,8 @@ WEB_DIR = web EXE = $(WEB_DIR)/index.html IMGUI_DIR = ../.. SOURCES = main.cpp -SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_wgpu.cpp +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) UNAME_S := $(shell uname -s) CPPFLAGS = @@ -40,11 +40,7 @@ LDFLAGS += -s ASYNCIFY=1 LDFLAGS += -s NO_EXIT_RUNTIME=0 LDFLAGS += -s ASSERTIONS=1 -# (1) Using legacy WebGPU implementation (Emscripten < 4.0.10) -#EMS += -DIMGUI_IMPL_WEBGPU_BACKEND_WGPU -#LDFLAGS += -s USE_WEBGPU=1 - -# or (2) Using newer Dawn-based WebGPU port (Emscripten >= 4.0.10) +# Using Dawn-based WebGPU port (requires Emscripten >= 4.0.10) EMS += --use-port=emdawnwebgpu LDFLAGS += --use-port=emdawnwebgpu diff --git a/examples/example_glfw_wgpu/README.md b/examples/example_glfw_wgpu/README.md index 04320d22c..c1c40a59f 100644 --- a/examples/example_glfw_wgpu/README.md +++ b/examples/example_glfw_wgpu/README.md @@ -60,14 +60,10 @@ For the WASM code produced by Emscripten to work correctly, it will also be nece CMake checks the EMSCRIPEN version then: - if EMS >= 4.0.10 uses `--use-port=emdawnwebgpu` flag to build - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - - if EMS < 4.0.10 uses `-sUSE_WEBGPU=1` flag to build - - it set `IMGUI_IMPL_WEBGPU_BACKEND_WGPU` compiler define - -#### Generate Emscripten forcing `-sUSE_WEBGPU=1` deprecated flag even with EMS >= 4.0.10 -- `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="-sUSE_WEBGPU=1" -B where_to_build_dir` - - it set `IMGUI_IMPL_WEBGPU_BACKEND_WGPU` compiler define + - if EMS < 4.0.10 the build aborts (`-sUSE_WEBGPU=1` is no longer supported by our examples and our WGPU backend) #### Generate Emscripten using external WebGPU library (emdawnwebgpu_pkg) + - `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="--use-port=path_to_emdawnwebgpu_pkg" -B where_to_build_dir` - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - *To use external WebGPU library it's necessary to have EMS >= 4.0.10 or the minimum requirements specified by the package:* diff --git a/examples/example_glfw_wgpu/main.cpp b/examples/example_glfw_wgpu/main.cpp index 73764dfee..9ba6398bb 100644 --- a/examples/example_glfw_wgpu/main.cpp +++ b/examples/example_glfw_wgpu/main.cpp @@ -19,9 +19,6 @@ #ifdef __EMSCRIPTEN__ #include #include -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#include -#endif #include "../libs/emscripten/emscripten_mainloop_stub.h" #endif @@ -345,17 +342,6 @@ static WGPUDevice RequestDevice(wgpu::Instance& instance, wgpu::Adapter& adapter return acquired_device.MoveToCHandle(); } #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#ifdef __EMSCRIPTEN__ -// Adapter and device initialization via JS -EM_ASYNC_JS( void, getAdapterAndDeviceViaJS, (), -{ - if (!navigator.gpu) - throw Error("WebGPU not supported."); - const adapter = await navigator.gpu.requestAdapter(); - const device = await adapter.requestDevice(); - Module.preinitializedWebGPUDevice = device; -} ); -#else // __EMSCRIPTEN__ static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestAdapterStatus_Success) @@ -412,7 +398,6 @@ static WGPUDevice RequestDevice(WGPUInstance& instance, WGPUAdapter& adapter) IM_ASSERT(local_device && "Error on Device request"); return local_device; } -#endif // __EMSCRIPTEN__ #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU bool InitWGPU(GLFWwindow* window) @@ -462,23 +447,6 @@ bool InitWGPU(GLFWwindow* window) instanceDesc.requiredFeatures = &timedWaitAny; wgpu_instance = wgpuCreateInstance(&instanceDesc); -#ifdef __EMSCRIPTEN__ - getAdapterAndDeviceViaJS(); - - wgpu_device = emscripten_webgpu_get_device(); - IM_ASSERT(wgpu_device != nullptr && "Error creating the Device"); - - WGPUSurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {}; - html_surface_desc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector; - html_surface_desc.selector = "#canvas"; - - WGPUSurfaceDescriptor surface_desc = {}; - surface_desc.nextInChain = &html_surface_desc.chain; - - // Create the surface. - wgpu_surface = wgpuInstanceCreateSurface(wgpu_instance, &surface_desc); - preferred_fmt = wgpuSurfaceGetPreferredFormat(wgpu_surface, {} /* adapter */); -#else // __EMSCRIPTEN__ wgpuSetLogCallback( [](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr ); @@ -498,7 +466,6 @@ bool InitWGPU(GLFWwindow* window) wgpuSurfaceGetCapabilities(wgpu_surface, adapter, &surface_capabilities); preferred_fmt = surface_capabilities.formats[0]; -#endif // __EMSCRIPTEN__ #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU wgpu_surface_configuration.presentMode = WGPUPresentMode_Fifo; diff --git a/examples/example_sdl2_wgpu/CMakeLists.txt b/examples/example_sdl2_wgpu/CMakeLists.txt index ae0d626a1..c2c45094d 100644 --- a/examples/example_sdl2_wgpu/CMakeLists.txt +++ b/examples/example_sdl2_wgpu/CMakeLists.txt @@ -52,17 +52,10 @@ set(IMGUI_EXAMPLE_SOURCE_FILES ) if(EMSCRIPTEN) - if(NOT IMGUI_EMSCRIPTEN_WEBGPU_FLAG) # if IMGUI_EMSCRIPTEN_WEBGPU_FLAG not used, set by current EMSCRIPTEN version - if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "4.0.10") - set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "--use-port=emdawnwebgpu" CACHE STRING "Choose between --use-port=emdawnwebgpu (Dawn implementation of EMSCRIPTEN) and -sUSE_WEBGPU=1 (WGPU implementation of EMSCRIPTEN, deprecated in 4.0.10): default to --use-port=emdawnwebgpu for EMSCRIPTEN >= 4.0.10") - else() - set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "-sUSE_WEBGPU=1" CACHE STRING "Use -sUSE_WEBGPU=1 for EMSCRIPTEN WGPU implementation") - endif() - else() # if IMGUI_EMSCRIPTEN_WEBGPU_FLAG used, check correct version - if(EMSCRIPTEN_VERSION VERSION_LESS "4.0.10" AND "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}" MATCHES "emdawnwebgpu") - # it's necessary EMSCRIPTEN >= v4.0.10 (although "--use-port=path/to/emdawnwebgpu.port.py" is supported/tested from v4.0.8) - message(FATAL_ERROR "emdawnwebgpu needs EMSCRIPTEN version >= 4.0.10") - endif() + if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "4.0.10") + set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "--use-port=emdawnwebgpu" CACHE STRING "Default to --use-port=emdawnwebgpu. You can override to provide your own local port.") + else() + message(FATAL_ERROR "emdawnwebgpu needs EMSCRIPTEN version >= 4.0.10") endif() add_compile_options(-sDISABLE_EXCEPTION_CATCHING=1 -DIMGUI_DISABLE_FILE_FUNCTIONS=1) @@ -160,7 +153,6 @@ endif() # IMGUI_IMPL_WEBGPU_BACKEND_DAWN/WGPU internal define is set according to: # EMSCRIPTEN: by used FLAG # --use-port=emdawnwebgpu --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN enabled (+EMSCRIPTEN) -# -sUSE_WEBGPU=1 --> IMGUI_IMPL_WEBGPU_BACKEND_WGPU enabled (+EMSCRIPTEN) # NATIVE: by used SDK installation directory # if IMGUI_DAWN_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN enabled # if IMGUI_WGPU_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_WGPU enabled @@ -180,12 +172,8 @@ if(NOT EMSCRIPTEN) # WegGPU-Native settings else() # Emscripten settings set(CMAKE_EXECUTABLE_SUFFIX ".html") - if("${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}" MATCHES "emdawnwebgpu") - target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}") - target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN") - else() - target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGPU") - endif() + target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}") + target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN") message(STATUS "Using ${IMGUI_EMSCRIPTEN_WEBGPU_FLAG} WebGPU implementation") target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "-sUSE_SDL=2") diff --git a/examples/example_sdl2_wgpu/Makefile.emscripten b/examples/example_sdl2_wgpu/Makefile.emscripten index 69bcb00e7..ebc7f97c9 100644 --- a/examples/example_sdl2_wgpu/Makefile.emscripten +++ b/examples/example_sdl2_wgpu/Makefile.emscripten @@ -19,8 +19,8 @@ WEB_DIR = web EXE = $(WEB_DIR)/index.html IMGUI_DIR = ../.. SOURCES = main.cpp -SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_wgpu.cpp +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) UNAME_S := $(shell uname -s) CPPFLAGS = @@ -40,11 +40,7 @@ LDFLAGS += -s ASYNCIFY=1 LDFLAGS += -s NO_EXIT_RUNTIME=0 LDFLAGS += -s ASSERTIONS=1 -# (1) Using legacy WebGPU implementation (Emscripten < 4.0.10) -#EMS += -DIMGUI_IMPL_WEBGPU_BACKEND_WGPU -#LDFLAGS += -s USE_WEBGPU=1 - -# or (2) Using newer Dawn-based WebGPU port (Emscripten >= 4.0.10) +# Using Dawn-based WebGPU port (requires Emscripten >= 4.0.10) EMS += --use-port=emdawnwebgpu LDFLAGS += --use-port=emdawnwebgpu diff --git a/examples/example_sdl2_wgpu/README.md b/examples/example_sdl2_wgpu/README.md index afba7b857..3a0f2a630 100644 --- a/examples/example_sdl2_wgpu/README.md +++ b/examples/example_sdl2_wgpu/README.md @@ -60,14 +60,10 @@ For the WASM code produced by Emscripten to work correctly, it will also be nece CMake checks the EMSCRIPEN version then: - if EMS >= 4.0.10 uses `--use-port=emdawnwebgpu` flag to build - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - - if EMS < 4.0.10 uses `-sUSE_WEBGPU=1` flag to build - - it set `IMGUI_IMPL_WEBGPU_BACKEND_WGPU` compiler define - -#### Generate Emscripten forcing `-sUSE_WEBGPU=1` deprecated flag even with EMS >= 4.0.10 -- `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="-sUSE_WEBGPU=1" -B where_to_build_dir` - - it set `IMGUI_IMPL_WEBGPU_BACKEND_WGPU` compiler define + - if EMS < 4.0.10 the build aborts (`-sUSE_WEBGPU=1` is no longer supported by our examples and our WGPU backend) #### Generate Emscripten using external WebGPU library (emdawnwebgpu_pkg) + - `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="--use-port=path_to_emdawnwebgpu_pkg" -B where_to_build_dir` - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - *To use external WebGPU library it's necessary to have EMS >= 4.0.10 or the minimum requirements specified by the package:* diff --git a/examples/example_sdl2_wgpu/main.cpp b/examples/example_sdl2_wgpu/main.cpp index 66bd77015..b4c1be965 100644 --- a/examples/example_sdl2_wgpu/main.cpp +++ b/examples/example_sdl2_wgpu/main.cpp @@ -18,9 +18,6 @@ #ifdef __EMSCRIPTEN__ #include #include -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#include -#endif #include "../libs/emscripten/emscripten_mainloop_stub.h" #endif @@ -328,17 +325,6 @@ static WGPUDevice RequestDevice(wgpu::Instance& instance, wgpu::Adapter& adapter return acquired_device.MoveToCHandle(); } #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#ifdef __EMSCRIPTEN__ -// Adapter and device initialization via JS -EM_ASYNC_JS( void, getAdapterAndDeviceViaJS, (), -{ - if (!navigator.gpu) - throw Error("WebGPU not supported."); - const adapter = await navigator.gpu.requestAdapter(); - const device = await adapter.requestDevice(); - Module.preinitializedWebGPUDevice = device; -} ); -#else // __EMSCRIPTEN__ static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestAdapterStatus_Success) @@ -395,7 +381,6 @@ static WGPUDevice RequestDevice(WGPUInstance& instance, WGPUAdapter& adapter) IM_ASSERT(local_device && "Error on Device request"); return local_device; } -#endif // __EMSCRIPTEN__ #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU static bool InitWGPU(SDL_Window* window) @@ -446,23 +431,6 @@ static bool InitWGPU(SDL_Window* window) instanceDesc.requiredFeatures = &timedWaitAny; wgpu_instance = wgpuCreateInstance(&instanceDesc); -#ifdef __EMSCRIPTEN__ - getAdapterAndDeviceViaJS(); - - wgpu_device = emscripten_webgpu_get_device(); - assert(wgpu_device != nullptr && "Error creating the Device"); - - WGPUSurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {}; - html_surface_desc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector; - html_surface_desc.selector = "#canvas"; - - WGPUSurfaceDescriptor surface_desc = {}; - surface_desc.nextInChain = &html_surface_desc.chain; - - // Create the surface. - wgpu_surface = wgpuInstanceCreateSurface(wgpu_instance, &surface_desc); - preferred_fmt = wgpuSurfaceGetPreferredFormat(wgpu_surface, {} /* adapter */); -#else // __EMSCRIPTEN__ wgpuSetLogCallback( [](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr ); @@ -482,7 +450,6 @@ static bool InitWGPU(SDL_Window* window) wgpuSurfaceGetCapabilities(wgpu_surface, adapter, &surface_capabilities); preferred_fmt = surface_capabilities.formats[0]; -#endif // __EMSCRIPTEN__ #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU wgpu_surface_configuration.presentMode = WGPUPresentMode_Fifo; diff --git a/examples/example_sdl3_wgpu/CMakeLists.txt b/examples/example_sdl3_wgpu/CMakeLists.txt index 2f3d48f62..6e418821c 100644 --- a/examples/example_sdl3_wgpu/CMakeLists.txt +++ b/examples/example_sdl3_wgpu/CMakeLists.txt @@ -55,18 +55,8 @@ if(EMSCRIPTEN) if(EMSCRIPTEN_VERSION VERSION_LESS "4.0.15") message(FATAL_ERROR "Using Emscripten with SDL3 needs Emscripten version >= 4.0.15") endif() - if(NOT IMGUI_EMSCRIPTEN_WEBGPU_FLAG) # if IMGUI_EMSCRIPTEN_WEBGPU_FLAG not used, set by current EMSCRIPTEN version - if(EMSCRIPTEN_VERSION VERSION_GREATER_EQUAL "4.0.10") - set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "--use-port=emdawnwebgpu" CACHE STRING "Choose between --use-port=emdawnwebgpu (Dawn implementation of EMSCRIPTEN) and -sUSE_WEBGPU=1 (WGPU implementation of EMSCRIPTEN, deprecated in 4.0.10): default to --use-port=emdawnwebgpu for EMSCRIPTEN >= 4.0.10") - else() - set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "-sUSE_WEBGPU=1" CACHE STRING "Use -sUSE_WEBGPU=1 for EMSCRIPTEN WGPU implementation") - endif() - else() # if IMGUI_EMSCRIPTEN_WEBGPU_FLAG used, check correct version - if(EMSCRIPTEN_VERSION VERSION_LESS "4.0.10" AND "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}" MATCHES "emdawnwebgpu") - # it's necessary EMSCRIPTEN >= v4.0.10 (although "--use-port=path/to/emdawnwebgpu.port.py" is supported/tested from v4.0.8) - message(FATAL_ERROR "emdawnwebgpu needs EMSCRIPTEN version >= 4.0.10") - endif() - endif() + # emdawnwebgpu was introduced in 4.0.10 so, due to the prior requirement, this will work + set(IMGUI_EMSCRIPTEN_WEBGPU_FLAG "--use-port=emdawnwebgpu" CACHE STRING "Default to --use-port=emdawnwebgpu. You can override to provide your own local port.") add_compile_options(-sDISABLE_EXCEPTION_CATCHING=1 -DIMGUI_DISABLE_FILE_FUNCTIONS=1) else() # Native/Desktop build @@ -162,7 +152,6 @@ endif() # IMGUI_IMPL_WEBGPU_BACKEND_DAWN/WGPU internal define is set according to: # EMSCRIPTEN: by used FLAG # --use-port=emdawnwebgpu --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN enabled (+EMSCRIPTEN) -# -sUSE_WEBGPU=1 --> IMGUI_IMPL_WEBGPU_BACKEND_WGPU enabled (+EMSCRIPTEN) # NATIVE: by used SDK installation directory # if IMGUI_DAWN_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_DAWN enabled # if IMGUI_WGPU_DIR is valid --> IMGUI_IMPL_WEBGPU_BACKEND_WGPU enabled @@ -182,12 +171,8 @@ if(NOT EMSCRIPTEN) # WegGPU-Native settings else() # Emscripten settings set(CMAKE_EXECUTABLE_SUFFIX ".html") - if("${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}" MATCHES "emdawnwebgpu") - target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}") - target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN") - else() - target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGPU") - endif() + target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "${IMGUI_EMSCRIPTEN_WEBGPU_FLAG}") + target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_DAWN") message(STATUS "Using ${IMGUI_EMSCRIPTEN_WEBGPU_FLAG} WebGPU implementation") target_compile_options(${IMGUI_EXECUTABLE} PUBLIC "-sUSE_SDL=3") diff --git a/examples/example_sdl3_wgpu/Makefile.emscripten b/examples/example_sdl3_wgpu/Makefile.emscripten index 58639a1fd..c84acc77f 100644 --- a/examples/example_sdl3_wgpu/Makefile.emscripten +++ b/examples/example_sdl3_wgpu/Makefile.emscripten @@ -19,8 +19,8 @@ WEB_DIR = web EXE = $(WEB_DIR)/index.html IMGUI_DIR = ../.. SOURCES = main.cpp -SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_wgpu.cpp +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) UNAME_S := $(shell uname -s) CPPFLAGS = @@ -40,11 +40,7 @@ LDFLAGS += -s ASYNCIFY=1 LDFLAGS += -s NO_EXIT_RUNTIME=0 LDFLAGS += -s ASSERTIONS=1 -# (1) Using legacy WebGPU implementation (Emscripten < 4.0.10) -#EMS += -DIMGUI_IMPL_WEBGPU_BACKEND_WGPU -#LDFLAGS += -s USE_WEBGPU=1 - -# or (2) Using newer Dawn-based WebGPU port (Emscripten >= 4.0.10) +# Using Dawn-based WebGPU port (requires Emscripten >= 4.0.10) EMS += --use-port=emdawnwebgpu LDFLAGS += --use-port=emdawnwebgpu diff --git a/examples/example_sdl3_wgpu/README.md b/examples/example_sdl3_wgpu/README.md index 35857be9e..c7d6aec7b 100644 --- a/examples/example_sdl3_wgpu/README.md +++ b/examples/example_sdl3_wgpu/README.md @@ -60,14 +60,10 @@ For the WASM code produced by Emscripten to work correctly, it will also be nece CMake checks the EMSCRIPEN version then: - if EMS >= 4.0.10 uses `--use-port=emdawnwebgpu` flag to build - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - - if EMS < 4.0.10 uses `-sUSE_WEBGPU=1` flag to build - - it set `IMGUI_IMPL_WEBGPU_BACKEND_WGPU` compiler define - -#### Generate Emscripten forcing `-sUSE_WEBGPU=1` deprecated flag even with EMS >= 4.0.10 -- `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="-sUSE_WEBGPU=1" -B where_to_build_dir` - - it set `IMGUI_IMPL_WEBGPU_BACKEND_WGPU` compiler define + - if EMS < 4.0.10 the build aborts (`-sUSE_WEBGPU=1` is no longer supported by our examples and our WGPU backend #### Generate Emscripten using external WebGPU library (emdawnwebgpu_pkg) + - `emcmake cmake -G Ninja -DIMGUI_EMSCRIPTEN_WEBGPU_FLAG="--use-port=path_to_emdawnwebgpu_pkg" -B where_to_build_dir` - it set `IMGUI_IMPL_WEBGPU_BACKEND_DAWN` compiler define - *To use external WebGPU library it's necessary to have EMS >= 4.0.10 or the minimum requirements specified by the package:* diff --git a/examples/example_sdl3_wgpu/main.cpp b/examples/example_sdl3_wgpu/main.cpp index aa67d3098..523d62156 100644 --- a/examples/example_sdl3_wgpu/main.cpp +++ b/examples/example_sdl3_wgpu/main.cpp @@ -20,9 +20,6 @@ #ifdef __EMSCRIPTEN__ #include #include -#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#include -#endif #include "../libs/emscripten/emscripten_mainloop_stub.h" #endif @@ -339,17 +336,6 @@ static WGPUDevice RequestDevice(wgpu::Instance& instance, wgpu::Adapter& adapter return acquired_device.MoveToCHandle(); } #elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) -#ifdef __EMSCRIPTEN__ -// Adapter and device initialization via JS -EM_ASYNC_JS( void, getAdapterAndDeviceViaJS, (), -{ - if (!navigator.gpu) - throw Error("WebGPU not supported."); - const adapter = await navigator.gpu.requestAdapter(); - const device = await adapter.requestDevice(); - Module.preinitializedWebGPUDevice = device; -} ); -#else // __EMSCRIPTEN__ static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2) { if (status == WGPURequestAdapterStatus_Success) @@ -406,7 +392,6 @@ static WGPUDevice RequestDevice(WGPUInstance& instance, WGPUAdapter& adapter) IM_ASSERT(local_device && "Error on Device request"); return local_device; } -#endif // __EMSCRIPTEN__ #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU static bool InitWGPU(SDL_Window* window) @@ -457,23 +442,6 @@ static bool InitWGPU(SDL_Window* window) instanceDesc.requiredFeatures = &timedWaitAny; wgpu_instance = wgpuCreateInstance(&instanceDesc); -#ifdef __EMSCRIPTEN__ - getAdapterAndDeviceViaJS(); - - wgpu_device = emscripten_webgpu_get_device(); - IM_ASSERT(wgpu_device != nullptr && "Error creating the Device"); - - WGPUSurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {}; - html_surface_desc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector; - html_surface_desc.selector = "#canvas"; - - WGPUSurfaceDescriptor surface_desc = {}; - surface_desc.nextInChain = &html_surface_desc.chain; - - // Create the surface. - wgpu_surface = wgpuInstanceCreateSurface(wgpu_instance, &surface_desc); - preferred_fmt = wgpuSurfaceGetPreferredFormat(wgpu_surface, {} /* adapter */); -#else // __EMSCRIPTEN__ wgpuSetLogCallback( [](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr ); @@ -493,7 +461,6 @@ static bool InitWGPU(SDL_Window* window) wgpuSurfaceGetCapabilities(wgpu_surface, adapter, &surface_capabilities); preferred_fmt = surface_capabilities.formats[0]; -#endif // __EMSCRIPTEN__ #endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU wgpu_surface_configuration.presentMode = WGPUPresentMode_Fifo; diff --git a/examples/libs/emscripten/shell_minimal.html b/examples/libs/emscripten/shell_minimal.html index bcc5834a1..939dc1779 100644 --- a/examples/libs/emscripten/shell_minimal.html +++ b/examples/libs/emscripten/shell_minimal.html @@ -5,7 +5,7 @@ Dear ImGui Emscripten example diff --git a/imgui.cpp b/imgui.cpp index 3c3258d12..5f16d8250 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -20,7 +20,7 @@ // - Software using Dear ImGui https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui // - Issues & support ........... https://github.com/ocornut/imgui/issues // - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your apps) -// - Web version of the Demo .... https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html (w/ source code browser) +// - Web version of the Demo .... https://pthom.github.io/imgui_explorer (w/ source code browser) // For FIRST-TIME users having issues compiling/linking/running: // please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. @@ -208,7 +208,7 @@ CODE The UI can be highly dynamic, there are no construction or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, fewer bugs. - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features. - Or browse https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html for interactive web version. + Or browse pthom's online imgui_explorer: https://pthom.github.io/imgui_explorer for a web version w/ source code browser. - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build. - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori). You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki. @@ -402,7 +402,17 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: - likewise io.MousePos and GetMousePos() will use OS coordinates. If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos. - - 2026/02/27 (1.92.7) - Commented out legacy signature for Combo(), ListBox(), signatures which were obsoleted in 1.90 (Nov 2023), when the getter callback type was changed. + - 2026/02/26 (1.92.7) - Separator: fixed a legacy quirk where Separator() was submitting a zero-height item for layout purpose, even though it draws a 1-pixel separator. + The fix could affect code e.g. computing height from multiple widgets in order to allocate vertical space for a footer or multi-line status bar. (#2657, #9263) + The "Console" example had such a bug: + float footer_height = style.ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + BeginChild("ScrollingRegion", { 0, -footer_height }); + Should be: + float footer_height = style.ItemSpacing.y + style.SeparatorSize + ImGui::GetFrameHeightWithSpacing(); + BeginChild("ScrollingRegion", { 0, -footer_height }); + When such idiom was used and assuming zero-height Separator, it is likely that + in 1.92.7 the resulting window will have unexpected 1 pixel scrolling range. + - 2026/02/23 (1.92.7) - Commented out legacy signature for Combo(), ListBox(), signatures which were obsoleted in 1.90 (Nov 2023), when the getter callback type was changed. - Old getter type: bool (*getter)(void* user_data, int idx, const char** out_text) // Set label + return bool. False replaced label with placeholder. - New getter type: const char* (*getter)(void* user_data, int idx) // Return label or NULL/empty label if missing - 2026/01/08 (1.92.6) - Commented out legacy names obsoleted in 1.90 (Sept 2023): 'BeginChildFrame()' --> 'BeginChild()' with 'ImGuiChildFlags_FrameStyle'. 'EndChildFrame()' --> 'EndChild()'. 'ShowStackToolWindow()' --> 'ShowIDStackToolWindow()'. 'IM_OFFSETOF()' --> 'offsetof()'. @@ -1116,6 +1126,8 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: - Run the examples/ applications and explore them. - Read Getting Started (https://github.com/ocornut/imgui/wiki/Getting-Started) guide. - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function. + - See pthom's online imgui_explorer (https://pthom.github.io/imgui_explorer) which is a web + version of the demo with a source code browser. - The demo covers most features of Dear ImGui, so you can read the code and see its output. - See documentation and comments at the top of imgui.cpp + effectively imgui.h. - 20+ standalone example applications using e.g. OpenGL/DirectX are provided in the @@ -1526,7 +1538,8 @@ ImGuiStyle::ImGuiStyle() ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. - SeparatorTextBorderSize = 3.0f; // Thickness of border in SeparatorText() + SeparatorSize = 1.0f; // Thickness of border in Separator(). + SeparatorTextBorderSize = 3.0f; // Thickness of border in SeparatorText(). SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows. @@ -1601,8 +1614,9 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) DragDropTargetBorderSize = ImTrunc(DragDropTargetBorderSize * scale_factor); DragDropTargetPadding = ImTrunc(DragDropTargetPadding * scale_factor); ColorMarkerSize = ImTrunc(ColorMarkerSize * scale_factor); - SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor); + SeparatorSize = ImTrunc(SeparatorSize * scale_factor); SeparatorTextBorderSize = ImTrunc(SeparatorTextBorderSize * scale_factor); + SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor); DockingSeparatorSize = ImTrunc(DockingSeparatorSize * scale_factor); DisplayWindowPadding = ImTrunc(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImTrunc(DisplaySafeAreaPadding * scale_factor); @@ -3572,7 +3586,7 @@ bool ImGuiListClipper::Step() return ret; } -// Generic helper, equivalent to old ImGui::CalcListClipping() but statelesss +// Generic helper, equivalent to old ImGui::CalcListClipping() but stateless void ImGui::CalcClipRectVisibleItemsY(const ImRect& clip_rect, const ImVec2& pos, float items_height, int* out_visible_start, int* out_visible_end) { *out_visible_start = ImMax((int)((clip_rect.Min.y - pos.y) / items_height), 0); @@ -3706,6 +3720,7 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] = { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesRounding)}, // ImGuiStyleVar_TreeLinesRounding { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorSize)}, // ImGuiStyleVar_SeparatorSize { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)}, // ImGuiStyleVar_SeparatorTextBorderSize { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding @@ -4351,6 +4366,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) MouseStationaryTimer = 0.0f; InputTextPasswordFontBackupFlags = ImFontFlags_None; + InputTextReactivateId = 0; TempInputId = 0; memset(&DataTypeZeroValue, 0, sizeof(DataTypeZeroValue)); BeginMenuDepth = BeginComboDepth = 0; @@ -5752,6 +5768,8 @@ void ImGui::NewFrame() g.ActiveIdIsJustActivated = false; if (g.TempInputId != 0 && g.ActiveId != g.TempInputId) g.TempInputId = 0; + if (g.InputTextReactivateId != 0 && g.InputTextReactivateId != g.DeactivatedItemData.ID) + g.InputTextReactivateId = 0; if (g.ActiveId == 0) { g.ActiveIdUsingNavDirMask = 0x00; @@ -6090,7 +6108,7 @@ static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 draw_list->ChannelsMerge(); if (draw_list->CmdBuffer.Size == 0) draw_list->AddDrawCmd(); - draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to stricty ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that) + draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to strictly ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that) ImDrawCmd cmd = draw_list->CmdBuffer.back(); IM_ASSERT(cmd.ElemCount == 0); draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col); @@ -12950,16 +12968,16 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to // - Each popups may contain child windows, which is why we compare ->RootWindowDockTree! // Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child // We step through every popup from bottom to top to validate their position relative to reference window. - bool ref_window_is_descendent_of_popup = false; + bool ref_window_is_descendant_of_popup = false; for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++) if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window) //if (popup_window->RootWindowDockTree == ref_window->RootWindowDockTree) // FIXME-MERGE if (IsWindowWithinBeginStackOf(ref_window, popup_window)) { - ref_window_is_descendent_of_popup = true; + ref_window_is_descendant_of_popup = true; break; } - if (!ref_window_is_descendent_of_popup) + if (!ref_window_is_descendant_of_popup) break; } } @@ -15467,7 +15485,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) // Magic fallback to handle items with no assigned ID, e.g. Text(), Image() // We build a throwaway ID based on current ID stack + relative AABB of items in window. - // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZINGG OF THE WIDGET, so if your widget moves your dragging operation will be canceled. + // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING/RESIZING OF THE WIDGET, so if your widget moves your dragging operation will be canceled. // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive. // Rely on keeping other window->LastItemXXX fields intact. source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect); @@ -23297,7 +23315,7 @@ void ImGui::DebugNodeFont(ImFont* font) src_n, src->Name, src->OversampleH, oversample_h, src->OversampleV, oversample_v, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y); } - DebugNodeFontGlyphesForSrcMask(font, baked, ~0); + DebugNodeFontGlyphsForSrcMask(font, baked, ~0); TreePop(); } PopID(); @@ -23306,7 +23324,7 @@ void ImGui::DebugNodeFont(ImFont* font) Unindent(); } -void ImGui::DebugNodeFontGlyphesForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask) +void ImGui::DebugNodeFontGlyphsForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask) { ImDrawList* draw_list = GetWindowDrawList(); const ImU32 glyph_col = GetColorU32(ImGuiCol_Text); @@ -24110,7 +24128,7 @@ void ImGui::DebugNodeColumns(ImGuiOldColumns*) {} void ImGui::DebugNodeDrawList(ImGuiWindow*, ImGuiViewportP*, const ImDrawList*, const char*) {} void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList*, const ImDrawList*, const ImDrawCmd*, bool, bool) {} void ImGui::DebugNodeFont(ImFont*) {} -void ImGui::DebugNodeFontGlyphesForSrcMask(ImFont*, ImFontBaked*, int) {} +void ImGui::DebugNodeFontGlyphsForSrcMask(ImFont*, ImFontBaked*, int) {} void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {} void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {} void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {} diff --git a/imgui.h b/imgui.h index 91cc3e716..dfa272da1 100644 --- a/imgui.h +++ b/imgui.h @@ -20,7 +20,7 @@ // - Software using Dear ImGui https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui // - Issues & support ........... https://github.com/ocornut/imgui/issues // - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your apps) -// - Web version of the Demo .... https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html (w/ source code browser) +// - Web version of the Demo .... https://pthom.github.io/imgui_manual (w/ source code browser) // For FIRST-TIME users having issues compiling/linking/running: // please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. @@ -30,7 +30,7 @@ // Library Version // (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_NUM 19263 +#define IMGUI_VERSION_NUM 19264 #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_VIEWPORT // In 'docking' WIP branch. @@ -1937,6 +1937,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_TreeLinesRounding, // float TreeLinesRounding ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign + ImGuiStyleVar_SeparatorSize, // float SeparatorSize ImGuiStyleVar_SeparatorTextBorderSize, // float SeparatorTextBorderSize ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign ImGuiStyleVar_SeparatorTextPadding, // ImVec2 SeparatorTextPadding @@ -2417,6 +2418,7 @@ struct ImGuiStyle ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. + float SeparatorSize; // Thickness of border in Separator() float SeparatorTextBorderSize; // Thickness of border in SeparatorText() ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y. @@ -2533,7 +2535,7 @@ struct ImGuiIO bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl. bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates. bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). - bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will keep item active and select contents (single-line only). + bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will reactivate item and select all text (single-line only). bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. @@ -3774,7 +3776,7 @@ enum ImFontAtlasFlags_ // - Call Build() + GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. // - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. // Common pitfalls: -// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the +// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persists up until the // atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data. // - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction. // You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed, diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5c7ee8bc0..d656d7d66 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -12,7 +12,7 @@ // How to easily locate code? // - Use Tools->Item Picker to debug break in code by clicking any widgets: https://github.com/ocornut/imgui/wiki/Debug-Tools -// - Browse an online version the demo with code linked to hovered widgets: https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html +// - Browse pthom's online imgui_explorer: web version the demo w/ source code browser: https://pthom.github.io/imgui_explorer // - Find a visible string and search for it in the code! //--------------------------------------------------- @@ -294,9 +294,9 @@ static void ShowDockingDisabledMessage() io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; } -// Helper to wire demo markers located in code to an interactive browser (e.g. imgui_manual) +// Helper to wire demo markers located in code to an interactive browser (e.g. https://pthom.github.io/imgui_explorer) #if IMGUI_VERSION_NUM >= 19263 -namespace ImGui { extern IMGUI_API void DemoMarker(const char* file, int line, const char* section); }; +namespace ImGui { extern IMGUI_API void DemoMarker(const char* file, int line, const char* section); } #define IMGUI_DEMO_MARKER(section) do { ImGui::DemoMarker("imgui_demo.cpp", __LINE__, section); } while (0) #endif @@ -459,6 +459,9 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::BulletText("The \"Examples\" menu above leads to more demo contents."); ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n" "and Metrics/Debugger (general purpose Dear ImGui debugging tool)."); + ImGui::BulletText("Web demo (w/ source code browser): "); + ImGui::SameLine(0, 0); + ImGui::TextLinkOpenURL("https://pthom.github.io/imgui_explorer"); ImGui::SeparatorText("PROGRAMMER GUIDE:"); ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!"); @@ -587,7 +590,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive); - ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only)."); + ImGui::SameLine(); HelpMarker("Pressing Enter will reactivate item and select all text (single-line only)."); ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText); ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors); @@ -1794,7 +1797,6 @@ static void DemoWindowWidgetsDragsAndSliders() ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround); ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)"); ImGui::CheckboxFlags("ImGuiSliderFlags_ColorMarkers", &flags, ImGuiSliderFlags_ColorMarkers); - //ImGui::CheckboxFlags("ImGuiSliderFlags_ColorMarkersG", &flags, 1 << ImGuiSliderFlags_ColorMarkersIndexShift_); // Not explicitly documented but possible. // Drags static float drag_f = 0.5f; @@ -2010,29 +2012,32 @@ static void DemoWindowWidgetsMultiComponents() static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; static int vec4i[4] = { 1, 5, 100, 255 }; + static ImGuiSliderFlags flags = 0; + ImGui::CheckboxFlags("ImGuiSliderFlags_ColorMarkers", &flags, ImGuiSliderFlags_ColorMarkers); // Only passing this to Drag/Sliders + ImGui::SeparatorText("2-wide"); ImGui::InputFloat2("input float2", vec4f); - ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); - ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); ImGui::InputInt2("input int2", vec4i); - ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); - ImGui::SliderInt2("slider int2", vec4i, 0, 255); + ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f, NULL, flags); + ImGui::DragInt2("drag int2", vec4i, 1, 0, 255, NULL, flags); + ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f, NULL, flags); + ImGui::SliderInt2("slider int2", vec4i, 0, 255, NULL, flags); ImGui::SeparatorText("3-wide"); ImGui::InputFloat3("input float3", vec4f); - ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); - ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); ImGui::InputInt3("input int3", vec4i); - ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); - ImGui::SliderInt3("slider int3", vec4i, 0, 255); + ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f, NULL, flags); + ImGui::DragInt3("drag int3", vec4i, 1, 0, 255, NULL, flags); + ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f, NULL, flags); + ImGui::SliderInt3("slider int3", vec4i, 0, 255, NULL, flags); ImGui::SeparatorText("4-wide"); ImGui::InputFloat4("input float4", vec4f); - ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); - ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); ImGui::InputInt4("input int4", vec4i); - ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); - ImGui::SliderInt4("slider int4", vec4i, 0, 255); + ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f, NULL, flags); + ImGui::DragInt4("drag int4", vec4i, 1, 0, 255, NULL, flags); + ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f, NULL, flags); + ImGui::SliderInt4("slider int4", vec4i, 0, 255, NULL, flags); ImGui::SeparatorText("Ranges"); static float begin = 10, end = 90; @@ -8613,6 +8618,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); + SliderFloat("SeparatorSize", &style.SeparatorSize, 0.0f, 10.0f, "%.0f"); SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f"); SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f"); SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f"); @@ -9086,7 +9092,8 @@ struct ExampleAppConsole ImGui::Separator(); // Reserve enough left-over height for 1 separator + 1 input text - const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + ImGuiStyle& style = ImGui::GetStyle(); + const float footer_height_to_reserve = style.SeparatorSize + style.ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_HorizontalScrollbar)) { if (ImGui::BeginPopupContextWindow()) @@ -10115,7 +10122,7 @@ static void ShowExampleAppWindowTitles(bool*) ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver); ImGui::Begin("Same title as another window##2"); - IMGUI_DEMO_MARKER("Examples/Manipulating window titles##2");; + IMGUI_DEMO_MARKER("Examples/Manipulating window titles##2"); ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique."); ImGui::End(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 7aff2ccdf..d8da6df4e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3209,7 +3209,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); if (font_cfg.Name[0] == '\0') { - // Store a short copy of filename into into the font name for convenience + // Store a short copy of filename into the font name for convenience const char* p; for (p = filename + ImStrlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {} ImFormatString(font_cfg.Name, IM_COUNTOF(font_cfg.Name), "%s", p); @@ -3217,7 +3217,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges); } -// NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build(). +// NB: Transfer ownership of 'font_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build(). ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); diff --git a/imgui_internal.h b/imgui_internal.h index a24e6c024..39e7e35ab 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -545,7 +545,7 @@ inline float ImLinearSweep(float current, float target, float speed) { if (cu inline float ImLinearRemapClamp(float s0, float s1, float d0, float d1, float x) { return ImSaturate((x - s0) / (s1 - s0)) * (d1 - d0) + d0; } inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; } -inline float ImExponentialMovingAverage(float avg, float sample, int n){ avg -= avg / n; avg += sample / n; return avg; } +inline float ImExponentialMovingAverage(float avg, float sample, int n){ avg -= avg / (float)n; avg += sample / (float)n; return avg; } IM_MSVC_RUNTIME_CHECKS_RESTORE // Helpers: Geometry @@ -2667,6 +2667,7 @@ struct ImGuiContext ImGuiInputTextDeactivatedState InputTextDeactivatedState; ImFontBaked InputTextPasswordFontBackupBaked; ImFontFlags InputTextPasswordFontBackupFlags; + ImGuiID InputTextReactivateId; // ID of InputText to reactivate on next frame (for io.ConfigInputTextEnterKeepActive behavior) ImGuiID TempInputId; // Temporary text input when using Ctrl+Click on a slider, etc. ImGuiDataTypeStorage DataTypeZeroValue; // 0 for all data types int BeginMenuDepth; @@ -3938,6 +3939,7 @@ namespace ImGui IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis); IMGUI_API ImGuiID GetWindowResizeCornerID(ImGuiWindow* window, int n); // 0..3: corners IMGUI_API ImGuiID GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir); + IMGUI_API void ExtendHitBoxWhenNearViewportEdge(ImGuiWindow* window, ImRect* bb, float threshold, ImGuiAxis axis); // Widgets low-level behaviors IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0); @@ -3956,8 +3958,8 @@ namespace ImGui // Template functions are instantiated in imgui_widgets.cpp for a finite number of types. // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036). // e.g. " extern template IMGUI_API float RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, float v); " - template IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); - template IMGUI_API T ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size); + template IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, float logarithmic_zero_epsilon, float zero_deadzone_size); + template IMGUI_API T ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, float logarithmic_zero_epsilon, float zero_deadzone_size); template IMGUI_API bool DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, ImGuiSliderFlags flags); template IMGUI_API bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb); template IMGUI_API T RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v); @@ -4011,7 +4013,7 @@ namespace ImGui IMGUI_API bool BeginErrorTooltip(); IMGUI_API void EndErrorTooltip(); - // Demo Doc Marker for e.g. imgui_manual + // Demo Doc Marker for e.g. imgui_explorer IMGUI_API void DemoMarker(const char* file, int line, const char* section); // Debug Tools @@ -4034,7 +4036,7 @@ namespace ImGui IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label); IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); IMGUI_API void DebugNodeFont(ImFont* font); - IMGUI_API void DebugNodeFontGlyphesForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask); + IMGUI_API void DebugNodeFontGlyphsForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask); IMGUI_API void DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph); IMGUI_API void DebugNodeTexture(ImTextureData* tex, int int_id, const ImFontAtlasRect* highlight_rect = NULL); // ID used to facilitate persisting the "current" texture. IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 8f341251c..f24caf76a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -919,7 +919,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) const ImU32 cross_col = GetColorU32(ImGuiCol_Text); const ImVec2 cross_center = bb.GetCenter() - ImVec2(0.5f, 0.5f); const float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f; - const float cross_thickness = 1.0f; // FIXME-DPI + const float cross_thickness = 1.0f * (float)(int)g.Style._MainScale; // FIXME-DPI window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, +cross_extent), cross_center + ImVec2(-cross_extent, -cross_extent), cross_col, cross_thickness); window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, -cross_extent), cross_center + ImVec2(-cross_extent, +cross_extent), cross_col, cross_thickness); @@ -980,6 +980,16 @@ ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis) return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y + border_top, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size); } +void ImGui::ExtendHitBoxWhenNearViewportEdge(ImGuiWindow* window, ImRect* bb, float threshold, ImGuiAxis axis) +{ + ImRect window_rect = window->RootWindow->Rect(); + ImRect viewport_rect = window->Viewport->GetMainRect(); + if (window_rect.Min[axis] == viewport_rect.Min[axis] && bb->Min[axis] > window_rect.Min[axis] && bb->Min[axis] - threshold <= window_rect.Min[axis]) + bb->Min[axis] = window_rect.Min[axis]; + if (window_rect.Max[axis] == viewport_rect.Max[axis] && bb->Max[axis] < window_rect.Max[axis] && bb->Max[axis] + threshold >= window_rect.Max[axis]) + bb->Max[axis] = window_rect.Max[axis]; +} + void ImGui::Scrollbar(ImGuiAxis axis) { ImGuiContext& g = *GImGui; @@ -1042,11 +1052,15 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6 const float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_visible_v / (float)win_size_v), grab_h_minsize, scrollbar_size_v); const float grab_h_norm = grab_h_pixels / scrollbar_size_v; + // As a special thing, we allow scrollbar near the edge of a screen/viewport to be reachable with mouse at the extreme edge (#9276) + ImRect bb_hit = bb_frame; + ExtendHitBoxWhenNearViewportEdge(window, &bb_hit, g.Style.WindowBorderSize, (ImGuiAxis)(axis ^ 1)); + // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar(). bool held = false; bool hovered = false; ItemAdd(bb_frame, id, NULL, ImGuiItemFlags_NoNav); - ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus); + ButtonBehavior(bb_hit, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus); const ImS64 scroll_max = ImMax((ImS64)1, size_contents_v - size_visible_v); float scroll_ratio = ImSaturate((float)*p_scroll_v / (float)scroll_max); @@ -1536,7 +1550,7 @@ bool ImGui::TextLink(const char* label) } float line_y = bb.Max.y + ImFloor(g.FontBaked->Descent * g.FontBakedScale * 0.20f); - window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf)); // FIXME-TEXT: Underline mode // FIXME-DPI + window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf), 1.0f * (float)(int)g.Style._MainScale); // FIXME-TEXT: Underline mode // FIXME-DPI PushStyleColor(ImGuiCol_Text, GetColorU32(text_colf)); RenderText(bb.Min, label, label_end); @@ -1671,9 +1685,13 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness) // We don't provide our width to the layout so that it doesn't get feed back into AutoFit // FIXME: This prevents ->CursorMaxPos based bounding box evaluation from working (e.g. TableEndCell) - const float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change. + + // Between 1.71 and 1.92.7, we maintained a hack where a 1.0f thin Separator() would not impact layout. + // This was mostly chosen to allow backward compatibility with user's code assuming zero-height when calculating height for layout (e.g. bottom alignment of a status bar). + // In order to handle scaling we need to scale separator thickness and it would not makes sense to have a disparity depending on height. + ////float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change. const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness)); - ItemSize(ImVec2(0.0f, thickness_for_layout)); + ItemSize(ImVec2(0.0f, thickness)); if (ItemAdd(bb, 0)) { @@ -1699,14 +1717,13 @@ void ImGui::Separator() return; // Those flags should eventually be configurable by the user - // FIXME: We cannot g.Style.SeparatorTextBorderSize for thickness as it relates to SeparatorText() which is a decorated separator, not defaulting to 1.0f. ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal; // Only applies to legacy Columns() api as they relied on Separator() a lot. if (window->DC.CurrentColumns) flags |= ImGuiSeparatorFlags_SpanAllColumns; - SeparatorEx(flags, 1.0f); + SeparatorEx(flags, g.Style.SeparatorSize); } void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w) @@ -2568,9 +2585,9 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const logarithmic_zero_epsilon = ImPow(0.1f, (float)decimal_precision); // Convert to parametric space, apply delta, convert back - float v_old_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float v_old_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); float v_new_parametric = v_old_parametric + g.DragCurrentAccum; - v_cur = ScaleValueFromRatioT(data_type, v_new_parametric, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + v_cur = ScaleValueFromRatioT(data_type, v_new_parametric, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); v_old_ref_for_accum_remainder = v_old_parametric; } else @@ -2587,7 +2604,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const if (is_logarithmic) { // Convert to parametric space, apply delta, convert back - float v_new_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float v_new_parametric = ScaleRatioFromValueT(data_type, v_cur, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); g.DragCurrentAccum -= (float)(v_new_parametric - v_old_ref_for_accum_remainder); } else @@ -2663,6 +2680,20 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v return false; } +// Only clamp Ctrl+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via ImGuiSliderFlags_AlwaysClamp) +static bool TempInputIsClampEnabled(ImGuiSliderFlags flags, ImGuiDataType data_type, const void* p_min, const void* p_max) +{ + if ((flags & ImGuiSliderFlags_ClampOnInput) && (p_min != NULL || p_max != NULL)) + { + const int clamp_range_dir = (p_min != NULL && p_max != NULL) ? ImGui::DataTypeCompare(data_type, p_min, p_max) : 0; // -1 when *p_min < *p_max, == 0 when *p_min == *p_max + if (p_min == NULL || p_max == NULL || clamp_range_dir < 0) + return true; + if (clamp_range_dir == 0) + return ImGui::DataTypeIsZero(data_type, p_min) ? ((flags & ImGuiSliderFlags_ClampZeroRange) != 0) : true; + } + return false; +} + // Note: p_data, p_min and p_max are _pointers_ to a memory address holding the data. For a Drag widget, p_min and p_max are optional. // Read code of e.g. DragFloat(), DragInt() etc. or examples in 'Demo->Widgets->Data Types' to understand how to use this function directly. bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags) @@ -2728,16 +2759,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, if (temp_input_is_active) { - // Only clamp Ctrl+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via ImGuiSliderFlags_AlwaysClamp) - bool clamp_enabled = false; - if ((flags & ImGuiSliderFlags_ClampOnInput) && (p_min != NULL || p_max != NULL)) - { - const int clamp_range_dir = (p_min != NULL && p_max != NULL) ? DataTypeCompare(data_type, p_min, p_max) : 0; // -1 when *p_min < *p_max, == 0 when *p_min == *p_max - if (p_min == NULL || p_max == NULL || clamp_range_dir < 0) - clamp_enabled = true; - else if (clamp_range_dir == 0) - clamp_enabled = DataTypeIsZero(data_type, p_min) ? ((flags & ImGuiSliderFlags_ClampZeroRange) != 0) : true; - } + const bool clamp_enabled = TempInputIsClampEnabled(flags, data_type, p_min, p_max); return TempInputScalar(frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL, clamp_enabled ? p_max : NULL); } @@ -2937,14 +2959,14 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_ // Convert a value v in the output space of a slider into a parametric position on the slider itself (the logical opposite of ScaleValueFromRatioT) template -float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) +float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) { if (v_min == v_max) return 0.0f; IM_UNUSED(data_type); const TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); - if (is_logarithmic) + if (logarithmic_zero_epsilon > 0.0f) // == is_logarithmic from caller { bool flipped = v_max < v_min; @@ -2994,7 +3016,7 @@ float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, T // Convert a parametric position on a slider into a value v in the output space (the logical opposite of ScaleRatioFromValueT) template -TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) +TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) { // We special-case the extents because otherwise our logarithmic fudging can lead to "mathematically correct" // but non-intuitive behaviors like a fully-left slider not actually reaching the minimum value. Also generally simpler. @@ -3004,7 +3026,7 @@ TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, T return v_max; TYPE result = (TYPE)0; - if (is_logarithmic) + if (logarithmic_zero_epsilon > 0.0f) // == is_logarithmic from caller { // Fudge min/max to avoid getting silly results close to zero FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min; @@ -3109,7 +3131,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ const float mouse_abs_pos = g.IO.MousePos[axis]; if (g.ActiveIdIsJustActivated) { - float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); if (axis == ImGuiAxis_Y) grab_t = 1.0f - grab_t; const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); @@ -3164,7 +3186,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ } else if (g.SliderCurrentAccumDirty) { - clicked_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + clicked_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits { @@ -3178,10 +3200,10 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ clicked_t = ImSaturate(clicked_t + delta); // Calculate what our "new" clicked_t will be, and thus how far we actually moved the slider, and subtract this from the accumulator - TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat)) v_new = RoundScalarWithFormatT(format, data_type, v_new); - float new_clicked_t = ScaleRatioFromValueT(data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float new_clicked_t = ScaleRatioFromValueT(data_type, v_new, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); if (delta > 0) g.SliderCurrentAccum -= ImMin(new_clicked_t - old_clicked_t, delta); @@ -3199,7 +3221,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ if (set_new_value) { - TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + TYPE v_new = ScaleValueFromRatioT(data_type, clicked_t, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); // Round to user desired precision based on format string if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat)) @@ -3221,7 +3243,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ else { // Output grab position so it can be displayed by the caller - float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); + float grab_t = ScaleRatioFromValueT(data_type, *v, v_min, v_max, logarithmic_zero_epsilon, zero_deadzone_halfsize); if (axis == ImGuiAxis_Y) grab_t = 1.0f - grab_t; const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); @@ -3329,7 +3351,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if (temp_input_is_active) { // Only clamp Ctrl+Click input when ImGuiSliderFlags_ClampOnInput is set (generally via ImGuiSliderFlags_AlwaysClamp) - const bool clamp_enabled = (flags & ImGuiSliderFlags_ClampOnInput) != 0; + const bool clamp_enabled = (flags & ImGuiSliderFlags_ClampOnInput) != 0; // Don't use TempInputIsClampEnabled() return TempInputScalar(frame_bb, id, label, data_type, p_data, format, clamp_enabled ? p_min : NULL, clamp_enabled ? p_max : NULL); } @@ -3714,29 +3736,28 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_LocalizeDecimalPoint; g.LastItemData.ItemFlags |= ImGuiItemFlags_NoMarkEdited; // Because TempInputText() uses ImGuiInputTextFlags_MergedItem it doesn't submit a new item, so we poke LastItemData. - bool value_changed = false; - if (TempInputText(bb, id, label, data_buf, IM_COUNTOF(data_buf), flags)) + if (!TempInputText(bb, id, label, data_buf, IM_COUNTOF(data_buf), flags)) + return false; + + // Backup old value + size_t data_type_size = type_info->Size; + ImGuiDataTypeStorage data_backup; + memcpy(&data_backup, p_data, data_type_size); + + // Apply new value (or operations) then clamp + DataTypeApplyFromText(data_buf, data_type, p_data, format, NULL); + if (p_clamp_min || p_clamp_max) { - // Backup old value - size_t data_type_size = type_info->Size; - ImGuiDataTypeStorage data_backup; - memcpy(&data_backup, p_data, data_type_size); - - // Apply new value (or operations) then clamp - DataTypeApplyFromText(data_buf, data_type, p_data, format, NULL); - if (p_clamp_min || p_clamp_max) - { - if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0) - ImSwap(p_clamp_min, p_clamp_max); - DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max); - } - - // Only mark as edited if new value is different - g.LastItemData.ItemFlags &= ~ImGuiItemFlags_NoMarkEdited; - value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; - if (value_changed) - MarkItemEdited(id); + if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0) + ImSwap(p_clamp_min, p_clamp_max); + DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max); } + + // Only mark as edited if new value is different + g.LastItemData.ItemFlags &= ~ImGuiItemFlags_NoMarkEdited; + bool value_changed = memcmp(&data_backup, p_data, data_type_size) != 0; + if (value_changed) + MarkItemEdited(id); return value_changed; } @@ -4747,7 +4768,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ wrap_width = ImMax(1.0f, GetContentRegionAvail().x + (draw_window->ScrollbarY ? 0.0f : -g.Style.ScrollbarSize)); const bool input_requested_by_nav = (g.ActiveId != id) && ((g.NavActivateId == id) && ((g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || (g.NavInputSource == ImGuiInputSource_Keyboard))); - + const bool input_requested_by_reactivate = (g.InputTextReactivateId == id); // for io.ConfigInputTextEnterKeepActive const bool user_clicked = hovered && io.MouseClicked[0]; const bool user_scroll_finish = is_multiline && state != NULL && g.ActiveId == 0 && g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y); @@ -4758,7 +4779,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_changed_specs = (state != NULL && state->Stb->single_line != !is_multiline); // state != NULL means its our state. - const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav); + const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav || input_requested_by_reactivate); const bool init_state = (init_make_active || user_scroll_active); if (init_reload_from_user_buf) { @@ -5095,11 +5116,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ bool is_new_line = is_multiline && !is_gamepad_validate && (is_shift_enter || (is_enter && !ctrl_enter_for_new_line) || (is_ctrl_enter && ctrl_enter_for_new_line)); if (!is_new_line) { - validated = true; + validated = clear_active_id = true; if (io.ConfigInputTextEnterKeepActive && !is_multiline) + { + // Queue reactivation, so that e.g. IsItemDeactivatedAfterEdit() will work. (#9001) state->SelectAll(); // No need to scroll - else - clear_active_id = true; + g.InputTextReactivateId = id; // Mark for reactivation on next frame + } } else if (!is_readonly) { @@ -5573,7 +5596,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ ImVec2 cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll); ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) - draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_InputTextCursor), 1.0f); // FIXME-DPI: Cursor thickness (#7031) + draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_InputTextCursor), 1.0f * (float)(int)style._MainScale); // FIXME-DPI: Cursor thickness (#7031) // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) // This is required for some backends (SDL3) to start emitting character/text inputs. @@ -6431,7 +6454,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if (g.Style.FrameBorderSize > 0.0f) RenderFrameBorder(bb.Min, bb.Max, rounding); else - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color buttons are often in need of some sort of border // FIXME-DPI + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding, 0, 1.0f * (float)(int)g.Style._MainScale); // Color buttons are often in need of some sort of border // FIXME-DPI } // Drag and Drop Source diff --git a/imstb_rectpack.h b/imstb_rectpack.h index f6917e7a6..ad0892130 100644 --- a/imstb_rectpack.h +++ b/imstb_rectpack.h @@ -315,7 +315,7 @@ static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0 if (node->y > min_y) { // raise min_y higher. // we've accounted for all waste up to min_y, - // but we'll now add more waste for everything we've visted + // but we'll now add more waste for everything we've visited waste_area += visited_width * (node->y - min_y); min_y = node->y; // the first time through, visited_width might be reduced @@ -470,7 +470,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i // insert the new node into the right starting point, and // let 'cur' point to the remaining nodes needing to be - // stiched back in + // stitched back in cur = *res.prev_link; if (cur->x < res.x) { diff --git a/imstb_truetype.h b/imstb_truetype.h index cf33289f6..ec4d42c7d 100644 --- a/imstb_truetype.h +++ b/imstb_truetype.h @@ -886,7 +886,7 @@ STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, fl // xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); -// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel +// the same as stbtt_GetCodepointBitmap, but you can specify a subpixel // shift for the character STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);