ImGui-dockingと交換
守矢諏訪子 <suwako@076.moe>、2026-06-26 04:33
コミット d917edd61860e582f371aedd95c8d5d01b98e3eb
・親 8ac5aaf
・ファイルを見る
104個のファイル、+7663 -849
| @@ -11,6 +11,7 @@ | ||
| 11 | 11 | // [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually. |
| 12 | 12 | // [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: Allegro5 cannot enable/disable LINEAR bitmap flags after creation. |
| 13 | 13 | // [ ] Platform: Missing gamepad support. |
| 14 | +// [ ] Renderer: Multi-viewport support (multiple windows). | |
| 14 | 15 | |
| 15 | 16 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 16 | 17 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -11,6 +11,7 @@ | ||
| 11 | 11 | // [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually. |
| 12 | 12 | // [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: Allegro5 cannot enable/disable LINEAR bitmap flags after creation. |
| 13 | 13 | // [ ] Platform: Missing gamepad support. |
| 14 | +// [ ] Renderer: Multi-viewport support (multiple windows). | |
| 14 | 15 | |
| 15 | 16 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 16 | 17 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -8,6 +8,7 @@ | ||
| 8 | 8 | // [ ] Platform: Clipboard support. |
| 9 | 9 | // [ ] Platform: Gamepad support. |
| 10 | 10 | // [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. |
| 11 | +// [ ] Platform: Multi-viewport support (multiple windows). Not meaningful on Android. | |
| 11 | 12 | // Important: |
| 12 | 13 | // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. |
| 13 | 14 | // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) |
| @@ -8,6 +8,7 @@ | ||
| 8 | 8 | // [ ] Platform: Clipboard support. |
| 9 | 9 | // [ ] Platform: Gamepad support. |
| 10 | 10 | // [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. |
| 11 | +// [ ] Platform: Multi-viewport support (multiple windows). Not meaningful on Android. | |
| 11 | 12 | // Important: |
| 12 | 13 | // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. |
| 13 | 14 | // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) |
| @@ -5,6 +5,7 @@ | ||
| 5 | 5 | // [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! |
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 8 | 9 | |
| 9 | 10 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 10 | 11 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -16,6 +17,7 @@ | ||
| 16 | 17 | |
| 17 | 18 | // CHANGELOG |
| 18 | 19 | // (minor and older changes stripped away, please see git history for details) |
| 20 | +// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 19 | 21 | // 2026-04-23: DirectX10: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplDX10_RenderState. (#9378) |
| 20 | 22 | // 2026-01-19: DirectX10: Added 'SamplerNearest' in ImGui_ImplDX10_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'. |
| 21 | 23 | // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. |
| @@ -99,6 +101,10 @@ | ||
| 99 | 101 | return ImGui::GetCurrentContext() ? (ImGui_ImplDX10_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; |
| 100 | 102 | } |
| 101 | 103 | |
| 104 | +// Forward Declarations | |
| 105 | +static void ImGui_ImplDX10_InitMultiViewportSupport(); | |
| 106 | +static void ImGui_ImplDX10_ShutdownMultiViewportSupport(); | |
| 107 | + | |
| 102 | 108 | // Functions |
| 103 | 109 | static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* device) |
| 104 | 110 | { |
| @@ -613,6 +619,7 @@ | ||
| 613 | 619 | io.BackendRendererName = "imgui_impl_dx10"; |
| 614 | 620 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. |
| 615 | 621 | io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. |
| 622 | + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) | |
| 616 | 623 | |
| 617 | 624 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 618 | 625 | platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; |
| @@ -635,6 +642,8 @@ | ||
| 635 | 642 | if (pDXGIAdapter) pDXGIAdapter->Release(); |
| 636 | 643 | bd->pd3dDevice->AddRef(); |
| 637 | 644 | |
| 645 | + ImGui_ImplDX10_InitMultiViewportSupport(); | |
| 646 | + | |
| 638 | 647 | return true; |
| 639 | 648 | } |
| 640 | 649 | |
| @@ -645,13 +654,14 @@ | ||
| 645 | 654 | ImGuiIO& io = ImGui::GetIO(); |
| 646 | 655 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 647 | 656 | |
| 657 | + ImGui_ImplDX10_ShutdownMultiViewportSupport(); | |
| 648 | 658 | ImGui_ImplDX10_InvalidateDeviceObjects(); |
| 649 | 659 | if (bd->pFactory) { bd->pFactory->Release(); } |
| 650 | 660 | if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } |
| 651 | 661 | |
| 652 | 662 | io.BackendRendererName = nullptr; |
| 653 | 663 | io.BackendRendererUserData = nullptr; |
| 654 | - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); | |
| 664 | + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports); | |
| 655 | 665 | platform_io.ClearRendererHandlers(); |
| 656 | 666 | IM_DELETE(bd); |
| 657 | 667 | } |
| @@ -664,6 +674,131 @@ | ||
| 664 | 674 | if (!bd->pVertexShader) |
| 665 | 675 | if (!ImGui_ImplDX10_CreateDeviceObjects()) |
| 666 | 676 | IM_ASSERT(0 && "ImGui_ImplDX10_CreateDeviceObjects() failed!"); |
| 677 | +} | |
| 678 | + | |
| 679 | +//-------------------------------------------------------------------------------------------------------- | |
| 680 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 681 | +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. | |
| 682 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 683 | +//-------------------------------------------------------------------------------------------------------- | |
| 684 | + | |
| 685 | +// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data. | |
| 686 | +struct ImGui_ImplDX10_ViewportData | |
| 687 | +{ | |
| 688 | + IDXGISwapChain* SwapChain; | |
| 689 | + ID3D10RenderTargetView* RTView; | |
| 690 | + | |
| 691 | + ImGui_ImplDX10_ViewportData() { SwapChain = nullptr; RTView = nullptr; } | |
| 692 | + ~ImGui_ImplDX10_ViewportData() { IM_ASSERT(SwapChain == nullptr && RTView == nullptr); } | |
| 693 | +}; | |
| 694 | + | |
| 695 | +static void ImGui_ImplDX10_CreateWindow(ImGuiViewport* viewport) | |
| 696 | +{ | |
| 697 | + ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); | |
| 698 | + ImGui_ImplDX10_ViewportData* vd = IM_NEW(ImGui_ImplDX10_ViewportData)(); | |
| 699 | + viewport->RendererUserData = vd; | |
| 700 | + | |
| 701 | + // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID). | |
| 702 | + // Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND. | |
| 703 | + HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle; | |
| 704 | + IM_ASSERT(hwnd != 0); | |
| 705 | + | |
| 706 | + // Create swap chain | |
| 707 | + DXGI_SWAP_CHAIN_DESC sd; | |
| 708 | + ZeroMemory(&sd, sizeof(sd)); | |
| 709 | + sd.BufferDesc.Width = (UINT)viewport->Size.x; | |
| 710 | + sd.BufferDesc.Height = (UINT)viewport->Size.y; | |
| 711 | + sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
| 712 | + sd.SampleDesc.Count = 1; | |
| 713 | + sd.SampleDesc.Quality = 0; | |
| 714 | + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; | |
| 715 | + sd.BufferCount = 1; | |
| 716 | + sd.OutputWindow = hwnd; | |
| 717 | + sd.Windowed = TRUE; | |
| 718 | + sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; | |
| 719 | + sd.Flags = 0; | |
| 720 | + | |
| 721 | + IM_ASSERT(vd->SwapChain == nullptr && vd->RTView == nullptr); | |
| 722 | + bd->pFactory->CreateSwapChain(bd->pd3dDevice, &sd, &vd->SwapChain); | |
| 723 | + bd->pFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES); // Disable e.g. Alt+Enter | |
| 724 | + | |
| 725 | + // Create the render target | |
| 726 | + if (vd->SwapChain) | |
| 727 | + { | |
| 728 | + ID3D10Texture2D* pBackBuffer; | |
| 729 | + vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); | |
| 730 | + bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView); | |
| 731 | + pBackBuffer->Release(); | |
| 732 | + } | |
| 733 | +} | |
| 734 | + | |
| 735 | +static void ImGui_ImplDX10_DestroyWindow(ImGuiViewport* viewport) | |
| 736 | +{ | |
| 737 | + // The main viewport (owned by the application) will always have RendererUserData == 0 here since we didn't create the data for it. | |
| 738 | + if (ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData) | |
| 739 | + { | |
| 740 | + if (vd->SwapChain) | |
| 741 | + vd->SwapChain->Release(); | |
| 742 | + vd->SwapChain = nullptr; | |
| 743 | + if (vd->RTView) | |
| 744 | + vd->RTView->Release(); | |
| 745 | + vd->RTView = nullptr; | |
| 746 | + IM_DELETE(vd); | |
| 747 | + } | |
| 748 | + viewport->RendererUserData = nullptr; | |
| 749 | +} | |
| 750 | + | |
| 751 | +static void ImGui_ImplDX10_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) | |
| 752 | +{ | |
| 753 | + ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); | |
| 754 | + ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData; | |
| 755 | + if (vd->RTView) | |
| 756 | + { | |
| 757 | + vd->RTView->Release(); | |
| 758 | + vd->RTView = nullptr; | |
| 759 | + } | |
| 760 | + if (vd->SwapChain) | |
| 761 | + { | |
| 762 | + ID3D10Texture2D* pBackBuffer = nullptr; | |
| 763 | + vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0); | |
| 764 | + vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); | |
| 765 | + if (pBackBuffer == nullptr) { fprintf(stderr, "ImGui_ImplDX10_SetWindowSize() failed creating buffers.\n"); return; } | |
| 766 | + bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView); | |
| 767 | + pBackBuffer->Release(); | |
| 768 | + } | |
| 769 | +} | |
| 770 | + | |
| 771 | +static void ImGui_ImplDX10_RenderViewport(ImGuiViewport* viewport, void*) | |
| 772 | +{ | |
| 773 | + ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); | |
| 774 | + ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData; | |
| 775 | + ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); | |
| 776 | + bd->pd3dDevice->OMSetRenderTargets(1, &vd->RTView, nullptr); | |
| 777 | + if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear)) | |
| 778 | + bd->pd3dDevice->ClearRenderTargetView(vd->RTView, (float*)&clear_color); | |
| 779 | + ImGui_ImplDX10_RenderDrawData(viewport->DrawData); | |
| 780 | +} | |
| 781 | + | |
| 782 | +static void ImGui_ImplDX10_SwapBuffers(ImGuiViewport* viewport, void*) | |
| 783 | +{ | |
| 784 | + ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData; | |
| 785 | + if (vd->SwapChain) | |
| 786 | + vd->SwapChain->Present(0, 0); // Present without vsync | |
| 787 | +} | |
| 788 | + | |
| 789 | +void ImGui_ImplDX10_InitMultiViewportSupport() | |
| 790 | +{ | |
| 791 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 792 | + platform_io.Renderer_CreateWindow = ImGui_ImplDX10_CreateWindow; | |
| 793 | + platform_io.Renderer_DestroyWindow = ImGui_ImplDX10_DestroyWindow; | |
| 794 | + platform_io.Renderer_SetWindowSize = ImGui_ImplDX10_SetWindowSize; | |
| 795 | + platform_io.Renderer_RenderWindow = ImGui_ImplDX10_RenderViewport; | |
| 796 | + platform_io.Renderer_SwapBuffers = ImGui_ImplDX10_SwapBuffers; | |
| 797 | +} | |
| 798 | + | |
| 799 | +void ImGui_ImplDX10_ShutdownMultiViewportSupport() | |
| 800 | +{ | |
| 801 | + ImGui::DestroyPlatformWindows(); | |
| 667 | 802 | } |
| 668 | 803 | |
| 669 | 804 | //----------------------------------------------------------------------------- |
| @@ -5,6 +5,7 @@ | ||
| 5 | 5 | // [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! |
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 8 | 9 | |
| 9 | 10 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 10 | 11 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -6,6 +6,7 @@ | ||
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | 8 | // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. |
| 9 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 9 | 10 | |
| 10 | 11 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 11 | 12 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -17,11 +18,13 @@ | ||
| 17 | 18 | |
| 18 | 19 | // CHANGELOG |
| 19 | 20 | // (minor and older changes stripped away, please see git history for details) |
| 21 | +// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 20 | 22 | // 2026-04-23: DirectX11: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplDX11_RenderState. (#9378) |
| 21 | 23 | // 2026-01-19: DirectX11: Added 'SamplerNearest' in ImGui_ImplDX11_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'. |
| 22 | 24 | // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. |
| 23 | 25 | // 2025-06-11: DirectX11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. |
| 24 | 26 | // 2025-05-07: DirectX11: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). |
| 27 | +// 2025-02-24: [Docking] Added undocumented ImGui_ImplDX11_SetSwapChainDescs() to configure swap chain creation for secondary viewports. | |
| 25 | 28 | // 2025-01-06: DirectX11: Expose VertexConstantBuffer in ImGui_ImplDX11_RenderState. Reset projection matrix in ImDrawCallback_ResetRenderState handler. |
| 26 | 29 | // 2024-10-07: DirectX11: Changed default texture sampler to Clamp instead of Repeat/Wrap. |
| 27 | 30 | // 2024-10-07: DirectX11: Expose selected render state in ImGui_ImplDX11_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. |
| @@ -87,6 +90,7 @@ | ||
| 87 | 90 | int VertexBufferSize; |
| 88 | 91 | int IndexBufferSize; |
| 89 | 92 | ImGui_ImplDX11_RenderState* RenderState; // == (ImGui_ImplDX11_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState during rendering. |
| 93 | + ImVector<DXGI_SWAP_CHAIN_DESC> SwapChainDescsForViewports; | |
| 90 | 94 | |
| 91 | 95 | ImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; } |
| 92 | 96 | }; |
| @@ -103,6 +107,10 @@ | ||
| 103 | 107 | return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; |
| 104 | 108 | } |
| 105 | 109 | |
| 110 | +// Forward Declarations | |
| 111 | +static void ImGui_ImplDX11_InitMultiViewportSupport(); | |
| 112 | +static void ImGui_ImplDX11_ShutdownMultiViewportSupport(); | |
| 113 | + | |
| 106 | 114 | // Functions |
| 107 | 115 | static void ImGui_ImplDX11_SetupRenderState(const ImDrawData* draw_data, ID3D11DeviceContext* device_ctx) |
| 108 | 116 | { |
| @@ -630,6 +638,7 @@ | ||
| 630 | 638 | io.BackendRendererName = "imgui_impl_dx11"; |
| 631 | 639 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. |
| 632 | 640 | io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. |
| 641 | + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) | |
| 633 | 642 | |
| 634 | 643 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 635 | 644 | platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; |
| @@ -655,6 +664,8 @@ | ||
| 655 | 664 | bd->pd3dDevice->AddRef(); |
| 656 | 665 | bd->pd3dDeviceContext->AddRef(); |
| 657 | 666 | |
| 667 | + ImGui_ImplDX11_InitMultiViewportSupport(); | |
| 668 | + | |
| 658 | 669 | return true; |
| 659 | 670 | } |
| 660 | 671 | |
| @@ -665,6 +676,7 @@ | ||
| 665 | 676 | ImGuiIO& io = ImGui::GetIO(); |
| 666 | 677 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 667 | 678 | |
| 679 | + ImGui_ImplDX11_ShutdownMultiViewportSupport(); | |
| 668 | 680 | ImGui_ImplDX11_InvalidateDeviceObjects(); |
| 669 | 681 | if (bd->pFactory) { bd->pFactory->Release(); } |
| 670 | 682 | if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } |
| @@ -672,7 +684,7 @@ | ||
| 672 | 684 | |
| 673 | 685 | io.BackendRendererName = nullptr; |
| 674 | 686 | io.BackendRendererUserData = nullptr; |
| 675 | - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); | |
| 687 | + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports); | |
| 676 | 688 | platform_io.ClearRendererHandlers(); |
| 677 | 689 | IM_DELETE(bd); |
| 678 | 690 | } |
| @@ -685,6 +697,152 @@ | ||
| 685 | 697 | if (!bd->pVertexShader) |
| 686 | 698 | if (!ImGui_ImplDX11_CreateDeviceObjects()) |
| 687 | 699 | IM_ASSERT(0 && "ImGui_ImplDX11_CreateDeviceObjects() failed!"); |
| 700 | +} | |
| 701 | + | |
| 702 | +//-------------------------------------------------------------------------------------------------------- | |
| 703 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 704 | +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. | |
| 705 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 706 | +//-------------------------------------------------------------------------------------------------------- | |
| 707 | + | |
| 708 | +// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data. | |
| 709 | +struct ImGui_ImplDX11_ViewportData | |
| 710 | +{ | |
| 711 | + IDXGISwapChain* SwapChain; | |
| 712 | + ID3D11RenderTargetView* RTView; | |
| 713 | + | |
| 714 | + ImGui_ImplDX11_ViewportData() { SwapChain = nullptr; RTView = nullptr; } | |
| 715 | + ~ImGui_ImplDX11_ViewportData() { IM_ASSERT(SwapChain == nullptr && RTView == nullptr); } | |
| 716 | +}; | |
| 717 | + | |
| 718 | +// Multi-Viewports: configure templates used when creating swapchains for secondary viewports. Will try them in order. | |
| 719 | +// This is intentionally not declared in the .h file yet, so you will need to copy this declaration: | |
| 720 | +void ImGui_ImplDX11_SetSwapChainDescs(const DXGI_SWAP_CHAIN_DESC* desc_templates, int desc_templates_count); | |
| 721 | +void ImGui_ImplDX11_SetSwapChainDescs(const DXGI_SWAP_CHAIN_DESC* desc_templates, int desc_templates_count) | |
| 722 | +{ | |
| 723 | + ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); | |
| 724 | + bd->SwapChainDescsForViewports.resize(desc_templates_count); | |
| 725 | + memcpy(bd->SwapChainDescsForViewports.Data, desc_templates, sizeof(DXGI_SWAP_CHAIN_DESC)); | |
| 726 | +} | |
| 727 | + | |
| 728 | +static void ImGui_ImplDX11_CreateWindow(ImGuiViewport* viewport) | |
| 729 | +{ | |
| 730 | + ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); | |
| 731 | + ImGui_ImplDX11_ViewportData* vd = IM_NEW(ImGui_ImplDX11_ViewportData)(); | |
| 732 | + viewport->RendererUserData = vd; | |
| 733 | + | |
| 734 | + // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID). | |
| 735 | + // Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND. | |
| 736 | + HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle; | |
| 737 | + IM_ASSERT(hwnd != 0); | |
| 738 | + IM_ASSERT(vd->SwapChain == nullptr && vd->RTView == nullptr); | |
| 739 | + | |
| 740 | + // Create swap chain | |
| 741 | + HRESULT hr = DXGI_ERROR_UNSUPPORTED; | |
| 742 | + for (const DXGI_SWAP_CHAIN_DESC& sd_template : bd->SwapChainDescsForViewports) | |
| 743 | + { | |
| 744 | + IM_ASSERT(sd_template.BufferDesc.Width == 0 && sd_template.BufferDesc.Height == 0 && sd_template.OutputWindow == nullptr); | |
| 745 | + DXGI_SWAP_CHAIN_DESC sd = sd_template; | |
| 746 | + sd.BufferDesc.Width = (UINT)viewport->Size.x; | |
| 747 | + sd.BufferDesc.Height = (UINT)viewport->Size.y; | |
| 748 | + sd.OutputWindow = hwnd; | |
| 749 | + hr = bd->pFactory->CreateSwapChain(bd->pd3dDevice, &sd, &vd->SwapChain); | |
| 750 | + if (SUCCEEDED(hr)) | |
| 751 | + break; | |
| 752 | + } | |
| 753 | + IM_ASSERT(SUCCEEDED(hr)); | |
| 754 | + bd->pFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES); // Disable e.g. Alt+Enter | |
| 755 | + | |
| 756 | + // Create the render target | |
| 757 | + if (vd->SwapChain != nullptr) | |
| 758 | + { | |
| 759 | + ID3D11Texture2D* pBackBuffer; | |
| 760 | + vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); | |
| 761 | + bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView); | |
| 762 | + pBackBuffer->Release(); | |
| 763 | + } | |
| 764 | +} | |
| 765 | + | |
| 766 | +static void ImGui_ImplDX11_DestroyWindow(ImGuiViewport* viewport) | |
| 767 | +{ | |
| 768 | + // The main viewport (owned by the application) will always have RendererUserData == nullptr since we didn't create the data for it. | |
| 769 | + if (ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData) | |
| 770 | + { | |
| 771 | + if (vd->SwapChain) | |
| 772 | + vd->SwapChain->Release(); | |
| 773 | + vd->SwapChain = nullptr; | |
| 774 | + if (vd->RTView) | |
| 775 | + vd->RTView->Release(); | |
| 776 | + vd->RTView = nullptr; | |
| 777 | + IM_DELETE(vd); | |
| 778 | + } | |
| 779 | + viewport->RendererUserData = nullptr; | |
| 780 | +} | |
| 781 | + | |
| 782 | +static void ImGui_ImplDX11_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) | |
| 783 | +{ | |
| 784 | + ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); | |
| 785 | + ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData; | |
| 786 | + if (vd->RTView) | |
| 787 | + { | |
| 788 | + vd->RTView->Release(); | |
| 789 | + vd->RTView = nullptr; | |
| 790 | + } | |
| 791 | + if (vd->SwapChain) | |
| 792 | + { | |
| 793 | + ID3D11Texture2D* pBackBuffer = nullptr; | |
| 794 | + vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0); | |
| 795 | + vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); | |
| 796 | + if (pBackBuffer == nullptr) { fprintf(stderr, "ImGui_ImplDX11_SetWindowSize() failed creating buffers.\n"); return; } | |
| 797 | + bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView); | |
| 798 | + pBackBuffer->Release(); | |
| 799 | + } | |
| 800 | +} | |
| 801 | + | |
| 802 | +static void ImGui_ImplDX11_RenderWindow(ImGuiViewport* viewport, void*) | |
| 803 | +{ | |
| 804 | + ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); | |
| 805 | + ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData; | |
| 806 | + ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); | |
| 807 | + bd->pd3dDeviceContext->OMSetRenderTargets(1, &vd->RTView, nullptr); | |
| 808 | + if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear)) | |
| 809 | + bd->pd3dDeviceContext->ClearRenderTargetView(vd->RTView, (float*)&clear_color); | |
| 810 | + ImGui_ImplDX11_RenderDrawData(viewport->DrawData); | |
| 811 | +} | |
| 812 | + | |
| 813 | +static void ImGui_ImplDX11_SwapBuffers(ImGuiViewport* viewport, void*) | |
| 814 | +{ | |
| 815 | + ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData; | |
| 816 | + if (vd->SwapChain) | |
| 817 | + vd->SwapChain->Present(0, 0); // Present without vsync | |
| 818 | +} | |
| 819 | + | |
| 820 | +static void ImGui_ImplDX11_InitMultiViewportSupport() | |
| 821 | +{ | |
| 822 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 823 | + platform_io.Renderer_CreateWindow = ImGui_ImplDX11_CreateWindow; | |
| 824 | + platform_io.Renderer_DestroyWindow = ImGui_ImplDX11_DestroyWindow; | |
| 825 | + platform_io.Renderer_SetWindowSize = ImGui_ImplDX11_SetWindowSize; | |
| 826 | + platform_io.Renderer_RenderWindow = ImGui_ImplDX11_RenderWindow; | |
| 827 | + platform_io.Renderer_SwapBuffers = ImGui_ImplDX11_SwapBuffers; | |
| 828 | + | |
| 829 | + // Default swapchain format | |
| 830 | + DXGI_SWAP_CHAIN_DESC sd; | |
| 831 | + ZeroMemory(&sd, sizeof(sd)); | |
| 832 | + sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
| 833 | + sd.SampleDesc.Count = 1; | |
| 834 | + sd.SampleDesc.Quality = 0; | |
| 835 | + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; | |
| 836 | + sd.BufferCount = 1; | |
| 837 | + sd.Windowed = TRUE; | |
| 838 | + sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; | |
| 839 | + sd.Flags = 0; | |
| 840 | + ImGui_ImplDX11_SetSwapChainDescs(&sd, 1); | |
| 841 | +} | |
| 842 | + | |
| 843 | +static void ImGui_ImplDX11_ShutdownMultiViewportSupport() | |
| 844 | +{ | |
| 845 | + ImGui::DestroyPlatformWindows(); | |
| 688 | 846 | } |
| 689 | 847 | |
| 690 | 848 | //----------------------------------------------------------------------------- |
| @@ -6,6 +6,7 @@ | ||
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | 8 | // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. |
| 9 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 9 | 10 | |
| 10 | 11 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 11 | 12 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -6,6 +6,8 @@ | ||
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | 8 | // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. |
| 9 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 10 | +// FIXME: The transition from removing a viewport and moving the window in an existing hosted viewport tends to flicker. | |
| 9 | 11 | |
| 10 | 12 | // The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification. |
| 11 | 13 | // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ |
| @@ -20,7 +22,9 @@ | ||
| 20 | 22 | |
| 21 | 23 | // CHANGELOG |
| 22 | 24 | // (minor and older changes stripped away, please see git history for details) |
| 25 | +// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 23 | 26 | // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) |
| 27 | +// 2025-10-23: [Docking] DirectX12: Fixed an issue in synchronization logic improving rendering throughput for secondary viewports. (#8961, #9025) | |
| 24 | 28 | // 2025-10-11: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002) |
| 25 | 29 | // 2025-09-29: DirectX12: Rework synchronization logic. (#8961) |
| 26 | 30 | // 2025-09-29: DirectX12: Enable swapchain tearing to eliminate viewports framerate throttling. (#8965) |
| @@ -118,9 +122,6 @@ | ||
| 118 | 122 | UINT pTexUploadBufferSize; |
| 119 | 123 | void* pTexUploadBufferMapped; |
| 120 | 124 | |
| 121 | - ImGui_ImplDX12_RenderBuffers* pFrameResources; | |
| 122 | - UINT frameIndex; | |
| 123 | - | |
| 124 | 125 | ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); } |
| 125 | 126 | }; |
| 126 | 127 | |
| @@ -140,11 +141,85 @@ | ||
| 140 | 141 | int VertexBufferSize; |
| 141 | 142 | }; |
| 142 | 143 | |
| 144 | +// Buffers used for secondary viewports created by the multi-viewports systems | |
| 145 | +struct ImGui_ImplDX12_FrameContext | |
| 146 | +{ | |
| 147 | + UINT64 FenceValue; | |
| 148 | + ID3D12CommandAllocator* CommandAllocator; | |
| 149 | + ID3D12Resource* RenderTarget; | |
| 150 | + D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetCpuDescriptors; | |
| 151 | +}; | |
| 152 | + | |
| 153 | +// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data. | |
| 154 | +// Main viewport created by application will only use the Resources field. | |
| 155 | +// Secondary viewports created by this backend will use all the fields (including Window fields), | |
| 156 | +struct ImGui_ImplDX12_ViewportData | |
| 157 | +{ | |
| 158 | + // Window | |
| 159 | + ID3D12CommandQueue* CommandQueue; | |
| 160 | + ID3D12GraphicsCommandList* CommandList; | |
| 161 | + ID3D12DescriptorHeap* RtvDescHeap; | |
| 162 | + IDXGISwapChain3* SwapChain; | |
| 163 | + HANDLE SwapChainWaitableObject; | |
| 164 | + UINT NumFramesInFlight; | |
| 165 | + ImGui_ImplDX12_FrameContext* FrameCtx; | |
| 166 | + | |
| 167 | + // Render buffers | |
| 168 | + UINT FrameIndex; | |
| 169 | + ImGui_ImplDX12_RenderBuffers* FrameRenderBuffers; | |
| 170 | + | |
| 171 | + ImGui_ImplDX12_ViewportData(UINT num_frames_in_flight) | |
| 172 | + { | |
| 173 | + CommandQueue = nullptr; | |
| 174 | + CommandList = nullptr; | |
| 175 | + RtvDescHeap = nullptr; | |
| 176 | + SwapChain = nullptr; | |
| 177 | + SwapChainWaitableObject = nullptr; | |
| 178 | + NumFramesInFlight = num_frames_in_flight; | |
| 179 | + FrameCtx = new ImGui_ImplDX12_FrameContext[NumFramesInFlight]; | |
| 180 | + FrameIndex = 0; | |
| 181 | + FrameRenderBuffers = new ImGui_ImplDX12_RenderBuffers[NumFramesInFlight]; | |
| 182 | + | |
| 183 | + for (UINT i = 0; i < NumFramesInFlight; ++i) | |
| 184 | + { | |
| 185 | + FrameCtx[i].FenceValue = 0; | |
| 186 | + FrameCtx[i].CommandAllocator = nullptr; | |
| 187 | + FrameCtx[i].RenderTarget = nullptr; | |
| 188 | + | |
| 189 | + // Create buffers with a default size (they will later be grown as needed) | |
| 190 | + FrameRenderBuffers[i].IndexBuffer = nullptr; | |
| 191 | + FrameRenderBuffers[i].VertexBuffer = nullptr; | |
| 192 | + FrameRenderBuffers[i].VertexBufferSize = 5000; | |
| 193 | + FrameRenderBuffers[i].IndexBufferSize = 10000; | |
| 194 | + } | |
| 195 | + } | |
| 196 | + ~ImGui_ImplDX12_ViewportData() | |
| 197 | + { | |
| 198 | + IM_ASSERT(CommandQueue == nullptr && CommandList == nullptr); | |
| 199 | + IM_ASSERT(RtvDescHeap == nullptr); | |
| 200 | + IM_ASSERT(SwapChain == nullptr); | |
| 201 | + IM_ASSERT(SwapChainWaitableObject == nullptr); | |
| 202 | + | |
| 203 | + for (UINT i = 0; i < NumFramesInFlight; ++i) | |
| 204 | + { | |
| 205 | + IM_ASSERT(FrameCtx[i].CommandAllocator == nullptr && FrameCtx[i].RenderTarget == nullptr); | |
| 206 | + IM_ASSERT(FrameRenderBuffers[i].IndexBuffer == nullptr && FrameRenderBuffers[i].VertexBuffer == nullptr); | |
| 207 | + } | |
| 208 | + | |
| 209 | + delete[] FrameCtx; FrameCtx = nullptr; | |
| 210 | + delete[] FrameRenderBuffers; FrameRenderBuffers = nullptr; | |
| 211 | + } | |
| 212 | +}; | |
| 213 | + | |
| 143 | 214 | struct VERTEX_CONSTANT_BUFFER_DX12 |
| 144 | 215 | { |
| 145 | 216 | float mvp[4][4]; |
| 146 | 217 | }; |
| 147 | 218 | |
| 219 | +// Forward Declarations | |
| 220 | +static void ImGui_ImplDX12_InitMultiViewportSupport(); | |
| 221 | +static void ImGui_ImplDX12_ShutdownMultiViewportSupport(); | |
| 222 | + | |
| 148 | 223 | // Functions |
| 149 | 224 | static void ImGui_ImplDX12_SetupSamplerLinear(ID3D12GraphicsCommandList* command_list) |
| 150 | 225 | { |
| @@ -240,8 +315,9 @@ | ||
| 240 | 315 | |
| 241 | 316 | // FIXME: We are assuming that this only gets called once per frame! |
| 242 | 317 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
| 243 | - bd->frameIndex = bd->frameIndex + 1; | |
| 244 | - ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[bd->frameIndex % bd->numFramesInFlight]; | |
| 318 | + ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)draw_data->OwnerViewport->RendererUserData; | |
| 319 | + ImGui_ImplDX12_RenderBuffers* fr = &vd->FrameRenderBuffers[vd->FrameIndex % bd->numFramesInFlight]; | |
| 320 | + vd->FrameIndex++; | |
| 245 | 321 | |
| 246 | 322 | // Create and grow vertex/index buffers if needed |
| 247 | 323 | if (fr->VertexBuffer == nullptr || fr->VertexBufferSize < draw_data->TotalVtxCount) |
| @@ -842,6 +918,13 @@ | ||
| 842 | 918 | return true; |
| 843 | 919 | } |
| 844 | 920 | |
| 921 | +static void ImGui_ImplDX12_DestroyRenderBuffers(ImGui_ImplDX12_RenderBuffers* render_buffers) | |
| 922 | +{ | |
| 923 | + SafeRelease(render_buffers->IndexBuffer); | |
| 924 | + SafeRelease(render_buffers->VertexBuffer); | |
| 925 | + render_buffers->IndexBufferSize = render_buffers->VertexBufferSize = 0; | |
| 926 | +} | |
| 927 | + | |
| 845 | 928 | void ImGui_ImplDX12_InvalidateDeviceObjects() |
| 846 | 929 | { |
| 847 | 930 | ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); |
| @@ -874,13 +957,6 @@ | ||
| 874 | 957 | for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) |
| 875 | 958 | if (tex->RefCount == 1) |
| 876 | 959 | ImGui_ImplDX12_DestroyTexture(tex); |
| 877 | - | |
| 878 | - for (UINT i = 0; i < bd->numFramesInFlight; i++) | |
| 879 | - { | |
| 880 | - ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i]; | |
| 881 | - SafeRelease(fr->IndexBuffer); | |
| 882 | - SafeRelease(fr->VertexBuffer); | |
| 883 | - } | |
| 884 | 960 | } |
| 885 | 961 | |
| 886 | 962 | #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS |
| @@ -929,7 +1005,16 @@ | ||
| 929 | 1005 | io.BackendRendererName = "imgui_impl_dx12"; |
| 930 | 1006 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. |
| 931 | 1007 | io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. |
| 1008 | + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) | |
| 932 | 1009 | |
| 1010 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 1011 | + ImGui_ImplDX12_InitMultiViewportSupport(); | |
| 1012 | + | |
| 1013 | + // Create a dummy ImGui_ImplDX12_ViewportData holder for the main viewport, | |
| 1014 | + // Since this is created and managed by the application, we will only use the ->Resources[] fields. | |
| 1015 | + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | |
| 1016 | + main_viewport->RendererUserData = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight); | |
| 1017 | + | |
| 933 | 1018 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 934 | 1019 | platform_io.DrawCallback_ResetRenderState = ImGui_ImplDX12_DrawCallback_ResetRenderState; |
| 935 | 1020 | platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplDX12_DrawCallback_SetSamplerLinear; |
| @@ -941,18 +1026,6 @@ | ||
| 941 | 1026 | #endif |
| 942 | 1027 | IM_ASSERT(init_info->SrvDescriptorAllocFn != nullptr && init_info->SrvDescriptorFreeFn != nullptr); |
| 943 | 1028 | |
| 944 | - // Create buffers with a default size (they will later be grown as needed) | |
| 945 | - bd->frameIndex = UINT_MAX; | |
| 946 | - bd->pFrameResources = new ImGui_ImplDX12_RenderBuffers[bd->numFramesInFlight]; | |
| 947 | - for (int i = 0; i < (int)bd->numFramesInFlight; i++) | |
| 948 | - { | |
| 949 | - ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i]; | |
| 950 | - fr->IndexBuffer = nullptr; | |
| 951 | - fr->VertexBuffer = nullptr; | |
| 952 | - fr->IndexBufferSize = 10000; | |
| 953 | - fr->VertexBufferSize = 5000; | |
| 954 | - } | |
| 955 | - | |
| 956 | 1029 | return true; |
| 957 | 1030 | } |
| 958 | 1031 | |
| @@ -994,12 +1067,23 @@ | ||
| 994 | 1067 | ImGuiIO& io = ImGui::GetIO(); |
| 995 | 1068 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 996 | 1069 | |
| 1070 | + // Manually delete main viewport render resources in-case we haven't initialized for viewports | |
| 1071 | + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | |
| 1072 | + if (ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)main_viewport->RendererUserData) | |
| 1073 | + { | |
| 1074 | + // We could just call ImGui_ImplDX12_DestroyWindow(main_viewport) as a convenience but that would be misleading since we only use data->Resources[] | |
| 1075 | + for (UINT i = 0; i < bd->numFramesInFlight; i++) | |
| 1076 | + ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]); | |
| 1077 | + IM_DELETE(vd); | |
| 1078 | + main_viewport->RendererUserData = nullptr; | |
| 1079 | + } | |
| 1080 | + | |
| 1081 | + ImGui_ImplDX12_ShutdownMultiViewportSupport(); | |
| 997 | 1082 | ImGui_ImplDX12_InvalidateDeviceObjects(); |
| 998 | - delete[] bd->pFrameResources; | |
| 999 | 1083 | |
| 1000 | 1084 | io.BackendRendererName = nullptr; |
| 1001 | 1085 | io.BackendRendererUserData = nullptr; |
| 1002 | - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); | |
| 1086 | + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports); | |
| 1003 | 1087 | platform_io.ClearRendererHandlers(); |
| 1004 | 1088 | IM_DELETE(bd); |
| 1005 | 1089 | } |
| @@ -1012,6 +1096,254 @@ | ||
| 1012 | 1096 | if (!bd->pPipelineStateLinear) |
| 1013 | 1097 | if (!ImGui_ImplDX12_CreateDeviceObjects()) |
| 1014 | 1098 | IM_ASSERT(0 && "ImGui_ImplDX12_CreateDeviceObjects() failed!"); |
| 1099 | +} | |
| 1100 | + | |
| 1101 | +//-------------------------------------------------------------------------------------------------------- | |
| 1102 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 1103 | +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. | |
| 1104 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 1105 | +//-------------------------------------------------------------------------------------------------------- | |
| 1106 | + | |
| 1107 | +static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport) | |
| 1108 | +{ | |
| 1109 | + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); | |
| 1110 | + ImGui_ImplDX12_ViewportData* vd = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight); | |
| 1111 | + viewport->RendererUserData = vd; | |
| 1112 | + | |
| 1113 | + // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID). | |
| 1114 | + // Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND. | |
| 1115 | + HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle; | |
| 1116 | + IM_ASSERT(hwnd != 0); | |
| 1117 | + | |
| 1118 | + // Use shared command queue from init info | |
| 1119 | + vd->FrameIndex = 0; | |
| 1120 | + vd->CommandQueue = bd->pCommandQueue; | |
| 1121 | + | |
| 1122 | + // Create command allocator. | |
| 1123 | + HRESULT res = S_OK; | |
| 1124 | + for (UINT i = 0; i < bd->numFramesInFlight; ++i) | |
| 1125 | + { | |
| 1126 | + res = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&vd->FrameCtx[i].CommandAllocator)); | |
| 1127 | + IM_ASSERT(res == S_OK); | |
| 1128 | + } | |
| 1129 | + | |
| 1130 | + // Create command list. | |
| 1131 | + res = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, vd->FrameCtx[0].CommandAllocator, nullptr, IID_PPV_ARGS(&vd->CommandList)); | |
| 1132 | + IM_ASSERT(res == S_OK); | |
| 1133 | + vd->CommandList->Close(); | |
| 1134 | + | |
| 1135 | + // Create swap chain | |
| 1136 | + // FIXME-VIEWPORT: May want to copy/inherit swap chain settings from the user/application. | |
| 1137 | + DXGI_SWAP_CHAIN_DESC1 sd1; | |
| 1138 | + ZeroMemory(&sd1, sizeof(sd1)); | |
| 1139 | + sd1.BufferCount = bd->numFramesInFlight; | |
| 1140 | + sd1.Width = (UINT)viewport->Size.x; | |
| 1141 | + sd1.Height = (UINT)viewport->Size.y; | |
| 1142 | + sd1.Format = bd->RTVFormat; | |
| 1143 | + sd1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; | |
| 1144 | + sd1.SampleDesc.Count = 1; | |
| 1145 | + sd1.SampleDesc.Quality = 0; | |
| 1146 | + sd1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; | |
| 1147 | + sd1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; | |
| 1148 | + sd1.Scaling = DXGI_SCALING_NONE; | |
| 1149 | + sd1.Stereo = FALSE; | |
| 1150 | + sd1.Flags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; | |
| 1151 | + | |
| 1152 | + if (bd->tearingSupport) | |
| 1153 | + sd1.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; | |
| 1154 | + | |
| 1155 | + IDXGISwapChain1* swap_chain = nullptr; | |
| 1156 | + res = bd->pdxgiFactory->CreateSwapChainForHwnd(vd->CommandQueue, hwnd, &sd1, nullptr, nullptr, &swap_chain); | |
| 1157 | + IM_ASSERT(res == S_OK); | |
| 1158 | + res = bd->pdxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES); // Disable e.g. Alt+Enter | |
| 1159 | + IM_ASSERT(res == S_OK); | |
| 1160 | + | |
| 1161 | + // Or swapChain.As(&mSwapChain) | |
| 1162 | + IM_ASSERT(vd->SwapChain == nullptr); | |
| 1163 | + swap_chain->QueryInterface(IID_PPV_ARGS(&vd->SwapChain)); | |
| 1164 | + swap_chain->Release(); | |
| 1165 | + | |
| 1166 | + // Create the render targets and waitable object | |
| 1167 | + if (vd->SwapChain) | |
| 1168 | + { | |
| 1169 | + D3D12_DESCRIPTOR_HEAP_DESC desc = {}; | |
| 1170 | + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; | |
| 1171 | + desc.NumDescriptors = bd->numFramesInFlight; | |
| 1172 | + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; | |
| 1173 | + desc.NodeMask = 1; | |
| 1174 | + | |
| 1175 | + HRESULT hr = bd->pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&vd->RtvDescHeap)); | |
| 1176 | + IM_ASSERT(hr == S_OK); | |
| 1177 | + | |
| 1178 | + SIZE_T rtv_descriptor_size = bd->pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); | |
| 1179 | + D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = vd->RtvDescHeap->GetCPUDescriptorHandleForHeapStart(); | |
| 1180 | + for (UINT i = 0; i < bd->numFramesInFlight; i++) | |
| 1181 | + { | |
| 1182 | + vd->FrameCtx[i].RenderTargetCpuDescriptors = rtv_handle; | |
| 1183 | + rtv_handle.ptr += rtv_descriptor_size; | |
| 1184 | + } | |
| 1185 | + | |
| 1186 | + ID3D12Resource* back_buffer; | |
| 1187 | + for (UINT i = 0; i < bd->numFramesInFlight; i++) | |
| 1188 | + { | |
| 1189 | + IM_ASSERT(vd->FrameCtx[i].RenderTarget == nullptr); | |
| 1190 | + vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer)); | |
| 1191 | + bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors); | |
| 1192 | + vd->FrameCtx[i].RenderTarget = back_buffer; | |
| 1193 | + } | |
| 1194 | + | |
| 1195 | + hr = vd->SwapChain->SetMaximumFrameLatency(bd->numFramesInFlight); | |
| 1196 | + IM_ASSERT(hr == S_OK); | |
| 1197 | + vd->SwapChainWaitableObject = vd->SwapChain->GetFrameLatencyWaitableObject(); | |
| 1198 | + } | |
| 1199 | + | |
| 1200 | + for (UINT i = 0; i < bd->numFramesInFlight; i++) | |
| 1201 | + ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]); | |
| 1202 | +} | |
| 1203 | + | |
| 1204 | +static void ImGui_WaitForPendingOperations(ImGui_ImplDX12_ViewportData* vd) | |
| 1205 | +{ | |
| 1206 | + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); | |
| 1207 | + HRESULT hr = vd->CommandQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue); | |
| 1208 | + IM_ASSERT(hr == S_OK); | |
| 1209 | + | |
| 1210 | + hr = bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent); | |
| 1211 | + IM_ASSERT(hr == S_OK); | |
| 1212 | + ::WaitForSingleObject(bd->FenceEvent, INFINITE); | |
| 1213 | +} | |
| 1214 | + | |
| 1215 | +static ImGui_ImplDX12_FrameContext* ImGui_WaitForNextFrameContext(ImGui_ImplDX12_ViewportData* vd) | |
| 1216 | +{ | |
| 1217 | + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); | |
| 1218 | + ImGui_ImplDX12_FrameContext* frame_context = &vd->FrameCtx[vd->FrameIndex % vd->NumFramesInFlight]; | |
| 1219 | + if (bd->Fence->GetCompletedValue() < frame_context->FenceValue) | |
| 1220 | + { | |
| 1221 | + HRESULT hr = bd->Fence->SetEventOnCompletion(frame_context->FenceValue, bd->FenceEvent); | |
| 1222 | + IM_ASSERT(hr == S_OK); | |
| 1223 | + HANDLE waitableObjects[] = { vd->SwapChainWaitableObject, bd->FenceEvent }; | |
| 1224 | + ::WaitForMultipleObjects(2, waitableObjects, TRUE, INFINITE); | |
| 1225 | + } | |
| 1226 | + else | |
| 1227 | + { | |
| 1228 | + ::WaitForSingleObject(vd->SwapChainWaitableObject, INFINITE); | |
| 1229 | + } | |
| 1230 | + return frame_context; | |
| 1231 | +} | |
| 1232 | + | |
| 1233 | +static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport) | |
| 1234 | +{ | |
| 1235 | + // The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it. | |
| 1236 | + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); | |
| 1237 | + if (ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData) | |
| 1238 | + { | |
| 1239 | + ImGui_WaitForPendingOperations(vd); | |
| 1240 | + | |
| 1241 | + vd->CommandQueue = nullptr; | |
| 1242 | + ::CloseHandle(vd->SwapChainWaitableObject); | |
| 1243 | + vd->SwapChainWaitableObject = nullptr; | |
| 1244 | + SafeRelease(vd->CommandList); | |
| 1245 | + SafeRelease(vd->SwapChain); | |
| 1246 | + SafeRelease(vd->RtvDescHeap); | |
| 1247 | + | |
| 1248 | + for (UINT i = 0; i < bd->numFramesInFlight; i++) | |
| 1249 | + { | |
| 1250 | + SafeRelease(vd->FrameCtx[i].RenderTarget); | |
| 1251 | + SafeRelease(vd->FrameCtx[i].CommandAllocator); | |
| 1252 | + ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]); | |
| 1253 | + } | |
| 1254 | + IM_DELETE(vd); | |
| 1255 | + } | |
| 1256 | + viewport->RendererUserData = nullptr; | |
| 1257 | +} | |
| 1258 | + | |
| 1259 | +static void ImGui_ImplDX12_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) | |
| 1260 | +{ | |
| 1261 | + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); | |
| 1262 | + ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData; | |
| 1263 | + | |
| 1264 | + ImGui_WaitForPendingOperations(vd); | |
| 1265 | + | |
| 1266 | + for (UINT i = 0; i < bd->numFramesInFlight; i++) | |
| 1267 | + SafeRelease(vd->FrameCtx[i].RenderTarget); | |
| 1268 | + | |
| 1269 | + if (vd->SwapChain) | |
| 1270 | + { | |
| 1271 | + ID3D12Resource* back_buffer = nullptr; | |
| 1272 | + DXGI_SWAP_CHAIN_DESC1 desc = {}; | |
| 1273 | + vd->SwapChain->GetDesc1(&desc); | |
| 1274 | + vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, desc.Format, desc.Flags); | |
| 1275 | + for (UINT i = 0; i < bd->numFramesInFlight; i++) | |
| 1276 | + { | |
| 1277 | + vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer)); | |
| 1278 | + bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors); | |
| 1279 | + vd->FrameCtx[i].RenderTarget = back_buffer; | |
| 1280 | + } | |
| 1281 | + } | |
| 1282 | +} | |
| 1283 | + | |
| 1284 | +static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*) | |
| 1285 | +{ | |
| 1286 | + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); | |
| 1287 | + ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData; | |
| 1288 | + | |
| 1289 | + ImGui_ImplDX12_FrameContext* frame_context = ImGui_WaitForNextFrameContext(vd); | |
| 1290 | + UINT back_buffer_idx = vd->SwapChain->GetCurrentBackBufferIndex(); | |
| 1291 | + | |
| 1292 | + const ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); | |
| 1293 | + D3D12_RESOURCE_BARRIER barrier = {}; | |
| 1294 | + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; | |
| 1295 | + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; | |
| 1296 | + barrier.Transition.pResource = vd->FrameCtx[back_buffer_idx].RenderTarget; | |
| 1297 | + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; | |
| 1298 | + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; | |
| 1299 | + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; | |
| 1300 | + | |
| 1301 | + // Draw | |
| 1302 | + ID3D12GraphicsCommandList* cmd_list = vd->CommandList; | |
| 1303 | + | |
| 1304 | + frame_context->CommandAllocator->Reset(); | |
| 1305 | + cmd_list->Reset(frame_context->CommandAllocator, nullptr); | |
| 1306 | + cmd_list->ResourceBarrier(1, &barrier); | |
| 1307 | + cmd_list->OMSetRenderTargets(1, &vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, FALSE, nullptr); | |
| 1308 | + if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear)) | |
| 1309 | + cmd_list->ClearRenderTargetView(vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, (const float*)&clear_color, 0, nullptr); | |
| 1310 | + cmd_list->SetDescriptorHeaps(1, &bd->pd3dSrvDescHeap); | |
| 1311 | + | |
| 1312 | + ImGui_ImplDX12_RenderDrawData(viewport->DrawData, cmd_list); | |
| 1313 | + | |
| 1314 | + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; | |
| 1315 | + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; | |
| 1316 | + cmd_list->ResourceBarrier(1, &barrier); | |
| 1317 | + cmd_list->Close(); | |
| 1318 | + | |
| 1319 | + vd->CommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmd_list); | |
| 1320 | + | |
| 1321 | + HRESULT hr = vd->CommandQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue); | |
| 1322 | + IM_ASSERT(hr == S_OK); | |
| 1323 | + frame_context->FenceValue = bd->FenceLastSignaledValue; | |
| 1324 | +} | |
| 1325 | + | |
| 1326 | +static void ImGui_ImplDX12_SwapBuffers(ImGuiViewport* viewport, void*) | |
| 1327 | +{ | |
| 1328 | + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); | |
| 1329 | + ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData; | |
| 1330 | + | |
| 1331 | + vd->SwapChain->Present(0, bd->tearingSupport ? DXGI_PRESENT_ALLOW_TEARING : 0); | |
| 1332 | +} | |
| 1333 | + | |
| 1334 | +void ImGui_ImplDX12_InitMultiViewportSupport() | |
| 1335 | +{ | |
| 1336 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 1337 | + platform_io.Renderer_CreateWindow = ImGui_ImplDX12_CreateWindow; | |
| 1338 | + platform_io.Renderer_DestroyWindow = ImGui_ImplDX12_DestroyWindow; | |
| 1339 | + platform_io.Renderer_SetWindowSize = ImGui_ImplDX12_SetWindowSize; | |
| 1340 | + platform_io.Renderer_RenderWindow = ImGui_ImplDX12_RenderWindow; | |
| 1341 | + platform_io.Renderer_SwapBuffers = ImGui_ImplDX12_SwapBuffers; | |
| 1342 | +} | |
| 1343 | + | |
| 1344 | +void ImGui_ImplDX12_ShutdownMultiViewportSupport() | |
| 1345 | +{ | |
| 1346 | + ImGui::DestroyPlatformWindows(); | |
| 1015 | 1347 | } |
| 1016 | 1348 | |
| 1017 | 1349 | //----------------------------------------------------------------------------- |
| @@ -6,6 +6,7 @@ | ||
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | 8 | // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. |
| 9 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 9 | 10 | |
| 10 | 11 | // The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification. |
| 11 | 12 | // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ |
| @@ -6,6 +6,7 @@ | ||
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | 8 | // [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9. |
| 9 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 9 | 10 | |
| 10 | 11 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 11 | 12 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -17,6 +18,7 @@ | ||
| 17 | 18 | |
| 18 | 19 | // CHANGELOG |
| 19 | 20 | // (minor and older changes stripped away, please see git history for details) |
| 21 | +// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 20 | 22 | // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) |
| 21 | 23 | // 2026-03-19: Fixed issue in ImGui_ImplDX9_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) |
| 22 | 24 | // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. |
| @@ -89,6 +91,12 @@ | ||
| 89 | 91 | return ImGui::GetCurrentContext() ? (ImGui_ImplDX9_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; |
| 90 | 92 | } |
| 91 | 93 | |
| 94 | +// Forward Declarations | |
| 95 | +static void ImGui_ImplDX9_InitMultiViewportSupport(); | |
| 96 | +static void ImGui_ImplDX9_ShutdownMultiViewportSupport(); | |
| 97 | +static void ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows(); | |
| 98 | +static void ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows(); | |
| 99 | + | |
| 92 | 100 | // Functions |
| 93 | 101 | static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data) |
| 94 | 102 | { |
| @@ -302,6 +310,11 @@ | ||
| 302 | 310 | global_vtx_offset += draw_list->VtxBuffer.Size; |
| 303 | 311 | } |
| 304 | 312 | |
| 313 | + // When using multi-viewports, it appears that there's an odd logic in DirectX9 which prevent subsequent windows | |
| 314 | + // from rendering until the first window submits at least one draw call, even once. That's our workaround. (see #2560) | |
| 315 | + if (global_vtx_offset == 0) | |
| 316 | + bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 0, 0, 0); | |
| 317 | + | |
| 305 | 318 | // Restore the DX9 transform |
| 306 | 319 | device->SetTransform(D3DTS_WORLD, &last_world); |
| 307 | 320 | device->SetTransform(D3DTS_VIEW, &last_view); |
| @@ -415,6 +428,7 @@ | ||
| 415 | 428 | ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); |
| 416 | 429 | if (!bd || !bd->pd3dDevice) |
| 417 | 430 | return false; |
| 431 | + ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows(); | |
| 418 | 432 | return true; |
| 419 | 433 | } |
| 420 | 434 | |
| @@ -433,6 +447,7 @@ | ||
| 433 | 447 | } |
| 434 | 448 | if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } |
| 435 | 449 | if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } |
| 450 | + ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows(); | |
| 436 | 451 | } |
| 437 | 452 | |
| 438 | 453 | void ImGui_ImplDX9_NewFrame() |
| @@ -442,7 +457,6 @@ | ||
| 442 | 457 | IM_UNUSED(bd); |
| 443 | 458 | } |
| 444 | 459 | |
| 445 | - | |
| 446 | 460 | bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) |
| 447 | 461 | { |
| 448 | 462 | ImGuiIO& io = ImGui::GetIO(); |
| @@ -455,6 +469,7 @@ | ||
| 455 | 469 | io.BackendRendererName = "imgui_impl_dx9"; |
| 456 | 470 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. |
| 457 | 471 | io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. |
| 472 | + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) | |
| 458 | 473 | |
| 459 | 474 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 460 | 475 | platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = 4096; |
| @@ -466,6 +481,8 @@ | ||
| 466 | 481 | bd->pd3dDevice->AddRef(); |
| 467 | 482 | bd->HasRgbaSupport = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8); |
| 468 | 483 | |
| 484 | + ImGui_ImplDX9_InitMultiViewportSupport(); | |
| 485 | + | |
| 469 | 486 | return true; |
| 470 | 487 | } |
| 471 | 488 | |
| @@ -476,14 +493,157 @@ | ||
| 476 | 493 | ImGuiIO& io = ImGui::GetIO(); |
| 477 | 494 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 478 | 495 | |
| 496 | + ImGui_ImplDX9_ShutdownMultiViewportSupport(); | |
| 479 | 497 | ImGui_ImplDX9_InvalidateDeviceObjects(); |
| 480 | 498 | if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } |
| 481 | 499 | |
| 482 | 500 | io.BackendRendererName = nullptr; |
| 483 | 501 | io.BackendRendererUserData = nullptr; |
| 484 | - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); | |
| 502 | + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports); | |
| 485 | 503 | platform_io.ClearRendererHandlers(); |
| 486 | 504 | IM_DELETE(bd); |
| 505 | +} | |
| 506 | + | |
| 507 | +//-------------------------------------------------------------------------------------------------------- | |
| 508 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 509 | +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. | |
| 510 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 511 | +//-------------------------------------------------------------------------------------------------------- | |
| 512 | + | |
| 513 | +// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data. | |
| 514 | +struct ImGui_ImplDX9_ViewportData | |
| 515 | +{ | |
| 516 | + IDirect3DSwapChain9* SwapChain; | |
| 517 | + D3DPRESENT_PARAMETERS d3dpp; | |
| 518 | + | |
| 519 | + ImGui_ImplDX9_ViewportData() { SwapChain = nullptr; ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS)); } | |
| 520 | + ~ImGui_ImplDX9_ViewportData() { IM_ASSERT(SwapChain == nullptr); } | |
| 521 | +}; | |
| 522 | + | |
| 523 | +static void ImGui_ImplDX9_CreateWindow(ImGuiViewport* viewport) | |
| 524 | +{ | |
| 525 | + ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); | |
| 526 | + ImGui_ImplDX9_ViewportData* vd = IM_NEW(ImGui_ImplDX9_ViewportData)(); | |
| 527 | + viewport->RendererUserData = vd; | |
| 528 | + | |
| 529 | + // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID). | |
| 530 | + // Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND. | |
| 531 | + HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle; | |
| 532 | + IM_ASSERT(hwnd != 0); | |
| 533 | + | |
| 534 | + ZeroMemory(&vd->d3dpp, sizeof(D3DPRESENT_PARAMETERS)); | |
| 535 | + vd->d3dpp.Windowed = TRUE; | |
| 536 | + vd->d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; | |
| 537 | + vd->d3dpp.BackBufferWidth = (UINT)viewport->Size.x; | |
| 538 | + vd->d3dpp.BackBufferHeight = (UINT)viewport->Size.y; | |
| 539 | + vd->d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; | |
| 540 | + vd->d3dpp.hDeviceWindow = hwnd; | |
| 541 | + vd->d3dpp.EnableAutoDepthStencil = FALSE; | |
| 542 | + vd->d3dpp.AutoDepthStencilFormat = D3DFMT_D16; | |
| 543 | + vd->d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Present without vsync | |
| 544 | + | |
| 545 | + HRESULT hr = bd->pd3dDevice->CreateAdditionalSwapChain(&vd->d3dpp, &vd->SwapChain); IM_UNUSED(hr); | |
| 546 | + IM_ASSERT(hr == D3D_OK); | |
| 547 | + IM_ASSERT(vd->SwapChain != nullptr); | |
| 548 | +} | |
| 549 | + | |
| 550 | +static void ImGui_ImplDX9_DestroyWindow(ImGuiViewport* viewport) | |
| 551 | +{ | |
| 552 | + // The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it. | |
| 553 | + if (ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData) | |
| 554 | + { | |
| 555 | + if (vd->SwapChain) | |
| 556 | + vd->SwapChain->Release(); | |
| 557 | + vd->SwapChain = nullptr; | |
| 558 | + ZeroMemory(&vd->d3dpp, sizeof(D3DPRESENT_PARAMETERS)); | |
| 559 | + IM_DELETE(vd); | |
| 560 | + } | |
| 561 | + viewport->RendererUserData = nullptr; | |
| 562 | +} | |
| 563 | + | |
| 564 | +static void ImGui_ImplDX9_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) | |
| 565 | +{ | |
| 566 | + ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); | |
| 567 | + ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData; | |
| 568 | + if (vd->SwapChain) | |
| 569 | + { | |
| 570 | + vd->SwapChain->Release(); | |
| 571 | + vd->SwapChain = nullptr; | |
| 572 | + vd->d3dpp.BackBufferWidth = (UINT)size.x; | |
| 573 | + vd->d3dpp.BackBufferHeight = (UINT)size.y; | |
| 574 | + HRESULT hr = bd->pd3dDevice->CreateAdditionalSwapChain(&vd->d3dpp, &vd->SwapChain); IM_UNUSED(hr); | |
| 575 | + IM_ASSERT(hr == D3D_OK); | |
| 576 | + } | |
| 577 | +} | |
| 578 | + | |
| 579 | +static void ImGui_ImplDX9_RenderWindow(ImGuiViewport* viewport, void*) | |
| 580 | +{ | |
| 581 | + ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); | |
| 582 | + ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData; | |
| 583 | + ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); | |
| 584 | + | |
| 585 | + LPDIRECT3DSURFACE9 render_target = nullptr; | |
| 586 | + LPDIRECT3DSURFACE9 last_render_target = nullptr; | |
| 587 | + LPDIRECT3DSURFACE9 last_depth_stencil = nullptr; | |
| 588 | + vd->SwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &render_target); | |
| 589 | + bd->pd3dDevice->GetRenderTarget(0, &last_render_target); | |
| 590 | + bd->pd3dDevice->GetDepthStencilSurface(&last_depth_stencil); | |
| 591 | + bd->pd3dDevice->SetRenderTarget(0, render_target); | |
| 592 | + bd->pd3dDevice->SetDepthStencilSurface(nullptr); | |
| 593 | + | |
| 594 | + if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear)) | |
| 595 | + { | |
| 596 | + D3DCOLOR clear_col_dx = D3DCOLOR_RGBA((int)(clear_color.x*255.0f), (int)(clear_color.y*255.0f), (int)(clear_color.z*255.0f), (int)(clear_color.w*255.0f)); | |
| 597 | + bd->pd3dDevice->Clear(0, nullptr, D3DCLEAR_TARGET, clear_col_dx, 1.0f, 0); | |
| 598 | + } | |
| 599 | + | |
| 600 | + ImGui_ImplDX9_RenderDrawData(viewport->DrawData); | |
| 601 | + | |
| 602 | + // Restore render target | |
| 603 | + bd->pd3dDevice->SetRenderTarget(0, last_render_target); | |
| 604 | + bd->pd3dDevice->SetDepthStencilSurface(last_depth_stencil); | |
| 605 | + render_target->Release(); | |
| 606 | + last_render_target->Release(); | |
| 607 | + if (last_depth_stencil) last_depth_stencil->Release(); | |
| 608 | +} | |
| 609 | + | |
| 610 | +static void ImGui_ImplDX9_SwapBuffers(ImGuiViewport* viewport, void*) | |
| 611 | +{ | |
| 612 | + ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData; | |
| 613 | + HRESULT hr = vd->SwapChain->Present(nullptr, nullptr, vd->d3dpp.hDeviceWindow, nullptr, 0); | |
| 614 | + // Let main application handle D3DERR_DEVICELOST by resetting the device. | |
| 615 | + IM_ASSERT(SUCCEEDED(hr) || hr == D3DERR_DEVICELOST); | |
| 616 | +} | |
| 617 | + | |
| 618 | +static void ImGui_ImplDX9_InitMultiViewportSupport() | |
| 619 | +{ | |
| 620 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 621 | + platform_io.Renderer_CreateWindow = ImGui_ImplDX9_CreateWindow; | |
| 622 | + platform_io.Renderer_DestroyWindow = ImGui_ImplDX9_DestroyWindow; | |
| 623 | + platform_io.Renderer_SetWindowSize = ImGui_ImplDX9_SetWindowSize; | |
| 624 | + platform_io.Renderer_RenderWindow = ImGui_ImplDX9_RenderWindow; | |
| 625 | + platform_io.Renderer_SwapBuffers = ImGui_ImplDX9_SwapBuffers; | |
| 626 | +} | |
| 627 | + | |
| 628 | +static void ImGui_ImplDX9_ShutdownMultiViewportSupport() | |
| 629 | +{ | |
| 630 | + ImGui::DestroyPlatformWindows(); | |
| 631 | +} | |
| 632 | + | |
| 633 | +static void ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows() | |
| 634 | +{ | |
| 635 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 636 | + for (int i = 1; i < platform_io.Viewports.Size; i++) | |
| 637 | + if (!platform_io.Viewports[i]->RendererUserData) | |
| 638 | + ImGui_ImplDX9_CreateWindow(platform_io.Viewports[i]); | |
| 639 | +} | |
| 640 | + | |
| 641 | +static void ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows() | |
| 642 | +{ | |
| 643 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 644 | + for (int i = 1; i < platform_io.Viewports.Size; i++) | |
| 645 | + if (platform_io.Viewports[i]->RendererUserData) | |
| 646 | + ImGui_ImplDX9_DestroyWindow(platform_io.Viewports[i]); | |
| 487 | 647 | } |
| 488 | 648 | |
| 489 | 649 | //----------------------------------------------------------------------------- |
| @@ -6,6 +6,7 @@ | ||
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | 8 | // [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9. |
| 9 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 9 | 10 | |
| 10 | 11 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 11 | 12 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -9,10 +9,12 @@ | ||
| 9 | 9 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] |
| 10 | 10 | // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. |
| 11 | 11 | // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors) with GLFW 3.1+. Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. |
| 12 | +// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 12 | 13 | // [X] Multiple Dear ImGui contexts support. |
| 13 | 14 | // Missing features or Issues: |
| 14 | 15 | // [ ] Platform: Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. |
| 15 | 16 | // [ ] Platform: Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. |
| 17 | +// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either. | |
| 16 | 18 | |
| 17 | 19 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 18 | 20 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -29,19 +31,27 @@ | ||
| 29 | 31 | |
| 30 | 32 | // CHANGELOG |
| 31 | 33 | // (minor and older changes stripped away, please see git history for details) |
| 34 | +// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 32 | 35 | // 2026-04-21: Added a Win32-specific implementation of ImGui_ImplGlfw_GetContentScaleXXXX functions for legacy GLFW 3.2. |
| 33 | 36 | // 2026-03-25: Mouse cursor is properly restored if changed by user app/code while using glfwSetInputMode(..., GLFW_CURSOR_DISABLED) or ImGuiConfigFlags_NoMouseCursorChange. Amend change from 2025-12-10. |
| 34 | 37 | // 2026-02-10: Try to set IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND automatically if corresponding headers are not accessible. (#9225) |
| 38 | +// 2026-01-25: [Docking] Improve workarounds for cases where GLFW is unable to provide any reliable monitor info. Preserve existing monitor list when none of the new one is valid. (#9195, #7902, #5683) | |
| 39 | +// 2026-01-18: [Docking] Dynamically load X11 functions to avoid -lx11 linking requirement introduced on 2025-09-10. | |
| 35 | 40 | // 2025-12-12: Added IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND to forcefully disable either. |
| 36 | 41 | // 2025-12-10: Avoid repeated glfwSetCursor()/glfwSetInputMode() calls when unnecessary. Lowers overhead for very high framerates (e.g. 10k+ FPS). |
| 37 | 42 | // 2025-11-06: Lower minimum requirement to GLFW 3.0. Though a recent version e.g GLFW 3.4 is highly recommended. |
| 38 | 43 | // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. |
| 39 | 44 | // 2025-09-15: Content Scales are always reported as 1.0 on Wayland. FramebufferScale are always reported as 1.0 on X11. (#8920, #8921) |
| 45 | +// 2025-09-10: [Docking] Improve multi-viewport behavior in tiling WMs on X11 via the ImGui_ImplGlfw_SetWindowFloating() function. Note: using GLFW backend on Linux/BSD etc. requires linking with -lX11. (#8884, #8474, #8289) | |
| 40 | 46 | // 2025-07-08: Made ImGui_ImplGlfw_GetContentScaleForWindow(), ImGui_ImplGlfw_GetContentScaleForMonitor() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) |
| 41 | 47 | // 2025-06-18: Added support for multiple Dear ImGui contexts. (#8676, #8239, #8069) |
| 42 | 48 | // 2025-06-11: Added ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) and ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) helper to facilitate making DPI-aware apps. |
| 49 | +// 2025-05-15: [Docking] Add Platform_GetWindowFramebufferScale() handler, to allow varying Retina display density on multiple monitors. | |
| 50 | +// 2025-04-26: [Docking] Disable multi-viewports under Wayland. (#8587) | |
| 43 | 51 | // 2025-03-10: Map GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 into ImGuiKey_Oem102. |
| 44 | 52 | // 2025-03-03: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. |
| 53 | +// 2025-02-21: [Docking] Update monitors and work areas information every frame, as the later may change regardless of monitor changes. (#8415) | |
| 54 | +// 2024-11-05: [Docking] Added Linux workaround for spurious mouse up events emitted while dragging and creating new viewport. (#3158, #7733, #7922) | |
| 45 | 55 | // 2024-08-22: Moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: |
| 46 | 56 | // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn |
| 47 | 57 | // - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn |
| @@ -58,6 +68,7 @@ | ||
| 58 | 68 | // 2023-03-16: Inputs: Fixed key modifiers handling on secondary viewports (docking branch). Broken on 2023/01/04. (#6248, #6034) |
| 59 | 69 | // 2023-03-14: Emscripten: Avoid using glfwGetError() and glfwGetGamepadState() which are not correctly implemented in Emscripten emulation. (#6240) |
| 60 | 70 | // 2023-02-03: Emscripten: Registering custom low-level mouse wheel handler to get more accurate scrolling impulses on Emscripten. (#4019, #6096) |
| 71 | +// 2023-01-18: Handle unsupported glfwGetVideoMode() call on e.g. Emscripten. | |
| 61 | 72 | // 2023-01-04: Inputs: Fixed mods state on Linux when using Alt-GR text input (e.g. German keyboard layout), could lead to broken text input. Revert a 2022/01/17 change were we resumed using mods provided by GLFW, turns out they were faulty. |
| 62 | 73 | // 2022-11-22: Perform a dummy glfwGetError() read to cancel missing names with glfwGetKeyName(). (#5908) |
| 63 | 74 | // 2022-10-18: Perform a dummy glfwGetError() read to cancel missing mouse cursors errors. Using GLFW_VERSION_COMBINED directly. (#5785) |
| @@ -110,6 +121,8 @@ | ||
| 110 | 121 | #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness |
| 111 | 122 | #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. |
| 112 | 123 | #pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. |
| 124 | +#elif defined(__GNUC__) | |
| 125 | +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe | |
| 113 | 126 | #endif |
| 114 | 127 | |
| 115 | 128 | #if defined(__has_include) |
| @@ -147,10 +160,13 @@ | ||
| 147 | 160 | #elif GLFW_HAS_X11 |
| 148 | 161 | #ifndef GLFW_EXPOSE_NATIVE_X11 // for glfwGetX11Display(), glfwGetX11Window() on Freedesktop (Linux, BSD, etc.) |
| 149 | 162 | #define GLFW_EXPOSE_NATIVE_X11 |
| 163 | +#include <X11/Xatom.h> | |
| 164 | +#include <dlfcn.h> // for dlopen() | |
| 150 | 165 | #endif |
| 151 | 166 | #include <GLFW/glfw3native.h> |
| 152 | -#endif | |
| 153 | 167 | #undef Status // X11 headers are leaking this. |
| 168 | +#endif | |
| 169 | + | |
| 154 | 170 | #ifndef _WIN32 |
| 155 | 171 | #include <unistd.h> // for usleep() |
| 156 | 172 | #endif |
| @@ -169,12 +185,29 @@ | ||
| 169 | 185 | // We gather version tests as define in order to easily see which features are version-dependent. |
| 170 | 186 | #define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION) |
| 171 | 187 | #define GLFW_HAS_CREATECURSOR (GLFW_VERSION_COMBINED >= 3100) // 3.1+ glfwCreateCursor() |
| 188 | +#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_COMBINED >= 3200) // 3.2+ GLFW_FLOATING | |
| 189 | +#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_COMBINED >= 3300) // 3.3+ GLFW_HOVERED | |
| 190 | +#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwSetWindowOpacity | |
| 172 | 191 | #define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorContentScale |
| 192 | +#if defined(__EMSCRIPTEN__) || defined(__SWITCH__) // no Vulkan support in GLFW for Emscripten or homebrew Nintendo Switch | |
| 193 | +#define GLFW_HAS_VULKAN (0) | |
| 194 | +#else | |
| 195 | +#define GLFW_HAS_VULKAN (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwCreateWindowSurface | |
| 196 | +#endif | |
| 197 | +#define GLFW_HAS_FOCUS_WINDOW (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwFocusWindow | |
| 198 | +#define GLFW_HAS_FOCUS_ON_SHOW (GLFW_VERSION_COMBINED >= 3300) // 3.3+ GLFW_FOCUS_ON_SHOW | |
| 199 | +#define GLFW_HAS_MONITOR_WORK_AREA (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorWorkarea | |
| 200 | +#define GLFW_HAS_OSX_WINDOW_POS_FIX (GLFW_VERSION_COMBINED >= 3301) // 3.3.1+ Fixed: Resizing window repositions it on MacOS #1553 | |
| 173 | 201 | #ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released? |
| 174 | 202 | #define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR |
| 175 | 203 | #else |
| 176 | 204 | #define GLFW_HAS_NEW_CURSORS (0) |
| 177 | 205 | #endif |
| 206 | +#ifdef GLFW_MOUSE_PASSTHROUGH // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2020-07-17 (passthrough) | |
| 207 | +#define GLFW_HAS_MOUSE_PASSTHROUGH (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_MOUSE_PASSTHROUGH | |
| 208 | +#else | |
| 209 | +#define GLFW_HAS_MOUSE_PASSTHROUGH (0) | |
| 210 | +#endif | |
| 178 | 211 | #define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetGamepadState() new api |
| 179 | 212 | #define GLFW_HAS_GETKEYNAME (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwGetKeyName() |
| 180 | 213 | #define GLFW_HAS_GETERROR (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetError() |
| @@ -197,6 +230,13 @@ | ||
| 197 | 230 | GlfwClientApi_Unknown, // Anything else fits here. |
| 198 | 231 | }; |
| 199 | 232 | |
| 233 | +#if GLFW_HAS_X11 | |
| 234 | +typedef Atom (*PFN_XInternAtom)(Display*, const char* ,Bool); | |
| 235 | +typedef int (*PFN_XChangeProperty)(Display*, Window, Atom, Atom, int, int, const unsigned char*, int); | |
| 236 | +typedef int (*PFN_XChangeWindowAttributes)(Display*, Window, unsigned long, XSetWindowAttributes*); | |
| 237 | +typedef int (*PFN_XFlush)(Display*); | |
| 238 | +#endif | |
| 239 | + | |
| 200 | 240 | // GLFW data |
| 201 | 241 | struct ImGui_ImplGlfw_Data |
| 202 | 242 | { |
| @@ -209,7 +249,10 @@ | ||
| 209 | 249 | GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT]; |
| 210 | 250 | GLFWcursor* LastMouseCursor; |
| 211 | 251 | #endif |
| 252 | + bool MouseIgnoreButtonUpWaitForFocusLoss; | |
| 253 | + bool MouseIgnoreButtonUp; | |
| 212 | 254 | ImVec2 LastValidMousePos; |
| 255 | + GLFWwindow* KeyOwnerWindows[GLFW_KEY_LAST]; | |
| 213 | 256 | bool IsWayland; |
| 214 | 257 | bool InstalledCallbacks; |
| 215 | 258 | bool CallbacksChainForAllWindows; |
| @@ -231,6 +274,15 @@ | ||
| 231 | 274 | WNDPROC PrevWndProc; |
| 232 | 275 | #endif |
| 233 | 276 | |
| 277 | +#if GLFW_HAS_X11 | |
| 278 | + // Module and function pointers loaded at initialization to avoid linking statically with X11. | |
| 279 | + void* X11Module; | |
| 280 | + PFN_XInternAtom XInternAtom; | |
| 281 | + PFN_XChangeProperty XChangeProperty; | |
| 282 | + PFN_XChangeWindowAttributes XChangeWindowAttributes; | |
| 283 | + PFN_XFlush XFlush; | |
| 284 | +#endif | |
| 285 | + | |
| 234 | 286 | ImGui_ImplGlfw_Data() { memset((void*)this, 0, sizeof(*this)); } |
| 235 | 287 | }; |
| 236 | 288 | |
| @@ -254,6 +306,11 @@ | ||
| 254 | 306 | return (ImGui_ImplGlfw_Data*)ImGui::GetIO(ctx).BackendPlatformUserData; |
| 255 | 307 | } |
| 256 | 308 | |
| 309 | +// Forward Declarations | |
| 310 | +static void ImGui_ImplGlfw_UpdateMonitors(); | |
| 311 | +static void ImGui_ImplGlfw_InitMultiViewportSupport(); | |
| 312 | +static void ImGui_ImplGlfw_ShutdownMultiViewportSupport(); | |
| 313 | + | |
| 257 | 314 | // Functions |
| 258 | 315 | static bool ImGui_ImplGlfw_IsWayland() |
| 259 | 316 | { |
| @@ -424,6 +481,10 @@ | ||
| 424 | 481 | if (bd->PrevUserCallbackMousebutton != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) |
| 425 | 482 | bd->PrevUserCallbackMousebutton(window, button, action, mods); |
| 426 | 483 | |
| 484 | + // Workaround for Linux: ignore mouse up events which are following an focus loss following a viewport creation | |
| 485 | + if (bd->MouseIgnoreButtonUp && action == GLFW_RELEASE) | |
| 486 | + return; | |
| 487 | + | |
| 427 | 488 | ImGuiIO& io = ImGui::GetIO(bd->Context); |
| 428 | 489 | ImGui_ImplGlfw_UpdateKeyModifiers(io, window); |
| 429 | 490 | if (button >= 0 && button < ImGuiMouseButton_COUNT) |
| @@ -491,6 +552,9 @@ | ||
| 491 | 552 | ImGuiIO& io = ImGui::GetIO(bd->Context); |
| 492 | 553 | ImGui_ImplGlfw_UpdateKeyModifiers(io, window); |
| 493 | 554 | |
| 555 | + if (keycode >= 0 && keycode < IM_COUNTOF(bd->KeyOwnerWindows)) | |
| 556 | + bd->KeyOwnerWindows[keycode] = (action == GLFW_PRESS) ? window : nullptr; | |
| 557 | + | |
| 494 | 558 | keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode); |
| 495 | 559 | |
| 496 | 560 | ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode, scancode); |
| @@ -504,6 +568,10 @@ | ||
| 504 | 568 | if (bd->PrevUserCallbackWindowFocus != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) |
| 505 | 569 | bd->PrevUserCallbackWindowFocus(window, focused); |
| 506 | 570 | |
| 571 | + // Workaround for Linux: when losing focus with MouseIgnoreButtonUpWaitForFocusLoss set, we will temporarily ignore subsequent Mouse Up events | |
| 572 | + bd->MouseIgnoreButtonUp = (bd->MouseIgnoreButtonUpWaitForFocusLoss && focused == 0); | |
| 573 | + bd->MouseIgnoreButtonUpWaitForFocusLoss = false; | |
| 574 | + | |
| 507 | 575 | ImGuiIO& io = ImGui::GetIO(bd->Context); |
| 508 | 576 | io.AddFocusEvent(focused != 0); |
| 509 | 577 | } |
| @@ -515,6 +583,13 @@ | ||
| 515 | 583 | bd->PrevUserCallbackCursorPos(window, x, y); |
| 516 | 584 | |
| 517 | 585 | ImGuiIO& io = ImGui::GetIO(bd->Context); |
| 586 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 587 | + { | |
| 588 | + int window_x, window_y; | |
| 589 | + glfwGetWindowPos(window, &window_x, &window_y); | |
| 590 | + x += window_x; | |
| 591 | + y += window_y; | |
| 592 | + } | |
| 518 | 593 | io.AddMousePosEvent((float)x, (float)y); |
| 519 | 594 | bd->LastValidMousePos = ImVec2((float)x, (float)y); |
| 520 | 595 | } |
| @@ -553,7 +628,7 @@ | ||
| 553 | 628 | |
| 554 | 629 | void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int) |
| 555 | 630 | { |
| 556 | - // Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too. | |
| 631 | + // This function is technically part of the API even if we stopped using the callback, so leaving it around. | |
| 557 | 632 | } |
| 558 | 633 | |
| 559 | 634 | #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 |
| @@ -576,35 +651,7 @@ | ||
| 576 | 651 | #endif |
| 577 | 652 | |
| 578 | 653 | #ifdef _WIN32 |
| 579 | -// GLFW doesn't allow to distinguish Mouse vs TouchScreen vs Pen. | |
| 580 | -// Add support for Win32 (based on imgui_impl_win32), because we rely on _TouchScreen info to trickle inputs differently. | |
| 581 | -static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() | |
| 582 | -{ | |
| 583 | - LPARAM extra_info = ::GetMessageExtraInfo(); | |
| 584 | - if ((extra_info & 0xFFFFFF80) == 0xFF515700) | |
| 585 | - return ImGuiMouseSource_Pen; | |
| 586 | - if ((extra_info & 0xFFFFFF80) == 0xFF515780) | |
| 587 | - return ImGuiMouseSource_TouchScreen; | |
| 588 | - return ImGuiMouseSource_Mouse; | |
| 589 | -} | |
| 590 | -static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) | |
| 591 | -{ | |
| 592 | - ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)::GetPropA(hWnd, "IMGUI_BACKEND_DATA"); | |
| 593 | - ImGuiIO& io = ImGui::GetIO(bd->Context); | |
| 594 | - | |
| 595 | - switch (msg) | |
| 596 | - { | |
| 597 | - case WM_MOUSEMOVE: case WM_NCMOUSEMOVE: | |
| 598 | - case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONUP: | |
| 599 | - case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_RBUTTONUP: | |
| 600 | - case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_MBUTTONUP: | |
| 601 | - case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: case WM_XBUTTONUP: | |
| 602 | - io.AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo()); | |
| 603 | - break; | |
| 604 | - default: break; | |
| 605 | - } | |
| 606 | - return ::CallWindowProcW(bd->PrevWndProc, hWnd, msg, wParam, lParam); | |
| 607 | -} | |
| 654 | +static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); | |
| 608 | 655 | #endif |
| 609 | 656 | |
| 610 | 657 | void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window) |
| @@ -684,6 +731,20 @@ | ||
| 684 | 731 | #endif |
| 685 | 732 | io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) |
| 686 | 733 | |
| 734 | + bool has_viewports = false; | |
| 735 | +#ifndef __EMSCRIPTEN__ | |
| 736 | + has_viewports = true; | |
| 737 | +#if GLFW_HAS_GETPLATFORM | |
| 738 | + if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) | |
| 739 | + has_viewports = false; | |
| 740 | +#endif | |
| 741 | + if (has_viewports) | |
| 742 | + io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) | |
| 743 | +#endif | |
| 744 | +#if GLFW_HAS_MOUSE_PASSTHROUGH || GLFW_HAS_WINDOW_HOVERED | |
| 745 | + io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional) | |
| 746 | +#endif | |
| 747 | + | |
| 687 | 748 | bd->Context = ImGui::GetCurrentContext(); |
| 688 | 749 | bd->Window = window; |
| 689 | 750 | bd->Time = 0.0; |
| @@ -735,6 +796,11 @@ | ||
| 735 | 796 | if (install_callbacks) |
| 736 | 797 | ImGui_ImplGlfw_InstallCallbacks(window); |
| 737 | 798 | |
| 799 | + // Update monitor a first time during init | |
| 800 | + // (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784) | |
| 801 | + ImGui_ImplGlfw_UpdateMonitors(); | |
| 802 | + glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback); | |
| 803 | + | |
| 738 | 804 | // Set platform dependent data in viewport |
| 739 | 805 | ImGuiViewport* main_viewport = ImGui::GetMainViewport(); |
| 740 | 806 | main_viewport->PlatformHandle = (void*)bd->Window; |
| @@ -745,6 +811,8 @@ | ||
| 745 | 811 | #else |
| 746 | 812 | IM_UNUSED(main_viewport); |
| 747 | 813 | #endif |
| 814 | + if (has_viewports) | |
| 815 | + ImGui_ImplGlfw_InitMultiViewportSupport(); | |
| 748 | 816 | |
| 749 | 817 | // Windows: register a WndProc hook so we can intercept some messages. |
| 750 | 818 | #ifdef _WIN32 |
| @@ -755,6 +823,26 @@ | ||
| 755 | 823 | ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc); |
| 756 | 824 | #endif |
| 757 | 825 | |
| 826 | +#if GLFW_HAS_X11 | |
| 827 | + if (!bd->IsWayland) | |
| 828 | + { | |
| 829 | + // Load X11 module dynamically. Copied from the way that GLFW does it in x11_init.c | |
| 830 | +#if defined(__CYGWIN__) | |
| 831 | + const char* x11_module_path = "libX11-6.so"; | |
| 832 | +#elif defined(__OpenBSD__) || defined(__NetBSD__) | |
| 833 | + const char* x11_module_path = "libX11.so"; | |
| 834 | +#else | |
| 835 | + const char* x11_module_path = "libX11.so.6"; | |
| 836 | +#endif | |
| 837 | + bd->X11Module = dlopen(x11_module_path, RTLD_LAZY | RTLD_LOCAL); | |
| 838 | + bd->XInternAtom = (PFN_XInternAtom)dlsym(bd->X11Module, "XInternAtom"); | |
| 839 | + bd->XChangeProperty = (PFN_XChangeProperty)dlsym(bd->X11Module, "XChangeProperty"); | |
| 840 | + bd->XChangeWindowAttributes = (PFN_XChangeWindowAttributes)dlsym(bd->X11Module, "XChangeWindowAttributes"); | |
| 841 | + bd->XFlush = (PFN_XFlush)dlsym(bd->X11Module, "XFlush"); | |
| 842 | + IM_ASSERT(bd->XInternAtom != nullptr && bd->XChangeProperty != nullptr && bd->XChangeWindowAttributes != nullptr && bd->XFlush != nullptr); | |
| 843 | + } | |
| 844 | +#endif | |
| 845 | + | |
| 758 | 846 | // Emscripten: the same application can run on various platforms, so we detect the Apple platform at runtime |
| 759 | 847 | // to override io.ConfigMacOSXBehaviors from its default (which is always false in Emscripten). |
| 760 | 848 | #ifdef __EMSCRIPTEN__ |
| @@ -799,6 +887,7 @@ | ||
| 799 | 887 | ImGuiIO& io = ImGui::GetIO(); |
| 800 | 888 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 801 | 889 | |
| 890 | + ImGui_ImplGlfw_ShutdownMultiViewportSupport(); | |
| 802 | 891 | if (bd->InstalledCallbacks) |
| 803 | 892 | ImGui_ImplGlfw_RestoreCallbacks(bd->Window); |
| 804 | 893 | #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 |
| @@ -817,9 +906,14 @@ | ||
| 817 | 906 | bd->PrevWndProc = nullptr; |
| 818 | 907 | #endif |
| 819 | 908 | |
| 909 | +#if GLFW_HAS_X11 | |
| 910 | + if (bd->X11Module != nullptr) | |
| 911 | + dlclose(bd->X11Module); | |
| 912 | +#endif | |
| 913 | + | |
| 820 | 914 | io.BackendPlatformName = nullptr; |
| 821 | 915 | io.BackendPlatformUserData = nullptr; |
| 822 | - io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad); | |
| 916 | + io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport); | |
| 823 | 917 | platform_io.ClearPlatformHandlers(); |
| 824 | 918 | ImGui_ImplGlfw_ContextMap_Remove(bd->Window); |
| 825 | 919 | IM_DELETE(bd); |
| @@ -829,10 +923,15 @@ | ||
| 829 | 923 | { |
| 830 | 924 | ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); |
| 831 | 925 | ImGuiIO& io = ImGui::GetIO(); |
| 926 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 832 | 927 | |
| 833 | - // (those braces are here to reduce diff with multi-viewports support in 'docking' branch) | |
| 928 | + ImGuiID mouse_viewport_id = 0; | |
| 929 | + const ImVec2 mouse_pos_prev = io.MousePos; | |
| 930 | + for (int n = 0; n < platform_io.Viewports.Size; n++) | |
| 834 | 931 | { |
| 835 | - GLFWwindow* window = bd->Window; | |
| 932 | + ImGuiViewport* viewport = platform_io.Viewports[n]; | |
| 933 | + GLFWwindow* window = (GLFWwindow*)viewport->PlatformHandle; | |
| 934 | + | |
| 836 | 935 | #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 |
| 837 | 936 | const bool is_window_focused = true; |
| 838 | 937 | #else |
| @@ -841,19 +940,54 @@ | ||
| 841 | 940 | if (is_window_focused) |
| 842 | 941 | { |
| 843 | 942 | // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user) |
| 943 | + // When multi-viewports are enabled, all Dear ImGui positions are same as OS positions. | |
| 844 | 944 | if (io.WantSetMousePos) |
| 845 | - glfwSetCursorPos(window, (double)io.MousePos.x, (double)io.MousePos.y); | |
| 945 | + glfwSetCursorPos(window, (double)(mouse_pos_prev.x - viewport->Pos.x), (double)(mouse_pos_prev.y - viewport->Pos.y)); | |
| 846 | 946 | |
| 847 | 947 | // (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured) |
| 848 | 948 | if (bd->MouseWindow == nullptr) |
| 849 | 949 | { |
| 850 | 950 | double mouse_x, mouse_y; |
| 851 | 951 | glfwGetCursorPos(window, &mouse_x, &mouse_y); |
| 952 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 953 | + { | |
| 954 | + // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) | |
| 955 | + // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) | |
| 956 | + int window_x, window_y; | |
| 957 | + glfwGetWindowPos(window, &window_x, &window_y); | |
| 958 | + mouse_x += window_x; | |
| 959 | + mouse_y += window_y; | |
| 960 | + } | |
| 852 | 961 | bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y); |
| 853 | 962 | io.AddMousePosEvent((float)mouse_x, (float)mouse_y); |
| 854 | 963 | } |
| 855 | 964 | } |
| 965 | + | |
| 966 | + // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering. | |
| 967 | + // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic. | |
| 968 | + // - [X] GLFW >= 3.3 backend ON WINDOWS ONLY does correctly ignore viewports with the _NoInputs flag (since we implement hit via our WndProc hook) | |
| 969 | + // On other platforms we rely on the library fallbacking to its own search when reporting a viewport with _NoInputs flag. | |
| 970 | + // - [!] GLFW <= 3.2 backend CANNOT correctly ignore viewports with the _NoInputs flag, and CANNOT reported Hovered Viewport because of mouse capture. | |
| 971 | + // Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window | |
| 972 | + // for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported | |
| 973 | + // by the backend, and use its flawed heuristic to guess the viewport behind. | |
| 974 | + // - [X] GLFW backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target). | |
| 975 | + // FIXME: This is currently only correct on Win32. See what we do below with the WM_NCHITTEST, missing an equivalent for other systems. | |
| 976 | + // See https://github.com/glfw/glfw/issues/1236 if you want to help in making this a GLFW feature. | |
| 977 | +#if GLFW_HAS_MOUSE_PASSTHROUGH | |
| 978 | + const bool window_no_input = (viewport->Flags & ImGuiViewportFlags_NoInputs) != 0; | |
| 979 | + glfwSetWindowAttrib(window, GLFW_MOUSE_PASSTHROUGH, window_no_input); | |
| 980 | +#endif | |
| 981 | +#if GLFW_HAS_MOUSE_PASSTHROUGH || GLFW_HAS_WINDOW_HOVERED | |
| 982 | + if (glfwGetWindowAttrib(window, GLFW_HOVERED)) | |
| 983 | + mouse_viewport_id = viewport->ID; | |
| 984 | +#else | |
| 985 | + // We cannot use bd->MouseWindow maintained from CursorEnter/Leave callbacks, because it is locked to the window capturing mouse. | |
| 986 | +#endif | |
| 856 | 987 | } |
| 988 | + | |
| 989 | + if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport) | |
| 990 | + io.AddMouseViewportEvent(mouse_viewport_id); | |
| 857 | 991 | } |
| 858 | 992 | |
| 859 | 993 | static void ImGui_ImplGlfw_UpdateMouseCursor() |
| @@ -867,9 +1001,10 @@ | ||
| 867 | 1001 | } |
| 868 | 1002 | |
| 869 | 1003 | ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); |
| 870 | - // (those braces are here to reduce diff with multi-viewports support in 'docking' branch) | |
| 1004 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 1005 | + for (int n = 0; n < platform_io.Viewports.Size; n++) | |
| 871 | 1006 | { |
| 872 | - GLFWwindow* window = bd->Window; | |
| 1007 | + GLFWwindow* window = (GLFWwindow*)platform_io.Viewports[n]->PlatformHandle; | |
| 873 | 1008 | if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) |
| 874 | 1009 | { |
| 875 | 1010 | if (bd->LastMouseCursor != nullptr) |
| @@ -949,6 +1084,49 @@ | ||
| 949 | 1084 | #undef MAP_ANALOG |
| 950 | 1085 | } |
| 951 | 1086 | |
| 1087 | +static void ImGui_ImplGlfw_UpdateMonitors() | |
| 1088 | +{ | |
| 1089 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 1090 | + int monitors_count = 0; | |
| 1091 | + GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count); | |
| 1092 | + | |
| 1093 | + bool updated_monitors = false; | |
| 1094 | + for (int n = 0; n < monitors_count; n++) | |
| 1095 | + { | |
| 1096 | + ImGuiPlatformMonitor monitor; | |
| 1097 | + int x, y; | |
| 1098 | + glfwGetMonitorPos(glfw_monitors[n], &x, &y); | |
| 1099 | + const GLFWvidmode* vid_mode = glfwGetVideoMode(glfw_monitors[n]); | |
| 1100 | + if (vid_mode == nullptr) | |
| 1101 | + continue; // Failed to get Video mode (e.g. Emscripten does not support this function) | |
| 1102 | + if (vid_mode->width <= 0 || vid_mode->height <= 0) | |
| 1103 | + continue; // Failed to query suitable monitor info (#9195) | |
| 1104 | + monitor.MainPos = monitor.WorkPos = ImVec2((float)x, (float)y); | |
| 1105 | + monitor.MainSize = monitor.WorkSize = ImVec2((float)vid_mode->width, (float)vid_mode->height); | |
| 1106 | +#if GLFW_HAS_MONITOR_WORK_AREA | |
| 1107 | + int w, h; | |
| 1108 | + glfwGetMonitorWorkarea(glfw_monitors[n], &x, &y, &w, &h); | |
| 1109 | + if (w > 0 && h > 0) // Workaround a small GLFW issue reporting zero on monitor changes: https://github.com/glfw/glfw/pull/1761 | |
| 1110 | + { | |
| 1111 | + monitor.WorkPos = ImVec2((float)x, (float)y); | |
| 1112 | + monitor.WorkSize = ImVec2((float)w, (float)h); | |
| 1113 | + } | |
| 1114 | +#endif | |
| 1115 | + float scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfw_monitors[n]); | |
| 1116 | + if (scale == 0.0f) | |
| 1117 | + continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0 (#7902) | |
| 1118 | + monitor.DpiScale = scale; | |
| 1119 | + monitor.PlatformHandle = (void*)glfw_monitors[n]; // [...] GLFW doc states: "guaranteed to be valid only until the monitor configuration changes" | |
| 1120 | + | |
| 1121 | + // Preserve existing monitor list until a valid one is added. | |
| 1122 | + // Happens on macOS sleeping (#5683) and seemingly occasionally on Windows (#9195) | |
| 1123 | + if (!updated_monitors) | |
| 1124 | + platform_io.Monitors.resize(0); | |
| 1125 | + updated_monitors = true; | |
| 1126 | + platform_io.Monitors.push_back(monitor); | |
| 1127 | + } | |
| 1128 | +} | |
| 1129 | + | |
| 952 | 1130 | // For GFLW 3.2 + Windows: include a simplified non-monitor aware version of ImGui_ImplWin32_GetDpiScaleForMonitor(). |
| 953 | 1131 | // This is merely a band-aid to make using GLFW 3.2 a little bit nicer, but prefer to use GLFW 3.3+ or the full correct functions from the Win32 backend. |
| 954 | 1132 | #if !GLFW_HAS_PER_MONITOR_DPI && defined(_WIN32) && !defined(NOGDI) |
| @@ -1022,6 +1200,7 @@ | ||
| 1022 | 1200 | |
| 1023 | 1201 | // Setup main viewport size (every frame to accommodate for window resizing) |
| 1024 | 1202 | ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(bd->Window, &io.DisplaySize, &io.DisplayFramebufferScale); |
| 1203 | + ImGui_ImplGlfw_UpdateMonitors(); | |
| 1025 | 1204 | |
| 1026 | 1205 | // Setup time step |
| 1027 | 1206 | // (Accept glfwGetTime() not returning a monotonically increasing value. Seems to happens on disconnecting peripherals and probably on VMs and Emscripten, see #6491, #6189, #6114, #3644) |
| @@ -1031,6 +1210,7 @@ | ||
| 1031 | 1210 | io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f); |
| 1032 | 1211 | bd->Time = current_time; |
| 1033 | 1212 | |
| 1213 | + bd->MouseIgnoreButtonUp = false; | |
| 1034 | 1214 | ImGui_ImplGlfw_UpdateMouseData(); |
| 1035 | 1215 | ImGui_ImplGlfw_UpdateMouseCursor(); |
| 1036 | 1216 | |
| @@ -1099,6 +1279,444 @@ | ||
| 1099 | 1279 | emscripten_glfw_make_canvas_resizable(window, "window", nullptr); |
| 1100 | 1280 | } |
| 1101 | 1281 | #endif // #ifdef EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 |
| 1282 | + | |
| 1283 | + | |
| 1284 | +//-------------------------------------------------------------------------------------------------------- | |
| 1285 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 1286 | +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. | |
| 1287 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 1288 | +//-------------------------------------------------------------------------------------------------------- | |
| 1289 | + | |
| 1290 | +// Helper structure we store in the void* PlatformUserData field of each ImGuiViewport to easily retrieve our backend data. | |
| 1291 | +struct ImGui_ImplGlfw_ViewportData | |
| 1292 | +{ | |
| 1293 | + GLFWwindow* Window; // Stored in ImGuiViewport::PlatformHandle | |
| 1294 | + bool WindowOwned; | |
| 1295 | + int IgnoreWindowPosEventFrame; | |
| 1296 | + int IgnoreWindowSizeEventFrame; | |
| 1297 | +#ifdef _WIN32 | |
| 1298 | + WNDPROC PrevWndProc; | |
| 1299 | +#endif | |
| 1300 | + | |
| 1301 | + ImGui_ImplGlfw_ViewportData() { memset((void*)this, 0, sizeof(*this)); IgnoreWindowSizeEventFrame = IgnoreWindowPosEventFrame = -1; } | |
| 1302 | + ~ImGui_ImplGlfw_ViewportData() { IM_ASSERT(Window == nullptr); } | |
| 1303 | +}; | |
| 1304 | + | |
| 1305 | +static void ImGui_ImplGlfw_WindowCloseCallback(GLFWwindow* window) | |
| 1306 | +{ | |
| 1307 | + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window)) | |
| 1308 | + viewport->PlatformRequestClose = true; | |
| 1309 | +} | |
| 1310 | + | |
| 1311 | +// GLFW may dispatch window pos/size events after calling glfwSetWindowPos()/glfwSetWindowSize(). | |
| 1312 | +// However: depending on the platform the callback may be invoked at different time: | |
| 1313 | +// - on Windows it appears to be called within the glfwSetWindowPos()/glfwSetWindowSize() call | |
| 1314 | +// - on Linux it is queued and invoked during glfwPollEvents() | |
| 1315 | +// Because the event doesn't always fire on glfwSetWindowXXX() we use a frame counter tag to only | |
| 1316 | +// ignore recent glfwSetWindowXXX() calls. | |
| 1317 | +static void ImGui_ImplGlfw_WindowPosCallback(GLFWwindow* window, int, int) | |
| 1318 | +{ | |
| 1319 | + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window)) | |
| 1320 | + { | |
| 1321 | + if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData) | |
| 1322 | + { | |
| 1323 | + bool ignore_event = (ImGui::GetFrameCount() <= vd->IgnoreWindowPosEventFrame + 1); | |
| 1324 | + //data->IgnoreWindowPosEventFrame = -1; | |
| 1325 | + if (ignore_event) | |
| 1326 | + return; | |
| 1327 | + } | |
| 1328 | + viewport->PlatformRequestMove = true; | |
| 1329 | + } | |
| 1330 | +} | |
| 1331 | + | |
| 1332 | +static void ImGui_ImplGlfw_WindowSizeCallback(GLFWwindow* window, int, int) | |
| 1333 | +{ | |
| 1334 | + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window)) | |
| 1335 | + { | |
| 1336 | + if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData) | |
| 1337 | + { | |
| 1338 | + bool ignore_event = (ImGui::GetFrameCount() <= vd->IgnoreWindowSizeEventFrame + 1); | |
| 1339 | + //data->IgnoreWindowSizeEventFrame = -1; | |
| 1340 | + if (ignore_event) | |
| 1341 | + return; | |
| 1342 | + } | |
| 1343 | + viewport->PlatformRequestResize = true; | |
| 1344 | + } | |
| 1345 | +} | |
| 1346 | + | |
| 1347 | +#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__EMSCRIPTEN__) && GLFW_HAS_GETPLATFORM | |
| 1348 | +#define IMGUI_GLFW_HAS_SETWINDOWFLOATING | |
| 1349 | +static void ImGui_ImplGlfw_SetWindowFloating(ImGui_ImplGlfw_Data* bd, GLFWwindow* window) | |
| 1350 | +{ | |
| 1351 | +#ifdef GLFW_EXPOSE_NATIVE_X11 | |
| 1352 | + if (glfwGetPlatform() == GLFW_PLATFORM_X11) | |
| 1353 | + { | |
| 1354 | + Display* display = glfwGetX11Display(); | |
| 1355 | + Window xwindow = glfwGetX11Window(window); | |
| 1356 | + Atom wm_type = bd->XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); | |
| 1357 | + Atom wm_type_dialog = bd->XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False); | |
| 1358 | + bd->XChangeProperty(display, xwindow, wm_type, XA_ATOM, 32, PropModeReplace, (unsigned char*)&wm_type_dialog, 1); | |
| 1359 | + XSetWindowAttributes attrs; | |
| 1360 | + attrs.override_redirect = False; | |
| 1361 | + bd->XChangeWindowAttributes(display, xwindow, CWOverrideRedirect, &attrs); | |
| 1362 | + bd->XFlush(display); | |
| 1363 | + } | |
| 1364 | +#endif // GLFW_EXPOSE_NATIVE_X11 | |
| 1365 | +#ifdef GLFW_EXPOSE_NATIVE_WAYLAND | |
| 1366 | + // FIXME: Help needed, see #8884, #8474 for discussions about this. | |
| 1367 | +#endif // GLFW_EXPOSE_NATIVE_X11 | |
| 1368 | +} | |
| 1369 | +#endif // IMGUI_GLFW_HAS_SETWINDOWFLOATING | |
| 1370 | + | |
| 1371 | +static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport) | |
| 1372 | +{ | |
| 1373 | + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | |
| 1374 | + ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)(); | |
| 1375 | + viewport->PlatformUserData = vd; | |
| 1376 | + | |
| 1377 | + // Workaround for Linux: ignore mouse up events corresponding to losing focus of the previously focused window (#7733, #3158, #7922) | |
| 1378 | +#ifdef __linux__ | |
| 1379 | + bd->MouseIgnoreButtonUpWaitForFocusLoss = true; | |
| 1380 | +#endif | |
| 1381 | + | |
| 1382 | + // GLFW 3.2 unfortunately always set focus on glfwCreateWindow() if GLFW_VISIBLE is set, regardless of GLFW_FOCUSED | |
| 1383 | + // With GLFW 3.3, the hint GLFW_FOCUS_ON_SHOW fixes this problem | |
| 1384 | + glfwWindowHint(GLFW_VISIBLE, false); | |
| 1385 | + glfwWindowHint(GLFW_FOCUSED, false); | |
| 1386 | +#if GLFW_HAS_FOCUS_ON_SHOW | |
| 1387 | + glfwWindowHint(GLFW_FOCUS_ON_SHOW, false); | |
| 1388 | +#endif | |
| 1389 | + glfwWindowHint(GLFW_DECORATED, (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? false : true); | |
| 1390 | +#if GLFW_HAS_WINDOW_TOPMOST | |
| 1391 | + glfwWindowHint(GLFW_FLOATING, (viewport->Flags & ImGuiViewportFlags_TopMost) ? true : false); | |
| 1392 | +#endif | |
| 1393 | + GLFWwindow* share_window = (bd->ClientApi == GlfwClientApi_OpenGL) ? bd->Window : nullptr; | |
| 1394 | + vd->Window = glfwCreateWindow((int)viewport->Size.x, (int)viewport->Size.y, "No Title Yet", nullptr, share_window); | |
| 1395 | + vd->WindowOwned = true; | |
| 1396 | + ImGui_ImplGlfw_ContextMap_Add(vd->Window, bd->Context); | |
| 1397 | + viewport->PlatformHandle = (void*)vd->Window; | |
| 1398 | +#ifdef IMGUI_GLFW_HAS_SETWINDOWFLOATING | |
| 1399 | + ImGui_ImplGlfw_SetWindowFloating(bd, vd->Window); | |
| 1400 | +#endif | |
| 1401 | +#ifdef _WIN32 | |
| 1402 | + viewport->PlatformHandleRaw = glfwGetWin32Window(vd->Window); | |
| 1403 | + ::SetPropA((HWND)viewport->PlatformHandleRaw, "IMGUI_BACKEND_DATA", bd); | |
| 1404 | +#elif defined(__APPLE__) | |
| 1405 | + viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(vd->Window); | |
| 1406 | +#endif | |
| 1407 | + glfwSetWindowPos(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y); | |
| 1408 | + | |
| 1409 | + // Install GLFW callbacks for secondary viewports | |
| 1410 | + glfwSetWindowFocusCallback(vd->Window, ImGui_ImplGlfw_WindowFocusCallback); | |
| 1411 | + glfwSetCursorEnterCallback(vd->Window, ImGui_ImplGlfw_CursorEnterCallback); | |
| 1412 | + glfwSetCursorPosCallback(vd->Window, ImGui_ImplGlfw_CursorPosCallback); | |
| 1413 | + glfwSetMouseButtonCallback(vd->Window, ImGui_ImplGlfw_MouseButtonCallback); | |
| 1414 | + glfwSetScrollCallback(vd->Window, ImGui_ImplGlfw_ScrollCallback); | |
| 1415 | + glfwSetKeyCallback(vd->Window, ImGui_ImplGlfw_KeyCallback); | |
| 1416 | + glfwSetCharCallback(vd->Window, ImGui_ImplGlfw_CharCallback); | |
| 1417 | + glfwSetWindowCloseCallback(vd->Window, ImGui_ImplGlfw_WindowCloseCallback); | |
| 1418 | + glfwSetWindowPosCallback(vd->Window, ImGui_ImplGlfw_WindowPosCallback); | |
| 1419 | + glfwSetWindowSizeCallback(vd->Window, ImGui_ImplGlfw_WindowSizeCallback); | |
| 1420 | + if (bd->ClientApi == GlfwClientApi_OpenGL) | |
| 1421 | + { | |
| 1422 | + glfwMakeContextCurrent(vd->Window); | |
| 1423 | + glfwSwapInterval(0); | |
| 1424 | + } | |
| 1425 | +} | |
| 1426 | + | |
| 1427 | +static void ImGui_ImplGlfw_DestroyWindow(ImGuiViewport* viewport) | |
| 1428 | +{ | |
| 1429 | + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | |
| 1430 | + if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData) | |
| 1431 | + { | |
| 1432 | + if (vd->WindowOwned) | |
| 1433 | + { | |
| 1434 | +#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32) | |
| 1435 | + HWND hwnd = (HWND)viewport->PlatformHandleRaw; | |
| 1436 | + ::RemovePropA(hwnd, "IMGUI_VIEWPORT"); | |
| 1437 | +#endif | |
| 1438 | + | |
| 1439 | + // Release any keys that were pressed in the window being destroyed and are still held down, | |
| 1440 | + // because we will not receive any release events after window is destroyed. | |
| 1441 | + for (int i = 0; i < IM_COUNTOF(bd->KeyOwnerWindows); i++) | |
| 1442 | + if (bd->KeyOwnerWindows[i] == vd->Window) | |
| 1443 | + ImGui_ImplGlfw_KeyCallback(vd->Window, i, 0, GLFW_RELEASE, 0); // Later params are only used for main viewport, on which this function is never called. | |
| 1444 | + | |
| 1445 | + ImGui_ImplGlfw_ContextMap_Remove(vd->Window); | |
| 1446 | + glfwDestroyWindow(vd->Window); | |
| 1447 | + } | |
| 1448 | + vd->Window = nullptr; | |
| 1449 | + IM_DELETE(vd); | |
| 1450 | + } | |
| 1451 | + viewport->PlatformUserData = viewport->PlatformHandle = nullptr; | |
| 1452 | +} | |
| 1453 | + | |
| 1454 | +static void ImGui_ImplGlfw_ShowWindow(ImGuiViewport* viewport) | |
| 1455 | +{ | |
| 1456 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1457 | + | |
| 1458 | +#if defined(_WIN32) | |
| 1459 | + // GLFW hack: Hide icon from task bar | |
| 1460 | + HWND hwnd = (HWND)viewport->PlatformHandleRaw; | |
| 1461 | + if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) | |
| 1462 | + { | |
| 1463 | + LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE); | |
| 1464 | + ex_style &= ~WS_EX_APPWINDOW; | |
| 1465 | + ex_style |= WS_EX_TOOLWINDOW; | |
| 1466 | + ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style); | |
| 1467 | + } | |
| 1468 | + | |
| 1469 | + // GLFW hack: install WndProc for mouse source event and WM_NCHITTEST message handler. | |
| 1470 | + ::SetPropA(hwnd, "IMGUI_VIEWPORT", viewport); | |
| 1471 | + vd->PrevWndProc = (WNDPROC)::GetWindowLongPtrW(hwnd, GWLP_WNDPROC); | |
| 1472 | + ::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc); | |
| 1473 | + | |
| 1474 | +#if !GLFW_HAS_FOCUS_ON_SHOW | |
| 1475 | + // GLFW hack: GLFW 3.2 has a bug where glfwShowWindow() also activates/focus the window. | |
| 1476 | + // The fix was pushed to GLFW repository on 2018/01/09 and should be included in GLFW 3.3 via a GLFW_FOCUS_ON_SHOW window attribute. | |
| 1477 | + // See https://github.com/glfw/glfw/issues/1189 | |
| 1478 | + // FIXME-VIEWPORT: Implement same work-around for Linux/OSX in the meanwhile. | |
| 1479 | + if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) | |
| 1480 | + { | |
| 1481 | + ::ShowWindow(hwnd, SW_SHOWNA); | |
| 1482 | + return; | |
| 1483 | + } | |
| 1484 | +#endif | |
| 1485 | +#endif | |
| 1486 | + | |
| 1487 | + glfwShowWindow(vd->Window); | |
| 1488 | +} | |
| 1489 | + | |
| 1490 | +static ImVec2 ImGui_ImplGlfw_GetWindowPos(ImGuiViewport* viewport) | |
| 1491 | +{ | |
| 1492 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1493 | + int x = 0, y = 0; | |
| 1494 | + glfwGetWindowPos(vd->Window, &x, &y); | |
| 1495 | + return ImVec2((float)x, (float)y); | |
| 1496 | +} | |
| 1497 | + | |
| 1498 | +static void ImGui_ImplGlfw_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos) | |
| 1499 | +{ | |
| 1500 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1501 | + vd->IgnoreWindowPosEventFrame = ImGui::GetFrameCount(); | |
| 1502 | + glfwSetWindowPos(vd->Window, (int)pos.x, (int)pos.y); | |
| 1503 | +} | |
| 1504 | + | |
| 1505 | +static ImVec2 ImGui_ImplGlfw_GetWindowSize(ImGuiViewport* viewport) | |
| 1506 | +{ | |
| 1507 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1508 | + int w = 0, h = 0; | |
| 1509 | + glfwGetWindowSize(vd->Window, &w, &h); | |
| 1510 | + return ImVec2((float)w, (float)h); | |
| 1511 | +} | |
| 1512 | + | |
| 1513 | +static void ImGui_ImplGlfw_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) | |
| 1514 | +{ | |
| 1515 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1516 | +#if defined(__APPLE__) && !GLFW_HAS_OSX_WINDOW_POS_FIX | |
| 1517 | + // Native OS windows are positioned from the bottom-left corner on macOS, whereas on other platforms they are | |
| 1518 | + // positioned from the upper-left corner. GLFW makes an effort to convert macOS style coordinates, however it | |
| 1519 | + // doesn't handle it when changing size. We are manually moving the window in order for changes of size to be based | |
| 1520 | + // on the upper-left corner. | |
| 1521 | + int x, y, width, height; | |
| 1522 | + glfwGetWindowPos(vd->Window, &x, &y); | |
| 1523 | + glfwGetWindowSize(vd->Window, &width, &height); | |
| 1524 | + glfwSetWindowPos(vd->Window, x, y - height + size.y); | |
| 1525 | +#endif | |
| 1526 | + vd->IgnoreWindowSizeEventFrame = ImGui::GetFrameCount(); | |
| 1527 | + glfwSetWindowSize(vd->Window, (int)size.x, (int)size.y); | |
| 1528 | +} | |
| 1529 | + | |
| 1530 | +static ImVec2 ImGui_ImplGlfw_GetWindowFramebufferScale(ImGuiViewport* viewport) | |
| 1531 | +{ | |
| 1532 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1533 | + ImVec2 framebuffer_scale; | |
| 1534 | + ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(vd->Window, nullptr, &framebuffer_scale); | |
| 1535 | + return framebuffer_scale; | |
| 1536 | +} | |
| 1537 | + | |
| 1538 | +static void ImGui_ImplGlfw_SetWindowTitle(ImGuiViewport* viewport, const char* title) | |
| 1539 | +{ | |
| 1540 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1541 | + glfwSetWindowTitle(vd->Window, title); | |
| 1542 | +} | |
| 1543 | + | |
| 1544 | +static void ImGui_ImplGlfw_SetWindowFocus(ImGuiViewport* viewport) | |
| 1545 | +{ | |
| 1546 | +#if GLFW_HAS_FOCUS_WINDOW | |
| 1547 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1548 | + glfwFocusWindow(vd->Window); | |
| 1549 | +#else | |
| 1550 | + // FIXME: What are the effect of not having this function? At the moment imgui doesn't actually call SetWindowFocus - we set that up ahead, will answer that question later. | |
| 1551 | + (void)viewport; | |
| 1552 | +#endif | |
| 1553 | +} | |
| 1554 | + | |
| 1555 | +static bool ImGui_ImplGlfw_GetWindowFocus(ImGuiViewport* viewport) | |
| 1556 | +{ | |
| 1557 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1558 | + return glfwGetWindowAttrib(vd->Window, GLFW_FOCUSED) != 0; | |
| 1559 | +} | |
| 1560 | + | |
| 1561 | +static bool ImGui_ImplGlfw_GetWindowMinimized(ImGuiViewport* viewport) | |
| 1562 | +{ | |
| 1563 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1564 | + return glfwGetWindowAttrib(vd->Window, GLFW_ICONIFIED) != 0; | |
| 1565 | +} | |
| 1566 | + | |
| 1567 | +#if GLFW_HAS_WINDOW_ALPHA | |
| 1568 | +static void ImGui_ImplGlfw_SetWindowAlpha(ImGuiViewport* viewport, float alpha) | |
| 1569 | +{ | |
| 1570 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1571 | + glfwSetWindowOpacity(vd->Window, alpha); | |
| 1572 | +} | |
| 1573 | +#endif | |
| 1574 | + | |
| 1575 | +static void ImGui_ImplGlfw_RenderWindow(ImGuiViewport* viewport, void*) | |
| 1576 | +{ | |
| 1577 | + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | |
| 1578 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1579 | + if (bd->ClientApi == GlfwClientApi_OpenGL) | |
| 1580 | + glfwMakeContextCurrent(vd->Window); | |
| 1581 | +} | |
| 1582 | + | |
| 1583 | +static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport, void*) | |
| 1584 | +{ | |
| 1585 | + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | |
| 1586 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1587 | + if (bd->ClientApi == GlfwClientApi_OpenGL) | |
| 1588 | + { | |
| 1589 | + glfwMakeContextCurrent(vd->Window); | |
| 1590 | + glfwSwapBuffers(vd->Window); | |
| 1591 | + } | |
| 1592 | +} | |
| 1593 | + | |
| 1594 | +//-------------------------------------------------------------------------------------------------------- | |
| 1595 | +// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface) | |
| 1596 | +//-------------------------------------------------------------------------------------------------------- | |
| 1597 | + | |
| 1598 | +// Avoid including <vulkan.h> so we can build without it | |
| 1599 | +#if GLFW_HAS_VULKAN | |
| 1600 | +#ifndef VULKAN_H_ | |
| 1601 | +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; | |
| 1602 | +#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) | |
| 1603 | +#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; | |
| 1604 | +#else | |
| 1605 | +#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; | |
| 1606 | +#endif | |
| 1607 | +VK_DEFINE_HANDLE(VkInstance) | |
| 1608 | +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) | |
| 1609 | +struct VkAllocationCallbacks; | |
| 1610 | +enum VkResult { VK_RESULT_MAX_ENUM = 0x7FFFFFFF }; | |
| 1611 | +#endif // VULKAN_H_ | |
| 1612 | +extern "C" { extern GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); } | |
| 1613 | +static int ImGui_ImplGlfw_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface) | |
| 1614 | +{ | |
| 1615 | + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | |
| 1616 | + ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; | |
| 1617 | + IM_UNUSED(bd); | |
| 1618 | + IM_ASSERT(bd->ClientApi == GlfwClientApi_Vulkan); | |
| 1619 | + VkResult err = glfwCreateWindowSurface((VkInstance)vk_instance, vd->Window, (const VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface); | |
| 1620 | + return (int)err; | |
| 1621 | +} | |
| 1622 | +#endif // GLFW_HAS_VULKAN | |
| 1623 | + | |
| 1624 | +static void ImGui_ImplGlfw_InitMultiViewportSupport() | |
| 1625 | +{ | |
| 1626 | + // Register platform interface (will be coupled with a renderer interface) | |
| 1627 | + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); | |
| 1628 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 1629 | + platform_io.Platform_CreateWindow = ImGui_ImplGlfw_CreateWindow; | |
| 1630 | + platform_io.Platform_DestroyWindow = ImGui_ImplGlfw_DestroyWindow; | |
| 1631 | + platform_io.Platform_ShowWindow = ImGui_ImplGlfw_ShowWindow; | |
| 1632 | + platform_io.Platform_SetWindowPos = ImGui_ImplGlfw_SetWindowPos; | |
| 1633 | + platform_io.Platform_GetWindowPos = ImGui_ImplGlfw_GetWindowPos; | |
| 1634 | + platform_io.Platform_SetWindowSize = ImGui_ImplGlfw_SetWindowSize; | |
| 1635 | + platform_io.Platform_GetWindowSize = ImGui_ImplGlfw_GetWindowSize; | |
| 1636 | + platform_io.Platform_GetWindowFramebufferScale = ImGui_ImplGlfw_GetWindowFramebufferScale; | |
| 1637 | + platform_io.Platform_SetWindowFocus = ImGui_ImplGlfw_SetWindowFocus; | |
| 1638 | + platform_io.Platform_GetWindowFocus = ImGui_ImplGlfw_GetWindowFocus; | |
| 1639 | + platform_io.Platform_GetWindowMinimized = ImGui_ImplGlfw_GetWindowMinimized; | |
| 1640 | + platform_io.Platform_SetWindowTitle = ImGui_ImplGlfw_SetWindowTitle; | |
| 1641 | + platform_io.Platform_RenderWindow = ImGui_ImplGlfw_RenderWindow; | |
| 1642 | + platform_io.Platform_SwapBuffers = ImGui_ImplGlfw_SwapBuffers; | |
| 1643 | +#if GLFW_HAS_WINDOW_ALPHA | |
| 1644 | + platform_io.Platform_SetWindowAlpha = ImGui_ImplGlfw_SetWindowAlpha; | |
| 1645 | +#endif | |
| 1646 | +#if GLFW_HAS_VULKAN | |
| 1647 | + platform_io.Platform_CreateVkSurface = ImGui_ImplGlfw_CreateVkSurface; | |
| 1648 | +#endif | |
| 1649 | + | |
| 1650 | + // Register main window handle (which is owned by the main application, not by us) | |
| 1651 | + // This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports. | |
| 1652 | + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | |
| 1653 | + ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)(); | |
| 1654 | + vd->Window = bd->Window; | |
| 1655 | + vd->WindowOwned = false; | |
| 1656 | + main_viewport->PlatformUserData = vd; | |
| 1657 | + main_viewport->PlatformHandle = (void*)bd->Window; | |
| 1658 | +} | |
| 1659 | + | |
| 1660 | +static void ImGui_ImplGlfw_ShutdownMultiViewportSupport() | |
| 1661 | +{ | |
| 1662 | + ImGui::DestroyPlatformWindows(); | |
| 1663 | +} | |
| 1664 | + | |
| 1665 | +//----------------------------------------------------------------------------- | |
| 1666 | + | |
| 1667 | +// WndProc hook (declared here because we will need access to ImGui_ImplGlfw_ViewportData) | |
| 1668 | +#ifdef _WIN32 | |
| 1669 | +static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() | |
| 1670 | +{ | |
| 1671 | + LPARAM extra_info = ::GetMessageExtraInfo(); | |
| 1672 | + if ((extra_info & 0xFFFFFF80) == 0xFF515700) | |
| 1673 | + return ImGuiMouseSource_Pen; | |
| 1674 | + if ((extra_info & 0xFFFFFF80) == 0xFF515780) | |
| 1675 | + return ImGuiMouseSource_TouchScreen; | |
| 1676 | + return ImGuiMouseSource_Mouse; | |
| 1677 | +} | |
| 1678 | +static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) | |
| 1679 | +{ | |
| 1680 | + ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)::GetPropA(hWnd, "IMGUI_BACKEND_DATA"); | |
| 1681 | + ImGuiIO& io = ImGui::GetIO(bd->Context); | |
| 1682 | + | |
| 1683 | + WNDPROC prev_wndproc = bd->PrevWndProc; | |
| 1684 | + ImGuiViewport* viewport = (ImGuiViewport*)::GetPropA(hWnd, "IMGUI_VIEWPORT"); | |
| 1685 | + if (viewport != NULL) | |
| 1686 | + if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData) | |
| 1687 | + prev_wndproc = vd->PrevWndProc; | |
| 1688 | + | |
| 1689 | + switch (msg) | |
| 1690 | + { | |
| 1691 | + // GLFW doesn't allow to distinguish Mouse vs TouchScreen vs Pen. | |
| 1692 | + // Add support for Win32 (based on imgui_impl_win32), because we rely on _TouchScreen info to trickle inputs differently. | |
| 1693 | + case WM_MOUSEMOVE: case WM_NCMOUSEMOVE: | |
| 1694 | + case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONUP: | |
| 1695 | + case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_RBUTTONUP: | |
| 1696 | + case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_MBUTTONUP: | |
| 1697 | + case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: case WM_XBUTTONUP: | |
| 1698 | + io.AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo()); | |
| 1699 | + break; | |
| 1700 | + | |
| 1701 | + // We have submitted https://github.com/glfw/glfw/pull/1568 to allow GLFW to support "transparent inputs". | |
| 1702 | + // In the meanwhile we implement custom per-platform workarounds here (FIXME-VIEWPORT: Implement same work-around for Linux/OSX!) | |
| 1703 | +#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED | |
| 1704 | + case WM_NCHITTEST: | |
| 1705 | + { | |
| 1706 | + // Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() properly (which is OPTIONAL). | |
| 1707 | + // The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging. | |
| 1708 | + // If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in | |
| 1709 | + // your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system. | |
| 1710 | + if (viewport && (viewport->Flags & ImGuiViewportFlags_NoInputs)) | |
| 1711 | + return HTTRANSPARENT; | |
| 1712 | + break; | |
| 1713 | + } | |
| 1714 | +#endif | |
| 1715 | + default: break; | |
| 1716 | + } | |
| 1717 | + return ::CallWindowProcW(prev_wndproc, hWnd, msg, wParam, lParam); | |
| 1718 | +} | |
| 1719 | +#endif // #ifdef _WIN32 | |
| 1102 | 1720 | |
| 1103 | 1721 | //----------------------------------------------------------------------------- |
| 1104 | 1722 |
| @@ -9,10 +9,12 @@ | ||
| 9 | 9 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] |
| 10 | 10 | // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. |
| 11 | 11 | // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors) with GLFW 3.1+. Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. |
| 12 | +// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 12 | 13 | // [X] Multiple Dear ImGui contexts support. |
| 13 | 14 | // Missing features or Issues: |
| 14 | 15 | // [ ] Platform: Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. |
| 15 | 16 | // [ ] Platform: Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. |
| 17 | +// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either. | |
| 16 | 18 | |
| 17 | 19 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 18 | 20 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -13,6 +13,7 @@ | ||
| 13 | 13 | // [ ] Platform: Missing mouse cursor shape/visibility support. |
| 14 | 14 | // [ ] Platform: Missing clipboard support (not supported by Glut). |
| 15 | 15 | // [ ] Platform: Missing gamepad support. |
| 16 | +// [ ] Platform: Missing multi-viewport support (multiple windows). | |
| 16 | 17 | |
| 17 | 18 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 18 | 19 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -13,6 +13,7 @@ | ||
| 13 | 13 | // [ ] Platform: Missing mouse cursor shape/visibility support. |
| 14 | 14 | // [ ] Platform: Missing clipboard support (not supported by Glut). |
| 15 | 15 | // [ ] Platform: Missing gamepad support. |
| 16 | +// [ ] Platform: Missing multi-viewport support (multiple windows). | |
| 16 | 17 | |
| 17 | 18 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 18 | 19 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -5,6 +5,7 @@ | ||
| 5 | 5 | // [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! |
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 8 | 9 | |
| 9 | 10 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 10 | 11 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -5,6 +5,7 @@ | ||
| 5 | 5 | // [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! |
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 8 | 9 | |
| 9 | 10 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 10 | 11 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -16,6 +17,7 @@ | ||
| 16 | 17 | |
| 17 | 18 | // CHANGELOG |
| 18 | 19 | // (minor and older changes stripped away, please see git history for details) |
| 20 | +// 2026-XX-XX: Metal: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 19 | 21 | // 2026-04-28: Added support for standard draw callbacks (in platform_io): DrawCallback_SetSamplerLinear and DrawCallback_SetSamplerNearest. (#9378, #9381) |
| 20 | 22 | // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others are not yet supported). (#9378) |
| 21 | 23 | // 2026-04-14: Metal: use a dedicated bufferCacheLock to avoid crashing when bufferCache is replaced by a new object while being used for @synchronize(). (#9367) |
| @@ -48,6 +50,12 @@ | ||
| 48 | 50 | #import <time.h> |
| 49 | 51 | #import <Metal/Metal.h> |
| 50 | 52 | |
| 53 | +// Forward Declarations | |
| 54 | +static void ImGui_ImplMetal_InitMultiViewportSupport(); | |
| 55 | +static void ImGui_ImplMetal_ShutdownMultiViewportSupport(); | |
| 56 | +static void ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows(); | |
| 57 | +static void ImGui_ImplMetal_InvalidateDeviceObjectsForPlatformWindows(); | |
| 58 | + | |
| 51 | 59 | #pragma mark - Support classes |
| 52 | 60 | |
| 53 | 61 | // A wrapper around a MTLBuffer object that knows the last time it was reused |
| @@ -398,6 +406,8 @@ | ||
| 398 | 406 | samplerDescriptor.magFilter = MTLSamplerMinMagFilterNearest; |
| 399 | 407 | samplerDescriptor.mipFilter = MTLSamplerMipFilterNearest; |
| 400 | 408 | bd->SharedMetalContext.samplerStateNearest = [device newSamplerStateWithDescriptor:samplerDescriptor]; |
| 409 | + | |
| 410 | + ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows(); | |
| 401 | 411 | #ifdef IMGUI_IMPL_METAL_CPP |
| 402 | 412 | [samplerDescriptor release]; |
| 403 | 413 | [depthStencilDescriptor release]; |
| @@ -415,6 +425,7 @@ | ||
| 415 | 425 | if (tex->RefCount == 1) |
| 416 | 426 | ImGui_ImplMetal_DestroyTexture(tex); |
| 417 | 427 | |
| 428 | + ImGui_ImplMetal_InvalidateDeviceObjectsForPlatformWindows(); | |
| 418 | 429 | [bd->SharedMetalContext.renderPipelineStateCache removeAllObjects]; |
| 419 | 430 | bd->SharedMetalContext.samplerStateLinear = nil; |
| 420 | 431 | bd->SharedMetalContext.samplerStateNearest = nil; |
| @@ -431,6 +442,7 @@ | ||
| 431 | 442 | io.BackendRendererName = "imgui_impl_metal"; |
| 432 | 443 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. |
| 433 | 444 | io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. |
| 445 | + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) | |
| 434 | 446 | |
| 435 | 447 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 436 | 448 | platform_io.DrawCallback_ResetRenderState = ImGui_ImplMetal_DrawCallback_ResetRenderState; |
| @@ -440,6 +452,8 @@ | ||
| 440 | 452 | bd->SharedMetalContext = [[MetalContext alloc] init]; |
| 441 | 453 | bd->SharedMetalContext.device = device; |
| 442 | 454 | |
| 455 | + ImGui_ImplMetal_InitMultiViewportSupport(); | |
| 456 | + | |
| 443 | 457 | return true; |
| 444 | 458 | } |
| 445 | 459 | |
| @@ -451,13 +465,158 @@ | ||
| 451 | 465 | ImGuiIO& io = ImGui::GetIO(); |
| 452 | 466 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 453 | 467 | |
| 468 | + ImGui_ImplMetal_ShutdownMultiViewportSupport(); | |
| 454 | 469 | ImGui_ImplMetal_DestroyDeviceObjects(); |
| 455 | 470 | ImGui_ImplMetal_DestroyBackendData(); |
| 456 | 471 | |
| 457 | 472 | io.BackendRendererName = nullptr; |
| 458 | 473 | io.BackendRendererUserData = nullptr; |
| 459 | - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); | |
| 474 | + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports); | |
| 460 | 475 | platform_io.ClearRendererHandlers(); |
| 476 | +} | |
| 477 | + | |
| 478 | +#pragma mark - Multi-viewport support | |
| 479 | + | |
| 480 | +#import <QuartzCore/CAMetalLayer.h> | |
| 481 | + | |
| 482 | +#if TARGET_OS_OSX | |
| 483 | +#import <Cocoa/Cocoa.h> | |
| 484 | +#endif | |
| 485 | + | |
| 486 | +//-------------------------------------------------------------------------------------------------------- | |
| 487 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 488 | +// This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously. | |
| 489 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 490 | +//-------------------------------------------------------------------------------------------------------- | |
| 491 | + | |
| 492 | +struct ImGuiViewportDataMetal | |
| 493 | +{ | |
| 494 | + CAMetalLayer* MetalLayer; | |
| 495 | + id<MTLCommandQueue> CommandQueue; | |
| 496 | + MTLRenderPassDescriptor* RenderPassDescriptor; | |
| 497 | + void* Handle = nullptr; | |
| 498 | + bool FirstFrame = true; | |
| 499 | +}; | |
| 500 | + | |
| 501 | +static void ImGui_ImplMetal_CreateWindow(ImGuiViewport* viewport) | |
| 502 | +{ | |
| 503 | + ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); | |
| 504 | + ImGuiViewportDataMetal* data = IM_NEW(ImGuiViewportDataMetal)(); | |
| 505 | + viewport->RendererUserData = data; | |
| 506 | + | |
| 507 | + // PlatformHandleRaw should always be a NSWindow*, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*). | |
| 508 | + // Some back-ends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the NSWindow*. | |
| 509 | + void* handle = viewport->PlatformHandleRaw ? viewport->PlatformHandleRaw : viewport->PlatformHandle; | |
| 510 | + IM_ASSERT(handle != nullptr); | |
| 511 | + | |
| 512 | + id<MTLDevice> device = bd->SharedMetalContext.device; | |
| 513 | + CAMetalLayer* layer = [CAMetalLayer layer]; | |
| 514 | + layer.device = device; | |
| 515 | + layer.framebufferOnly = YES; | |
| 516 | + layer.pixelFormat = bd->SharedMetalContext.framebufferDescriptor.colorPixelFormat; | |
| 517 | +#if TARGET_OS_OSX | |
| 518 | + NSWindow* window = (__bridge NSWindow*)handle; | |
| 519 | + NSView* view = window.contentView; | |
| 520 | + view.layer = layer; | |
| 521 | + view.wantsLayer = YES; | |
| 522 | +#endif | |
| 523 | + data->MetalLayer = layer; | |
| 524 | + data->CommandQueue = [device newCommandQueue]; | |
| 525 | + data->RenderPassDescriptor = [[MTLRenderPassDescriptor alloc] init]; | |
| 526 | + data->Handle = handle; | |
| 527 | +} | |
| 528 | + | |
| 529 | +static void ImGui_ImplMetal_DestroyWindow(ImGuiViewport* viewport) | |
| 530 | +{ | |
| 531 | + // The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it. | |
| 532 | + if (ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData) | |
| 533 | + IM_DELETE(data); | |
| 534 | + viewport->RendererUserData = nullptr; | |
| 535 | +} | |
| 536 | + | |
| 537 | +inline static CGSize MakeScaledSize(CGSize size, CGFloat scale) | |
| 538 | +{ | |
| 539 | + return CGSizeMake(size.width * scale, size.height * scale); | |
| 540 | +} | |
| 541 | + | |
| 542 | +static void ImGui_ImplMetal_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) | |
| 543 | +{ | |
| 544 | + ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData; | |
| 545 | + data->MetalLayer.drawableSize = MakeScaledSize(CGSizeMake(size.x, size.y), viewport->DpiScale); | |
| 546 | +} | |
| 547 | + | |
| 548 | +static void ImGui_ImplMetal_RenderWindow(ImGuiViewport* viewport, void*) | |
| 549 | +{ | |
| 550 | + ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData; | |
| 551 | + | |
| 552 | +#if TARGET_OS_OSX | |
| 553 | + void* handle = viewport->PlatformHandleRaw ? viewport->PlatformHandleRaw : viewport->PlatformHandle; | |
| 554 | + NSWindow* window = (__bridge NSWindow*)handle; | |
| 555 | + | |
| 556 | + // Always render the first frame, regardless of occlusionState, to avoid an initial flicker | |
| 557 | + if ((window.occlusionState & NSWindowOcclusionStateVisible) == 0 && !data->FirstFrame) | |
| 558 | + { | |
| 559 | + // Do not render windows which are completely occluded. Calling -[CAMetalLayer nextDrawable] will hang for | |
| 560 | + // approximately 1 second if the Metal layer is completely occluded. | |
| 561 | + return; | |
| 562 | + } | |
| 563 | + data->FirstFrame = false; | |
| 564 | + | |
| 565 | + float fb_scale = (float)window.backingScaleFactor; | |
| 566 | + if (data->MetalLayer.contentsScale != fb_scale) | |
| 567 | + { | |
| 568 | + data->MetalLayer.contentsScale = fb_scale; | |
| 569 | + data->MetalLayer.drawableSize = MakeScaledSize(window.frame.size, fb_scale); | |
| 570 | + } | |
| 571 | +#endif | |
| 572 | + | |
| 573 | + id <CAMetalDrawable> drawable = [data->MetalLayer nextDrawable]; | |
| 574 | + if (drawable == nil) | |
| 575 | + return; | |
| 576 | + | |
| 577 | + MTLRenderPassDescriptor* renderPassDescriptor = data->RenderPassDescriptor; | |
| 578 | + renderPassDescriptor.colorAttachments[0].texture = drawable.texture; | |
| 579 | + renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 0); | |
| 580 | + if ((viewport->Flags & ImGuiViewportFlags_NoRendererClear) == 0) | |
| 581 | + renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear; | |
| 582 | + | |
| 583 | + id <MTLCommandBuffer> commandBuffer = [data->CommandQueue commandBuffer]; | |
| 584 | + id <MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor]; | |
| 585 | + ImGui_ImplMetal_RenderDrawData(viewport->DrawData, commandBuffer, renderEncoder); | |
| 586 | + [renderEncoder endEncoding]; | |
| 587 | + | |
| 588 | + [commandBuffer presentDrawable:drawable]; | |
| 589 | + [commandBuffer commit]; | |
| 590 | +} | |
| 591 | + | |
| 592 | +static void ImGui_ImplMetal_InitMultiViewportSupport() | |
| 593 | +{ | |
| 594 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 595 | + platform_io.Renderer_CreateWindow = ImGui_ImplMetal_CreateWindow; | |
| 596 | + platform_io.Renderer_DestroyWindow = ImGui_ImplMetal_DestroyWindow; | |
| 597 | + platform_io.Renderer_SetWindowSize = ImGui_ImplMetal_SetWindowSize; | |
| 598 | + platform_io.Renderer_RenderWindow = ImGui_ImplMetal_RenderWindow; | |
| 599 | +} | |
| 600 | + | |
| 601 | +static void ImGui_ImplMetal_ShutdownMultiViewportSupport() | |
| 602 | +{ | |
| 603 | + ImGui::DestroyPlatformWindows(); | |
| 604 | +} | |
| 605 | + | |
| 606 | +static void ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows() | |
| 607 | +{ | |
| 608 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 609 | + for (int i = 1; i < platform_io.Viewports.Size; i++) | |
| 610 | + if (!platform_io.Viewports[i]->RendererUserData) | |
| 611 | + ImGui_ImplMetal_CreateWindow(platform_io.Viewports[i]); | |
| 612 | +} | |
| 613 | + | |
| 614 | +static void ImGui_ImplMetal_InvalidateDeviceObjectsForPlatformWindows() | |
| 615 | +{ | |
| 616 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 617 | + for (int i = 1; i < platform_io.Viewports.Size; i++) | |
| 618 | + if (platform_io.Viewports[i]->RendererUserData) | |
| 619 | + ImGui_ImplMetal_DestroyWindow(platform_io.Viewports[i]); | |
| 461 | 620 | } |
| 462 | 621 | |
| 463 | 622 | #pragma mark - MetalBuffer implementation |
| @@ -4,6 +4,7 @@ | ||
| 4 | 4 | // Implemented features: |
| 5 | 5 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! |
| 6 | 6 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 7 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 7 | 8 | // Missing features or Issues: |
| 8 | 9 | // [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 9 | 10 | // [ ] Renderer: Use of DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest is emulated by poking to glTexParameter(), as legacy OpenGL doesn't have glBindSampler(). |
| @@ -26,6 +27,7 @@ | ||
| 26 | 27 | |
| 27 | 28 | // CHANGELOG |
| 28 | 29 | // (minor and older changes stripped away, please see git history for details) |
| 30 | +// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 29 | 31 | // 2026-04-23: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) |
| 30 | 32 | // 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295) |
| 31 | 33 | // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. |
| @@ -101,6 +103,10 @@ | ||
| 101 | 103 | return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; |
| 102 | 104 | } |
| 103 | 105 | |
| 106 | +// Forward Declarations | |
| 107 | +static void ImGui_ImplOpenGL2_InitMultiViewportSupport(); | |
| 108 | +static void ImGui_ImplOpenGL2_ShutdownMultiViewportSupport(); | |
| 109 | + | |
| 104 | 110 | // Functions |
| 105 | 111 | void ImGui_ImplOpenGL2_NewFrame() |
| 106 | 112 | { |
| @@ -346,7 +352,10 @@ | ||
| 346 | 352 | io.BackendRendererUserData = (void*)bd; |
| 347 | 353 | io.BackendRendererName = "imgui_impl_opengl2"; |
| 348 | 354 | io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. |
| 355 | + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) | |
| 349 | 356 | |
| 357 | + ImGui_ImplOpenGL2_InitMultiViewportSupport(); | |
| 358 | + | |
| 350 | 359 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 351 | 360 | platform_io.DrawCallback_ResetRenderState = ImGui_ImplOpenGL2_DrawCallback_ResetRenderState; |
| 352 | 361 | platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplOpenGL2_DrawCallback_SetSamplerLinear; |
| @@ -362,13 +371,42 @@ | ||
| 362 | 371 | ImGuiIO& io = ImGui::GetIO(); |
| 363 | 372 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 364 | 373 | |
| 374 | + ImGui_ImplOpenGL2_ShutdownMultiViewportSupport(); | |
| 365 | 375 | ImGui_ImplOpenGL2_DestroyDeviceObjects(); |
| 366 | 376 | |
| 367 | 377 | io.BackendRendererName = nullptr; |
| 368 | 378 | io.BackendRendererUserData = nullptr; |
| 369 | - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasTextures); | |
| 379 | + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports); | |
| 370 | 380 | platform_io.ClearRendererHandlers(); |
| 371 | 381 | IM_DELETE(bd); |
| 382 | +} | |
| 383 | + | |
| 384 | +//-------------------------------------------------------------------------------------------------------- | |
| 385 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 386 | +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. | |
| 387 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 388 | +//-------------------------------------------------------------------------------------------------------- | |
| 389 | + | |
| 390 | +static void ImGui_ImplOpenGL2_RenderWindow(ImGuiViewport* viewport, void*) | |
| 391 | +{ | |
| 392 | + if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear)) | |
| 393 | + { | |
| 394 | + ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); | |
| 395 | + glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); | |
| 396 | + glClear(GL_COLOR_BUFFER_BIT); | |
| 397 | + } | |
| 398 | + ImGui_ImplOpenGL2_RenderDrawData(viewport->DrawData); | |
| 399 | +} | |
| 400 | + | |
| 401 | +static void ImGui_ImplOpenGL2_InitMultiViewportSupport() | |
| 402 | +{ | |
| 403 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 404 | + platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL2_RenderWindow; | |
| 405 | +} | |
| 406 | + | |
| 407 | +static void ImGui_ImplOpenGL2_ShutdownMultiViewportSupport() | |
| 408 | +{ | |
| 409 | + ImGui::DestroyPlatformWindows(); | |
| 372 | 410 | } |
| 373 | 411 | |
| 374 | 412 | //----------------------------------------------------------------------------- |
| @@ -4,6 +4,7 @@ | ||
| 4 | 4 | // Implemented features: |
| 5 | 5 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! |
| 6 | 6 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 7 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 7 | 8 | // Missing features or Issues: |
| 8 | 9 | // [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 9 | 10 | // [ ] Renderer: Use of DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest is emulated by poking to glTexParameter(), as legacy OpenGL doesn't have glBindSampler(). |
| @@ -7,6 +7,7 @@ | ||
| 7 | 7 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! |
| 8 | 8 | // [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!] |
| 9 | 9 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 10 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 10 | 11 | |
| 11 | 12 | // About WebGL/ES: |
| 12 | 13 | // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES. |
| @@ -23,7 +24,11 @@ | ||
| 23 | 24 | |
| 24 | 25 | // CHANGELOG |
| 25 | 26 | // (minor and older changes stripped away, please see git history for details) |
| 27 | +// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 28 | +// 2026-06-17: OpenGL: Expose selected render state in ImGui_ImplOpenGL3_RenderState, Allowing to dynamically select between use of glBindSampler() and glTexParameter(). You can access in 'void* platform_io.Renderer_RenderState' during rendering. | |
| 29 | +// 2026-06-03: OpenGL: GLSL version detection assume GLSL 410 when GL context is 4.1. Fixes an issue running on macOS with Wine. (#9427, #6577) | |
| 26 | 30 | // 2026-04-23: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) |
| 31 | +// (Breaking): this change prioritize using glBindSampler() when available, which would override glTexParameter() settings you may have set on custom textures. | |
| 27 | 32 | // 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295) |
| 28 | 33 | // 2025-12-11: OpenGL: Fixed embedded loader multiple init/shutdown cycles broken on some platforms. (#8792, #9112) |
| 29 | 34 | // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. |
| @@ -253,8 +258,6 @@ | ||
| 253 | 258 | bool HasBindSampler; |
| 254 | 259 | bool HasClipOrigin; |
| 255 | 260 | bool UseBufferSubData; |
| 256 | - bool UseTexParameterToSetSampler; | |
| 257 | - GLuint NextSampler; // Used if !HasBindSampler && UseTexParameterToSetSampler. | |
| 258 | 261 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER |
| 259 | 262 | GLuint TexSamplers[2]; // Used if HasBindSimpler. (0=linear, 1=nearest) |
| 260 | 263 | #endif |
| @@ -271,6 +274,10 @@ | ||
| 271 | 274 | return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; |
| 272 | 275 | } |
| 273 | 276 | |
| 277 | +// Forward Declarations | |
| 278 | +static void ImGui_ImplOpenGL3_InitMultiViewportSupport(); | |
| 279 | +static void ImGui_ImplOpenGL3_ShutdownMultiViewportSupport(); | |
| 280 | + | |
| 274 | 281 | // OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only) |
| 275 | 282 | #ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY |
| 276 | 283 | struct ImGui_ImplOpenGL3_VtxAttribState |
| @@ -330,7 +337,7 @@ | ||
| 330 | 337 | IM_ASSERT(0 && "ImGui_ImplOpenGL3_CreateDeviceObjects() failed!"); |
| 331 | 338 | } |
| 332 | 339 | |
| 333 | -static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object) | |
| 340 | +static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, ImGui_ImplOpenGL3_RenderState* render_state, int fb_width, int fb_height, GLuint vertex_array_object) | |
| 334 | 341 | { |
| 335 | 342 | ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); |
| 336 | 343 | |
| @@ -384,8 +391,11 @@ | ||
| 384 | 391 | glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); |
| 385 | 392 | |
| 386 | 393 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER |
| 387 | - if (bd->HasBindSampler) | |
| 388 | - glBindSampler(0, bd->TexSamplers[0]); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise. | |
| 394 | + if (render_state->UseBindSampler) | |
| 395 | + { | |
| 396 | + render_state->CurrentSampler = bd->TexSamplers[0]; | |
| 397 | + glBindSampler(0, render_state->CurrentSampler); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise. | |
| 398 | + } | |
| 389 | 399 | #endif |
| 390 | 400 | |
| 391 | 401 | (void)vertex_array_object; |
| @@ -406,13 +416,42 @@ | ||
| 406 | 416 | |
| 407 | 417 | // Draw callbacks |
| 408 | 418 | static void ImGui_ImplOpenGL3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. |
| 419 | +static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) | |
| 420 | +{ | |
| 421 | + ImGui_ImplOpenGL3_RenderState* render_state = ImGui_ImplOpenGL3_GetRenderState(); | |
| 409 | 422 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER |
| 410 | -static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->HasBindSampler) { glBindSampler(0, bd->TexSamplers[0]); } else { bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_LINEAR; } } | |
| 411 | -static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); if (bd->HasBindSampler) { glBindSampler(0, bd->TexSamplers[1]); } else { bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_NEAREST; } } | |
| 412 | -#else | |
| 413 | -static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_LINEAR; } | |
| 414 | -static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_NEAREST; } | |
| 423 | + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); | |
| 424 | + if (bd->HasBindSampler) | |
| 425 | + { | |
| 426 | + render_state->CurrentSampler = bd->TexSamplers[0]; | |
| 427 | + render_state->UseTexParameterFilter = false; | |
| 428 | + glBindSampler(0, render_state->CurrentSampler); | |
| 429 | + } | |
| 430 | + else | |
| 415 | 431 | #endif |
| 432 | + { | |
| 433 | + render_state->UseTexParameterFilter = true; | |
| 434 | + render_state->CurrentTexParameterFilter = GL_LINEAR; | |
| 435 | + } | |
| 436 | +} | |
| 437 | +static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) | |
| 438 | +{ | |
| 439 | + ImGui_ImplOpenGL3_RenderState* render_state = ImGui_ImplOpenGL3_GetRenderState(); | |
| 440 | +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER | |
| 441 | + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); | |
| 442 | + if (bd->HasBindSampler) | |
| 443 | + { | |
| 444 | + render_state->CurrentSampler = bd->TexSamplers[1]; | |
| 445 | + render_state->UseTexParameterFilter = false; | |
| 446 | + glBindSampler(0, render_state->CurrentSampler); | |
| 447 | + } | |
| 448 | + else | |
| 449 | +#endif | |
| 450 | + { | |
| 451 | + render_state->UseTexParameterFilter = true; | |
| 452 | + render_state->CurrentTexParameterFilter = GL_NEAREST; | |
| 453 | + } | |
| 454 | +} | |
| 416 | 455 | |
| 417 | 456 | // OpenGL3 Render function. |
| 418 | 457 | // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly. |
| @@ -482,8 +521,18 @@ | ||
| 482 | 521 | #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY |
| 483 | 522 | GL_CALL(glGenVertexArrays(1, &vertex_array_object)); |
| 484 | 523 | #endif |
| 485 | - ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); | |
| 486 | 524 | |
| 525 | + // Setup render state structure (for callbacks and custom texture bindings) | |
| 526 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 527 | + ImGui_ImplOpenGL3_RenderState render_state; | |
| 528 | + render_state.UseBindSampler = bd->HasBindSampler; | |
| 529 | + render_state.UseTexParameterFilter = false; | |
| 530 | + render_state.CurrentSampler = 0; | |
| 531 | + render_state.CurrentTexParameterFilter = 0; | |
| 532 | + platform_io.Renderer_RenderState = &render_state; | |
| 533 | + | |
| 534 | + ImGui_ImplOpenGL3_SetupRenderState(draw_data, &render_state, fb_width, fb_height, vertex_array_object); | |
| 535 | + | |
| 487 | 536 | // Will project scissor/clipping rectangles into framebuffer space |
| 488 | 537 | ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports |
| 489 | 538 | ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) |
| @@ -529,7 +578,7 @@ | ||
| 529 | 578 | { |
| 530 | 579 | // User callback, registered via ImDrawList::AddCallback() |
| 531 | 580 | if (pcmd->UserCallback == ImGui_ImplOpenGL3_DrawCallback_ResetRenderState) |
| 532 | - ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); | |
| 581 | + ImGui_ImplOpenGL3_SetupRenderState(draw_data, &render_state, fb_width, fb_height, vertex_array_object); | |
| 533 | 582 | else |
| 534 | 583 | pcmd->UserCallback(draw_list, pcmd); |
| 535 | 584 | } |
| @@ -548,11 +597,11 @@ | ||
| 548 | 597 | GL_CALL(glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID())); |
| 549 | 598 | |
| 550 | 599 | // Emulate sampler change (even though it is technically part of texture data) |
| 551 | - // As a sort of hack/workaround, we only start writing using glTextParameter() if sampler is ever changed explicitly. | |
| 552 | - if (!bd->HasBindSampler && bd->UseTexParameterToSetSampler) | |
| 600 | + // As a sort of hack/workaround, we only start writing using glTexParameter() if sampler is ever changed explicitly. | |
| 601 | + if (render_state.UseTexParameterFilter) | |
| 553 | 602 | { |
| 554 | - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bd->NextSampler); | |
| 555 | - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bd->NextSampler); | |
| 603 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, render_state.CurrentTexParameterFilter); | |
| 604 | + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, render_state.CurrentTexParameterFilter); | |
| 556 | 605 | } |
| 557 | 606 | |
| 558 | 607 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET |
| @@ -564,6 +613,7 @@ | ||
| 564 | 613 | } |
| 565 | 614 | } |
| 566 | 615 | } |
| 616 | + platform_io.Renderer_RenderState = nullptr; | |
| 567 | 617 | |
| 568 | 618 | // Destroy the temporary VAO |
| 569 | 619 | #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY |
| @@ -1030,6 +1080,7 @@ | ||
| 1030 | 1080 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. |
| 1031 | 1081 | #endif |
| 1032 | 1082 | io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. |
| 1083 | + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) | |
| 1033 | 1084 | |
| 1034 | 1085 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 1035 | 1086 | platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = (int)bd->MaxTextureSize; |
| @@ -1048,7 +1099,10 @@ | ||
| 1048 | 1099 | #elif defined(__APPLE__) |
| 1049 | 1100 | glsl_version = "#version 150"; |
| 1050 | 1101 | #else |
| 1051 | - glsl_version = "#version 130"; | |
| 1102 | + if (bd->GlVersion >= 410) | |
| 1103 | + glsl_version = "#version 410"; | |
| 1104 | + else | |
| 1105 | + glsl_version = "#version 130"; | |
| 1052 | 1106 | #endif |
| 1053 | 1107 | } |
| 1054 | 1108 | IM_ASSERT((int)strlen(glsl_version) + 2 < IM_COUNTOF(bd->GlslVersionString)); |
| @@ -1079,6 +1133,8 @@ | ||
| 1079 | 1133 | } |
| 1080 | 1134 | #endif |
| 1081 | 1135 | |
| 1136 | + ImGui_ImplOpenGL3_InitMultiViewportSupport(); | |
| 1137 | + | |
| 1082 | 1138 | return true; |
| 1083 | 1139 | } |
| 1084 | 1140 | |
| @@ -1089,15 +1145,44 @@ | ||
| 1089 | 1145 | ImGuiIO& io = ImGui::GetIO(); |
| 1090 | 1146 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 1091 | 1147 | |
| 1148 | + ImGui_ImplOpenGL3_ShutdownMultiViewportSupport(); | |
| 1092 | 1149 | ImGui_ImplOpenGL3_DestroyDeviceObjects(); |
| 1093 | 1150 | |
| 1094 | 1151 | io.BackendRendererName = nullptr; |
| 1095 | 1152 | io.BackendRendererUserData = nullptr; |
| 1096 | - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); | |
| 1153 | + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports); | |
| 1097 | 1154 | platform_io.ClearRendererHandlers(); |
| 1098 | 1155 | IM_DELETE(bd); |
| 1099 | 1156 | |
| 1100 | 1157 | ImGui_ImplOpenGL3_ShutdownLoader(); |
| 1158 | +} | |
| 1159 | + | |
| 1160 | +//-------------------------------------------------------------------------------------------------------- | |
| 1161 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 1162 | +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. | |
| 1163 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 1164 | +//-------------------------------------------------------------------------------------------------------- | |
| 1165 | + | |
| 1166 | +static void ImGui_ImplOpenGL3_RenderWindow(ImGuiViewport* viewport, void*) | |
| 1167 | +{ | |
| 1168 | + if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear)) | |
| 1169 | + { | |
| 1170 | + ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); | |
| 1171 | + glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); | |
| 1172 | + glClear(GL_COLOR_BUFFER_BIT); | |
| 1173 | + } | |
| 1174 | + ImGui_ImplOpenGL3_RenderDrawData(viewport->DrawData); | |
| 1175 | +} | |
| 1176 | + | |
| 1177 | +static void ImGui_ImplOpenGL3_InitMultiViewportSupport() | |
| 1178 | +{ | |
| 1179 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 1180 | + platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL3_RenderWindow; | |
| 1181 | +} | |
| 1182 | + | |
| 1183 | +static void ImGui_ImplOpenGL3_ShutdownMultiViewportSupport() | |
| 1184 | +{ | |
| 1185 | + ImGui::DestroyPlatformWindows(); | |
| 1101 | 1186 | } |
| 1102 | 1187 | |
| 1103 | 1188 | //----------------------------------------------------------------------------- |
| @@ -7,6 +7,7 @@ | ||
| 7 | 7 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! |
| 8 | 8 | // [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!] |
| 9 | 9 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 10 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 10 | 11 | |
| 11 | 12 | // About WebGL/ES: |
| 12 | 13 | // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES. |
| @@ -64,5 +65,18 @@ | ||
| 64 | 65 | #endif |
| 65 | 66 | |
| 66 | 67 | #endif |
| 68 | + | |
| 69 | +// [BETA] Selected render state data shared with callbacks. | |
| 70 | +// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplOpenGL3_RenderDrawData() call. | |
| 71 | +// (Please open an issue if you feel you need access to more data) | |
| 72 | +struct ImGui_ImplOpenGL3_RenderState | |
| 73 | +{ | |
| 74 | + bool UseBindSampler; | |
| 75 | + bool UseTexParameterFilter; | |
| 76 | + unsigned int CurrentSampler; // (GLuint) Used if UseBindSampler == true, otherwise always 0 | |
| 77 | + unsigned int CurrentTexParameterFilter; // (GLuint) Used if UseTexParameterToSetSampler == true | |
| 78 | +}; | |
| 79 | + | |
| 80 | +static inline ImGui_ImplOpenGL3_RenderState* ImGui_ImplOpenGL3_GetRenderState() { return (ImGui_ImplOpenGL3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; } | |
| 67 | 81 | |
| 68 | 82 | #endif // #ifndef IMGUI_DISABLE |
| @@ -10,6 +10,10 @@ | ||
| 10 | 10 | // [X] Platform: Gamepad support. |
| 11 | 11 | // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. |
| 12 | 12 | // [X] Platform: IME support. |
| 13 | +// [x] Platform: Multi-viewport / platform windows. | |
| 14 | +// Missing features or Issues: | |
| 15 | +// [ ] Platform: Multi-viewport: Window size not correctly reported when enabling io.ConfigViewportsNoDecoration | |
| 16 | +// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either. | |
| 13 | 17 | |
| 14 | 18 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 15 | 19 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -10,6 +10,10 @@ | ||
| 10 | 10 | // [X] Platform: Gamepad support. |
| 11 | 11 | // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. |
| 12 | 12 | // [X] Platform: IME support. |
| 13 | +// [x] Platform: Multi-viewport / platform windows. | |
| 14 | +// Missing features or Issues: | |
| 15 | +// [ ] Platform: Multi-viewport: Window size not correctly reported when enabling io.ConfigViewportsNoDecoration | |
| 16 | +// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either. | |
| 13 | 17 | |
| 14 | 18 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 15 | 19 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -29,9 +33,12 @@ | ||
| 29 | 33 | |
| 30 | 34 | // CHANGELOG |
| 31 | 35 | // (minor and older changes stripped away, please see git history for details) |
| 36 | +// 2026-XX-XX: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 32 | 37 | // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. |
| 38 | +// 2025-07-08: [Docking] Fixed multi-viewport handling broken on 2025-06-02. (#8644, #8777) | |
| 33 | 39 | // 2025-06-27: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. |
| 34 | 40 | // 2025-06-12: ImGui_ImplOSX_HandleEvent() only process event for window containing our view. (#8644) |
| 41 | +// 2025-05-15: [Docking] Add Platform_GetWindowFramebufferScale() handler, to allow varying Retina display density on multiple monitors. | |
| 35 | 42 | // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. |
| 36 | 43 | // 2025-01-20: Removed notification observer when shutting down. (#8331) |
| 37 | 44 | // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: |
| @@ -101,6 +108,9 @@ | ||
| 101 | 108 | static inline CFTimeInterval GetMachAbsoluteTimeInSeconds() { return (CFTimeInterval)(double)(clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1e9); } |
| 102 | 109 | |
| 103 | 110 | // Forward Declarations |
| 111 | +static void ImGui_ImplOSX_InitMultiViewportSupport(); | |
| 112 | +static void ImGui_ImplOSX_ShutdownMultiViewportSupport(); | |
| 113 | +static void ImGui_ImplOSX_UpdateMonitors(); | |
| 104 | 114 | static void ImGui_ImplOSX_AddTrackingArea(NSView* _Nonnull view); |
| 105 | 115 | static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view); |
| 106 | 116 | |
| @@ -148,7 +158,21 @@ | ||
| 148 | 158 | NSWindow* window = view.window; |
| 149 | 159 | if (!window) |
| 150 | 160 | return; |
| 161 | + | |
| 162 | + ImGuiIO& io = ImGui::GetIO(); | |
| 163 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 151 | 164 | { |
| 165 | + NSRect frame = window.frame; | |
| 166 | + NSRect contentRect = window.contentLayoutRect; | |
| 167 | + if (window.styleMask & NSWindowStyleMaskFullSizeContentView) // No title bar windows should be considered. | |
| 168 | + contentRect = frame; | |
| 169 | + | |
| 170 | + NSRect firstScreenFrame = NSScreen.screens[0].frame; | |
| 171 | + _imeRect = NSMakeRect(_posX, _posY, 0, 0); | |
| 172 | + _imeRect.origin.y = firstScreenFrame.size.height - _imeRect.size.height - _imeRect.origin.y; // Opposite of ConvertNSRect() | |
| 173 | + } | |
| 174 | + else | |
| 175 | + { | |
| 152 | 176 | NSRect contentRect = [window contentRectForFrameRect:window.frame]; |
| 153 | 177 | NSRect rect = NSMakeRect(_posX, contentRect.size.height - _posY, 0, 0); |
| 154 | 178 | _imeRect = [window convertRectToScreen:rect]; |
| @@ -247,6 +271,7 @@ | ||
| 247 | 271 | |
| 248 | 272 | - (void)onApplicationBecomeActive:(NSNotification*)aNotification; |
| 249 | 273 | - (void)onApplicationBecomeInactive:(NSNotification*)aNotification; |
| 274 | +- (void)displaysDidChange:(NSNotification*)aNotification; | |
| 250 | 275 | |
| 251 | 276 | @end |
| 252 | 277 | |
| @@ -264,6 +289,11 @@ | ||
| 264 | 289 | io.AddFocusEvent(false); |
| 265 | 290 | } |
| 266 | 291 | |
| 292 | +- (void)displaysDidChange:(NSNotification*)aNotification | |
| 293 | +{ | |
| 294 | + ImGui_ImplOSX_UpdateMonitors(); | |
| 295 | +} | |
| 296 | + | |
| 267 | 297 | @end |
| 268 | 298 | |
| 269 | 299 | // Functions |
| @@ -418,11 +448,15 @@ | ||
| 418 | 448 | io.BackendPlatformName = "imgui_impl_osx"; |
| 419 | 449 | io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) |
| 420 | 450 | //io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) |
| 451 | + io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) | |
| 452 | + //io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional) | |
| 421 | 453 | |
| 422 | 454 | bd->Observer = [ImGuiObserver new]; |
| 423 | 455 | bd->Window = view.window ?: NSApp.orderedWindows.firstObject; |
| 424 | 456 | ImGuiViewport* main_viewport = ImGui::GetMainViewport(); |
| 425 | 457 | main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (__bridge_retained void*)bd->Window; |
| 458 | + ImGui_ImplOSX_UpdateMonitors(); | |
| 459 | + ImGui_ImplOSX_InitMultiViewportSupport(); | |
| 426 | 460 | |
| 427 | 461 | // Load cursors. Some of them are undocumented. |
| 428 | 462 | bd->MouseCursorHidden = false; |
| @@ -514,14 +548,14 @@ | ||
| 514 | 548 | bd->Monitor = nullptr; |
| 515 | 549 | } |
| 516 | 550 | |
| 551 | + ImGui_ImplOSX_ShutdownMultiViewportSupport(); | |
| 517 | 552 | ImGui_ImplOSX_DestroyBackendData(); |
| 518 | - | |
| 519 | 553 | ImGuiIO& io = ImGui::GetIO(); |
| 520 | 554 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 521 | 555 | |
| 522 | 556 | io.BackendPlatformName = nullptr; |
| 523 | 557 | io.BackendPlatformUserData = nullptr; |
| 524 | - io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasGamepad); | |
| 558 | + io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports); | |
| 525 | 559 | platform_io.ClearPlatformHandlers(); |
| 526 | 560 | } |
| 527 | 561 | |
| @@ -672,10 +706,10 @@ | ||
| 672 | 706 | static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) |
| 673 | 707 | { |
| 674 | 708 | // Only process events from the window containing ImGui view |
| 675 | - if (event.window != view.window) | |
| 709 | + if (!ImGui::FindViewportByPlatformHandle((__bridge void*)event.window)) | |
| 676 | 710 | return false; |
| 677 | - ImGuiIO& io = ImGui::GetIO(); | |
| 678 | 711 | |
| 712 | + ImGuiIO& io = ImGui::GetIO(); | |
| 679 | 713 | if (event.type == NSEventTypeLeftMouseDown || event.type == NSEventTypeRightMouseDown || event.type == NSEventTypeOtherMouseDown) |
| 680 | 714 | { |
| 681 | 715 | int button = (int)[event buttonNumber]; |
| @@ -700,14 +734,23 @@ | ||
| 700 | 734 | |
| 701 | 735 | if (event.type == NSEventTypeMouseMoved || event.type == NSEventTypeLeftMouseDragged || event.type == NSEventTypeRightMouseDragged || event.type == NSEventTypeOtherMouseDragged) |
| 702 | 736 | { |
| 703 | - NSPoint mousePoint = event.locationInWindow; | |
| 704 | - if (event.window == nil) | |
| 705 | - mousePoint = [[view window] convertPointFromScreen:mousePoint]; | |
| 706 | - mousePoint = [view convertPoint:mousePoint fromView:nil]; | |
| 707 | - if ([view isFlipped]) | |
| 708 | - mousePoint = NSMakePoint(mousePoint.x, mousePoint.y); | |
| 737 | + NSPoint mousePoint; | |
| 738 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 739 | + { | |
| 740 | + mousePoint = NSEvent.mouseLocation; | |
| 741 | + mousePoint.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - mousePoint.y; // Normalize y coordinate to top-left of main display. | |
| 742 | + } | |
| 709 | 743 | else |
| 710 | - mousePoint = NSMakePoint(mousePoint.x, view.bounds.size.height - mousePoint.y); | |
| 744 | + { | |
| 745 | + mousePoint = event.locationInWindow; | |
| 746 | + if (event.window == nil) | |
| 747 | + mousePoint = [[view window] convertPointFromScreen:mousePoint]; | |
| 748 | + mousePoint = [view convertPoint:mousePoint fromView:nil]; // Convert to local coordinates of view | |
| 749 | + if ([view isFlipped]) | |
| 750 | + mousePoint = NSMakePoint(mousePoint.x, mousePoint.y); | |
| 751 | + else | |
| 752 | + mousePoint = NSMakePoint(mousePoint.x, view.bounds.size.height - mousePoint.y); | |
| 753 | + } | |
| 711 | 754 | io.AddMouseSourceEvent(GetMouseSource(event)); |
| 712 | 755 | io.AddMousePosEvent((float)mousePoint.x, (float)mousePoint.y); |
| 713 | 756 | return io.WantCaptureMouse; |
| @@ -831,6 +874,300 @@ | ||
| 831 | 874 | ImGui_ImplOSX_HandleEvent(event, view); |
| 832 | 875 | return event; |
| 833 | 876 | }]; |
| 877 | +} | |
| 878 | + | |
| 879 | +//-------------------------------------------------------------------------------------------------------- | |
| 880 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 881 | +// This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously. | |
| 882 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 883 | +//-------------------------------------------------------------------------------------------------------- | |
| 884 | + | |
| 885 | +struct ImGui_ImplOSX_ViewportData | |
| 886 | +{ | |
| 887 | + NSWindow* Window; | |
| 888 | + bool WindowOwned; | |
| 889 | + | |
| 890 | + ImGui_ImplOSX_ViewportData() { WindowOwned = false; } | |
| 891 | + ~ImGui_ImplOSX_ViewportData() { IM_ASSERT(Window == nil); } | |
| 892 | +}; | |
| 893 | + | |
| 894 | +@interface ImGui_ImplOSX_Window: NSWindow | |
| 895 | +@end | |
| 896 | + | |
| 897 | +@implementation ImGui_ImplOSX_Window | |
| 898 | + | |
| 899 | +- (BOOL)canBecomeKeyWindow | |
| 900 | +{ | |
| 901 | + return YES; | |
| 902 | +} | |
| 903 | + | |
| 904 | +@end | |
| 905 | + | |
| 906 | +static void ConvertNSRect(NSRect* r) | |
| 907 | +{ | |
| 908 | + NSRect firstScreenFrame = NSScreen.screens[0].frame; | |
| 909 | + IM_ASSERT(firstScreenFrame.origin.x == 0 && firstScreenFrame.origin.y == 0); | |
| 910 | + r->origin.y = firstScreenFrame.size.height - r->origin.y - r->size.height; | |
| 911 | +} | |
| 912 | + | |
| 913 | +static void ImGui_ImplOSX_CreateWindow(ImGuiViewport* viewport) | |
| 914 | +{ | |
| 915 | + ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); | |
| 916 | + ImGui_ImplOSX_ViewportData* vd = IM_NEW(ImGui_ImplOSX_ViewportData)(); | |
| 917 | + viewport->PlatformUserData = vd; | |
| 918 | + | |
| 919 | + NSScreen* screen = bd->Window.screen; | |
| 920 | + NSRect rect = NSMakeRect(viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y); | |
| 921 | + ConvertNSRect(&rect); | |
| 922 | + | |
| 923 | + NSWindowStyleMask styleMask = 0; | |
| 924 | + if (viewport->Flags & ImGuiViewportFlags_NoDecoration) | |
| 925 | + styleMask |= NSWindowStyleMaskBorderless; | |
| 926 | + else | |
| 927 | + styleMask |= NSWindowStyleMaskTitled | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; | |
| 928 | + | |
| 929 | + NSWindow* window = [[ImGui_ImplOSX_Window alloc] initWithContentRect:rect | |
| 930 | + styleMask:styleMask | |
| 931 | + backing:NSBackingStoreBuffered | |
| 932 | + defer:YES | |
| 933 | + screen:screen]; | |
| 934 | + if (viewport->Flags & ImGuiViewportFlags_TopMost) | |
| 935 | + [window setLevel:NSFloatingWindowLevel]; | |
| 936 | + | |
| 937 | + window.title = @"Untitled"; | |
| 938 | + window.opaque = YES; | |
| 939 | + | |
| 940 | + KeyEventResponder* view = [[KeyEventResponder alloc] initWithFrame:rect]; | |
| 941 | + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6 && ceil(NSAppKitVersionNumber) < NSAppKitVersionNumber10_15) | |
| 942 | + [view setWantsBestResolutionOpenGLSurface:YES]; | |
| 943 | + | |
| 944 | + window.contentView = view; | |
| 945 | + | |
| 946 | + vd->Window = window; | |
| 947 | + vd->WindowOwned = true; | |
| 948 | + viewport->PlatformRequestResize = false; | |
| 949 | + viewport->PlatformHandle = viewport->PlatformHandleRaw = (__bridge_retained void*)window; | |
| 950 | +} | |
| 951 | + | |
| 952 | +static void ImGui_ImplOSX_DestroyWindow(ImGuiViewport* viewport) | |
| 953 | +{ | |
| 954 | + if (ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData) | |
| 955 | + { | |
| 956 | + NSWindow* window = vd->Window; | |
| 957 | + if (window != nil && vd->WindowOwned) | |
| 958 | + { | |
| 959 | + window.contentView = nil; | |
| 960 | + window.contentViewController = nil; | |
| 961 | + [window orderOut:nil]; | |
| 962 | + } | |
| 963 | + vd->Window = nil; | |
| 964 | + IM_DELETE(vd); | |
| 965 | + } | |
| 966 | + viewport->PlatformUserData = viewport->PlatformHandle = viewport->PlatformHandleRaw = nullptr; | |
| 967 | +} | |
| 968 | + | |
| 969 | +static void ImGui_ImplOSX_ShowWindow(ImGuiViewport* viewport) | |
| 970 | +{ | |
| 971 | + ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData; | |
| 972 | + IM_ASSERT(vd->Window != 0); | |
| 973 | + | |
| 974 | + if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) | |
| 975 | + [vd->Window orderFront:nil]; | |
| 976 | + else | |
| 977 | + [vd->Window makeKeyAndOrderFront:nil]; | |
| 978 | + | |
| 979 | + [vd->Window setIsVisible:YES]; | |
| 980 | +} | |
| 981 | + | |
| 982 | +static ImVec2 ImGui_ImplOSX_GetWindowPos(ImGuiViewport* viewport) | |
| 983 | +{ | |
| 984 | + ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData; | |
| 985 | + IM_ASSERT(vd->Window != 0); | |
| 986 | + | |
| 987 | + NSWindow* window = vd->Window; | |
| 988 | + NSRect frame = window.frame; | |
| 989 | + NSRect contentRect = window.contentLayoutRect; | |
| 990 | + if (window.styleMask & NSWindowStyleMaskFullSizeContentView) // No title bar windows should be considered. | |
| 991 | + contentRect = frame; | |
| 992 | + | |
| 993 | + NSRect firstScreenFrame = NSScreen.screens[0].frame; | |
| 994 | + return ImVec2(frame.origin.x, firstScreenFrame.size.height - frame.origin.y - contentRect.size.height); | |
| 995 | +} | |
| 996 | + | |
| 997 | +static void ImGui_ImplOSX_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos) | |
| 998 | +{ | |
| 999 | + ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData; | |
| 1000 | + IM_ASSERT(vd->Window != 0); | |
| 1001 | + | |
| 1002 | + NSWindow* window = vd->Window; | |
| 1003 | + NSSize size = window.frame.size; | |
| 1004 | + | |
| 1005 | + NSRect r = NSMakeRect(pos.x, pos.y, size.width, size.height); | |
| 1006 | + ConvertNSRect(&r); | |
| 1007 | + [window setFrameOrigin:r.origin]; | |
| 1008 | +} | |
| 1009 | + | |
| 1010 | +static ImVec2 ImGui_ImplOSX_GetWindowSize(ImGuiViewport* viewport) | |
| 1011 | +{ | |
| 1012 | + ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData; | |
| 1013 | + IM_ASSERT(vd->Window != 0); | |
| 1014 | + | |
| 1015 | + NSWindow* window = vd->Window; | |
| 1016 | + NSSize size = window.contentLayoutRect.size; | |
| 1017 | + return ImVec2(size.width, size.height); | |
| 1018 | +} | |
| 1019 | + | |
| 1020 | +static void ImGui_ImplOSX_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) | |
| 1021 | +{ | |
| 1022 | + ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData; | |
| 1023 | + IM_ASSERT(vd->Window != 0); | |
| 1024 | + | |
| 1025 | + NSWindow* window = vd->Window; | |
| 1026 | + NSRect rect = window.frame; | |
| 1027 | + rect.origin.y -= (size.y - rect.size.height); | |
| 1028 | + rect.size.width = size.x; | |
| 1029 | + rect.size.height = size.y; | |
| 1030 | + [window setFrame:rect display:YES]; | |
| 1031 | +} | |
| 1032 | + | |
| 1033 | +static ImVec2 ImGui_ImplOSX_GetWindowFramebufferScale(ImGuiViewport* viewport) | |
| 1034 | +{ | |
| 1035 | + ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData; | |
| 1036 | + NSWindow* window = vd->Window; | |
| 1037 | + const float fb_scale = (float)[window backingScaleFactor]; | |
| 1038 | + return ImVec2(fb_scale, fb_scale); | |
| 1039 | +} | |
| 1040 | + | |
| 1041 | +static void ImGui_ImplOSX_SetWindowFocus(ImGuiViewport* viewport) | |
| 1042 | +{ | |
| 1043 | + ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); | |
| 1044 | + ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData; | |
| 1045 | + IM_ASSERT(vd->Window != 0); | |
| 1046 | + [vd->Window makeKeyAndOrderFront:bd->Window]; | |
| 1047 | +} | |
| 1048 | + | |
| 1049 | +static bool ImGui_ImplOSX_GetWindowFocus(ImGuiViewport* viewport) | |
| 1050 | +{ | |
| 1051 | + ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData; | |
| 1052 | + IM_ASSERT(vd->Window != 0); | |
| 1053 | + | |
| 1054 | + return vd->Window.isKeyWindow; | |
| 1055 | +} | |
| 1056 | + | |
| 1057 | +static bool ImGui_ImplOSX_GetWindowMinimized(ImGuiViewport* viewport) | |
| 1058 | +{ | |
| 1059 | + ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData; | |
| 1060 | + IM_ASSERT(vd->Window != 0); | |
| 1061 | + | |
| 1062 | + return vd->Window.isMiniaturized; | |
| 1063 | +} | |
| 1064 | + | |
| 1065 | +static void ImGui_ImplOSX_SetWindowTitle(ImGuiViewport* viewport, const char* title) | |
| 1066 | +{ | |
| 1067 | + ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData; | |
| 1068 | + IM_ASSERT(vd->Window != 0); | |
| 1069 | + | |
| 1070 | + vd->Window.title = [NSString stringWithUTF8String:title]; | |
| 1071 | +} | |
| 1072 | + | |
| 1073 | +static void ImGui_ImplOSX_SetWindowAlpha(ImGuiViewport* viewport, float alpha) | |
| 1074 | +{ | |
| 1075 | + ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData; | |
| 1076 | + IM_ASSERT(vd->Window != 0); | |
| 1077 | + IM_ASSERT(alpha >= 0.0f && alpha <= 1.0f); | |
| 1078 | + | |
| 1079 | + vd->Window.alphaValue = alpha; | |
| 1080 | +} | |
| 1081 | + | |
| 1082 | +static float ImGui_ImplOSX_GetWindowDpiScale(ImGuiViewport* viewport) | |
| 1083 | +{ | |
| 1084 | + ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData; | |
| 1085 | + IM_ASSERT(vd->Window != 0); | |
| 1086 | + | |
| 1087 | + return vd->Window.backingScaleFactor; | |
| 1088 | +} | |
| 1089 | + | |
| 1090 | +static void ImGui_ImplOSX_UpdateMonitors() | |
| 1091 | +{ | |
| 1092 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 1093 | + platform_io.Monitors.resize(0); | |
| 1094 | + | |
| 1095 | + NSRect firstScreenFrame = NSScreen.screens[0].frame; | |
| 1096 | + IM_ASSERT(firstScreenFrame.origin.x == 0 && firstScreenFrame.origin.y == 0); | |
| 1097 | + | |
| 1098 | + for (NSScreen* screen in NSScreen.screens) | |
| 1099 | + { | |
| 1100 | + NSRect frame = screen.frame; | |
| 1101 | + NSRect visibleFrame = screen.visibleFrame; | |
| 1102 | + ConvertNSRect(&frame); | |
| 1103 | + ConvertNSRect(&visibleFrame); | |
| 1104 | + | |
| 1105 | + ImGuiPlatformMonitor imgui_monitor; | |
| 1106 | + imgui_monitor.MainPos = ImVec2(frame.origin.x, frame.origin.y); | |
| 1107 | + imgui_monitor.MainSize = ImVec2(frame.size.width, frame.size.height); | |
| 1108 | + imgui_monitor.WorkPos = ImVec2(visibleFrame.origin.x, visibleFrame.origin.y); | |
| 1109 | + imgui_monitor.WorkSize = ImVec2(visibleFrame.size.width, visibleFrame.size.height); | |
| 1110 | + imgui_monitor.DpiScale = screen.backingScaleFactor; | |
| 1111 | + imgui_monitor.PlatformHandle = (__bridge_retained void*)screen; | |
| 1112 | + | |
| 1113 | + platform_io.Monitors.push_back(imgui_monitor); | |
| 1114 | + } | |
| 1115 | +} | |
| 1116 | + | |
| 1117 | +static void ImGui_ImplOSX_InitMultiViewportSupport() | |
| 1118 | +{ | |
| 1119 | + ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); | |
| 1120 | + | |
| 1121 | + // Register platform interface (will be coupled with a renderer interface) | |
| 1122 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 1123 | + platform_io.Platform_CreateWindow = ImGui_ImplOSX_CreateWindow; | |
| 1124 | + platform_io.Platform_DestroyWindow = ImGui_ImplOSX_DestroyWindow; | |
| 1125 | + platform_io.Platform_ShowWindow = ImGui_ImplOSX_ShowWindow; | |
| 1126 | + platform_io.Platform_SetWindowPos = ImGui_ImplOSX_SetWindowPos; | |
| 1127 | + platform_io.Platform_GetWindowPos = ImGui_ImplOSX_GetWindowPos; | |
| 1128 | + platform_io.Platform_SetWindowSize = ImGui_ImplOSX_SetWindowSize; | |
| 1129 | + platform_io.Platform_GetWindowSize = ImGui_ImplOSX_GetWindowSize; | |
| 1130 | + platform_io.Platform_GetWindowFramebufferScale = ImGui_ImplOSX_GetWindowFramebufferScale; | |
| 1131 | + platform_io.Platform_SetWindowFocus = ImGui_ImplOSX_SetWindowFocus; | |
| 1132 | + platform_io.Platform_GetWindowFocus = ImGui_ImplOSX_GetWindowFocus; | |
| 1133 | + platform_io.Platform_GetWindowMinimized = ImGui_ImplOSX_GetWindowMinimized; | |
| 1134 | + platform_io.Platform_SetWindowTitle = ImGui_ImplOSX_SetWindowTitle; | |
| 1135 | + platform_io.Platform_SetWindowAlpha = ImGui_ImplOSX_SetWindowAlpha; | |
| 1136 | + platform_io.Platform_GetWindowDpiScale = ImGui_ImplOSX_GetWindowDpiScale; // FIXME-DPI | |
| 1137 | + | |
| 1138 | + // Register main window handle (which is owned by the main application, not by us) | |
| 1139 | + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | |
| 1140 | + ImGui_ImplOSX_ViewportData* vd = IM_NEW(ImGui_ImplOSX_ViewportData)(); | |
| 1141 | + vd->Window = bd->Window; | |
| 1142 | + vd->WindowOwned = false; | |
| 1143 | + main_viewport->PlatformUserData = vd; | |
| 1144 | + main_viewport->PlatformHandle = (__bridge void*)bd->Window; | |
| 1145 | + | |
| 1146 | + [NSNotificationCenter.defaultCenter addObserver:bd->Observer | |
| 1147 | + selector:@selector(displaysDidChange:) | |
| 1148 | + name:NSApplicationDidChangeScreenParametersNotification | |
| 1149 | + object:nil]; | |
| 1150 | +} | |
| 1151 | + | |
| 1152 | +static void ImGui_ImplOSX_ShutdownMultiViewportSupport() | |
| 1153 | +{ | |
| 1154 | + ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); | |
| 1155 | + [NSNotificationCenter.defaultCenter removeObserver:bd->Observer | |
| 1156 | + name:NSApplicationDidChangeScreenParametersNotification | |
| 1157 | + object:nil]; | |
| 1158 | + bd->Observer = nullptr; | |
| 1159 | + bd->Window = nullptr; | |
| 1160 | + if (bd->Monitor != nullptr) | |
| 1161 | + { | |
| 1162 | + [NSEvent removeMonitor:bd->Monitor]; | |
| 1163 | + bd->Monitor = nullptr; | |
| 1164 | + } | |
| 1165 | + | |
| 1166 | + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | |
| 1167 | + ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)main_viewport->PlatformUserData; | |
| 1168 | + IM_DELETE(vd); | |
| 1169 | + main_viewport->PlatformUserData = nullptr; | |
| 1170 | + ImGui::DestroyPlatformWindows(); | |
| 834 | 1171 | } |
| 835 | 1172 | |
| 836 | 1173 | //----------------------------------------------------------------------------- |
| @@ -10,6 +10,10 @@ | ||
| 10 | 10 | // [X] Platform: Gamepad support. |
| 11 | 11 | // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. |
| 12 | 12 | // [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. |
| 13 | +// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 14 | +// Missing features or Issues: | |
| 15 | +// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows). | |
| 16 | +// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either. | |
| 13 | 17 | |
| 14 | 18 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 15 | 19 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -21,7 +25,9 @@ | ||
| 21 | 25 | |
| 22 | 26 | // CHANGELOG |
| 23 | 27 | // (minor and older changes stripped away, please see git history for details) |
| 28 | +// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 24 | 29 | // 2026-04-16: Made ImGui_ImplSDL2_GetContentScaleForWindow(), ImGui_ImplSDL2_GetContentScaleForDisplay() helpers return a minimum of 1.0f, as some Linux setup seems to report <1.0f value and this breaks scaling border size. (#9369) |
| 30 | +// 2026-03-09: [Docking] Fixed an issue dated 2025/04/09 (1.92 WIP) where a refactor+merge caused ImGuiBackendFlags_HasMouseHoveredViewport to never be set, causing foreign windows to be ignored when deciding of hovered viewport. (#9284) | |
| 25 | 31 | // 2026-02-13: Inputs: systems other than X11 are back to starting mouse capture on mouse down (reverts 2025-02-26 change). Only X11 requires waiting for a drag by default (not ideal, but a better default for X11 users). Added ImGui_ImplSDL2_SetMouseCaptureMode() for X11 debugger users. (#3650, #6410, #9235) |
| 26 | 32 | // 2026-01-15: Changed GetClipboardText() handler to return nullptr on error aka clipboard contents is not text. Consistent with other backends. (#9168) |
| 27 | 33 | // 2025-09-24: Skip using the SDL_GetGlobalMouseState() state when one of our window is hovered, as the SDL_MOUSEMOTION data is reliable. Fix macOS notch mouse coordinates issue in fullscreen mode + better perf on X11. (#7919, #7786) |
| @@ -29,11 +35,15 @@ | ||
| 29 | 35 | // 2025-09-15: Content Scales are always reported as 1.0 on Wayland. (#8921) |
| 30 | 36 | // 2025-07-08: Made ImGui_ImplSDL2_GetContentScaleForWindow(), ImGui_ImplSDL2_GetContentScaleForDisplay() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) |
| 31 | 37 | // 2025-06-11: Added ImGui_ImplSDL2_GetContentScaleForWindow(SDL_Window* window) and ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index) helper to facilitate making DPI-aware apps. |
| 38 | +// 2025-05-15: [Docking] Add Platform_GetWindowFramebufferScale() handler, to allow varying Retina display density on multiple monitors. | |
| 39 | +// 2025-04-09: [Docking] Revert update monitors and work areas information every frame. Only do it on Windows. (#8415, #8558) | |
| 32 | 40 | // 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) |
| 33 | 41 | // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. |
| 34 | 42 | // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) |
| 35 | 43 | // 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g. Linux debuggers not claiming capture back. (#6410, #3650) |
| 44 | +// 2025-02-25: [Docking] Revert to use SDL_GetDisplayBounds() for WorkPos/WorkRect if SDL_GetDisplayUsableBounds() failed. | |
| 36 | 45 | // 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode. |
| 46 | +// 2025-02-21: [Docking] Update monitors and work areas information every frame, as the later may change regardless of monitor changes. (#8415) | |
| 37 | 47 | // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. |
| 38 | 48 | // 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. |
| 39 | 49 | // 2025-01-20: Made ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode_Manual) accept an empty array. |
| @@ -74,7 +84,7 @@ | ||
| 74 | 84 | // 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. |
| 75 | 85 | // 2021-08-17: Calling io.AddFocusEvent() on SDL_WINDOWEVENT_FOCUS_GAINED/SDL_WINDOWEVENT_FOCUS_LOST. |
| 76 | 86 | // 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using SDL_GetMouseFocus() + SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, requires SDL 2.0.5+) |
| 77 | -// 2021-06-29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary. | |
| 87 | +// 2021-06:29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary. | |
| 78 | 88 | // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). |
| 79 | 89 | // 2021-03-22: Rework global mouse pos availability check listing supported platforms explicitly, effectively fixing mouse access on Raspberry Pi. (#2837, #3950) |
| 80 | 90 | // 2020-05-25: Misc: Report a zero display-size when window is minimized, to be consistent with other backends. |
| @@ -116,6 +126,7 @@ | ||
| 116 | 126 | #endif |
| 117 | 127 | |
| 118 | 128 | // SDL |
| 129 | +// (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended) | |
| 119 | 130 | #include <SDL.h> |
| 120 | 131 | #include <SDL_syswm.h> |
| 121 | 132 | #include <stdio.h> // for snprintf() |
| @@ -132,11 +143,18 @@ | ||
| 132 | 143 | #else |
| 133 | 144 | #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0 |
| 134 | 145 | #endif |
| 146 | +#define SDL_HAS_WINDOW_ALPHA SDL_VERSION_ATLEAST(2,0,5) | |
| 147 | +#define SDL_HAS_ALWAYS_ON_TOP SDL_VERSION_ATLEAST(2,0,5) | |
| 148 | +#define SDL_HAS_USABLE_DISPLAY_BOUNDS SDL_VERSION_ATLEAST(2,0,5) | |
| 135 | 149 | #define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4) |
| 136 | 150 | #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) |
| 151 | +#define SDL_HAS_DISPLAY_EVENT SDL_VERSION_ATLEAST(2,0,9) | |
| 137 | 152 | #define SDL_HAS_OPEN_URL SDL_VERSION_ATLEAST(2,0,14) |
| 153 | +#define SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT SDL_VERSION_ATLEAST(2,0,18) | |
| 138 | 154 | #if SDL_HAS_VULKAN |
| 139 | 155 | #include <SDL_vulkan.h> |
| 156 | +#else | |
| 157 | +static const Uint32 SDL_WINDOW_VULKAN = 0x10000000; | |
| 140 | 158 | #endif |
| 141 | 159 | |
| 142 | 160 | // SDL Data |
| @@ -148,6 +166,8 @@ | ||
| 148 | 166 | Uint64 Time; |
| 149 | 167 | char* ClipboardTextData; |
| 150 | 168 | char BackendPlatformName[48]; |
| 169 | + bool UseVulkan; | |
| 170 | + bool WantUpdateMonitors; | |
| 151 | 171 | |
| 152 | 172 | // Mouse handling |
| 153 | 173 | Uint32 MouseWindowID; |
| @@ -156,6 +176,7 @@ | ||
| 156 | 176 | SDL_Cursor* MouseLastCursor; |
| 157 | 177 | int MouseLastLeaveFrame; |
| 158 | 178 | bool MouseCanUseGlobalState; |
| 179 | + bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state. | |
| 159 | 180 | ImGui_ImplSDL2_MouseCaptureMode MouseCaptureMode; |
| 160 | 181 | |
| 161 | 182 | // Gamepad handling |
| @@ -175,6 +196,11 @@ | ||
| 175 | 196 | return ImGui::GetCurrentContext() ? (ImGui_ImplSDL2_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; |
| 176 | 197 | } |
| 177 | 198 | |
| 199 | +// Forward Declarations | |
| 200 | +static void ImGui_ImplSDL2_UpdateMonitors(); | |
| 201 | +static void ImGui_ImplSDL2_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context); | |
| 202 | +static void ImGui_ImplSDL2_ShutdownMultiViewportSupport(); | |
| 203 | + | |
| 178 | 204 | // Functions |
| 179 | 205 | static const char* ImGui_ImplSDL2_GetClipboardText(ImGuiContext*) |
| 180 | 206 | { |
| @@ -194,13 +220,13 @@ | ||
| 194 | 220 | } |
| 195 | 221 | |
| 196 | 222 | // Note: native IME will only display if user calls SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1") _before_ SDL_CreateWindow(). |
| 197 | -static void ImGui_ImplSDL2_PlatformSetImeData(ImGuiContext*, ImGuiViewport*, ImGuiPlatformImeData* data) | |
| 223 | +static void ImGui_ImplSDL2_PlatformSetImeData(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) | |
| 198 | 224 | { |
| 199 | 225 | if (data->WantVisible) |
| 200 | 226 | { |
| 201 | 227 | SDL_Rect r; |
| 202 | - r.x = (int)data->InputPos.x; | |
| 203 | - r.y = (int)data->InputPos.y; | |
| 228 | + r.x = (int)(data->InputPos.x - viewport->Pos.x); | |
| 229 | + r.y = (int)(data->InputPos.y - viewport->Pos.y); | |
| 204 | 230 | r.w = 1; |
| 205 | 231 | r.h = (int)data->InputLineHeight; |
| 206 | 232 | SDL_SetTextInputRect(&r); |
| @@ -366,8 +392,7 @@ | ||
| 366 | 392 | |
| 367 | 393 | static ImGuiViewport* ImGui_ImplSDL2_GetViewportForWindowID(Uint32 window_id) |
| 368 | 394 | { |
| 369 | - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); | |
| 370 | - return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : nullptr; | |
| 395 | + return ImGui::FindViewportByPlatformHandle((void*)(intptr_t)window_id); | |
| 371 | 396 | } |
| 372 | 397 | |
| 373 | 398 | // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. |
| @@ -387,6 +412,13 @@ | ||
| 387 | 412 | if (ImGui_ImplSDL2_GetViewportForWindowID(event->motion.windowID) == nullptr) |
| 388 | 413 | return false; |
| 389 | 414 | ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); |
| 415 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 416 | + { | |
| 417 | + int window_x, window_y; | |
| 418 | + SDL_GetWindowPosition(SDL_GetWindowFromID(event->motion.windowID), &window_x, &window_y); | |
| 419 | + mouse_pos.x += window_x; | |
| 420 | + mouse_pos.y += window_y; | |
| 421 | + } | |
| 390 | 422 | io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); |
| 391 | 423 | io.AddMousePosEvent(mouse_pos.x, mouse_pos.y); |
| 392 | 424 | return true; |
| @@ -438,20 +470,32 @@ | ||
| 438 | 470 | case SDL_KEYDOWN: |
| 439 | 471 | case SDL_KEYUP: |
| 440 | 472 | { |
| 441 | - if (ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID) == nullptr) | |
| 473 | + ImGuiViewport* viewport = ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID); | |
| 474 | + if (viewport == nullptr) | |
| 442 | 475 | return false; |
| 476 | + //IMGUI_DEBUG_LOG("SDL_KEY%s : key=0x%08X ('%s'), scancode=%d ('%s'), mod=%X, windowID=%d, viewport=%08X\n", | |
| 477 | + // (event->type == SDL_KEYDOWN) ? "DOWN" : "UP ", event->key.keysym.sym, SDL_GetKeyName(event->key.keysym.sym), event->key.keysym.scancode, SDL_GetScancodeName(event->key.keysym.scancode), event->key.keysym.mod, event->key.windowID, viewport ? viewport->ID : 0); | |
| 443 | 478 | ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod); |
| 444 | - //IMGUI_DEBUG_LOG("SDL_KEY_%s : key=%d ('%s'), scancode=%d ('%s'), mod=%X\n", | |
| 445 | - // (event->type == SDL_KEYDOWN) ? "DOWN" : "UP ", event->key.keysym.sym, SDL_GetKeyName(event->key.keysym.sym), event->key.keysym.scancode, SDL_GetScancodeName(event->key.keysym.scancode), event->key.keysym.mod); | |
| 446 | 479 | ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode); |
| 447 | 480 | io.AddKeyEvent(key, (event->type == SDL_KEYDOWN)); |
| 448 | 481 | io.SetKeyEventNativeData(key, (int)event->key.keysym.sym, (int)event->key.keysym.scancode, (int)event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. |
| 449 | 482 | return true; |
| 450 | 483 | } |
| 484 | +#if SDL_HAS_DISPLAY_EVENT | |
| 485 | + case SDL_DISPLAYEVENT: | |
| 486 | + { | |
| 487 | + // 2.0.26 has SDL_DISPLAYEVENT_CONNECTED/SDL_DISPLAYEVENT_DISCONNECTED/SDL_DISPLAYEVENT_ORIENTATION, | |
| 488 | + // so change of DPI/Scaling are not reflected in this event. (SDL3 has it) | |
| 489 | + bd->WantUpdateMonitors = true; | |
| 490 | + return true; | |
| 491 | + } | |
| 492 | +#endif | |
| 451 | 493 | case SDL_WINDOWEVENT: |
| 452 | 494 | { |
| 453 | - if (ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID) == nullptr) | |
| 495 | + ImGuiViewport* viewport = ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID); | |
| 496 | + if (viewport == NULL) | |
| 454 | 497 | return false; |
| 498 | + | |
| 455 | 499 | // - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right. |
| 456 | 500 | // - However we won't get a correct LEAVE event for a captured window. |
| 457 | 501 | // - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late, |
| @@ -465,10 +509,18 @@ | ||
| 465 | 509 | } |
| 466 | 510 | if (window_event == SDL_WINDOWEVENT_LEAVE) |
| 467 | 511 | bd->MouseLastLeaveFrame = ImGui::GetFrameCount() + 1; |
| 512 | + //if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED) { IMGUI_DEBUG_LOG("SDL_WINDOWEVENT_FOCUS_GAINED: windowId %d, viewport: %08X\n", event->window.windowID, viewport ? viewport->ID : 0); } | |
| 513 | + //if (window_event == SDL_WINDOWEVENT_FOCUS_LOST) { IMGUI_DEBUG_LOG("SDL_WINDOWEVENT_FOCUS_LOST: windowId %d, viewport: %08X\n", event->window.windowID, viewport ? viewport->ID : 0); } | |
| 468 | 514 | if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED) |
| 469 | 515 | io.AddFocusEvent(true); |
| 470 | 516 | if (window_event == SDL_WINDOWEVENT_FOCUS_LOST) |
| 471 | 517 | io.AddFocusEvent(false); |
| 518 | + if (window_event == SDL_WINDOWEVENT_CLOSE) | |
| 519 | + viewport->PlatformRequestClose = true; | |
| 520 | + if (window_event == SDL_WINDOWEVENT_MOVED) | |
| 521 | + viewport->PlatformRequestMove = true; | |
| 522 | + if (window_event == SDL_WINDOWEVENT_RESIZED) | |
| 523 | + viewport->PlatformRequestResize = true; | |
| 472 | 524 | return true; |
| 473 | 525 | } |
| 474 | 526 | case SDL_CONTROLLERDEVICEADDED: |
| @@ -508,6 +560,7 @@ | ||
| 508 | 560 | io.BackendPlatformName = bd->BackendPlatformName; |
| 509 | 561 | io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) |
| 510 | 562 | io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) |
| 563 | + // (ImGuiBackendFlags_PlatformHasViewports may be set just below) | |
| 511 | 564 | |
| 512 | 565 | bd->Window = window; |
| 513 | 566 | bd->WindowID = SDL_GetWindowID(window); |
| @@ -527,7 +580,17 @@ | ||
| 527 | 580 | bd->MouseCaptureMode = (strcmp(item, "x11") == 0) ? ImGui_ImplSDL2_MouseCaptureMode_EnabledAfterDrag : ImGui_ImplSDL2_MouseCaptureMode_Enabled; |
| 528 | 581 | } |
| 529 | 582 | #endif |
| 583 | + if (bd->MouseCanUseGlobalState) | |
| 584 | + io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) | |
| 530 | 585 | |
| 586 | + // SDL on Linux/OSX doesn't report events for unfocused windows (see https://github.com/ocornut/imgui/issues/4960) | |
| 587 | + // We will use 'MouseCanReportHoveredViewport' to set 'ImGuiBackendFlags_HasMouseHoveredViewport' dynamically each frame. | |
| 588 | +#ifndef __APPLE__ | |
| 589 | + bd->MouseCanReportHoveredViewport = bd->MouseCanUseGlobalState; | |
| 590 | +#else | |
| 591 | + bd->MouseCanReportHoveredViewport = false; | |
| 592 | +#endif | |
| 593 | + | |
| 531 | 594 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 532 | 595 | platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; |
| 533 | 596 | platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText; |
| @@ -539,6 +602,9 @@ | ||
| 539 | 602 | platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { return SDL_OpenURL(url) == 0; }; |
| 540 | 603 | #endif |
| 541 | 604 | |
| 605 | + // Update monitor a first time during init | |
| 606 | + ImGui_ImplSDL2_UpdateMonitors(); | |
| 607 | + | |
| 542 | 608 | // Gamepad handling |
| 543 | 609 | bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst; |
| 544 | 610 | bd->WantUpdateGamepadsList = true; |
| @@ -593,7 +659,11 @@ | ||
| 593 | 659 | SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0"); |
| 594 | 660 | #endif |
| 595 | 661 | |
| 596 | - (void)sdl_gl_context; // Unused in 'master' branch. | |
| 662 | + // We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports. | |
| 663 | + // We left the call to ImGui_ImplSDL2_InitMultiViewportSupport() outside of #ifdef to avoid unused-function warnings. | |
| 664 | + if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) | |
| 665 | + ImGui_ImplSDL2_InitMultiViewportSupport(window, sdl_gl_context); | |
| 666 | + | |
| 597 | 667 | return true; |
| 598 | 668 | } |
| 599 | 669 | |
| @@ -607,7 +677,11 @@ | ||
| 607 | 677 | #if !SDL_HAS_VULKAN |
| 608 | 678 | IM_ASSERT(0 && "Unsupported"); |
| 609 | 679 | #endif |
| 610 | - return ImGui_ImplSDL2_Init(window, nullptr, nullptr); | |
| 680 | + if (!ImGui_ImplSDL2_Init(window, nullptr, nullptr)) | |
| 681 | + return false; | |
| 682 | + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); | |
| 683 | + bd->UseVulkan = true; | |
| 684 | + return true; | |
| 611 | 685 | } |
| 612 | 686 | |
| 613 | 687 | bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window) |
| @@ -642,6 +716,7 @@ | ||
| 642 | 716 | ImGuiIO& io = ImGui::GetIO(); |
| 643 | 717 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 644 | 718 | |
| 719 | + ImGui_ImplSDL2_ShutdownMultiViewportSupport(); | |
| 645 | 720 | if (bd->ClipboardTextData) |
| 646 | 721 | SDL_free(bd->ClipboardTextData); |
| 647 | 722 | for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) |
| @@ -650,7 +725,7 @@ | ||
| 650 | 725 | |
| 651 | 726 | io.BackendPlatformName = nullptr; |
| 652 | 727 | io.BackendPlatformUserData = nullptr; |
| 653 | - io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad); | |
| 728 | + io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport); | |
| 654 | 729 | platform_io.ClearPlatformHandlers(); |
| 655 | 730 | IM_DELETE(bd); |
| 656 | 731 | } |
| @@ -663,6 +738,7 @@ | ||
| 663 | 738 | bd->MouseCaptureMode = mode; |
| 664 | 739 | } |
| 665 | 740 | |
| 741 | +// This code is rather messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4. | |
| 666 | 742 | static void ImGui_ImplSDL2_UpdateMouseData() |
| 667 | 743 | { |
| 668 | 744 | ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); |
| @@ -686,16 +762,24 @@ | ||
| 686 | 762 | } |
| 687 | 763 | |
| 688 | 764 | SDL_Window* focused_window = SDL_GetKeyboardFocus(); |
| 689 | - const bool is_app_focused = (bd->Window == focused_window); | |
| 765 | + const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui_ImplSDL2_GetViewportForWindowID(SDL_GetWindowID(focused_window)) != NULL)); | |
| 690 | 766 | #else |
| 691 | 767 | SDL_Window* focused_window = bd->Window; |
| 692 | 768 | const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only |
| 693 | 769 | #endif |
| 770 | + | |
| 694 | 771 | if (is_app_focused) |
| 695 | 772 | { |
| 696 | 773 | // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user) |
| 697 | 774 | if (io.WantSetMousePos) |
| 698 | - SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y); | |
| 775 | + { | |
| 776 | +#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE | |
| 777 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 778 | + SDL_WarpMouseGlobal((int)io.MousePos.x, (int)io.MousePos.y); | |
| 779 | + else | |
| 780 | +#endif | |
| 781 | + SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y); | |
| 782 | + } | |
| 699 | 783 | |
| 700 | 784 | // (Optional) Fallback to provide unclamped mouse position when focused but not hovered (SDL_MOUSEMOTION already provides this when hovered or captured) |
| 701 | 785 | // Note that SDL_GetGlobalMouseState() is in theory slow on X11, but this only runs on rather specific cases. If a problem we may provide a way to opt-out this feature. |
| @@ -704,15 +788,34 @@ | ||
| 704 | 788 | if (hovered_window == nullptr && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) |
| 705 | 789 | { |
| 706 | 790 | // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) |
| 791 | + // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) | |
| 707 | 792 | int mouse_x, mouse_y; |
| 708 | 793 | int window_x, window_y; |
| 709 | 794 | SDL_GetGlobalMouseState(&mouse_x, &mouse_y); |
| 710 | - SDL_GetWindowPosition(focused_window, &window_x, &window_y); | |
| 711 | - mouse_x -= window_x; | |
| 712 | - mouse_y -= window_y; | |
| 795 | + if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)) | |
| 796 | + { | |
| 797 | + SDL_GetWindowPosition(focused_window, &window_x, &window_y); | |
| 798 | + mouse_x -= window_x; | |
| 799 | + mouse_y -= window_y; | |
| 800 | + } | |
| 713 | 801 | io.AddMousePosEvent((float)mouse_x, (float)mouse_y); |
| 714 | 802 | } |
| 715 | 803 | } |
| 804 | + | |
| 805 | + // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering. | |
| 806 | + // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic. | |
| 807 | + // - [!] SDL backend does NOT correctly ignore viewports with the _NoInputs flag. | |
| 808 | + // Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window | |
| 809 | + // for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported | |
| 810 | + // by the backend, and use its flawed heuristic to guess the viewport behind. | |
| 811 | + // - [X] SDL backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target). | |
| 812 | + if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport) | |
| 813 | + { | |
| 814 | + ImGuiID mouse_viewport_id = 0; | |
| 815 | + if (ImGuiViewport* mouse_viewport = ImGui_ImplSDL2_GetViewportForWindowID(bd->MouseWindowID)) | |
| 816 | + mouse_viewport_id = mouse_viewport->ID; | |
| 817 | + io.AddMouseViewportEvent(mouse_viewport_id); | |
| 818 | + } | |
| 716 | 819 | } |
| 717 | 820 | |
| 718 | 821 | static void ImGui_ImplSDL2_UpdateMouseCursor() |
| @@ -872,6 +975,38 @@ | ||
| 872 | 975 | ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767); |
| 873 | 976 | } |
| 874 | 977 | |
| 978 | +// FIXME: Note that doesn't update with DPI/Scaling change only as SDL2 doesn't have an event for it (SDL3 has). | |
| 979 | +static void ImGui_ImplSDL2_UpdateMonitors() | |
| 980 | +{ | |
| 981 | + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); | |
| 982 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 983 | + platform_io.Monitors.resize(0); | |
| 984 | + bd->WantUpdateMonitors = false; | |
| 985 | + int display_count = SDL_GetNumVideoDisplays(); | |
| 986 | + for (int n = 0; n < display_count; n++) | |
| 987 | + { | |
| 988 | + // Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime. | |
| 989 | + ImGuiPlatformMonitor monitor; | |
| 990 | + SDL_Rect r; | |
| 991 | + SDL_GetDisplayBounds(n, &r); | |
| 992 | + monitor.MainPos = monitor.WorkPos = ImVec2((float)r.x, (float)r.y); | |
| 993 | + monitor.MainSize = monitor.WorkSize = ImVec2((float)r.w, (float)r.h); | |
| 994 | +#if SDL_HAS_USABLE_DISPLAY_BOUNDS | |
| 995 | + if (SDL_GetDisplayUsableBounds(n, &r) == 0 && r.w > 0 && r.h > 0) | |
| 996 | + { | |
| 997 | + monitor.WorkPos = ImVec2((float)r.x, (float)r.y); | |
| 998 | + monitor.WorkSize = ImVec2((float)r.w, (float)r.h); | |
| 999 | + } | |
| 1000 | +#endif | |
| 1001 | + float dpi_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(n); | |
| 1002 | + if (dpi_scale <= 0.0f) | |
| 1003 | + continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902. | |
| 1004 | + monitor.DpiScale = dpi_scale; | |
| 1005 | + monitor.PlatformHandle = (void*)(intptr_t)n; | |
| 1006 | + platform_io.Monitors.push_back(monitor); | |
| 1007 | + } | |
| 1008 | +} | |
| 1009 | + | |
| 875 | 1010 | static void ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(SDL_Window* window, SDL_Renderer* renderer, ImVec2* out_size, ImVec2* out_framebuffer_scale) |
| 876 | 1011 | { |
| 877 | 1012 | int w, h; |
| @@ -902,6 +1037,13 @@ | ||
| 902 | 1037 | // Setup main viewport size (every frame to accommodate for window resizing) |
| 903 | 1038 | ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(bd->Window, bd->Renderer, &io.DisplaySize, &io.DisplayFramebufferScale); |
| 904 | 1039 | |
| 1040 | + // Update monitors | |
| 1041 | +#ifdef WIN32 | |
| 1042 | + bd->WantUpdateMonitors = true; // Keep polling under Windows to handle changes of work area when resizing task-bar (#8415) | |
| 1043 | +#endif | |
| 1044 | + if (bd->WantUpdateMonitors) | |
| 1045 | + ImGui_ImplSDL2_UpdateMonitors(); | |
| 1046 | + | |
| 905 | 1047 | // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution) |
| 906 | 1048 | // (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644) |
| 907 | 1049 | static Uint64 frequency = SDL_GetPerformanceFrequency(); |
| @@ -918,11 +1060,278 @@ | ||
| 918 | 1060 | io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); |
| 919 | 1061 | } |
| 920 | 1062 | |
| 1063 | + // Our io.AddMouseViewportEvent() calls will only be valid when not capturing. | |
| 1064 | + // Technically speaking testing for 'bd->MouseButtonsDown == 0' would be more rigorous, but testing for payload reduces noise and potential side-effects. | |
| 1065 | + if (bd->MouseCanReportHoveredViewport && ImGui::GetDragDropPayload() == nullptr) | |
| 1066 | + io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; | |
| 1067 | + else | |
| 1068 | + io.BackendFlags &= ~ImGuiBackendFlags_HasMouseHoveredViewport; | |
| 1069 | + | |
| 921 | 1070 | ImGui_ImplSDL2_UpdateMouseData(); |
| 922 | 1071 | ImGui_ImplSDL2_UpdateMouseCursor(); |
| 923 | 1072 | |
| 924 | 1073 | // Update game controllers (if enabled and available) |
| 925 | 1074 | ImGui_ImplSDL2_UpdateGamepads(); |
| 1075 | +} | |
| 1076 | + | |
| 1077 | +//-------------------------------------------------------------------------------------------------------- | |
| 1078 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 1079 | +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. | |
| 1080 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 1081 | +//-------------------------------------------------------------------------------------------------------- | |
| 1082 | + | |
| 1083 | +// Helper structure we store in the void* PlatformUserData field of each ImGuiViewport to easily retrieve our backend data. | |
| 1084 | +struct ImGui_ImplSDL2_ViewportData | |
| 1085 | +{ | |
| 1086 | + SDL_Window* Window; | |
| 1087 | + Uint32 WindowID; // Stored in ImGuiViewport::PlatformHandle. Use SDL_GetWindowFromID() to get SDL_Window* from Uint32 WindowID. | |
| 1088 | + bool WindowOwned; | |
| 1089 | + SDL_GLContext GLContext; | |
| 1090 | + | |
| 1091 | + ImGui_ImplSDL2_ViewportData() { Window = nullptr; WindowID = 0; WindowOwned = false; GLContext = nullptr; } | |
| 1092 | + ~ImGui_ImplSDL2_ViewportData() { IM_ASSERT(Window == nullptr && GLContext == nullptr); } | |
| 1093 | +}; | |
| 1094 | + | |
| 1095 | +static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport) | |
| 1096 | +{ | |
| 1097 | + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); | |
| 1098 | + ImGui_ImplSDL2_ViewportData* vd = IM_NEW(ImGui_ImplSDL2_ViewportData)(); | |
| 1099 | + viewport->PlatformUserData = vd; | |
| 1100 | + | |
| 1101 | + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | |
| 1102 | + ImGui_ImplSDL2_ViewportData* main_viewport_data = (ImGui_ImplSDL2_ViewportData*)main_viewport->PlatformUserData; | |
| 1103 | + | |
| 1104 | + // Share GL resources with main context | |
| 1105 | + bool use_opengl = (main_viewport_data->GLContext != nullptr); | |
| 1106 | + SDL_GLContext backup_context = nullptr; | |
| 1107 | + if (use_opengl) | |
| 1108 | + { | |
| 1109 | + backup_context = SDL_GL_GetCurrentContext(); | |
| 1110 | + SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); | |
| 1111 | + SDL_GL_MakeCurrent(main_viewport_data->Window, main_viewport_data->GLContext); | |
| 1112 | + } | |
| 1113 | + | |
| 1114 | + Uint32 sdl_flags = 0; | |
| 1115 | + sdl_flags |= use_opengl ? SDL_WINDOW_OPENGL : (bd->UseVulkan ? SDL_WINDOW_VULKAN : 0); | |
| 1116 | + sdl_flags |= SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_ALLOW_HIGHDPI; | |
| 1117 | + sdl_flags |= SDL_WINDOW_HIDDEN; | |
| 1118 | + sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0; | |
| 1119 | + sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE; | |
| 1120 | +#if !defined(_WIN32) | |
| 1121 | + // See SDL hack in ImGui_ImplSDL2_ShowWindow(). | |
| 1122 | + sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) ? SDL_WINDOW_SKIP_TASKBAR : 0; | |
| 1123 | +#endif | |
| 1124 | +#if SDL_HAS_ALWAYS_ON_TOP | |
| 1125 | + sdl_flags |= (viewport->Flags & ImGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0; | |
| 1126 | +#endif | |
| 1127 | + vd->Window = SDL_CreateWindow("No Title Yet", (int)viewport->Pos.x, (int)viewport->Pos.y, (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags); | |
| 1128 | + vd->WindowOwned = true; | |
| 1129 | + if (use_opengl) | |
| 1130 | + { | |
| 1131 | + vd->GLContext = SDL_GL_CreateContext(vd->Window); | |
| 1132 | + SDL_GL_SetSwapInterval(0); | |
| 1133 | + } | |
| 1134 | + if (use_opengl && backup_context) | |
| 1135 | + SDL_GL_MakeCurrent(vd->Window, backup_context); | |
| 1136 | + | |
| 1137 | + viewport->PlatformHandle = (void*)(intptr_t)SDL_GetWindowID(vd->Window); | |
| 1138 | + viewport->PlatformHandleRaw = nullptr; | |
| 1139 | + SDL_SysWMinfo info; | |
| 1140 | + SDL_VERSION(&info.version); | |
| 1141 | + if (SDL_GetWindowWMInfo(vd->Window, &info)) | |
| 1142 | + { | |
| 1143 | +#if defined(SDL_VIDEO_DRIVER_WINDOWS) | |
| 1144 | + viewport->PlatformHandleRaw = info.info.win.window; | |
| 1145 | +#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA) | |
| 1146 | + viewport->PlatformHandleRaw = (void*)info.info.cocoa.window; | |
| 1147 | +#endif | |
| 1148 | + } | |
| 1149 | +} | |
| 1150 | + | |
| 1151 | +static void ImGui_ImplSDL2_DestroyWindow(ImGuiViewport* viewport) | |
| 1152 | +{ | |
| 1153 | + if (ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData) | |
| 1154 | + { | |
| 1155 | + if (vd->GLContext && vd->WindowOwned) | |
| 1156 | + SDL_GL_DeleteContext(vd->GLContext); | |
| 1157 | + if (vd->Window && vd->WindowOwned) | |
| 1158 | + SDL_DestroyWindow(vd->Window); | |
| 1159 | + vd->GLContext = nullptr; | |
| 1160 | + vd->Window = nullptr; | |
| 1161 | + IM_DELETE(vd); | |
| 1162 | + } | |
| 1163 | + viewport->PlatformUserData = viewport->PlatformHandle = nullptr; | |
| 1164 | +} | |
| 1165 | + | |
| 1166 | +static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport) | |
| 1167 | +{ | |
| 1168 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1169 | +#if defined(_WIN32) && !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_APP) && WINAPI_FAMILY == WINAPI_FAMILY_APP) || (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES))) | |
| 1170 | + HWND hwnd = (HWND)viewport->PlatformHandleRaw; | |
| 1171 | + | |
| 1172 | + // SDL hack: Hide icon from task bar | |
| 1173 | + // Note: SDL 2.0.6+ has a SDL_WINDOW_SKIP_TASKBAR flag which is supported under Windows but the way it create the window breaks our seamless transition. | |
| 1174 | + if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) | |
| 1175 | + { | |
| 1176 | + LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE); | |
| 1177 | + ex_style &= ~WS_EX_APPWINDOW; | |
| 1178 | + ex_style |= WS_EX_TOOLWINDOW; | |
| 1179 | + ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style); | |
| 1180 | + } | |
| 1181 | +#endif | |
| 1182 | + | |
| 1183 | +#if SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT | |
| 1184 | + SDL_SetHint(SDL_HINT_WINDOW_NO_ACTIVATION_WHEN_SHOWN, (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) ? "1" : "0"); | |
| 1185 | +#elif defined(_WIN32) | |
| 1186 | + // SDL hack: SDL always activate/focus windows :/ | |
| 1187 | + if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) | |
| 1188 | + { | |
| 1189 | + ::ShowWindow(hwnd, SW_SHOWNA); | |
| 1190 | + return; | |
| 1191 | + } | |
| 1192 | +#endif | |
| 1193 | + SDL_ShowWindow(vd->Window); | |
| 1194 | +} | |
| 1195 | + | |
| 1196 | +static ImVec2 ImGui_ImplSDL2_GetWindowPos(ImGuiViewport* viewport) | |
| 1197 | +{ | |
| 1198 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1199 | + int x = 0, y = 0; | |
| 1200 | + SDL_GetWindowPosition(vd->Window, &x, &y); | |
| 1201 | + return ImVec2((float)x, (float)y); | |
| 1202 | +} | |
| 1203 | + | |
| 1204 | +static void ImGui_ImplSDL2_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos) | |
| 1205 | +{ | |
| 1206 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1207 | + SDL_SetWindowPosition(vd->Window, (int)pos.x, (int)pos.y); | |
| 1208 | +} | |
| 1209 | + | |
| 1210 | +static ImVec2 ImGui_ImplSDL2_GetWindowSize(ImGuiViewport* viewport) | |
| 1211 | +{ | |
| 1212 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1213 | + int w = 0, h = 0; | |
| 1214 | + SDL_GetWindowSize(vd->Window, &w, &h); | |
| 1215 | + return ImVec2((float)w, (float)h); | |
| 1216 | +} | |
| 1217 | + | |
| 1218 | +static void ImGui_ImplSDL2_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) | |
| 1219 | +{ | |
| 1220 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1221 | + SDL_SetWindowSize(vd->Window, (int)size.x, (int)size.y); | |
| 1222 | +} | |
| 1223 | + | |
| 1224 | +static ImVec2 ImGui_ImplSDL2_GetWindowFramebufferScale(ImGuiViewport* viewport) | |
| 1225 | +{ | |
| 1226 | + // FIXME: SDL_Renderer does not support multi-viewport. | |
| 1227 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1228 | + ImVec2 framebuffer_scale; | |
| 1229 | + ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(vd->Window, nullptr, nullptr, &framebuffer_scale); | |
| 1230 | + return framebuffer_scale; | |
| 1231 | +} | |
| 1232 | + | |
| 1233 | +static void ImGui_ImplSDL2_SetWindowTitle(ImGuiViewport* viewport, const char* title) | |
| 1234 | +{ | |
| 1235 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1236 | + SDL_SetWindowTitle(vd->Window, title); | |
| 1237 | +} | |
| 1238 | + | |
| 1239 | +#if SDL_HAS_WINDOW_ALPHA | |
| 1240 | +static void ImGui_ImplSDL2_SetWindowAlpha(ImGuiViewport* viewport, float alpha) | |
| 1241 | +{ | |
| 1242 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1243 | + SDL_SetWindowOpacity(vd->Window, alpha); | |
| 1244 | +} | |
| 1245 | +#endif | |
| 1246 | + | |
| 1247 | +static void ImGui_ImplSDL2_SetWindowFocus(ImGuiViewport* viewport) | |
| 1248 | +{ | |
| 1249 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1250 | + SDL_RaiseWindow(vd->Window); | |
| 1251 | +} | |
| 1252 | + | |
| 1253 | +static bool ImGui_ImplSDL2_GetWindowFocus(ImGuiViewport* viewport) | |
| 1254 | +{ | |
| 1255 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1256 | + return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; | |
| 1257 | +} | |
| 1258 | + | |
| 1259 | +static bool ImGui_ImplSDL2_GetWindowMinimized(ImGuiViewport* viewport) | |
| 1260 | +{ | |
| 1261 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1262 | + return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_MINIMIZED) != 0; | |
| 1263 | +} | |
| 1264 | + | |
| 1265 | +static void ImGui_ImplSDL2_RenderWindow(ImGuiViewport* viewport, void*) | |
| 1266 | +{ | |
| 1267 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1268 | + if (vd->GLContext) | |
| 1269 | + SDL_GL_MakeCurrent(vd->Window, vd->GLContext); | |
| 1270 | +} | |
| 1271 | + | |
| 1272 | +static void ImGui_ImplSDL2_SwapBuffers(ImGuiViewport* viewport, void*) | |
| 1273 | +{ | |
| 1274 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1275 | + if (vd->GLContext) | |
| 1276 | + { | |
| 1277 | + SDL_GL_MakeCurrent(vd->Window, vd->GLContext); | |
| 1278 | + SDL_GL_SwapWindow(vd->Window); | |
| 1279 | + } | |
| 1280 | +} | |
| 1281 | + | |
| 1282 | +// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface) | |
| 1283 | +// SDL is graceful enough to _not_ need <vulkan/vulkan.h> so we can safely include this. | |
| 1284 | +#if SDL_HAS_VULKAN | |
| 1285 | +#include <SDL_vulkan.h> | |
| 1286 | +static int ImGui_ImplSDL2_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface) | |
| 1287 | +{ | |
| 1288 | + ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; | |
| 1289 | + (void)vk_allocator; | |
| 1290 | + SDL_bool ret = SDL_Vulkan_CreateSurface(vd->Window, (VkInstance)vk_instance, (VkSurfaceKHR*)out_vk_surface); | |
| 1291 | + return ret ? 0 : 1; // ret ? VK_SUCCESS : VK_NOT_READY | |
| 1292 | +} | |
| 1293 | +#endif // SDL_HAS_VULKAN | |
| 1294 | + | |
| 1295 | +static void ImGui_ImplSDL2_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context) | |
| 1296 | +{ | |
| 1297 | + // Register platform interface (will be coupled with a renderer interface) | |
| 1298 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 1299 | + platform_io.Platform_CreateWindow = ImGui_ImplSDL2_CreateWindow; | |
| 1300 | + platform_io.Platform_DestroyWindow = ImGui_ImplSDL2_DestroyWindow; | |
| 1301 | + platform_io.Platform_ShowWindow = ImGui_ImplSDL2_ShowWindow; | |
| 1302 | + platform_io.Platform_SetWindowPos = ImGui_ImplSDL2_SetWindowPos; | |
| 1303 | + platform_io.Platform_GetWindowPos = ImGui_ImplSDL2_GetWindowPos; | |
| 1304 | + platform_io.Platform_SetWindowSize = ImGui_ImplSDL2_SetWindowSize; | |
| 1305 | + platform_io.Platform_GetWindowSize = ImGui_ImplSDL2_GetWindowSize; | |
| 1306 | + platform_io.Platform_GetWindowFramebufferScale = ImGui_ImplSDL2_GetWindowFramebufferScale; | |
| 1307 | + platform_io.Platform_SetWindowFocus = ImGui_ImplSDL2_SetWindowFocus; | |
| 1308 | + platform_io.Platform_GetWindowFocus = ImGui_ImplSDL2_GetWindowFocus; | |
| 1309 | + platform_io.Platform_GetWindowMinimized = ImGui_ImplSDL2_GetWindowMinimized; | |
| 1310 | + platform_io.Platform_SetWindowTitle = ImGui_ImplSDL2_SetWindowTitle; | |
| 1311 | + platform_io.Platform_RenderWindow = ImGui_ImplSDL2_RenderWindow; | |
| 1312 | + platform_io.Platform_SwapBuffers = ImGui_ImplSDL2_SwapBuffers; | |
| 1313 | +#if SDL_HAS_WINDOW_ALPHA | |
| 1314 | + platform_io.Platform_SetWindowAlpha = ImGui_ImplSDL2_SetWindowAlpha; | |
| 1315 | +#endif | |
| 1316 | +#if SDL_HAS_VULKAN | |
| 1317 | + platform_io.Platform_CreateVkSurface = ImGui_ImplSDL2_CreateVkSurface; | |
| 1318 | +#endif | |
| 1319 | + | |
| 1320 | + // Register main window handle (which is owned by the main application, not by us) | |
| 1321 | + // This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports. | |
| 1322 | + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | |
| 1323 | + ImGui_ImplSDL2_ViewportData* vd = IM_NEW(ImGui_ImplSDL2_ViewportData)(); | |
| 1324 | + vd->Window = window; | |
| 1325 | + vd->WindowID = SDL_GetWindowID(window); | |
| 1326 | + vd->WindowOwned = false; | |
| 1327 | + vd->GLContext = sdl_gl_context; | |
| 1328 | + main_viewport->PlatformUserData = vd; | |
| 1329 | + main_viewport->PlatformHandle = (void*)(intptr_t)vd->WindowID; | |
| 1330 | +} | |
| 1331 | + | |
| 1332 | +static void ImGui_ImplSDL2_ShutdownMultiViewportSupport() | |
| 1333 | +{ | |
| 1334 | + ImGui::DestroyPlatformWindows(); | |
| 926 | 1335 | } |
| 927 | 1336 | |
| 928 | 1337 | //----------------------------------------------------------------------------- |
| @@ -9,6 +9,10 @@ | ||
| 9 | 9 | // [X] Platform: Gamepad support. |
| 10 | 10 | // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. |
| 11 | 11 | // [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. |
| 12 | +// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 13 | +// Missing features or Issues: | |
| 14 | +// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows). | |
| 15 | +// [ ] Platform: Multi-viewport: Missing ImGuiBackendFlags_HasParentViewport support. The viewport->ParentViewportID field is ignored, and therefore io.ConfigViewportsNoDefaultParent has no effect either. | |
| 12 | 16 | |
| 13 | 17 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 14 | 18 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -8,7 +8,10 @@ | ||
| 8 | 8 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] |
| 9 | 9 | // [X] Platform: Gamepad support. |
| 10 | 10 | // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. |
| 11 | -// [X] Platform: IME support. | |
| 11 | +// [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue. | |
| 12 | +// Missing features or Issues: | |
| 13 | +// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows). | |
| 14 | +// [x] Platform: IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. | |
| 12 | 15 | |
| 13 | 16 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 14 | 17 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -20,6 +23,9 @@ | ||
| 20 | 23 | |
| 21 | 24 | // CHANGELOG |
| 22 | 25 | // (minor and older changes stripped away, please see git history for details) |
| 26 | +// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 27 | +// 2026-03-25: [Docking] Use SDL_HAS_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED (SDL 3.4.0+) when available to avoid refreshing monitor work area every frame on Windows. (#8415) | |
| 28 | +// 2026-03-09: [Docking] Fixed an issue dated 2025/04/09 (1.92 WIP) where a refactor+merge caused ImGuiBackendFlags_HasMouseHoveredViewport to never be set, causing foreign windows to be ignored when deciding of hovered viewport. (#9284) | |
| 23 | 29 | // 2026-02-13: Inputs: systems other than X11 are back to starting mouse capture on mouse down (reverts 2025-02-26 change). Only X11 requires waiting for a drag by default (not ideal, but a better default for X11 users). Added ImGui_ImplSDL3_SetMouseCaptureMode() for X11 debugger users. (#3650, #6410, #9235) |
| 24 | 30 | // 2026-01-15: Changed GetClipboardText() handler to return nullptr on error aka clipboard contents is not text. Consistent with other backends. (#9168) |
| 25 | 31 | // 2025-11-05: Fixed an issue with missing characters events when an already active text field changes viewports. (#9054) |
| @@ -28,17 +34,23 @@ | ||
| 28 | 34 | // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. |
| 29 | 35 | // 2025-09-15: Use SDL_GetWindowDisplayScale() on Mac to output DisplayFrameBufferScale. The function is more reliable during resolution changes e.g. going fullscreen. (#8703, #4414) |
| 30 | 36 | // 2025-06-27: IME: avoid calling SDL_StartTextInput() again if already active. (#8727) |
| 37 | +// 2025-05-15: [Docking] Add Platform_GetWindowFramebufferScale() handler, to allow varying Retina display density on multiple monitors. | |
| 38 | +// 2025-05-06: [Docking] macOS: fixed secondary viewports not appearing on other monitors before of parenting. | |
| 39 | +// 2025-04-09: [Docking] Revert update monitors and work areas information every frame. Only do it on Windows. (#8415, #8558) | |
| 31 | 40 | // 2025-04-22: IME: honor ImGuiPlatformImeData->WantTextInput as an alternative way to call SDL_StartTextInput(), without IME being necessarily visible. |
| 32 | 41 | // 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) |
| 33 | 42 | // 2025-03-30: Update for SDL3 api changes: Revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) |
| 34 | 43 | // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. |
| 35 | 44 | // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) |
| 36 | 45 | // 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g. Linux debuggers not claiming capture back. (#6410, #3650) |
| 46 | +// 2025-02-25: [Docking] Revert to use SDL_GetDisplayBounds() for WorkPos/WorkRect if SDL_GetDisplayUsableBounds() failed. | |
| 37 | 47 | // 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode. |
| 48 | +// 2025-02-21: [Docking] Update monitors and work areas information every frame, as the later may change regardless of monitor changes. (#8415) | |
| 38 | 49 | // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. |
| 39 | 50 | // 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. |
| 40 | 51 | // 2025-01-20: Made ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode_Manual) accept an empty array. |
| 41 | 52 | // 2024-10-24: Emscripten: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f on Emscripten. |
| 53 | +// 2024-09-11: (Docking) Added support for viewport->ParentViewportId field to support parenting at OS level. (#7973) | |
| 42 | 54 | // 2024-09-03: Update for SDL3 api changes: SDL_GetGamepads() memory ownership revert. (#7918, #7898, #7807) |
| 43 | 55 | // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: |
| 44 | 56 | // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn |
| @@ -94,6 +106,7 @@ | ||
| 94 | 106 | #else |
| 95 | 107 | #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0 |
| 96 | 108 | #endif |
| 109 | +#define SDL_HAS_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED SDL_VERSION_ATLEAST(3,4,0) | |
| 97 | 110 | |
| 98 | 111 | // FIXME-LEGACY: remove when SDL 3.1.3 preview is released. |
| 99 | 112 | #ifndef SDLK_APOSTROPHE |
| @@ -112,6 +125,8 @@ | ||
| 112 | 125 | Uint64 Time; |
| 113 | 126 | char* ClipboardTextData; |
| 114 | 127 | char BackendPlatformName[48]; |
| 128 | + bool UseVulkan; | |
| 129 | + bool WantUpdateMonitors; | |
| 115 | 130 | |
| 116 | 131 | // IME handling |
| 117 | 132 | SDL_Window* ImeWindow; |
| @@ -125,12 +140,13 @@ | ||
| 125 | 140 | SDL_Cursor* MouseLastCursor; |
| 126 | 141 | int MousePendingLeaveFrame; |
| 127 | 142 | bool MouseCanUseGlobalState; |
| 143 | + bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state. | |
| 128 | 144 | ImGui_ImplSDL3_MouseCaptureMode MouseCaptureMode; |
| 129 | 145 | |
| 130 | 146 | // Gamepad handling |
| 131 | - ImVector<SDL_Gamepad*> Gamepads; | |
| 147 | + ImVector<SDL_Gamepad*> Gamepads; | |
| 132 | 148 | ImGui_ImplSDL3_GamepadMode GamepadMode; |
| 133 | - bool WantUpdateGamepadsList; | |
| 149 | + bool WantUpdateGamepadsList; | |
| 134 | 150 | |
| 135 | 151 | ImGui_ImplSDL3_Data() { memset((void*)this, 0, sizeof(*this)); } |
| 136 | 152 | }; |
| @@ -146,6 +162,9 @@ | ||
| 146 | 162 | |
| 147 | 163 | // Forward Declarations |
| 148 | 164 | static void ImGui_ImplSDL3_UpdateIme(); |
| 165 | +static void ImGui_ImplSDL3_UpdateMonitors(); | |
| 166 | +static void ImGui_ImplSDL3_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context); | |
| 167 | +static void ImGui_ImplSDL3_ShutdownMultiViewportSupport(); | |
| 149 | 168 | |
| 150 | 169 | // Functions |
| 151 | 170 | static const char* ImGui_ImplSDL3_GetClipboardText(ImGuiContext*) |
| @@ -167,8 +186,7 @@ | ||
| 167 | 186 | |
| 168 | 187 | static ImGuiViewport* ImGui_ImplSDL3_GetViewportForWindowID(SDL_WindowID window_id) |
| 169 | 188 | { |
| 170 | - ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); | |
| 171 | - return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : nullptr; | |
| 189 | + return ImGui::FindViewportByPlatformHandle((void*)(intptr_t)window_id); | |
| 172 | 190 | } |
| 173 | 191 | |
| 174 | 192 | static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport*, ImGuiPlatformImeData* data) |
| @@ -199,9 +217,12 @@ | ||
| 199 | 217 | bd->ImeDirty = false; |
| 200 | 218 | if (data->WantVisible) |
| 201 | 219 | { |
| 220 | + ImVec2 viewport_pos; | |
| 221 | + if (ImGuiViewport* viewport = ImGui_ImplSDL3_GetViewportForWindowID(SDL_GetWindowID(window))) | |
| 222 | + viewport_pos = viewport->Pos; | |
| 202 | 223 | SDL_Rect r; |
| 203 | - r.x = (int)data->InputPos.x; | |
| 204 | - r.y = (int)data->InputPos.y; | |
| 224 | + r.x = (int)(data->InputPos.x - viewport_pos.x); | |
| 225 | + r.y = (int)(data->InputPos.y - viewport_pos.y); | |
| 205 | 226 | r.w = 1; |
| 206 | 227 | r.h = (int)data->InputLineHeight; |
| 207 | 228 | SDL_SetTextInputArea(window, &r, 0); |
| @@ -390,6 +411,13 @@ | ||
| 390 | 411 | if (ImGui_ImplSDL3_GetViewportForWindowID(event->motion.windowID) == nullptr) |
| 391 | 412 | return false; |
| 392 | 413 | ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); |
| 414 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 415 | + { | |
| 416 | + int window_x, window_y; | |
| 417 | + SDL_GetWindowPosition(SDL_GetWindowFromID(event->motion.windowID), &window_x, &window_y); | |
| 418 | + mouse_pos.x += window_x; | |
| 419 | + mouse_pos.y += window_y; | |
| 420 | + } | |
| 393 | 421 | io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); |
| 394 | 422 | io.AddMousePosEvent(mouse_pos.x, mouse_pos.y); |
| 395 | 423 | return true; |
| @@ -433,16 +461,29 @@ | ||
| 433 | 461 | case SDL_EVENT_KEY_DOWN: |
| 434 | 462 | case SDL_EVENT_KEY_UP: |
| 435 | 463 | { |
| 436 | - if (ImGui_ImplSDL3_GetViewportForWindowID(event->key.windowID) == nullptr) | |
| 464 | + ImGuiViewport* viewport = ImGui_ImplSDL3_GetViewportForWindowID(event->key.windowID); | |
| 465 | + if (viewport == nullptr) | |
| 437 | 466 | return false; |
| 467 | + //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%s : key=0x%08X ('%s'), scancode=%d ('%s'), mod=%X, windowID=%d, viewport=%08X\n", | |
| 468 | + // (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP ", event->key.key, SDL_GetKeyName(event->key.key), event->key.scancode, SDL_GetScancodeName(event->key.scancode), event->key.mod, event->key.windowID, viewport ? viewport->ID : 0); | |
| 438 | 469 | ImGui_ImplSDL3_UpdateKeyModifiers((SDL_Keymod)event->key.mod); |
| 439 | - //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%s : key=%d ('%s'), scancode=%d ('%s'), mod=%X\n", | |
| 440 | - // (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP ", event->key.key, SDL_GetKeyName(event->key.key), event->key.scancode, SDL_GetScancodeName(event->key.scancode), event->key.mod); | |
| 441 | 470 | ImGuiKey key = ImGui_ImplSDL3_KeyEventToImGuiKey(event->key.key, event->key.scancode); |
| 442 | 471 | io.AddKeyEvent(key, (event->type == SDL_EVENT_KEY_DOWN)); |
| 443 | 472 | io.SetKeyEventNativeData(key, (int)event->key.key, (int)event->key.scancode, (int)event->key.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. |
| 444 | 473 | return true; |
| 445 | 474 | } |
| 475 | + case SDL_EVENT_DISPLAY_ORIENTATION: | |
| 476 | + case SDL_EVENT_DISPLAY_ADDED: | |
| 477 | + case SDL_EVENT_DISPLAY_REMOVED: | |
| 478 | + case SDL_EVENT_DISPLAY_MOVED: | |
| 479 | + case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED: | |
| 480 | +#if SDL_HAS_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED | |
| 481 | + case SDL_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED: | |
| 482 | +#endif | |
| 483 | + { | |
| 484 | + bd->WantUpdateMonitors = true; | |
| 485 | + return true; | |
| 486 | + } | |
| 446 | 487 | case SDL_EVENT_WINDOW_MOUSE_ENTER: |
| 447 | 488 | { |
| 448 | 489 | if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == nullptr) |
| @@ -465,11 +506,28 @@ | ||
| 465 | 506 | case SDL_EVENT_WINDOW_FOCUS_GAINED: |
| 466 | 507 | case SDL_EVENT_WINDOW_FOCUS_LOST: |
| 467 | 508 | { |
| 468 | - if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == nullptr) | |
| 509 | + ImGuiViewport* viewport = ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID); | |
| 510 | + if (viewport == nullptr) | |
| 469 | 511 | return false; |
| 512 | + //IMGUI_DEBUG_LOG("%s: windowId %d, viewport: %08X\n", (event->type == SDL_EVENT_WINDOW_FOCUS_GAINED) ? "SDL_EVENT_WINDOW_FOCUS_GAINED" : "SDL_WINDOWEVENT_FOCUS_LOST", event->window.windowID, viewport ? viewport->ID : 0); | |
| 470 | 513 | io.AddFocusEvent(event->type == SDL_EVENT_WINDOW_FOCUS_GAINED); |
| 471 | 514 | return true; |
| 472 | 515 | } |
| 516 | + case SDL_EVENT_WINDOW_CLOSE_REQUESTED: | |
| 517 | + case SDL_EVENT_WINDOW_MOVED: | |
| 518 | + case SDL_EVENT_WINDOW_RESIZED: | |
| 519 | + { | |
| 520 | + ImGuiViewport* viewport = ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID); | |
| 521 | + if (viewport == NULL) | |
| 522 | + return false; | |
| 523 | + if (event->type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) | |
| 524 | + viewport->PlatformRequestClose = true; | |
| 525 | + if (event->type == SDL_EVENT_WINDOW_MOVED) | |
| 526 | + viewport->PlatformRequestMove = true; | |
| 527 | + if (event->type == SDL_EVENT_WINDOW_RESIZED) | |
| 528 | + viewport->PlatformRequestResize = true; | |
| 529 | + return true; | |
| 530 | + } | |
| 473 | 531 | case SDL_EVENT_GAMEPAD_ADDED: |
| 474 | 532 | case SDL_EVENT_GAMEPAD_REMOVED: |
| 475 | 533 | { |
| @@ -511,6 +569,8 @@ | ||
| 511 | 569 | io.BackendPlatformName = bd->BackendPlatformName; |
| 512 | 570 | io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) |
| 513 | 571 | io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) |
| 572 | + // (ImGuiBackendFlags_PlatformHasViewports and ImGuiBackendFlags_HasParentViewport may be set just below) | |
| 573 | + // (ImGuiBackendFlags_HasMouseHoveredViewport is set dynamically in our _NewFrame function) | |
| 514 | 574 | |
| 515 | 575 | bd->Window = window; |
| 516 | 576 | bd->WindowID = SDL_GetWindowID(window); |
| @@ -530,13 +590,29 @@ | ||
| 530 | 590 | bd->MouseCaptureMode = (strcmp(item, "x11") == 0) ? ImGui_ImplSDL3_MouseCaptureMode_EnabledAfterDrag : ImGui_ImplSDL3_MouseCaptureMode_Enabled; |
| 531 | 591 | } |
| 532 | 592 | #endif |
| 593 | + if (bd->MouseCanUseGlobalState) | |
| 594 | + { | |
| 595 | + io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) | |
| 596 | + io.BackendFlags |= ImGuiBackendFlags_HasParentViewport; // We can honor viewport->ParentViewportId by applying the corresponding parent/child relationship at platform level (optional) | |
| 597 | + } | |
| 533 | 598 | |
| 599 | + // SDL on Linux/OSX doesn't report events for unfocused windows (see https://github.com/ocornut/imgui/issues/4960) | |
| 600 | + // We will use 'MouseCanReportHoveredViewport' to set 'ImGuiBackendFlags_HasMouseHoveredViewport' dynamically each frame. | |
| 601 | +#ifndef __APPLE__ | |
| 602 | + bd->MouseCanReportHoveredViewport = bd->MouseCanUseGlobalState; | |
| 603 | +#else | |
| 604 | + bd->MouseCanReportHoveredViewport = false; | |
| 605 | +#endif | |
| 606 | + | |
| 534 | 607 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 535 | 608 | platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText; |
| 536 | 609 | platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText; |
| 537 | 610 | platform_io.Platform_SetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData; |
| 538 | 611 | platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { return SDL_OpenURL(url); }; |
| 539 | 612 | |
| 613 | + // Update monitor a first time during init | |
| 614 | + ImGui_ImplSDL3_UpdateMonitors(); | |
| 615 | + | |
| 540 | 616 | // Gamepad handling |
| 541 | 617 | bd->GamepadMode = ImGui_ImplSDL3_GamepadMode_AutoFirst; |
| 542 | 618 | bd->WantUpdateGamepadsList = true; |
| @@ -569,6 +645,14 @@ | ||
| 569 | 645 | // From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710) |
| 570 | 646 | SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0"); |
| 571 | 647 | |
| 648 | + // SDL 3.x : see https://github.com/libsdl-org/SDL/issues/6659 | |
| 649 | + SDL_SetHint("SDL_BORDERLESS_WINDOWED_STYLE", "0"); | |
| 650 | + | |
| 651 | + // We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports. | |
| 652 | + // We left the call to ImGui_ImplSDL3_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings. | |
| 653 | + if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) | |
| 654 | + ImGui_ImplSDL3_InitMultiViewportSupport(window, sdl_gl_context); | |
| 655 | + | |
| 572 | 656 | return true; |
| 573 | 657 | } |
| 574 | 658 | |
| @@ -580,7 +664,11 @@ | ||
| 580 | 664 | |
| 581 | 665 | bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window) |
| 582 | 666 | { |
| 583 | - return ImGui_ImplSDL3_Init(window, nullptr, nullptr); | |
| 667 | + if (!ImGui_ImplSDL3_Init(window, nullptr, nullptr)) | |
| 668 | + return false; | |
| 669 | + ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); | |
| 670 | + bd->UseVulkan = true; | |
| 671 | + return true; | |
| 584 | 672 | } |
| 585 | 673 | |
| 586 | 674 | bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window) |
| @@ -620,6 +708,7 @@ | ||
| 620 | 708 | ImGuiIO& io = ImGui::GetIO(); |
| 621 | 709 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 622 | 710 | |
| 711 | + ImGui_ImplSDL3_ShutdownMultiViewportSupport(); | |
| 623 | 712 | if (bd->ClipboardTextData) |
| 624 | 713 | SDL_free(bd->ClipboardTextData); |
| 625 | 714 | for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) |
| @@ -628,7 +717,7 @@ | ||
| 628 | 717 | |
| 629 | 718 | io.BackendPlatformName = nullptr; |
| 630 | 719 | io.BackendPlatformUserData = nullptr; |
| 631 | - io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad); | |
| 720 | + io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport | ImGuiBackendFlags_HasParentViewport); | |
| 632 | 721 | platform_io.ClearPlatformHandlers(); |
| 633 | 722 | IM_DELETE(bd); |
| 634 | 723 | } |
| @@ -664,7 +753,7 @@ | ||
| 664 | 753 | } |
| 665 | 754 | |
| 666 | 755 | SDL_Window* focused_window = SDL_GetKeyboardFocus(); |
| 667 | - const bool is_app_focused = (bd->Window == focused_window); | |
| 756 | + const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui_ImplSDL3_GetViewportForWindowID(SDL_GetWindowID(focused_window)) != NULL)); | |
| 668 | 757 | #else |
| 669 | 758 | SDL_Window* focused_window = bd->Window; |
| 670 | 759 | const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only |
| @@ -673,7 +762,14 @@ | ||
| 673 | 762 | { |
| 674 | 763 | // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user) |
| 675 | 764 | if (io.WantSetMousePos) |
| 676 | - SDL_WarpMouseInWindow(bd->Window, io.MousePos.x, io.MousePos.y); | |
| 765 | + { | |
| 766 | +#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE | |
| 767 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 768 | + SDL_WarpMouseGlobal(io.MousePos.x, io.MousePos.y); | |
| 769 | + else | |
| 770 | +#endif | |
| 771 | + SDL_WarpMouseInWindow(bd->Window, io.MousePos.x, io.MousePos.y); | |
| 772 | + } | |
| 677 | 773 | |
| 678 | 774 | // (Optional) Fallback to provide unclamped mouse position when focused but not hovered (SDL_EVENT_MOUSE_MOTION already provides this when hovered or captured) |
| 679 | 775 | // Note that SDL_GetGlobalMouseState() is in theory slow on X11, but this only runs on rather specific cases. If a problem we may provide a way to opt-out this feature. |
| @@ -682,15 +778,34 @@ | ||
| 682 | 778 | if (hovered_window == nullptr && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) |
| 683 | 779 | { |
| 684 | 780 | // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) |
| 781 | + // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) | |
| 685 | 782 | float mouse_x, mouse_y; |
| 686 | 783 | int window_x, window_y; |
| 687 | 784 | SDL_GetGlobalMouseState(&mouse_x, &mouse_y); |
| 688 | - SDL_GetWindowPosition(focused_window, &window_x, &window_y); | |
| 689 | - mouse_x -= (float)window_x; | |
| 690 | - mouse_y -= (float)window_y; | |
| 785 | + if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)) | |
| 786 | + { | |
| 787 | + SDL_GetWindowPosition(focused_window, &window_x, &window_y); | |
| 788 | + mouse_x -= (float)window_x; | |
| 789 | + mouse_y -= (float)window_y; | |
| 790 | + } | |
| 691 | 791 | io.AddMousePosEvent(mouse_x, mouse_y); |
| 692 | 792 | } |
| 693 | 793 | } |
| 794 | + | |
| 795 | + // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering. | |
| 796 | + // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic. | |
| 797 | + // - [!] SDL backend does NOT correctly ignore viewports with the _NoInputs flag. | |
| 798 | + // Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window | |
| 799 | + // for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported | |
| 800 | + // by the backend, and use its flawed heuristic to guess the viewport behind. | |
| 801 | + // - [X] SDL backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target). | |
| 802 | + if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport) | |
| 803 | + { | |
| 804 | + ImGuiID mouse_viewport_id = 0; | |
| 805 | + if (ImGuiViewport* mouse_viewport = ImGui_ImplSDL3_GetViewportForWindowID(bd->MouseWindowID)) | |
| 806 | + mouse_viewport_id = mouse_viewport->ID; | |
| 807 | + io.AddMouseViewportEvent(mouse_viewport_id); | |
| 808 | + } | |
| 694 | 809 | } |
| 695 | 810 | |
| 696 | 811 | static void ImGui_ImplSDL3_UpdateMouseCursor() |
| @@ -822,6 +937,38 @@ | ||
| 822 | 937 | ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_GAMEPAD_AXIS_RIGHTY, +thumb_dead_zone, +32767); |
| 823 | 938 | } |
| 824 | 939 | |
| 940 | +static void ImGui_ImplSDL3_UpdateMonitors() | |
| 941 | +{ | |
| 942 | + ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); | |
| 943 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 944 | + platform_io.Monitors.resize(0); | |
| 945 | + bd->WantUpdateMonitors = false; | |
| 946 | + | |
| 947 | + int display_count; | |
| 948 | + SDL_DisplayID* displays = SDL_GetDisplays(&display_count); | |
| 949 | + for (int n = 0; n < display_count; n++) | |
| 950 | + { | |
| 951 | + // Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime. | |
| 952 | + SDL_DisplayID display_id = displays[n]; | |
| 953 | + ImGuiPlatformMonitor monitor; | |
| 954 | + SDL_Rect r; | |
| 955 | + SDL_GetDisplayBounds(display_id, &r); | |
| 956 | + monitor.MainPos = monitor.WorkPos = ImVec2((float)r.x, (float)r.y); | |
| 957 | + monitor.MainSize = monitor.WorkSize = ImVec2((float)r.w, (float)r.h); | |
| 958 | + if (SDL_GetDisplayUsableBounds(display_id, &r) && r.w > 0 && r.h > 0) | |
| 959 | + { | |
| 960 | + monitor.WorkPos = ImVec2((float)r.x, (float)r.y); | |
| 961 | + monitor.WorkSize = ImVec2((float)r.w, (float)r.h); | |
| 962 | + } | |
| 963 | + monitor.DpiScale = SDL_GetDisplayContentScale(display_id); // See https://wiki.libsdl.org/SDL3/README-highdpi for details. | |
| 964 | + monitor.PlatformHandle = (void*)(intptr_t)n; | |
| 965 | + if (monitor.DpiScale <= 0.0f) | |
| 966 | + continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902. | |
| 967 | + platform_io.Monitors.push_back(monitor); | |
| 968 | + } | |
| 969 | + SDL_free(displays); | |
| 970 | +} | |
| 971 | + | |
| 825 | 972 | static void ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(SDL_Window* window, ImVec2* out_size, ImVec2* out_framebuffer_scale) |
| 826 | 973 | { |
| 827 | 974 | int w, h; |
| @@ -854,6 +1001,13 @@ | ||
| 854 | 1001 | // Setup main viewport size (every frame to accommodate for window resizing) |
| 855 | 1002 | ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(bd->Window, &io.DisplaySize, &io.DisplayFramebufferScale); |
| 856 | 1003 | |
| 1004 | + // Update monitors | |
| 1005 | +#if defined(WIN32) && !SDL_HAS_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED | |
| 1006 | + bd->WantUpdateMonitors = true; // Keep polling under Windows to handle changes of work area when resizing task-bar (#8415) | |
| 1007 | +#endif | |
| 1008 | + if (bd->WantUpdateMonitors) | |
| 1009 | + ImGui_ImplSDL3_UpdateMonitors(); | |
| 1010 | + | |
| 857 | 1011 | // Setup time step (we could also use SDL_GetTicksNS() available since SDL3) |
| 858 | 1012 | // (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644) |
| 859 | 1013 | static Uint64 frequency = SDL_GetPerformanceFrequency(); |
| @@ -870,12 +1024,285 @@ | ||
| 870 | 1024 | io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); |
| 871 | 1025 | } |
| 872 | 1026 | |
| 1027 | + // Our io.AddMouseViewportEvent() calls will only be valid when not capturing. | |
| 1028 | + // Technically speaking testing for 'bd->MouseButtonsDown == 0' would be more rigorous, but testing for payload reduces noise and potential side-effects. | |
| 1029 | + if (bd->MouseCanReportHoveredViewport && ImGui::GetDragDropPayload() == nullptr) | |
| 1030 | + io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; | |
| 1031 | + else | |
| 1032 | + io.BackendFlags &= ~ImGuiBackendFlags_HasMouseHoveredViewport; | |
| 1033 | + | |
| 873 | 1034 | ImGui_ImplSDL3_UpdateMouseData(); |
| 874 | 1035 | ImGui_ImplSDL3_UpdateMouseCursor(); |
| 875 | 1036 | ImGui_ImplSDL3_UpdateIme(); |
| 876 | 1037 | |
| 877 | 1038 | // Update game controllers (if enabled and available) |
| 878 | 1039 | ImGui_ImplSDL3_UpdateGamepads(); |
| 1040 | +} | |
| 1041 | + | |
| 1042 | +//-------------------------------------------------------------------------------------------------------- | |
| 1043 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 1044 | +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. | |
| 1045 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 1046 | +//-------------------------------------------------------------------------------------------------------- | |
| 1047 | + | |
| 1048 | +// Helper structure we store in the void* PlatformUserData field of each ImGuiViewport to easily retrieve our backend data. | |
| 1049 | +struct ImGui_ImplSDL3_ViewportData | |
| 1050 | +{ | |
| 1051 | + SDL_Window* Window; | |
| 1052 | + SDL_Window* ParentWindow; | |
| 1053 | + Uint32 WindowID; // Stored in ImGuiViewport::PlatformHandle. Use SDL_GetWindowFromID() to get SDL_Window* from Uint32 WindowID. | |
| 1054 | + bool WindowOwned; | |
| 1055 | + SDL_GLContext GLContext; | |
| 1056 | + | |
| 1057 | + ImGui_ImplSDL3_ViewportData() { Window = ParentWindow = nullptr; WindowID = 0; WindowOwned = false; GLContext = nullptr; } | |
| 1058 | + ~ImGui_ImplSDL3_ViewportData() { IM_ASSERT(Window == nullptr && GLContext == nullptr); } | |
| 1059 | +}; | |
| 1060 | + | |
| 1061 | +static SDL_Window* ImGui_ImplSDL3_GetSDLWindowFromViewport(ImGuiViewport* viewport) | |
| 1062 | +{ | |
| 1063 | + if (viewport != nullptr) | |
| 1064 | + { | |
| 1065 | + SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle; | |
| 1066 | + return SDL_GetWindowFromID(window_id); | |
| 1067 | + } | |
| 1068 | + return nullptr; | |
| 1069 | +} | |
| 1070 | + | |
| 1071 | +static void ImGui_ImplSDL3_CreateWindow(ImGuiViewport* viewport) | |
| 1072 | +{ | |
| 1073 | + ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); | |
| 1074 | + ImGui_ImplSDL3_ViewportData* vd = IM_NEW(ImGui_ImplSDL3_ViewportData)(); | |
| 1075 | + viewport->PlatformUserData = vd; | |
| 1076 | + | |
| 1077 | + vd->ParentWindow = ImGui_ImplSDL3_GetSDLWindowFromViewport(viewport->ParentViewport); | |
| 1078 | + | |
| 1079 | + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | |
| 1080 | + ImGui_ImplSDL3_ViewportData* main_viewport_data = (ImGui_ImplSDL3_ViewportData*)main_viewport->PlatformUserData; | |
| 1081 | + | |
| 1082 | + // Share GL resources with main context | |
| 1083 | + bool use_opengl = (main_viewport_data->GLContext != nullptr); | |
| 1084 | + SDL_GLContext backup_context = nullptr; | |
| 1085 | + if (use_opengl) | |
| 1086 | + { | |
| 1087 | + backup_context = SDL_GL_GetCurrentContext(); | |
| 1088 | + SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); | |
| 1089 | + SDL_GL_MakeCurrent(main_viewport_data->Window, main_viewport_data->GLContext); | |
| 1090 | + } | |
| 1091 | + | |
| 1092 | + SDL_WindowFlags sdl_flags = 0; | |
| 1093 | + sdl_flags |= SDL_WINDOW_HIDDEN; | |
| 1094 | + sdl_flags |= use_opengl ? SDL_WINDOW_OPENGL : (bd->UseVulkan ? SDL_WINDOW_VULKAN : 0); | |
| 1095 | + sdl_flags |= SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_HIGH_PIXEL_DENSITY; | |
| 1096 | + sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0; | |
| 1097 | + sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE; | |
| 1098 | + sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) ? SDL_WINDOW_UTILITY : 0; | |
| 1099 | + sdl_flags |= (viewport->Flags & ImGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0; | |
| 1100 | + vd->Window = SDL_CreateWindow("No Title Yet", (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags); | |
| 1101 | +#ifndef __APPLE__ // On Mac, SDL3 Parenting appears to prevent viewport from appearing in another monitor | |
| 1102 | + SDL_SetWindowParent(vd->Window, vd->ParentWindow); | |
| 1103 | +#endif | |
| 1104 | + SDL_SetWindowPosition(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y); | |
| 1105 | + vd->WindowOwned = true; | |
| 1106 | + if (use_opengl) | |
| 1107 | + { | |
| 1108 | + vd->GLContext = SDL_GL_CreateContext(vd->Window); | |
| 1109 | + SDL_GL_SetSwapInterval(0); | |
| 1110 | + } | |
| 1111 | + if (use_opengl && backup_context) | |
| 1112 | + SDL_GL_MakeCurrent(vd->Window, backup_context); | |
| 1113 | + | |
| 1114 | + ImGui_ImplSDL3_SetupPlatformHandles(viewport, vd->Window); | |
| 1115 | +} | |
| 1116 | + | |
| 1117 | +static void ImGui_ImplSDL3_DestroyWindow(ImGuiViewport* viewport) | |
| 1118 | +{ | |
| 1119 | + if (ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData) | |
| 1120 | + { | |
| 1121 | + if (vd->GLContext && vd->WindowOwned) | |
| 1122 | + SDL_GL_DestroyContext(vd->GLContext); | |
| 1123 | + if (vd->Window && vd->WindowOwned) | |
| 1124 | + SDL_DestroyWindow(vd->Window); | |
| 1125 | + vd->GLContext = nullptr; | |
| 1126 | + vd->Window = nullptr; | |
| 1127 | + IM_DELETE(vd); | |
| 1128 | + } | |
| 1129 | + viewport->PlatformUserData = viewport->PlatformHandle = nullptr; | |
| 1130 | +} | |
| 1131 | + | |
| 1132 | +static void ImGui_ImplSDL3_ShowWindow(ImGuiViewport* viewport) | |
| 1133 | +{ | |
| 1134 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1135 | +#if defined(_WIN32) && !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_APP) && WINAPI_FAMILY == WINAPI_FAMILY_APP) || (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES))) | |
| 1136 | + HWND hwnd = (HWND)viewport->PlatformHandleRaw; | |
| 1137 | + | |
| 1138 | + // SDL hack: Show icon in task bar (#7989) | |
| 1139 | + // Note: SDL_WINDOW_UTILITY can be used to control task bar visibility, but on Windows, it does not affect child windows. | |
| 1140 | + if (!(viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon)) | |
| 1141 | + { | |
| 1142 | + LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE); | |
| 1143 | + ex_style |= WS_EX_APPWINDOW; | |
| 1144 | + ex_style &= ~WS_EX_TOOLWINDOW; | |
| 1145 | + ::ShowWindow(hwnd, SW_HIDE); | |
| 1146 | + ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style); | |
| 1147 | + } | |
| 1148 | +#endif | |
| 1149 | + | |
| 1150 | +#ifdef __APPLE__ | |
| 1151 | + SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN, "1"); // Otherwise new window appear under | |
| 1152 | +#else | |
| 1153 | + SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN, (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) ? "0" : "1"); | |
| 1154 | +#endif | |
| 1155 | + SDL_ShowWindow(vd->Window); | |
| 1156 | +} | |
| 1157 | + | |
| 1158 | +static void ImGui_ImplSDL3_UpdateWindow(ImGuiViewport* viewport) | |
| 1159 | +{ | |
| 1160 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1161 | + IM_UNUSED(vd); | |
| 1162 | + | |
| 1163 | +#ifndef __APPLE__ // On Mac, SDL3 Parenting appears to prevent viewport from appearing in another monitor | |
| 1164 | + // Update SDL3 parent if it changed _after_ creation. | |
| 1165 | + // This is for advanced apps that are manipulating ParentViewportID manually. | |
| 1166 | + SDL_Window* new_parent = ImGui_ImplSDL3_GetSDLWindowFromViewport(viewport->ParentViewport); | |
| 1167 | + if (new_parent != vd->ParentWindow) | |
| 1168 | + { | |
| 1169 | + vd->ParentWindow = new_parent; | |
| 1170 | + SDL_SetWindowParent(vd->Window, vd->ParentWindow); | |
| 1171 | + } | |
| 1172 | +#endif | |
| 1173 | +} | |
| 1174 | + | |
| 1175 | +static ImVec2 ImGui_ImplSDL3_GetWindowPos(ImGuiViewport* viewport) | |
| 1176 | +{ | |
| 1177 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1178 | + int x = 0, y = 0; | |
| 1179 | + SDL_GetWindowPosition(vd->Window, &x, &y); | |
| 1180 | + return ImVec2((float)x, (float)y); | |
| 1181 | +} | |
| 1182 | + | |
| 1183 | +static void ImGui_ImplSDL3_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos) | |
| 1184 | +{ | |
| 1185 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1186 | + SDL_SetWindowPosition(vd->Window, (int)pos.x, (int)pos.y); | |
| 1187 | +} | |
| 1188 | + | |
| 1189 | +static ImVec2 ImGui_ImplSDL3_GetWindowSize(ImGuiViewport* viewport) | |
| 1190 | +{ | |
| 1191 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1192 | + int w = 0, h = 0; | |
| 1193 | + SDL_GetWindowSize(vd->Window, &w, &h); | |
| 1194 | + return ImVec2((float)w, (float)h); | |
| 1195 | +} | |
| 1196 | + | |
| 1197 | +static void ImGui_ImplSDL3_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) | |
| 1198 | +{ | |
| 1199 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1200 | + SDL_SetWindowSize(vd->Window, (int)size.x, (int)size.y); | |
| 1201 | +} | |
| 1202 | + | |
| 1203 | +static ImVec2 ImGui_ImplSDL3_GetWindowFramebufferScale(ImGuiViewport* viewport) | |
| 1204 | +{ | |
| 1205 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1206 | + ImVec2 framebuffer_scale; | |
| 1207 | + ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(vd->Window, nullptr, &framebuffer_scale); | |
| 1208 | + return framebuffer_scale; | |
| 1209 | +} | |
| 1210 | + | |
| 1211 | +static void ImGui_ImplSDL3_SetWindowTitle(ImGuiViewport* viewport, const char* title) | |
| 1212 | +{ | |
| 1213 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1214 | + SDL_SetWindowTitle(vd->Window, title); | |
| 1215 | +} | |
| 1216 | + | |
| 1217 | +static void ImGui_ImplSDL3_SetWindowAlpha(ImGuiViewport* viewport, float alpha) | |
| 1218 | +{ | |
| 1219 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1220 | + SDL_SetWindowOpacity(vd->Window, alpha); | |
| 1221 | +} | |
| 1222 | + | |
| 1223 | +static void ImGui_ImplSDL3_SetWindowFocus(ImGuiViewport* viewport) | |
| 1224 | +{ | |
| 1225 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1226 | + SDL_RaiseWindow(vd->Window); | |
| 1227 | +} | |
| 1228 | + | |
| 1229 | +static bool ImGui_ImplSDL3_GetWindowFocus(ImGuiViewport* viewport) | |
| 1230 | +{ | |
| 1231 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1232 | + return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; | |
| 1233 | +} | |
| 1234 | + | |
| 1235 | +static bool ImGui_ImplSDL3_GetWindowMinimized(ImGuiViewport* viewport) | |
| 1236 | +{ | |
| 1237 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1238 | + return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_MINIMIZED) != 0; | |
| 1239 | +} | |
| 1240 | + | |
| 1241 | +static void ImGui_ImplSDL3_RenderWindow(ImGuiViewport* viewport, void*) | |
| 1242 | +{ | |
| 1243 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1244 | + if (vd->GLContext) | |
| 1245 | + SDL_GL_MakeCurrent(vd->Window, vd->GLContext); | |
| 1246 | +} | |
| 1247 | + | |
| 1248 | +static void ImGui_ImplSDL3_SwapBuffers(ImGuiViewport* viewport, void*) | |
| 1249 | +{ | |
| 1250 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1251 | + if (vd->GLContext) | |
| 1252 | + { | |
| 1253 | + SDL_GL_MakeCurrent(vd->Window, vd->GLContext); | |
| 1254 | + SDL_GL_SwapWindow(vd->Window); | |
| 1255 | + } | |
| 1256 | +} | |
| 1257 | + | |
| 1258 | +// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface) | |
| 1259 | +// SDL is graceful enough to _not_ need <vulkan/vulkan.h> so we can safely include this. | |
| 1260 | +#include <SDL3/SDL_vulkan.h> | |
| 1261 | +static int ImGui_ImplSDL3_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface) | |
| 1262 | +{ | |
| 1263 | + ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData; | |
| 1264 | + (void)vk_allocator; | |
| 1265 | + bool ret = SDL_Vulkan_CreateSurface(vd->Window, (VkInstance)vk_instance, (const VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface); | |
| 1266 | + return ret ? 0 : 1; // ret ? VK_SUCCESS : VK_NOT_READY | |
| 1267 | +} | |
| 1268 | + | |
| 1269 | +static void ImGui_ImplSDL3_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context) | |
| 1270 | +{ | |
| 1271 | + // Register platform interface (will be coupled with a renderer interface) | |
| 1272 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 1273 | + platform_io.Platform_CreateWindow = ImGui_ImplSDL3_CreateWindow; | |
| 1274 | + platform_io.Platform_DestroyWindow = ImGui_ImplSDL3_DestroyWindow; | |
| 1275 | + platform_io.Platform_ShowWindow = ImGui_ImplSDL3_ShowWindow; | |
| 1276 | + platform_io.Platform_UpdateWindow = ImGui_ImplSDL3_UpdateWindow; | |
| 1277 | + platform_io.Platform_SetWindowPos = ImGui_ImplSDL3_SetWindowPos; | |
| 1278 | + platform_io.Platform_GetWindowPos = ImGui_ImplSDL3_GetWindowPos; | |
| 1279 | + platform_io.Platform_SetWindowSize = ImGui_ImplSDL3_SetWindowSize; | |
| 1280 | + platform_io.Platform_GetWindowSize = ImGui_ImplSDL3_GetWindowSize; | |
| 1281 | + platform_io.Platform_GetWindowFramebufferScale = ImGui_ImplSDL3_GetWindowFramebufferScale; | |
| 1282 | + platform_io.Platform_SetWindowFocus = ImGui_ImplSDL3_SetWindowFocus; | |
| 1283 | + platform_io.Platform_GetWindowFocus = ImGui_ImplSDL3_GetWindowFocus; | |
| 1284 | + platform_io.Platform_GetWindowMinimized = ImGui_ImplSDL3_GetWindowMinimized; | |
| 1285 | + platform_io.Platform_SetWindowTitle = ImGui_ImplSDL3_SetWindowTitle; | |
| 1286 | + platform_io.Platform_RenderWindow = ImGui_ImplSDL3_RenderWindow; | |
| 1287 | + platform_io.Platform_SwapBuffers = ImGui_ImplSDL3_SwapBuffers; | |
| 1288 | + platform_io.Platform_SetWindowAlpha = ImGui_ImplSDL3_SetWindowAlpha; | |
| 1289 | + platform_io.Platform_CreateVkSurface = ImGui_ImplSDL3_CreateVkSurface; | |
| 1290 | + | |
| 1291 | + // Register main window handle (which is owned by the main application, not by us) | |
| 1292 | + // This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports. | |
| 1293 | + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | |
| 1294 | + ImGui_ImplSDL3_ViewportData* vd = IM_NEW(ImGui_ImplSDL3_ViewportData)(); | |
| 1295 | + vd->Window = window; | |
| 1296 | + vd->WindowID = SDL_GetWindowID(window); | |
| 1297 | + vd->WindowOwned = false; | |
| 1298 | + vd->GLContext = (SDL_GLContext)sdl_gl_context; | |
| 1299 | + main_viewport->PlatformUserData = vd; | |
| 1300 | + main_viewport->PlatformHandle = (void*)(intptr_t)vd->WindowID; | |
| 1301 | +} | |
| 1302 | + | |
| 1303 | +static void ImGui_ImplSDL3_ShutdownMultiViewportSupport() | |
| 1304 | +{ | |
| 1305 | + ImGui::DestroyPlatformWindows(); | |
| 879 | 1306 | } |
| 880 | 1307 | |
| 881 | 1308 | //----------------------------------------------------------------------------- |
| @@ -8,7 +8,10 @@ | ||
| 8 | 8 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] |
| 9 | 9 | // [X] Platform: Gamepad support. |
| 10 | 10 | // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. |
| 11 | -// [X] Platform: IME support. | |
| 11 | +// [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue. | |
| 12 | +// Missing features or Issues: | |
| 13 | +// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows). | |
| 14 | +// [x] Platform: IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. | |
| 12 | 15 | |
| 13 | 16 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 14 | 17 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -5,6 +5,7 @@ | ||
| 5 | 5 | // [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct. |
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 8 | 9 | |
| 9 | 10 | // The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification. |
| 10 | 11 | // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ |
| @@ -22,6 +23,7 @@ | ||
| 22 | 23 | // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. |
| 23 | 24 | |
| 24 | 25 | // CHANGELOG |
| 26 | +// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 25 | 27 | // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplSDLGPU3_RenderState. (#9378) |
| 26 | 28 | // 2026-03-19: Fixed issue in ImGui_ImplSDLGPU3_DestroyTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) |
| 27 | 29 | // 2026-02-25: Removed unnecessary call to SDL_WaitForGPUIdle when releasing vertex/index buffers. (#9262) |
| @@ -652,6 +654,9 @@ | ||
| 652 | 654 | if (bd->Pipeline) { SDL_ReleaseGPUGraphicsPipeline(v->Device, bd->Pipeline); bd->Pipeline = nullptr; } |
| 653 | 655 | } |
| 654 | 656 | |
| 657 | +static void ImGui_ImplSDLGPU3_InitMultiViewportSupport(); | |
| 658 | +static void ImGui_ImplSDLGPU3_ShutdownMultiViewportSupport(); | |
| 659 | + | |
| 655 | 660 | bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info) |
| 656 | 661 | { |
| 657 | 662 | ImGuiIO& io = ImGui::GetIO(); |
| @@ -664,6 +669,7 @@ | ||
| 664 | 669 | io.BackendRendererName = "imgui_impl_sdlgpu3"; |
| 665 | 670 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. |
| 666 | 671 | io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. |
| 672 | + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) | |
| 667 | 673 | |
| 668 | 674 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 669 | 675 | platform_io.DrawCallback_ResetRenderState = ImGui_ImplSDLGPU3_DrawCallback_ResetRenderState; |
| @@ -675,6 +681,8 @@ | ||
| 675 | 681 | |
| 676 | 682 | bd->InitInfo = *info; |
| 677 | 683 | |
| 684 | + ImGui_ImplSDLGPU3_InitMultiViewportSupport(); | |
| 685 | + | |
| 678 | 686 | return true; |
| 679 | 687 | } |
| 680 | 688 | |
| @@ -685,11 +693,12 @@ | ||
| 685 | 693 | ImGuiIO& io = ImGui::GetIO(); |
| 686 | 694 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 687 | 695 | |
| 696 | + ImGui_ImplSDLGPU3_ShutdownMultiViewportSupport(); | |
| 688 | 697 | ImGui_ImplSDLGPU3_DestroyDeviceObjects(); |
| 689 | 698 | |
| 690 | 699 | io.BackendRendererName = nullptr; |
| 691 | 700 | io.BackendRendererUserData = nullptr; |
| 692 | - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); | |
| 701 | + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports); | |
| 693 | 702 | platform_io.ClearRendererHandlers(); |
| 694 | 703 | IM_DELETE(bd); |
| 695 | 704 | } |
| @@ -702,5 +711,77 @@ | ||
| 702 | 711 | if (!bd->TexSamplerLinear) |
| 703 | 712 | ImGui_ImplSDLGPU3_CreateDeviceObjects(); |
| 704 | 713 | } |
| 714 | + | |
| 715 | +//-------------------------------------------------------------------------------------------------------- | |
| 716 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 717 | +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. | |
| 718 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 719 | +//-------------------------------------------------------------------------------------------------------- | |
| 720 | + | |
| 721 | +static void ImGui_ImplSDLGPU3_CreateWindow(ImGuiViewport* viewport) | |
| 722 | +{ | |
| 723 | + ImGui_ImplSDLGPU3_Data* data = ImGui_ImplSDLGPU3_GetBackendData(); | |
| 724 | + SDL_Window* window = SDL_GetWindowFromID((SDL_WindowID)(intptr_t)viewport->PlatformHandle); | |
| 725 | + SDL_ClaimWindowForGPUDevice(data->InitInfo.Device, window); | |
| 726 | + SDL_SetGPUSwapchainParameters(data->InitInfo.Device, window, data->InitInfo.SwapchainComposition, data->InitInfo.PresentMode); | |
| 727 | + viewport->RendererUserData = (void*)1; | |
| 728 | +} | |
| 729 | + | |
| 730 | +static void ImGui_ImplSDLGPU3_RenderWindow(ImGuiViewport* viewport, void*) | |
| 731 | +{ | |
| 732 | + ImGui_ImplSDLGPU3_Data* data = ImGui_ImplSDLGPU3_GetBackendData(); | |
| 733 | + SDL_Window* window = SDL_GetWindowFromID((SDL_WindowID)(intptr_t)viewport->PlatformHandle); | |
| 734 | + | |
| 735 | + ImDrawData* draw_data = viewport->DrawData; | |
| 736 | + | |
| 737 | + SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(data->InitInfo.Device); | |
| 738 | + | |
| 739 | + SDL_GPUTexture* swapchain_texture; | |
| 740 | + SDL_AcquireGPUSwapchainTexture(command_buffer, window, &swapchain_texture, nullptr, nullptr); | |
| 741 | + | |
| 742 | + if (swapchain_texture != nullptr) | |
| 743 | + { | |
| 744 | + ImGui_ImplSDLGPU3_PrepareDrawData(draw_data, command_buffer); // FIXME-OPT: Not optimal, may this be done earlier? | |
| 745 | + SDL_GPUColorTargetInfo target_info = {}; | |
| 746 | + target_info.texture = swapchain_texture; | |
| 747 | + target_info.clear_color = SDL_FColor{ 0.0f,0.0f,0.0f,1.0f }; | |
| 748 | + target_info.load_op = SDL_GPU_LOADOP_CLEAR; | |
| 749 | + target_info.store_op = SDL_GPU_STOREOP_STORE; | |
| 750 | + target_info.mip_level = 0; | |
| 751 | + target_info.layer_or_depth_plane = 0; | |
| 752 | + target_info.cycle = false; | |
| 753 | + SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(command_buffer, &target_info, 1, nullptr); | |
| 754 | + ImGui_ImplSDLGPU3_RenderDrawData(draw_data, command_buffer, render_pass); | |
| 755 | + SDL_EndGPURenderPass(render_pass); | |
| 756 | + } | |
| 757 | + | |
| 758 | + SDL_SubmitGPUCommandBuffer(command_buffer); | |
| 759 | +} | |
| 760 | + | |
| 761 | +static void ImGui_ImplSDLGPU3_DestroyWindow(ImGuiViewport* viewport) | |
| 762 | +{ | |
| 763 | + ImGui_ImplSDLGPU3_Data* data = ImGui_ImplSDLGPU3_GetBackendData(); | |
| 764 | + if (viewport->RendererUserData) | |
| 765 | + { | |
| 766 | + SDL_Window* window = SDL_GetWindowFromID((SDL_WindowID)(intptr_t)viewport->PlatformHandle); | |
| 767 | + SDL_ReleaseWindowFromGPUDevice(data->InitInfo.Device, window); | |
| 768 | + } | |
| 769 | + viewport->RendererUserData = nullptr; | |
| 770 | +} | |
| 771 | + | |
| 772 | +static void ImGui_ImplSDLGPU3_InitMultiViewportSupport() | |
| 773 | +{ | |
| 774 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 775 | + platform_io.Renderer_RenderWindow = ImGui_ImplSDLGPU3_RenderWindow; | |
| 776 | + platform_io.Renderer_CreateWindow = ImGui_ImplSDLGPU3_CreateWindow; | |
| 777 | + platform_io.Renderer_DestroyWindow = ImGui_ImplSDLGPU3_DestroyWindow; | |
| 778 | +} | |
| 779 | + | |
| 780 | +static void ImGui_ImplSDLGPU3_ShutdownMultiViewportSupport() | |
| 781 | +{ | |
| 782 | + ImGui::DestroyPlatformWindows(); | |
| 783 | +} | |
| 784 | + | |
| 785 | +//----------------------------------------------------------------------------- | |
| 705 | 786 | |
| 706 | 787 | #endif // #ifndef IMGUI_DISABLE |
| @@ -5,6 +5,7 @@ | ||
| 5 | 5 | // [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct. |
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | +// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 8 | 9 | |
| 9 | 10 | // The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification. |
| 10 | 11 | // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ |
| @@ -15,6 +15,7 @@ | ||
| 15 | 15 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 16 | 16 | // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. |
| 17 | 17 | // Missing features or Issues: |
| 18 | +// [ ] Renderer: Multi-viewport support (multiple windows). | |
| 18 | 19 | // [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: SDLRenderer2 does not support changing SDL_SCALE_MODE while rendering. |
| 19 | 20 | |
| 20 | 21 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| @@ -15,6 +15,7 @@ | ||
| 15 | 15 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 16 | 16 | // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. |
| 17 | 17 | // Missing features or Issues: |
| 18 | +// [ ] Renderer: Multi-viewport support (multiple windows). | |
| 18 | 19 | // [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: SDLRenderer2 does not support changing SDL_SCALE_MODE while rendering. |
| 19 | 20 | |
| 20 | 21 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| @@ -14,6 +14,8 @@ | ||
| 14 | 14 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 15 | 15 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 16 | 16 | // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. |
| 17 | +// Missing features: | |
| 18 | +// [ ] Renderer: Multi-viewport support (multiple windows). | |
| 17 | 19 | |
| 18 | 20 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 19 | 21 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -14,6 +14,8 @@ | ||
| 14 | 14 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 15 | 15 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 16 | 16 | // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. |
| 17 | +// Missing features: | |
| 18 | +// [ ] Renderer: Multi-viewport support (multiple windows). | |
| 17 | 19 | |
| 18 | 20 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 19 | 21 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -6,6 +6,7 @@ | ||
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | 8 | // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. |
| 9 | +// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport). | |
| 9 | 10 | |
| 10 | 11 | // The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. |
| 11 | 12 | // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ |
| @@ -27,6 +28,7 @@ | ||
| 27 | 28 | |
| 28 | 29 | // CHANGELOG |
| 29 | 30 | // (minor and older changes stripped away, please see git history for details) |
| 31 | +// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 30 | 32 | // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) |
| 31 | 33 | // 2026-04-22: *BREAKING CHANGE* redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. This change allows us to facilitate changing samplers, in line with other backends. |
| 32 | 34 | // - When registering custom textures: changed ImGui_ImplVulkan_AddTexture() signature to remove Sampler. |
| @@ -41,11 +43,13 @@ | ||
| 41 | 43 | // 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) |
| 42 | 44 | // 2026-01-05: [Helpers] *BREAKING CHANGE*: Vulkan: Helper for creating render pass uses ImGui_ImplVulkanH_Window::AttachmentDesc to create render pass. Removed ClearEnabled. (#9152) |
| 43 | 45 | // 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) |
| 46 | +// 2025-11-13: [Docking] Handle viewport surface creation failure without crashing. (#9068) | |
| 44 | 47 | // 2025-10-15: Vulkan: Added IMGUI_IMPL_VULKAN_VOLK_FILENAME to configure path to volk.h header. (#9008) |
| 45 | 48 | // 2025-09-26: *BREAKING CHANGE*: moved some fields in ImGui_ImplVulkan_InitInfo: init_info.RenderPass --> init_info.PipelineInfoMain.RenderPass, init_info.Subpass --> init_info.PipelineInfoMain.Subpass, init_info.MSAASamples --> init_info.PipelineInfoMain.MSAASamples, init_info.PipelineRenderingCreateInfo --> init_info.PipelineInfoMain.PipelineRenderingCreateInfo. |
| 46 | 49 | // 2025-09-26: *BREAKING CHANGE*: renamed ImGui_ImplVulkan_MainPipelineCreateInfo to ImGui_ImplVulkan_PipelineInfo. Introduced very recently so shouldn't affect many users. |
| 47 | 50 | // 2025-09-26: [Helpers] *BREAKING CHANGE*: Helper ImGui_ImplVulkanH_CreateOrResizeWindow() added a VkImageUsageFlags image_usage` argument, default to VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT if 0. |
| 48 | 51 | // 2025-09-26: Vulkan: Added a way to customize shaders by filling ImGui_ImplVulkan_InitInfo::CustomShaderVertCreateInfo/CustomShaderFragCreateInfo. (#8585) |
| 52 | +// 2025-09-22: [Docking] Added ImGui_ImplVulkanH_GetWindowDataFromViewport() accessor/helper. (#8946, #8940) | |
| 49 | 53 | // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. |
| 50 | 54 | // 2025-09-04: Vulkan: Added ImGui_ImplVulkan_CreateMainPipeline(). (#8110, #8111) |
| 51 | 55 | // 2025-07-27: Vulkan: Fixed texture update corruption introduced on 2025-06-11. (#8801, #8755, #8840) |
| @@ -144,6 +148,7 @@ | ||
| 144 | 148 | void ImGui_ImplVulkan_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkan_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator); |
| 145 | 149 | void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator); |
| 146 | 150 | void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator); |
| 151 | +void ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(VkDevice device, const VkAllocationCallbacks* allocator); | |
| 147 | 152 | void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count, VkImageUsageFlags image_usage); |
| 148 | 153 | void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator); |
| 149 | 154 | |
| @@ -160,15 +165,18 @@ | ||
| 160 | 165 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateCommandBuffers) \ |
| 161 | 166 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateDescriptorSets) \ |
| 162 | 167 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateMemory) \ |
| 168 | + IMGUI_VULKAN_FUNC_MAP_MACRO(vkAcquireNextImageKHR) \ | |
| 163 | 169 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkBeginCommandBuffer) \ |
| 164 | 170 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindBufferMemory) \ |
| 165 | 171 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindImageMemory) \ |
| 172 | + IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBeginRenderPass) \ | |
| 166 | 173 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindDescriptorSets) \ |
| 167 | 174 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindIndexBuffer) \ |
| 168 | 175 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindPipeline) \ |
| 169 | 176 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindVertexBuffers) \ |
| 170 | 177 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdCopyBufferToImage) \ |
| 171 | 178 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdDrawIndexed) \ |
| 179 | + IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdEndRenderPass) \ | |
| 172 | 180 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPipelineBarrier) \ |
| 173 | 181 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPushConstants) \ |
| 174 | 182 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetScissor) \ |
| @@ -220,8 +228,10 @@ | ||
| 220 | 228 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \ |
| 221 | 229 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceFormatsKHR) \ |
| 222 | 230 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfacePresentModesKHR) \ |
| 231 | + IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceSupportKHR) \ | |
| 223 | 232 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetSwapchainImagesKHR) \ |
| 224 | 233 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkMapMemory) \ |
| 234 | + IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueuePresentKHR) \ | |
| 225 | 235 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueSubmit) \ |
| 226 | 236 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueWaitIdle) \ |
| 227 | 237 | IMGUI_VULKAN_FUNC_MAP_MACRO(vkResetCommandPool) \ |
| @@ -272,6 +282,20 @@ | ||
| 272 | 282 | ImGui_ImplVulkan_Texture() { memset((void*)this, 0, sizeof(*this)); } |
| 273 | 283 | }; |
| 274 | 284 | |
| 285 | +// For multi-viewport support: | |
| 286 | +// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data. | |
| 287 | +struct ImGui_ImplVulkan_ViewportData | |
| 288 | +{ | |
| 289 | + ImGui_ImplVulkanH_Window Window; // Used by secondary viewports only | |
| 290 | + ImGui_ImplVulkan_WindowRenderBuffers RenderBuffers; // Used by all viewports | |
| 291 | + bool WindowOwned; | |
| 292 | + bool SwapChainNeedRebuild; // Flag when viewport swapchain resized in the middle of processing a frame | |
| 293 | + bool SwapChainSuboptimal; // Flag when VK_SUBOPTIMAL_KHR was returned. | |
| 294 | + | |
| 295 | + ImGui_ImplVulkan_ViewportData() { WindowOwned = SwapChainNeedRebuild = SwapChainSuboptimal = false; memset((void*)&RenderBuffers, 0, sizeof(RenderBuffers)); } | |
| 296 | + ~ImGui_ImplVulkan_ViewportData() { } | |
| 297 | +}; | |
| 298 | + | |
| 275 | 299 | // Vulkan data |
| 276 | 300 | struct ImGui_ImplVulkan_Data |
| 277 | 301 | { |
| @@ -284,6 +308,7 @@ | ||
| 284 | 308 | VkDescriptorSetLayout DescriptorSetLayoutSampler; |
| 285 | 309 | VkPipelineLayout PipelineLayout; |
| 286 | 310 | VkPipeline Pipeline; // pipeline for main render pass (created by app) |
| 311 | + VkPipeline PipelineForViewports; // pipeline for secondary viewports (created by backend) | |
| 287 | 312 | VkShaderModule ShaderModuleVert; |
| 288 | 313 | VkShaderModule ShaderModuleFrag; |
| 289 | 314 | VkDescriptorPool DescriptorPool; |
| @@ -312,6 +337,10 @@ | ||
| 312 | 337 | // SHADERS |
| 313 | 338 | //----------------------------------------------------------------------------- |
| 314 | 339 | |
| 340 | +// Forward Declarations | |
| 341 | +static void ImGui_ImplVulkan_InitMultiViewportSupport(); | |
| 342 | +static void ImGui_ImplVulkan_ShutdownMultiViewportSupport(); | |
| 343 | + | |
| 315 | 344 | // backends/vulkan/glsl_shader.vert, compiled with: |
| 316 | 345 | // # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert |
| 317 | 346 | /* |
| @@ -537,9 +566,18 @@ | ||
| 537 | 566 | |
| 538 | 567 | // Draw callbacks |
| 539 | 568 | static void ImGui_ImplVulkan_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way. |
| 540 | -static void ImGui_ImplVulkan_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); } | |
| 541 | -static void ImGui_ImplVulkan_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerNearestDS, 0, nullptr); } | |
| 569 | +static void ImGui_ImplVulkan_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->RenderState->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); } | |
| 570 | +static void ImGui_ImplVulkan_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->RenderState->PipelineLayout, 1, 1, &bd->SamplerNearestDS, 0, nullptr); } | |
| 542 | 571 | |
| 572 | +// If you want to use your own sampler, you can create your own callback, access ImGui_ImplVulkan_RenderState for command-buffer and pipeline layout, e.g. | |
| 573 | +/* | |
| 574 | +void ImGui_ImplVulkan_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd) | |
| 575 | +{ | |
| 576 | + ImGui_ImplVulkan_RenderState* render_state = (ImGui_ImplVulkan_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; | |
| 577 | + vkCmdBindDescriptorSets(render_state->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, render_state->PipelineLayout, 1, 1, (VkDescriptorSet*)cmd->UserCallbackData, 0, nullptr); | |
| 578 | +} | |
| 579 | +*/ | |
| 580 | + | |
| 543 | 581 | // Render function |
| 544 | 582 | void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline) |
| 545 | 583 | { |
| @@ -561,8 +599,10 @@ | ||
| 561 | 599 | if (pipeline == VK_NULL_HANDLE) |
| 562 | 600 | pipeline = bd->Pipeline; |
| 563 | 601 | |
| 564 | - // Allocate array to store enough vertex/index buffers | |
| 565 | - ImGui_ImplVulkan_WindowRenderBuffers* wrb = &bd->MainWindowRenderBuffers; | |
| 602 | + // Allocate array to store enough vertex/index buffers. Each unique viewport gets its own storage. | |
| 603 | + ImGui_ImplVulkan_ViewportData* viewport_renderer_data = (ImGui_ImplVulkan_ViewportData*)draw_data->OwnerViewport->RendererUserData; | |
| 604 | + IM_ASSERT(viewport_renderer_data != nullptr); | |
| 605 | + ImGui_ImplVulkan_WindowRenderBuffers* wrb = &viewport_renderer_data->RenderBuffers; | |
| 566 | 606 | if (wrb->FrameRenderBuffers.Size == 0) |
| 567 | 607 | { |
| 568 | 608 | wrb->Index = 0; |
| @@ -1252,7 +1292,7 @@ | ||
| 1252 | 1292 | { |
| 1253 | 1293 | ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); |
| 1254 | 1294 | ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; |
| 1255 | - ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator); | |
| 1295 | + ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(v->Device, v->Allocator); | |
| 1256 | 1296 | |
| 1257 | 1297 | // Destroy all textures |
| 1258 | 1298 | for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) |
| @@ -1269,6 +1309,7 @@ | ||
| 1269 | 1309 | if (bd->DescriptorSetLayoutSampler) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayoutSampler, v->Allocator); bd->DescriptorSetLayoutSampler = VK_NULL_HANDLE; } |
| 1270 | 1310 | if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; } |
| 1271 | 1311 | if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; } |
| 1312 | + if (bd->PipelineForViewports) { vkDestroyPipeline(v->Device, bd->PipelineForViewports, v->Allocator); bd->PipelineForViewports = VK_NULL_HANDLE; } | |
| 1272 | 1313 | if (bd->DescriptorPool) { vkDestroyDescriptorPool(v->Device, bd->DescriptorPool, v->Allocator); bd->DescriptorPool = VK_NULL_HANDLE; } |
| 1273 | 1314 | } |
| 1274 | 1315 | |
| @@ -1361,6 +1402,7 @@ | ||
| 1361 | 1402 | io.BackendRendererName = "imgui_impl_vulkan"; |
| 1362 | 1403 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. |
| 1363 | 1404 | io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. |
| 1405 | + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) | |
| 1364 | 1406 | |
| 1365 | 1407 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 1366 | 1408 | platform_io.DrawCallback_ResetRenderState = ImGui_ImplVulkan_DrawCallback_ResetRenderState; |
| @@ -1379,7 +1421,7 @@ | ||
| 1379 | 1421 | else |
| 1380 | 1422 | IM_ASSERT(info->DescriptorPoolSize > 0); |
| 1381 | 1423 | if (info->UseDynamicRendering) |
| 1382 | - IM_ASSERT(info->PipelineInfoMain.RenderPass == VK_NULL_HANDLE); | |
| 1424 | + IM_ASSERT(info->PipelineInfoMain.RenderPass == VK_NULL_HANDLE && info->PipelineInfoForViewports.RenderPass == VK_NULL_HANDLE); | |
| 1383 | 1425 | |
| 1384 | 1426 | bd->VulkanInitInfo = *info; |
| 1385 | 1427 | |
| @@ -1390,6 +1432,12 @@ | ||
| 1390 | 1432 | if (!ImGui_ImplVulkan_CreateDeviceObjects()) |
| 1391 | 1433 | IM_ASSERT(0 && "ImGui_ImplVulkan_CreateDeviceObjects() failed!"); // <- Can't be hit yet. |
| 1392 | 1434 | |
| 1435 | + // Our render function expect RendererUserData to be storing the window render buffer we need (for the main viewport we won't use ->Window) | |
| 1436 | + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | |
| 1437 | + main_viewport->RendererUserData = IM_NEW(ImGui_ImplVulkan_ViewportData)(); | |
| 1438 | + | |
| 1439 | + ImGui_ImplVulkan_InitMultiViewportSupport(); | |
| 1440 | + | |
| 1393 | 1441 | return true; |
| 1394 | 1442 | } |
| 1395 | 1443 | |
| @@ -1400,11 +1448,21 @@ | ||
| 1400 | 1448 | ImGuiIO& io = ImGui::GetIO(); |
| 1401 | 1449 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 1402 | 1450 | |
| 1451 | + // First destroy objects in all viewports | |
| 1403 | 1452 | ImGui_ImplVulkan_DestroyDeviceObjects(); |
| 1404 | 1453 | |
| 1454 | + // Manually delete main viewport render data in-case we haven't initialized for viewports | |
| 1455 | + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | |
| 1456 | + if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)main_viewport->RendererUserData) | |
| 1457 | + IM_DELETE(vd); | |
| 1458 | + main_viewport->RendererUserData = nullptr; | |
| 1459 | + | |
| 1460 | + // Clean up windows | |
| 1461 | + ImGui_ImplVulkan_ShutdownMultiViewportSupport(); | |
| 1462 | + | |
| 1405 | 1463 | io.BackendRendererName = nullptr; |
| 1406 | 1464 | io.BackendRendererUserData = nullptr; |
| 1407 | - io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); | |
| 1465 | + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports); | |
| 1408 | 1466 | platform_io.ClearRendererHandlers(); |
| 1409 | 1467 | IM_DELETE(bd); |
| 1410 | 1468 | } |
| @@ -1423,10 +1481,12 @@ | ||
| 1423 | 1481 | if (bd->VulkanInitInfo.MinImageCount == min_image_count) |
| 1424 | 1482 | return; |
| 1425 | 1483 | |
| 1484 | + IM_ASSERT(0); // FIXME-VIEWPORT: Unsupported. Need to recreate all swap chains! | |
| 1426 | 1485 | ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; |
| 1427 | 1486 | VkResult err = vkDeviceWaitIdle(v->Device); |
| 1428 | 1487 | check_vk_result(err); |
| 1429 | - ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator); | |
| 1488 | + ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(v->Device, v->Allocator); | |
| 1489 | + | |
| 1430 | 1490 | bd->VulkanInitInfo.MinImageCount = min_image_count; |
| 1431 | 1491 | } |
| 1432 | 1492 | |
| @@ -1711,8 +1771,6 @@ | ||
| 1711 | 1771 | wd->ImageCount = 0; |
| 1712 | 1772 | if (wd->RenderPass) |
| 1713 | 1773 | vkDestroyRenderPass(device, wd->RenderPass, allocator); |
| 1714 | - if (wd->Pipeline) | |
| 1715 | - vkDestroyPipeline(device, wd->Pipeline, allocator); | |
| 1716 | 1774 | |
| 1717 | 1775 | // If min image count was not specified, request different count of images dependent on selected present mode |
| 1718 | 1776 | if (min_image_count == 0) |
| @@ -1956,7 +2014,6 @@ | ||
| 1956 | 2014 | ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator); |
| 1957 | 2015 | wd->Frames.clear(); |
| 1958 | 2016 | wd->FrameSemaphores.clear(); |
| 1959 | - vkDestroyPipeline(device, wd->Pipeline, allocator); | |
| 1960 | 2017 | vkDestroyRenderPass(device, wd->RenderPass, allocator); |
| 1961 | 2018 | vkDestroySwapchainKHR(device, wd->Swapchain, allocator); |
| 1962 | 2019 | wd->RenderPass = VK_NULL_HANDLE; |
| @@ -1984,6 +2041,333 @@ | ||
| 1984 | 2041 | vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator); |
| 1985 | 2042 | vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator); |
| 1986 | 2043 | fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE; |
| 2044 | +} | |
| 2045 | + | |
| 2046 | +void ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(VkDevice device, const VkAllocationCallbacks* allocator) | |
| 2047 | +{ | |
| 2048 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 2049 | + for (int n = 0; n < platform_io.Viewports.Size; n++) | |
| 2050 | + if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)platform_io.Viewports[n]->RendererUserData) | |
| 2051 | + ImGui_ImplVulkan_DestroyWindowRenderBuffers(device, &vd->RenderBuffers, allocator); | |
| 2052 | +} | |
| 2053 | + | |
| 2054 | +ImGui_ImplVulkanH_Window* ImGui_ImplVulkanH_GetWindowDataFromViewport(ImGuiViewport* viewport) | |
| 2055 | +{ | |
| 2056 | + ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData; | |
| 2057 | + return vd ? &vd->Window : nullptr; | |
| 2058 | +} | |
| 2059 | + | |
| 2060 | +//-------------------------------------------------------------------------------------------------------- | |
| 2061 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 2062 | +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. | |
| 2063 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 2064 | +//-------------------------------------------------------------------------------------------------------- | |
| 2065 | + | |
| 2066 | +static void ImGui_ImplVulkan_CreateWindow(ImGuiViewport* viewport) | |
| 2067 | +{ | |
| 2068 | + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); | |
| 2069 | + ImGui_ImplVulkan_ViewportData* vd = IM_NEW(ImGui_ImplVulkan_ViewportData)(); | |
| 2070 | + ImGui_ImplVulkanH_Window* wd = &vd->Window; | |
| 2071 | + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; | |
| 2072 | + | |
| 2073 | + // Create surface | |
| 2074 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 2075 | + VkResult err = (VkResult)platform_io.Platform_CreateVkSurface(viewport, (ImU64)v->Instance, (const void*)v->Allocator, (ImU64*)&wd->Surface); | |
| 2076 | + check_vk_result(err); | |
| 2077 | + | |
| 2078 | + // Check if surface creation failed | |
| 2079 | + if (err != VK_SUCCESS || wd->Surface == VK_NULL_HANDLE) | |
| 2080 | + { | |
| 2081 | + IM_DELETE(vd); | |
| 2082 | + return; | |
| 2083 | + } | |
| 2084 | + | |
| 2085 | + // Check for WSI support | |
| 2086 | + VkBool32 res; | |
| 2087 | + vkGetPhysicalDeviceSurfaceSupportKHR(v->PhysicalDevice, v->QueueFamily, wd->Surface, &res); | |
| 2088 | + if (res != VK_TRUE) | |
| 2089 | + { | |
| 2090 | + vkDestroySurfaceKHR(v->Instance, wd->Surface, v->Allocator); // Error: no WSI support on physical device, clean up and return | |
| 2091 | + IM_DELETE(vd); | |
| 2092 | + return; | |
| 2093 | + } | |
| 2094 | + viewport->RendererUserData = vd; | |
| 2095 | + | |
| 2096 | + // Select Surface Format | |
| 2097 | + ImGui_ImplVulkan_PipelineInfo* pipeline_info = &v->PipelineInfoForViewports; | |
| 2098 | + ImVector<VkFormat> requestSurfaceImageFormats; | |
| 2099 | +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING | |
| 2100 | + for (uint32_t n = 0; n < pipeline_info->PipelineRenderingCreateInfo.colorAttachmentCount; n++) | |
| 2101 | + requestSurfaceImageFormats.push_back(pipeline_info->PipelineRenderingCreateInfo.pColorAttachmentFormats[n]); | |
| 2102 | +#endif | |
| 2103 | + const VkFormat defaultFormats[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM }; | |
| 2104 | + for (VkFormat format : defaultFormats) | |
| 2105 | + requestSurfaceImageFormats.push_back(format); | |
| 2106 | + | |
| 2107 | + const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; | |
| 2108 | + wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(v->PhysicalDevice, wd->Surface, requestSurfaceImageFormats.Data, requestSurfaceImageFormats.Size, requestSurfaceColorSpace); | |
| 2109 | + | |
| 2110 | + // Select Present Mode | |
| 2111 | + // FIXME-VULKAN: Even thought mailbox seems to get us maximum framerate with a single window, it halves framerate with a second window etc. (w/ Nvidia and SDK 1.82.1) | |
| 2112 | + VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR }; | |
| 2113 | + wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(v->PhysicalDevice, wd->Surface, &present_modes[0], IM_COUNTOF(present_modes)); | |
| 2114 | + //printf("[vulkan] Secondary window selected PresentMode = %d\n", wd->PresentMode); | |
| 2115 | + | |
| 2116 | + // Create SwapChain, RenderPass, Framebuffer, etc. | |
| 2117 | + wd->UseDynamicRendering = v->UseDynamicRendering; | |
| 2118 | + wd->AttachmentDesc.loadOp = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_LOAD_OP_CLEAR; | |
| 2119 | + ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount, pipeline_info->SwapChainImageUsage); | |
| 2120 | + vd->WindowOwned = true; | |
| 2121 | + | |
| 2122 | + // Create pipeline (shared by all secondary viewports) | |
| 2123 | + if (bd->PipelineForViewports == VK_NULL_HANDLE) | |
| 2124 | + { | |
| 2125 | +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING | |
| 2126 | + if (wd->UseDynamicRendering) | |
| 2127 | + { | |
| 2128 | + pipeline_info->PipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; | |
| 2129 | + pipeline_info->PipelineRenderingCreateInfo.colorAttachmentCount = 1; | |
| 2130 | + pipeline_info->PipelineRenderingCreateInfo.pColorAttachmentFormats = &wd->SurfaceFormat.format; | |
| 2131 | + } | |
| 2132 | + else | |
| 2133 | + { | |
| 2134 | + pipeline_info->RenderPass = wd->RenderPass; | |
| 2135 | + } | |
| 2136 | +#endif | |
| 2137 | + bd->PipelineForViewports = ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, VK_NULL_HANDLE, &v->PipelineInfoForViewports); | |
| 2138 | + } | |
| 2139 | +} | |
| 2140 | + | |
| 2141 | +static void ImGui_ImplVulkan_DestroyWindow(ImGuiViewport* viewport) | |
| 2142 | +{ | |
| 2143 | + // The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it. | |
| 2144 | + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); | |
| 2145 | + if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData) | |
| 2146 | + { | |
| 2147 | + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; | |
| 2148 | + if (vd->WindowOwned) | |
| 2149 | + { | |
| 2150 | + ImGui_ImplVulkanH_DestroyWindow(v->Instance, v->Device, &vd->Window, v->Allocator); | |
| 2151 | + vkDestroySurfaceKHR(v->Instance, vd->Window.Surface, v->Allocator); | |
| 2152 | + } | |
| 2153 | + ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &vd->RenderBuffers, v->Allocator); | |
| 2154 | + IM_DELETE(vd); | |
| 2155 | + } | |
| 2156 | + viewport->RendererUserData = nullptr; | |
| 2157 | +} | |
| 2158 | + | |
| 2159 | +static void ImGui_ImplVulkan_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) | |
| 2160 | +{ | |
| 2161 | + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); | |
| 2162 | + ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData; | |
| 2163 | + if (vd == nullptr) // This is nullptr for the main viewport (which is left to the user/app to handle) | |
| 2164 | + return; | |
| 2165 | + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; | |
| 2166 | + ImGui_ImplVulkanH_Window* wd = &vd->Window; | |
| 2167 | + wd->AttachmentDesc.loadOp = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : VK_ATTACHMENT_LOAD_OP_CLEAR; | |
| 2168 | + ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, &vd->Window, v->QueueFamily, v->Allocator, (int)size.x, (int)size.y, v->MinImageCount, v->PipelineInfoForViewports.SwapChainImageUsage); | |
| 2169 | +} | |
| 2170 | + | |
| 2171 | +static void ImGui_ImplVulkan_RenderWindow(ImGuiViewport* viewport, void*) | |
| 2172 | +{ | |
| 2173 | + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); | |
| 2174 | + ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData; | |
| 2175 | + if (vd == nullptr) | |
| 2176 | + return; | |
| 2177 | + ImGui_ImplVulkanH_Window* wd = &vd->Window; | |
| 2178 | + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; | |
| 2179 | + VkResult err; | |
| 2180 | + | |
| 2181 | + if (vd->SwapChainNeedRebuild || vd->SwapChainSuboptimal) | |
| 2182 | + { | |
| 2183 | + ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount, v->PipelineInfoForViewports.SwapChainImageUsage); | |
| 2184 | + vd->SwapChainNeedRebuild = vd->SwapChainSuboptimal = false; | |
| 2185 | + } | |
| 2186 | + | |
| 2187 | + ImGui_ImplVulkanH_Frame* fd = nullptr; | |
| 2188 | + ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex]; | |
| 2189 | + { | |
| 2190 | + { | |
| 2191 | + err = vkAcquireNextImageKHR(v->Device, wd->Swapchain, UINT64_MAX, fsd->ImageAcquiredSemaphore, VK_NULL_HANDLE, &wd->FrameIndex); | |
| 2192 | + if (err == VK_ERROR_OUT_OF_DATE_KHR) | |
| 2193 | + { | |
| 2194 | + vd->SwapChainNeedRebuild = true; // Since we are not going to swap this frame anyway, it's ok that recreation happens on next frame. | |
| 2195 | + return; | |
| 2196 | + } | |
| 2197 | + if (err == VK_SUBOPTIMAL_KHR) | |
| 2198 | + vd->SwapChainSuboptimal = true; | |
| 2199 | + else | |
| 2200 | + check_vk_result(err); | |
| 2201 | + fd = &wd->Frames[wd->FrameIndex]; | |
| 2202 | + } | |
| 2203 | + for (;;) | |
| 2204 | + { | |
| 2205 | + err = vkWaitForFences(v->Device, 1, &fd->Fence, VK_TRUE, 100); | |
| 2206 | + if (err == VK_SUCCESS) break; | |
| 2207 | + if (err == VK_TIMEOUT) continue; | |
| 2208 | + check_vk_result(err); | |
| 2209 | + } | |
| 2210 | + { | |
| 2211 | + err = vkResetCommandPool(v->Device, fd->CommandPool, 0); | |
| 2212 | + check_vk_result(err); | |
| 2213 | + VkCommandBufferBeginInfo info = {}; | |
| 2214 | + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; | |
| 2215 | + info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; | |
| 2216 | + err = vkBeginCommandBuffer(fd->CommandBuffer, &info); | |
| 2217 | + check_vk_result(err); | |
| 2218 | + } | |
| 2219 | + { | |
| 2220 | + ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); | |
| 2221 | + memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float)); | |
| 2222 | + } | |
| 2223 | +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING | |
| 2224 | + if (v->UseDynamicRendering) | |
| 2225 | + { | |
| 2226 | + // Transition swapchain image to a layout suitable for drawing. | |
| 2227 | + VkImageMemoryBarrier barrier = {}; | |
| 2228 | + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; | |
| 2229 | + barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; | |
| 2230 | + barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; | |
| 2231 | + barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | |
| 2232 | + barrier.image = fd->Backbuffer; | |
| 2233 | + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | |
| 2234 | + barrier.subresourceRange.levelCount = 1; | |
| 2235 | + barrier.subresourceRange.layerCount = 1; | |
| 2236 | + vkCmdPipelineBarrier(fd->CommandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_NONE, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier); | |
| 2237 | + | |
| 2238 | + VkRenderingAttachmentInfo attachmentInfo = {}; | |
| 2239 | + attachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; | |
| 2240 | + attachmentInfo.imageView = fd->BackbufferView; | |
| 2241 | + attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | |
| 2242 | + attachmentInfo.resolveMode = VK_RESOLVE_MODE_NONE; | |
| 2243 | + attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; | |
| 2244 | + attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; | |
| 2245 | + attachmentInfo.clearValue = wd->ClearValue; | |
| 2246 | + | |
| 2247 | + VkRenderingInfo renderingInfo = {}; | |
| 2248 | + renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR; | |
| 2249 | + renderingInfo.renderArea.extent.width = wd->Width; | |
| 2250 | + renderingInfo.renderArea.extent.height = wd->Height; | |
| 2251 | + renderingInfo.layerCount = 1; | |
| 2252 | + renderingInfo.viewMask = 0; | |
| 2253 | + renderingInfo.colorAttachmentCount = 1; | |
| 2254 | + renderingInfo.pColorAttachments = &attachmentInfo; | |
| 2255 | + | |
| 2256 | + ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR(fd->CommandBuffer, &renderingInfo); | |
| 2257 | + } | |
| 2258 | + else | |
| 2259 | +#endif | |
| 2260 | + { | |
| 2261 | + VkRenderPassBeginInfo info = {}; | |
| 2262 | + info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; | |
| 2263 | + info.renderPass = wd->RenderPass; | |
| 2264 | + info.framebuffer = fd->Framebuffer; | |
| 2265 | + info.renderArea.extent.width = wd->Width; | |
| 2266 | + info.renderArea.extent.height = wd->Height; | |
| 2267 | + info.clearValueCount = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? 0 : 1; | |
| 2268 | + info.pClearValues = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? nullptr : &wd->ClearValue; | |
| 2269 | + vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE); | |
| 2270 | + } | |
| 2271 | + } | |
| 2272 | + | |
| 2273 | + ImGui_ImplVulkan_RenderDrawData(viewport->DrawData, fd->CommandBuffer, bd->PipelineForViewports); | |
| 2274 | + | |
| 2275 | + { | |
| 2276 | +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING | |
| 2277 | + if (v->UseDynamicRendering) | |
| 2278 | + { | |
| 2279 | + ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR(fd->CommandBuffer); | |
| 2280 | + | |
| 2281 | + // Transition image to a layout suitable for presentation | |
| 2282 | + VkImageMemoryBarrier barrier = {}; | |
| 2283 | + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; | |
| 2284 | + barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; | |
| 2285 | + barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | |
| 2286 | + barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; | |
| 2287 | + barrier.image = fd->Backbuffer; | |
| 2288 | + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | |
| 2289 | + barrier.subresourceRange.levelCount = 1; | |
| 2290 | + barrier.subresourceRange.layerCount = 1; | |
| 2291 | + vkCmdPipelineBarrier(fd->CommandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier); | |
| 2292 | + } | |
| 2293 | + else | |
| 2294 | +#endif | |
| 2295 | + { | |
| 2296 | + vkCmdEndRenderPass(fd->CommandBuffer); | |
| 2297 | + } | |
| 2298 | + { | |
| 2299 | + VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; | |
| 2300 | + VkSubmitInfo info = {}; | |
| 2301 | + info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; | |
| 2302 | + info.waitSemaphoreCount = 1; | |
| 2303 | + info.pWaitSemaphores = &fsd->ImageAcquiredSemaphore; | |
| 2304 | + info.pWaitDstStageMask = &wait_stage; | |
| 2305 | + info.commandBufferCount = 1; | |
| 2306 | + info.pCommandBuffers = &fd->CommandBuffer; | |
| 2307 | + info.signalSemaphoreCount = 1; | |
| 2308 | + info.pSignalSemaphores = &fsd->RenderCompleteSemaphore; | |
| 2309 | + | |
| 2310 | + err = vkEndCommandBuffer(fd->CommandBuffer); | |
| 2311 | + check_vk_result(err); | |
| 2312 | + err = vkResetFences(v->Device, 1, &fd->Fence); | |
| 2313 | + check_vk_result(err); | |
| 2314 | + err = vkQueueSubmit(v->Queue, 1, &info, fd->Fence); | |
| 2315 | + check_vk_result(err); | |
| 2316 | + } | |
| 2317 | + } | |
| 2318 | +} | |
| 2319 | + | |
| 2320 | +static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*) | |
| 2321 | +{ | |
| 2322 | + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); | |
| 2323 | + ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData; | |
| 2324 | + if (vd == nullptr) | |
| 2325 | + return; | |
| 2326 | + ImGui_ImplVulkanH_Window* wd = &vd->Window; | |
| 2327 | + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; | |
| 2328 | + | |
| 2329 | + if (vd->SwapChainNeedRebuild) // Frame data became invalid in the middle of rendering | |
| 2330 | + return; | |
| 2331 | + | |
| 2332 | + VkResult err; | |
| 2333 | + uint32_t present_index = wd->FrameIndex; | |
| 2334 | + | |
| 2335 | + ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex]; | |
| 2336 | + VkPresentInfoKHR info = {}; | |
| 2337 | + info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; | |
| 2338 | + info.waitSemaphoreCount = 1; | |
| 2339 | + info.pWaitSemaphores = &fsd->RenderCompleteSemaphore; | |
| 2340 | + info.swapchainCount = 1; | |
| 2341 | + info.pSwapchains = &wd->Swapchain; | |
| 2342 | + info.pImageIndices = &present_index; | |
| 2343 | + err = vkQueuePresentKHR(v->Queue, &info); | |
| 2344 | + if (err == VK_ERROR_OUT_OF_DATE_KHR) | |
| 2345 | + { | |
| 2346 | + vd->SwapChainNeedRebuild = true; | |
| 2347 | + return; | |
| 2348 | + } | |
| 2349 | + if (err == VK_SUBOPTIMAL_KHR) | |
| 2350 | + vd->SwapChainSuboptimal = true; | |
| 2351 | + else | |
| 2352 | + check_vk_result(err); | |
| 2353 | + wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores | |
| 2354 | +} | |
| 2355 | + | |
| 2356 | +void ImGui_ImplVulkan_InitMultiViewportSupport() | |
| 2357 | +{ | |
| 2358 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 2359 | + if (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_PlatformHasViewports) | |
| 2360 | + IM_ASSERT(platform_io.Platform_CreateVkSurface != nullptr && "Platform needs to setup the CreateVkSurface handler."); | |
| 2361 | + platform_io.Renderer_CreateWindow = ImGui_ImplVulkan_CreateWindow; | |
| 2362 | + platform_io.Renderer_DestroyWindow = ImGui_ImplVulkan_DestroyWindow; | |
| 2363 | + platform_io.Renderer_SetWindowSize = ImGui_ImplVulkan_SetWindowSize; | |
| 2364 | + platform_io.Renderer_RenderWindow = ImGui_ImplVulkan_RenderWindow; | |
| 2365 | + platform_io.Renderer_SwapBuffers = ImGui_ImplVulkan_SwapBuffers; | |
| 2366 | +} | |
| 2367 | + | |
| 2368 | +void ImGui_ImplVulkan_ShutdownMultiViewportSupport() | |
| 2369 | +{ | |
| 2370 | + ImGui::DestroyPlatformWindows(); | |
| 1987 | 2371 | } |
| 1988 | 2372 | |
| 1989 | 2373 | //----------------------------------------------------------------------------- |
| @@ -6,6 +6,7 @@ | ||
| 6 | 6 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 7 | 7 | // [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). |
| 8 | 8 | // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. |
| 9 | +// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport). | |
| 9 | 10 | |
| 10 | 11 | // The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. |
| 11 | 12 | // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ |
| @@ -84,13 +85,19 @@ | ||
| 84 | 85 | // Specify settings to create pipeline and swapchain |
| 85 | 86 | struct ImGui_ImplVulkan_PipelineInfo |
| 86 | 87 | { |
| 88 | + // For Main viewport only | |
| 87 | 89 | VkRenderPass RenderPass; // Ignored if using dynamic rendering |
| 90 | + | |
| 91 | + // For Main and Secondary viewports | |
| 88 | 92 | uint32_t Subpass; // |
| 89 | 93 | VkSampleCountFlagBits MSAASamples = {}; // 0 defaults to VK_SAMPLE_COUNT_1_BIT |
| 90 | 94 | ImVector<VkDynamicState> ExtraDynamicStates; // Optional, allows to insert more dynamic states into our VkPipeline |
| 91 | 95 | #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING |
| 92 | 96 | VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; // Optional, valid if .sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR |
| 93 | 97 | #endif |
| 98 | + | |
| 99 | + // For Secondary viewports only (created/managed by backend) | |
| 100 | + VkImageUsageFlags SwapChainImageUsage; // Extra flags for vkCreateSwapchainKHR() calls for secondary viewports. We automatically add VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT. You can add e.g. VK_IMAGE_USAGE_TRANSFER_SRC_BIT if you need to capture from viewports. | |
| 94 | 101 | }; |
| 95 | 102 | |
| 96 | 103 | // Initialization data, for ImGui_ImplVulkan_Init() |
| @@ -117,13 +124,14 @@ | ||
| 117 | 124 | |
| 118 | 125 | // Pipeline |
| 119 | 126 | ImGui_ImplVulkan_PipelineInfo PipelineInfoMain; // Infos for Main Viewport (created by app/user) |
| 127 | + ImGui_ImplVulkan_PipelineInfo PipelineInfoForViewports; // Infos for Secondary Viewports (created by backend) | |
| 120 | 128 | //VkRenderPass RenderPass; // --> Since 2025/09/26: set 'PipelineInfoMain.RenderPass' instead |
| 121 | 129 | //uint32_t Subpass; // --> Since 2025/09/26: set 'PipelineInfoMain.Subpass' instead |
| 122 | 130 | //VkSampleCountFlagBits MSAASamples; // --> Since 2025/09/26: set 'PipelineInfoMain.MSAASamples' instead |
| 123 | 131 | //VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; // Since 2025/09/26: set 'PipelineInfoMain.PipelineRenderingCreateInfo' instead |
| 124 | 132 | |
| 125 | 133 | // (Optional) Dynamic Rendering |
| 126 | - // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3 + setup PipelineInfoMain.PipelineRenderingCreateInfo. | |
| 134 | + // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3 + setup PipelineInfoMain.PipelineRenderingCreateInfo and PipelineInfoViewports.PipelineRenderingCreateInfo. | |
| 127 | 135 | bool UseDynamicRendering; |
| 128 | 136 | |
| 129 | 137 | // (Optional) Allocation, Debugging |
| @@ -167,6 +175,7 @@ | ||
| 167 | 175 | |
| 168 | 176 | // [BETA] Selected render state data shared with callbacks. |
| 169 | 177 | // This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplVulkan_RenderDrawData() call. |
| 178 | +// ImGui_ImplVulkan_RenderState* render_state = (ImGui_ImplVulkan_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; | |
| 170 | 179 | // (Please open an issue if you feel you need access to more data) |
| 171 | 180 | struct ImGui_ImplVulkan_RenderState |
| 172 | 181 | { |
| @@ -207,6 +216,7 @@ | ||
| 207 | 216 | IMGUI_IMPL_API VkPhysicalDevice ImGui_ImplVulkanH_SelectPhysicalDevice(VkInstance instance); |
| 208 | 217 | IMGUI_IMPL_API uint32_t ImGui_ImplVulkanH_SelectQueueFamilyIndex(VkPhysicalDevice physical_device); |
| 209 | 218 | IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode); |
| 219 | +IMGUI_IMPL_API ImGui_ImplVulkanH_Window* ImGui_ImplVulkanH_GetWindowDataFromViewport(ImGuiViewport* viewport); // Access to Vulkan objects associated with a viewport (e.g to export a screenshot) | |
| 210 | 220 | |
| 211 | 221 | // Helper structure to hold the data needed by one rendering frame |
| 212 | 222 | // (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.) |
| @@ -244,7 +254,6 @@ | ||
| 244 | 254 | int Height; |
| 245 | 255 | VkSwapchainKHR Swapchain; |
| 246 | 256 | VkRenderPass RenderPass; |
| 247 | - VkPipeline Pipeline; // The window pipeline may uses a different VkRenderPass than the one passed in ImGui_ImplVulkan_InitInfo | |
| 248 | 257 | uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount) |
| 249 | 258 | uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count) |
| 250 | 259 | uint32_t SemaphoreCount; // Number of simultaneous in-flight frames + 1, to be able to use it in vkAcquireNextImageKHR |
| @@ -7,6 +7,8 @@ | ||
| 7 | 7 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 8 | 8 | // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. |
| 9 | 9 | // [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). |
| 10 | +// Missing features or Issues: | |
| 11 | +// [ ] Renderer: Multi-viewport support (multiple windows), useful for desktop. | |
| 10 | 12 | |
| 11 | 13 | // Read imgui_impl_wgpu.h about how to use the IMGUI_IMPL_WEBGPU_BACKEND_WGPU or IMGUI_IMPL_WEBGPU_BACKEND_DAWN flags. |
| 12 | 14 |
| @@ -19,6 +19,8 @@ | ||
| 19 | 19 | // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). |
| 20 | 20 | // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. |
| 21 | 21 | // [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). |
| 22 | +// Missing features or Issues: | |
| 23 | +// [ ] Renderer: Multi-viewport support (multiple windows), useful for desktop. | |
| 22 | 24 | |
| 23 | 25 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 24 | 26 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -7,6 +7,7 @@ | ||
| 7 | 7 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5] |
| 8 | 8 | // [X] Platform: Gamepad support. |
| 9 | 9 | // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. |
| 10 | +// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 10 | 11 | |
| 11 | 12 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 12 | 13 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -21,14 +22,24 @@ | ||
| 21 | 22 | |
| 22 | 23 | // CHANGELOG |
| 23 | 24 | // (minor and older changes stripped away, please see git history for details) |
| 25 | +// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. | |
| 26 | +// 2026-05-19: DPI: ImGui_ImplWin32_EnableDpiAwareness() helper uses SetProcessDpiAwarenessContext() instead of SetThreadDpiAwarenessContext(), fixes DPI scaling issues with e.g. OpenGL. (#9403) | |
| 27 | +// 2026-03-31: [Viewports] Fixed setting/getting size when viewports have OS decorations (e.g. io.ConfigViewportsNoDecoration = false) and process is running in Per-Monitor V2 DPI mode. (#8897) | |
| 24 | 28 | // 2026-01-28: Inputs: Minor optimization not submitting gamepad input if packet number has not changed (reworked from 2025-09-23 attempt). (#9202, #8556) |
| 29 | +// 2026-01-26: [Viewports] Fixed an issue from 1.90.5 where newly appearing windows that are not parented to the main viewport don't have task bar icon appear before the windows was explicited refocused. (#7354, #8669) | |
| 25 | 30 | // 2025-12-03: Inputs: handle WM_IME_CHAR/WM_IME_COMPOSITION messages to support Unicode inputs on MBCS (non-Unicode) Windows. (#9099, #3653, #5961) |
| 26 | 31 | // 2025-10-19: Inputs: Revert previous change to allow for io.ClearInputKeys() on focus-out not losing gamepad state. |
| 27 | 32 | // 2025-09-23: Inputs: Minor optimization not submitting gamepad input if packet number has not changed. |
| 28 | 33 | // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. |
| 34 | +// 2025-06-02: [Viewports] WM_DPICHANGED also apply io.ConfigDpiScaleViewports for main viewport instead of letting it be done by application code. | |
| 29 | 35 | // 2025-04-30: Inputs: Fixed an issue where externally losing mouse capture (due to e.g. focus loss) would fail to claim it again the next subsequent click. (#8594) |
| 36 | +// 2025-03-26: [Viewports] Viewports: fixed an issue when closing a window from the OS close button (with io.ConfigViewportsNoDecoration = false) while user code was discarding the 'bool* p_open = false' output from Begin(). Because we allowed the Win32 window to close early, Windows destroyed it and our imgui window became not visible even though user code was still submitting it. | |
| 30 | 37 | // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) |
| 38 | +// 2025-02-21: [Viewports] WM_SETTINGCHANGE's SPI_SETWORKAREA message also triggers a refresh of monitor list. (#8415) | |
| 31 | 39 | // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. |
| 40 | +// 2024-11-21: [Viewports] Fixed a crash when multiple processes are running with multi-viewports, caused by misusage of GetProp(). (#8162, #8069) | |
| 41 | +// 2024-10-28: [Viewports] Rely on property stored inside HWND to retrieve context/viewport, should facilitate attempt to use this for parallel contexts. (#8069) | |
| 42 | +// 2024-09-16: [Viewports] Inputs: fixed an issue where a viewport destroyed while clicking would hog mouse tracking and temporary lead to incorrect update of HoveredWindow. (#7971) | |
| 32 | 43 | // 2024-07-08: Inputs: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. (#7768) |
| 33 | 44 | // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys. |
| 34 | 45 | // 2023-09-25: Inputs: Synthesize key-down event on key-up for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit it (same behavior as GLFW/SDL). |
| @@ -99,6 +110,7 @@ | ||
| 99 | 110 | typedef DWORD(WINAPI* PFN_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*); |
| 100 | 111 | typedef DWORD(WINAPI* PFN_XInputGetState)(DWORD, XINPUT_STATE*); |
| 101 | 112 | #endif |
| 113 | +typedef BOOL(WINAPI* PFN_AdjustWindowRectExForDpi)(LPRECT, DWORD, BOOL, DWORD, UINT); | |
| 102 | 114 | |
| 103 | 115 | // Clang/GCC warnings with -Weverything |
| 104 | 116 | #if defined(__clang__) |
| @@ -111,6 +123,12 @@ | ||
| 111 | 123 | #pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader) |
| 112 | 124 | #endif |
| 113 | 125 | |
| 126 | +// Forward Declarations | |
| 127 | +static void ImGui_ImplWin32_InitMultiViewportSupport(bool platform_has_own_dc); | |
| 128 | +static void ImGui_ImplWin32_ShutdownMultiViewportSupport(); | |
| 129 | +static void ImGui_ImplWin32_UpdateMonitors(); | |
| 130 | +static bool ImGui_ImplWin32_IsDpiAwarenessPerMonitorAwareV2(); | |
| 131 | + | |
| 114 | 132 | struct ImGui_ImplWin32_Data |
| 115 | 133 | { |
| 116 | 134 | HWND hWnd; |
| @@ -121,6 +139,9 @@ | ||
| 121 | 139 | INT64 TicksPerSecond; |
| 122 | 140 | ImGuiMouseCursor LastMouseCursor; |
| 123 | 141 | UINT32 KeyboardCodePage; |
| 142 | + bool WantUpdateMonitors; | |
| 143 | + bool IsPerMonitorDpiAwareV2; | |
| 144 | + PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi; | |
| 124 | 145 | |
| 125 | 146 | #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD |
| 126 | 147 | bool HasGamepad; |
| @@ -176,6 +197,9 @@ | ||
| 176 | 197 | io.BackendPlatformName = "imgui_impl_win32"; |
| 177 | 198 | io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) |
| 178 | 199 | io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) |
| 200 | + io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) | |
| 201 | + io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional) | |
| 202 | + io.BackendFlags |= ImGuiBackendFlags_HasParentViewport; // We can honor viewport->ParentViewportId by applying the corresponding parent/child relationship at platform levle (optional) | |
| 179 | 203 | |
| 180 | 204 | bd->hWnd = (HWND)hwnd; |
| 181 | 205 | bd->TicksPerSecond = perf_frequency; |
| @@ -183,11 +207,22 @@ | ||
| 183 | 207 | bd->LastMouseCursor = ImGuiMouseCursor_COUNT; |
| 184 | 208 | ImGui_ImplWin32_UpdateKeyboardCodePage(io); |
| 185 | 209 | |
| 210 | + // Update monitor a first time during init | |
| 211 | + ImGui_ImplWin32_UpdateMonitors(); | |
| 212 | + | |
| 186 | 213 | // Our mouse update function expect PlatformHandle to be filled for the main viewport |
| 187 | 214 | ImGuiViewport* main_viewport = ImGui::GetMainViewport(); |
| 188 | 215 | main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (void*)bd->hWnd; |
| 189 | - IM_UNUSED(platform_has_own_dc); // Used in 'docking' branch | |
| 190 | 216 | |
| 217 | + // Be aware that GetPropA()/SetPropA() may be accessed from other processes. | |
| 218 | + // So as we store a pointer in IMGUI_CONTEXT we need to make sure we only call GetPropA() on windows owned by our process. | |
| 219 | + ::SetPropA(bd->hWnd, "IMGUI_CONTEXT", ImGui::GetCurrentContext()); | |
| 220 | + ImGui_ImplWin32_InitMultiViewportSupport(platform_has_own_dc); | |
| 221 | + | |
| 222 | + if (HINSTANCE user32_dll = ::GetModuleHandleA("user32.dll")) | |
| 223 | + bd->AdjustWindowRectExForDpi = (PFN_AdjustWindowRectExForDpi)::GetProcAddress(user32_dll, "AdjustWindowRectExForDpi"); | |
| 224 | + bd->IsPerMonitorDpiAwareV2 = ImGui_ImplWin32_IsDpiAwarenessPerMonitorAwareV2(); | |
| 225 | + | |
| 191 | 226 | // Dynamically load XInput library |
| 192 | 227 | #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD |
| 193 | 228 | bd->WantUpdateHasGamepad = true; |
| @@ -230,6 +265,9 @@ | ||
| 230 | 265 | ImGuiIO& io = ImGui::GetIO(); |
| 231 | 266 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 232 | 267 | |
| 268 | + ::SetPropA(bd->hWnd, "IMGUI_CONTEXT", nullptr); | |
| 269 | + ImGui_ImplWin32_ShutdownMultiViewportSupport(); | |
| 270 | + | |
| 233 | 271 | // Unload XInput library |
| 234 | 272 | #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD |
| 235 | 273 | if (bd->XInputDLL) |
| @@ -238,7 +276,7 @@ | ||
| 238 | 276 | |
| 239 | 277 | io.BackendPlatformName = nullptr; |
| 240 | 278 | io.BackendPlatformUserData = nullptr; |
| 241 | - io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad); | |
| 279 | + io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport | ImGuiBackendFlags_HasParentViewport); | |
| 242 | 280 | platform_io.ClearPlatformHandlers(); |
| 243 | 281 | IM_DELETE(bd); |
| 244 | 282 | } |
| @@ -311,32 +349,69 @@ | ||
| 311 | 349 | io.AddKeyEvent(ImGuiMod_Super, IsVkDown(VK_LWIN) || IsVkDown(VK_RWIN)); |
| 312 | 350 | } |
| 313 | 351 | |
| 314 | -static void ImGui_ImplWin32_UpdateMouseData(ImGuiIO& io) | |
| 352 | +static ImGuiViewport* ImGui_ImplWin32_FindViewportByPlatformHandle(ImGuiPlatformIO& platform_io, HWND hwnd) | |
| 315 | 353 | { |
| 354 | + // We cannot use ImGui::FindViewportByPlatformHandle() because it doesn't take a context. | |
| 355 | + // When called from ImGui_ImplWin32_WndProcHandler_PlatformWindow() we don't assume that context is bound. | |
| 356 | + //return ImGui::FindViewportByPlatformHandle((void*)hwnd); | |
| 357 | + for (ImGuiViewport* viewport : platform_io.Viewports) | |
| 358 | + if (viewport->PlatformHandle == hwnd) | |
| 359 | + return viewport; | |
| 360 | + return nullptr; | |
| 361 | +} | |
| 362 | + | |
| 363 | +// This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports) | |
| 364 | +// Because of that, it is a little more complicated than your typical single-viewport binding code! | |
| 365 | +static void ImGui_ImplWin32_UpdateMouseData(ImGuiIO& io, ImGuiPlatformIO& platform_io) | |
| 366 | +{ | |
| 316 | 367 | ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); |
| 317 | 368 | IM_ASSERT(bd->hWnd != 0); |
| 318 | 369 | |
| 370 | + POINT mouse_screen_pos; | |
| 371 | + bool has_mouse_screen_pos = ::GetCursorPos(&mouse_screen_pos) != 0; | |
| 372 | + | |
| 319 | 373 | HWND focused_window = ::GetForegroundWindow(); |
| 320 | - const bool is_app_focused = (focused_window == bd->hWnd); | |
| 374 | + const bool is_app_focused = (focused_window && (focused_window == bd->hWnd || ::IsChild(focused_window, bd->hWnd) || ImGui_ImplWin32_FindViewportByPlatformHandle(platform_io, focused_window))); | |
| 321 | 375 | if (is_app_focused) |
| 322 | 376 | { |
| 323 | 377 | // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user) |
| 378 | + // When multi-viewports are enabled, all Dear ImGui positions are same as OS positions. | |
| 324 | 379 | if (io.WantSetMousePos) |
| 325 | 380 | { |
| 326 | 381 | POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y }; |
| 327 | - if (::ClientToScreen(bd->hWnd, &pos)) | |
| 328 | - ::SetCursorPos(pos.x, pos.y); | |
| 382 | + if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) == 0) | |
| 383 | + ::ClientToScreen(focused_window, &pos); | |
| 384 | + ::SetCursorPos(pos.x, pos.y); | |
| 329 | 385 | } |
| 330 | 386 | |
| 331 | 387 | // (Optional) Fallback to provide mouse position when focused (WM_MOUSEMOVE already provides this when hovered or captured) |
| 332 | 388 | // This also fills a short gap when clicking non-client area: WM_NCMOUSELEAVE -> modal OS move -> gap -> WM_NCMOUSEMOVE |
| 333 | - if (!io.WantSetMousePos && bd->MouseTrackedArea == 0) | |
| 389 | + if (!io.WantSetMousePos && bd->MouseTrackedArea == 0 && has_mouse_screen_pos) | |
| 334 | 390 | { |
| 335 | - POINT pos; | |
| 336 | - if (::GetCursorPos(&pos) && ::ScreenToClient(bd->hWnd, &pos)) | |
| 337 | - io.AddMousePosEvent((float)pos.x, (float)pos.y); | |
| 391 | + // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) | |
| 392 | + // (This is the position you can get with ::GetCursorPos() + ::ScreenToClient() or WM_MOUSEMOVE.) | |
| 393 | + // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) | |
| 394 | + // (This is the position you can get with ::GetCursorPos() or WM_MOUSEMOVE + ::ClientToScreen(). In theory adding viewport->Pos to a client position would also be the same.) | |
| 395 | + POINT mouse_pos = mouse_screen_pos; | |
| 396 | + if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)) | |
| 397 | + ::ScreenToClient(bd->hWnd, &mouse_pos); | |
| 398 | + io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y); | |
| 338 | 399 | } |
| 339 | 400 | } |
| 401 | + | |
| 402 | + // (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering. | |
| 403 | + // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic. | |
| 404 | + // - [X] Win32 backend correctly ignore viewports with the _NoInputs flag (here using ::WindowFromPoint with WM_NCHITTEST + HTTRANSPARENT in WndProc does that) | |
| 405 | + // Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window | |
| 406 | + // for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported | |
| 407 | + // by the backend, and use its flawed heuristic to guess the viewport behind. | |
| 408 | + // - [X] Win32 backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target). | |
| 409 | + ImGuiID mouse_viewport_id = 0; | |
| 410 | + if (has_mouse_screen_pos) | |
| 411 | + if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos)) | |
| 412 | + if (ImGuiViewport* viewport = ImGui_ImplWin32_FindViewportByPlatformHandle(platform_io, hovered_hwnd)) | |
| 413 | + mouse_viewport_id = viewport->ID; | |
| 414 | + io.AddMouseViewportEvent(mouse_viewport_id); | |
| 340 | 415 | } |
| 341 | 416 | |
| 342 | 417 | // Gamepad navigation mapping |
| @@ -398,16 +473,50 @@ | ||
| 398 | 473 | #endif |
| 399 | 474 | } |
| 400 | 475 | |
| 476 | +static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc(HMONITOR monitor, HDC, LPRECT, LPARAM) | |
| 477 | +{ | |
| 478 | + MONITORINFO info = {}; | |
| 479 | + info.cbSize = sizeof(MONITORINFO); | |
| 480 | + if (!::GetMonitorInfo(monitor, &info)) | |
| 481 | + return TRUE; | |
| 482 | + ImGuiPlatformMonitor imgui_monitor; | |
| 483 | + imgui_monitor.MainPos = ImVec2((float)info.rcMonitor.left, (float)info.rcMonitor.top); | |
| 484 | + imgui_monitor.MainSize = ImVec2((float)(info.rcMonitor.right - info.rcMonitor.left), (float)(info.rcMonitor.bottom - info.rcMonitor.top)); | |
| 485 | + imgui_monitor.WorkPos = ImVec2((float)info.rcWork.left, (float)info.rcWork.top); | |
| 486 | + imgui_monitor.WorkSize = ImVec2((float)(info.rcWork.right - info.rcWork.left), (float)(info.rcWork.bottom - info.rcWork.top)); | |
| 487 | + imgui_monitor.DpiScale = ImGui_ImplWin32_GetDpiScaleForMonitor(monitor); | |
| 488 | + imgui_monitor.PlatformHandle = (void*)monitor; | |
| 489 | + if (imgui_monitor.DpiScale <= 0.0f) | |
| 490 | + return TRUE; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902. | |
| 491 | + ImGuiPlatformIO& io = ImGui::GetPlatformIO(); | |
| 492 | + if (info.dwFlags & MONITORINFOF_PRIMARY) | |
| 493 | + io.Monitors.push_front(imgui_monitor); | |
| 494 | + else | |
| 495 | + io.Monitors.push_back(imgui_monitor); | |
| 496 | + return TRUE; | |
| 497 | +} | |
| 498 | + | |
| 499 | +static void ImGui_ImplWin32_UpdateMonitors() | |
| 500 | +{ | |
| 501 | + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); | |
| 502 | + ImGui::GetPlatformIO().Monitors.resize(0); | |
| 503 | + ::EnumDisplayMonitors(nullptr, nullptr, ImGui_ImplWin32_UpdateMonitors_EnumFunc, 0); | |
| 504 | + bd->WantUpdateMonitors = false; | |
| 505 | +} | |
| 506 | + | |
| 401 | 507 | void ImGui_ImplWin32_NewFrame() |
| 402 | 508 | { |
| 403 | 509 | ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); |
| 404 | 510 | IM_ASSERT(bd != nullptr && "Context or backend not initialized? Did you call ImGui_ImplWin32_Init()?"); |
| 405 | 511 | ImGuiIO& io = ImGui::GetIO(); |
| 512 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 406 | 513 | |
| 407 | 514 | // Setup display size (every frame to accommodate for window resizing) |
| 408 | 515 | RECT rect = { 0, 0, 0, 0 }; |
| 409 | 516 | ::GetClientRect(bd->hWnd, &rect); |
| 410 | 517 | io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); |
| 518 | + if (bd->WantUpdateMonitors) | |
| 519 | + ImGui_ImplWin32_UpdateMonitors(); | |
| 411 | 520 | |
| 412 | 521 | // Setup time step |
| 413 | 522 | INT64 current_time = 0; |
| @@ -416,7 +525,7 @@ | ||
| 416 | 525 | bd->Time = current_time; |
| 417 | 526 | |
| 418 | 527 | // Update OS mouse position |
| 419 | - ImGui_ImplWin32_UpdateMouseData(io); | |
| 528 | + ImGui_ImplWin32_UpdateMouseData(io, platform_io); | |
| 420 | 529 | |
| 421 | 530 | // Process workarounds for known Windows key handling issues |
| 422 | 531 | ImGui_ImplWin32_ProcessKeyEventsWorkarounds(io); |
| @@ -621,6 +730,10 @@ | ||
| 621 | 730 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Use ImGui::GetCurrentContext() |
| 622 | 731 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, ImGuiIO& io); // Doesn't use ImGui::GetCurrentContext() |
| 623 | 732 | |
| 733 | +#ifndef WM_DPICHANGED | |
| 734 | +#define WM_DPICHANGED 0x02E0 // From Windows SDK 8.1+ headers | |
| 735 | +#endif | |
| 736 | + | |
| 624 | 737 | IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) |
| 625 | 738 | { |
| 626 | 739 | // Most backends don't have silent checks like this one, but we need it because WndProc are called early in CreateWindow(). |
| @@ -655,8 +768,11 @@ | ||
| 655 | 768 | bd->MouseTrackedArea = area; |
| 656 | 769 | } |
| 657 | 770 | POINT mouse_pos = { (LONG)GET_X_LPARAM(lParam), (LONG)GET_Y_LPARAM(lParam) }; |
| 658 | - if (msg == WM_NCMOUSEMOVE) // WM_NCMOUSEMOVE are absolute coordinates. | |
| 659 | - ::ScreenToClient(hwnd, &mouse_pos); | |
| 771 | + bool want_absolute_pos = (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) != 0; | |
| 772 | + if (msg == WM_MOUSEMOVE && want_absolute_pos) // WM_MOUSEMOVE are client-relative coordinates. | |
| 773 | + ::ClientToScreen(hwnd, &mouse_pos); | |
| 774 | + if (msg == WM_NCMOUSEMOVE && !want_absolute_pos) // WM_NCMOUSEMOVE are absolute coordinates. | |
| 775 | + ::ScreenToClient(hwnd, &mouse_pos); | |
| 660 | 776 | io.AddMouseSourceEvent(mouse_source); |
| 661 | 777 | io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y); |
| 662 | 778 | return 0; |
| @@ -826,7 +942,22 @@ | ||
| 826 | 942 | bd->WantUpdateHasGamepad = true; |
| 827 | 943 | #endif |
| 828 | 944 | return 0; |
| 945 | + case WM_DISPLAYCHANGE: | |
| 946 | + bd->WantUpdateMonitors = true; | |
| 947 | + return 0; | |
| 948 | + case WM_SETTINGCHANGE: | |
| 949 | + if (wParam == SPI_SETWORKAREA) | |
| 950 | + bd->WantUpdateMonitors = true; | |
| 951 | + return 0; | |
| 952 | + case WM_DPICHANGED: | |
| 953 | + { | |
| 954 | + // FIXME-DPI: see SDL3's WM_GETDPISCALEDSIZE handler. | |
| 955 | + const RECT* suggested_rect = (RECT*)lParam; | |
| 956 | + if (io.ConfigDpiScaleViewports) | |
| 957 | + ::SetWindowPos(hwnd, nullptr, suggested_rect->left, suggested_rect->top, suggested_rect->right - suggested_rect->left, suggested_rect->bottom - suggested_rect->top, SWP_NOZORDER | SWP_NOACTIVATE); | |
| 958 | + return 0; | |
| 829 | 959 | } |
| 960 | + } | |
| 830 | 961 | return 0; |
| 831 | 962 | } |
| 832 | 963 | |
| @@ -883,18 +1014,30 @@ | ||
| 883 | 1014 | #ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 |
| 884 | 1015 | #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4 |
| 885 | 1016 | #endif |
| 886 | -typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib + dll, Windows 8.1+ | |
| 887 | -typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib + dll, Windows 8.1+ | |
| 888 | -typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update) | |
| 1017 | +typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib + dll, Windows 8.1+ | |
| 1018 | +typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib + dll, Windows 8.1+ | |
| 1019 | +typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update) | |
| 1020 | +typedef BOOL (WINAPI* PFN_SetProcessDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1703+ (Creators Update) | |
| 1021 | +typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_GetThreadDpiAwarenessContext)(); // " | |
| 1022 | +typedef BOOL(WINAPI* PFN_AreDpiAwarenessContextsEqual)(DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT); // " | |
| 889 | 1023 | |
| 890 | 1024 | // Helper function to enable DPI awareness without setting up a manifest |
| 891 | 1025 | void ImGui_ImplWin32_EnableDpiAwareness() |
| 892 | 1026 | { |
| 1027 | + // Make sure monitors will be updated with latest correct scaling | |
| 1028 | + if (ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData()) | |
| 1029 | + bd->WantUpdateMonitors = true; | |
| 1030 | + | |
| 893 | 1031 | if (_IsWindows10OrGreater()) |
| 894 | 1032 | { |
| 895 | 1033 | static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process |
| 896 | - if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext")) | |
| 1034 | + if (PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContextFn = (PFN_SetProcessDpiAwarenessContext)::GetProcAddress(user32_dll, "SetProcessDpiAwarenessContext")) // Windows 10 v1703+ | |
| 897 | 1035 | { |
| 1036 | + SetProcessDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); | |
| 1037 | + return; | |
| 1038 | + } | |
| 1039 | + if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext")) // Windows 10 v1607+ | |
| 1040 | + { | |
| 898 | 1041 | SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); |
| 899 | 1042 | return; |
| 900 | 1043 | } |
| @@ -913,6 +1056,18 @@ | ||
| 913 | 1056 | #endif |
| 914 | 1057 | } |
| 915 | 1058 | |
| 1059 | +static bool ImGui_ImplWin32_IsDpiAwarenessPerMonitorAwareV2() | |
| 1060 | +{ | |
| 1061 | + if (!_IsWindows10OrGreater()) | |
| 1062 | + return false; | |
| 1063 | + static HINSTANCE user32_dll = ::GetModuleHandleA("user32.dll"); | |
| 1064 | + PFN_GetThreadDpiAwarenessContext GetThreadDpiAwarenessContextFn = (PFN_GetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "GetThreadDpiAwarenessContext"); | |
| 1065 | + PFN_AreDpiAwarenessContextsEqual AreDpiAwarenessContextsEqualFn = (PFN_AreDpiAwarenessContextsEqual)::GetProcAddress(user32_dll, "AreDpiAwarenessContextsEqual"); | |
| 1066 | + if (GetThreadDpiAwarenessContextFn && AreDpiAwarenessContextsEqualFn) | |
| 1067 | + return AreDpiAwarenessContextsEqualFn(GetThreadDpiAwarenessContextFn(), DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) != 0; | |
| 1068 | + return false; | |
| 1069 | +} | |
| 1070 | + | |
| 916 | 1071 | #if defined(_MSC_VER) && !defined(NOGDI) |
| 917 | 1072 | #pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps(). MinGW will require linking with '-lgdi32' |
| 918 | 1073 | #endif |
| @@ -987,6 +1142,398 @@ | ||
| 987 | 1142 | bb.dwFlags = DWM_BB_ENABLE; |
| 988 | 1143 | ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb); |
| 989 | 1144 | } |
| 1145 | +} | |
| 1146 | + | |
| 1147 | +//--------------------------------------------------------------------------------------------------------- | |
| 1148 | +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT | |
| 1149 | +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. | |
| 1150 | +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. | |
| 1151 | +//-------------------------------------------------------------------------------------------------------- | |
| 1152 | + | |
| 1153 | +// Helper structure we store in the void* PlatformUserData field of each ImGuiViewport to easily retrieve our backend data. | |
| 1154 | +struct ImGui_ImplWin32_ViewportData | |
| 1155 | +{ | |
| 1156 | + HWND Hwnd; // Stored in ImGuiViewport::PlatformHandle + PlatformHandleRaw | |
| 1157 | + HWND HwndParent; | |
| 1158 | + bool HwndOwned; | |
| 1159 | + DWORD DwStyle; | |
| 1160 | + DWORD DwExStyle; | |
| 1161 | + | |
| 1162 | + ImGui_ImplWin32_ViewportData() { Hwnd = HwndParent = nullptr; HwndOwned = false; DwStyle = DwExStyle = 0; } | |
| 1163 | + ~ImGui_ImplWin32_ViewportData() { IM_ASSERT(Hwnd == nullptr); } | |
| 1164 | +}; | |
| 1165 | + | |
| 1166 | +static void ImGui_ImplWin32_GetWin32StyleFromViewportFlags(ImGuiViewportFlags flags, DWORD* out_style, DWORD* out_ex_style) | |
| 1167 | +{ | |
| 1168 | + if (flags & ImGuiViewportFlags_NoDecoration) | |
| 1169 | + *out_style = WS_POPUP; | |
| 1170 | + else | |
| 1171 | + *out_style = WS_OVERLAPPEDWINDOW; | |
| 1172 | + | |
| 1173 | + if (flags & ImGuiViewportFlags_NoTaskBarIcon) | |
| 1174 | + *out_ex_style = WS_EX_TOOLWINDOW; | |
| 1175 | + else | |
| 1176 | + *out_ex_style = WS_EX_APPWINDOW; | |
| 1177 | + | |
| 1178 | + if (flags & ImGuiViewportFlags_TopMost) | |
| 1179 | + *out_ex_style |= WS_EX_TOPMOST; | |
| 1180 | +} | |
| 1181 | + | |
| 1182 | +static HWND ImGui_ImplWin32_GetHwndFromViewport(ImGuiViewport* viewport) | |
| 1183 | +{ | |
| 1184 | + if (viewport != nullptr) | |
| 1185 | + return (HWND)viewport->PlatformHandle; | |
| 1186 | + return nullptr; | |
| 1187 | +} | |
| 1188 | + | |
| 1189 | +static void ImGui_ImplWin32_AdjustWindowRect(ImGuiViewport* viewport, RECT* rect, DWORD style, DWORD ex_style) | |
| 1190 | +{ | |
| 1191 | + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); | |
| 1192 | + if (bd->AdjustWindowRectExForDpi && bd->IsPerMonitorDpiAwareV2) | |
| 1193 | + { | |
| 1194 | + UINT dpi = (UINT)(viewport->DpiScale * 96.0f + 0.5f); | |
| 1195 | + if (dpi != 0 && bd->AdjustWindowRectExForDpi(rect, style, FALSE, ex_style, dpi)) | |
| 1196 | + return; | |
| 1197 | + } | |
| 1198 | + ::AdjustWindowRectEx(rect, style, FALSE, ex_style); | |
| 1199 | +} | |
| 1200 | + | |
| 1201 | +static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport) | |
| 1202 | +{ | |
| 1203 | + ImGui_ImplWin32_ViewportData* vd = IM_NEW(ImGui_ImplWin32_ViewportData)(); | |
| 1204 | + viewport->PlatformUserData = vd; | |
| 1205 | + | |
| 1206 | + // Select style and parent window | |
| 1207 | + ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &vd->DwStyle, &vd->DwExStyle); | |
| 1208 | + vd->HwndParent = ImGui_ImplWin32_GetHwndFromViewport(viewport->ParentViewport); | |
| 1209 | + | |
| 1210 | + // Create window | |
| 1211 | + RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) }; | |
| 1212 | + ImGui_ImplWin32_AdjustWindowRect(viewport, &rect, vd->DwStyle, vd->DwExStyle); | |
| 1213 | + vd->Hwnd = ::CreateWindowExW( | |
| 1214 | + vd->DwExStyle, L"ImGui Platform", L"Untitled", vd->DwStyle, // Style, class name, window name | |
| 1215 | + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area | |
| 1216 | + vd->HwndParent, nullptr, ::GetModuleHandle(nullptr), nullptr); // Owner window, Menu, Instance, Param | |
| 1217 | + vd->HwndOwned = true; | |
| 1218 | + viewport->PlatformRequestResize = false; | |
| 1219 | + viewport->PlatformHandle = viewport->PlatformHandleRaw = vd->Hwnd; | |
| 1220 | + | |
| 1221 | + // Secondary viewports store their imgui context | |
| 1222 | + ::SetPropA(vd->Hwnd, "IMGUI_CONTEXT", ImGui::GetCurrentContext()); | |
| 1223 | +} | |
| 1224 | + | |
| 1225 | +static void ImGui_ImplWin32_DestroyWindow(ImGuiViewport* viewport) | |
| 1226 | +{ | |
| 1227 | + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); | |
| 1228 | + if (ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData) | |
| 1229 | + { | |
| 1230 | + if (::GetCapture() == vd->Hwnd) | |
| 1231 | + { | |
| 1232 | + // Transfer capture so if we started dragging from a window that later disappears, we'll still receive the MOUSEUP event. | |
| 1233 | + ::ReleaseCapture(); | |
| 1234 | + ::SetCapture(bd->hWnd); | |
| 1235 | + } | |
| 1236 | + if (vd->Hwnd && vd->HwndOwned) | |
| 1237 | + ::DestroyWindow(vd->Hwnd); | |
| 1238 | + vd->Hwnd = nullptr; | |
| 1239 | + IM_DELETE(vd); | |
| 1240 | + } | |
| 1241 | + viewport->PlatformUserData = viewport->PlatformHandle = nullptr; | |
| 1242 | +} | |
| 1243 | + | |
| 1244 | +static void ImGui_ImplWin32_ShowWindow(ImGuiViewport* viewport) | |
| 1245 | +{ | |
| 1246 | + ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; | |
| 1247 | + IM_ASSERT(vd->Hwnd != 0); | |
| 1248 | + | |
| 1249 | + // ShowParent() even with SW_SHOWNA also brings parent to front, which is not always desirable, | |
| 1250 | + // so we temporarily disable parenting. (#7354, #8669) | |
| 1251 | + bool avoid_bringing_parent_to_front = vd->HwndParent != NULL && (viewport->Flags & (ImGuiViewportFlags_NoFocusOnAppearing | ImGuiViewportFlags_NoTaskBarIcon)) != 0; | |
| 1252 | + if (avoid_bringing_parent_to_front) | |
| 1253 | + ::SetWindowLongPtr(vd->Hwnd, GWLP_HWNDPARENT, (LONG_PTR)nullptr); | |
| 1254 | + | |
| 1255 | + if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) | |
| 1256 | + ::ShowWindow(vd->Hwnd, SW_SHOWNA); | |
| 1257 | + else | |
| 1258 | + ::ShowWindow(vd->Hwnd, SW_SHOW); | |
| 1259 | + | |
| 1260 | + // Restore | |
| 1261 | + if (avoid_bringing_parent_to_front) | |
| 1262 | + ::SetWindowLongPtr(vd->Hwnd, GWLP_HWNDPARENT, (LONG_PTR)vd->HwndParent); | |
| 1263 | +} | |
| 1264 | + | |
| 1265 | +static void ImGui_ImplWin32_UpdateWindow(ImGuiViewport* viewport) | |
| 1266 | +{ | |
| 1267 | + ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; | |
| 1268 | + IM_ASSERT(vd->Hwnd != 0); | |
| 1269 | + | |
| 1270 | + // Update Win32 parent if it changed _after_ creation | |
| 1271 | + // Unlike style settings derived from configuration flags, this is more likely to change for advanced apps that are manipulating ParentViewportID manually. | |
| 1272 | + HWND new_parent = ImGui_ImplWin32_GetHwndFromViewport(viewport->ParentViewport); | |
| 1273 | + if (new_parent != vd->HwndParent) | |
| 1274 | + { | |
| 1275 | + // Win32 windows can either have a "Parent" (for WS_CHILD window) or an "Owner" (which among other thing keeps window above its owner). | |
| 1276 | + // Our Dear Imgui-side concept of parenting only mostly care about what Win32 call "Owner". | |
| 1277 | + // The parent parameter of CreateWindowEx() sets up Parent OR Owner depending on WS_CHILD flag. In our case an Owner as we never use WS_CHILD. | |
| 1278 | + // Calling ::SetParent() here would be incorrect: it will create a full child relation, alter coordinate system and clipping. | |
| 1279 | + // Calling ::SetWindowLongPtr() with GWLP_HWNDPARENT seems correct although poorly documented. | |
| 1280 | + // https://devblogs.microsoft.com/oldnewthing/20100315-00/?p=14613 | |
| 1281 | + vd->HwndParent = new_parent; | |
| 1282 | + ::SetWindowLongPtr(vd->Hwnd, GWLP_HWNDPARENT, (LONG_PTR)vd->HwndParent); | |
| 1283 | + } | |
| 1284 | + | |
| 1285 | + // (Optional) Update Win32 style if it changed _after_ creation. | |
| 1286 | + // Generally they won't change unless configuration flags are changed, but advanced uses (such as manually rewriting viewport flags) make this useful. | |
| 1287 | + DWORD new_style; | |
| 1288 | + DWORD new_ex_style; | |
| 1289 | + ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &new_style, &new_ex_style); | |
| 1290 | + | |
| 1291 | + // Only reapply the flags that have been changed from our point of view (as other flags are being modified by Windows) | |
| 1292 | + if (vd->DwStyle != new_style || vd->DwExStyle != new_ex_style) | |
| 1293 | + { | |
| 1294 | + // (Optional) Update TopMost state if it changed _after_ creation | |
| 1295 | + bool top_most_changed = (vd->DwExStyle & WS_EX_TOPMOST) != (new_ex_style & WS_EX_TOPMOST); | |
| 1296 | + HWND insert_after = top_most_changed ? ((viewport->Flags & ImGuiViewportFlags_TopMost) ? HWND_TOPMOST : HWND_NOTOPMOST) : 0; | |
| 1297 | + UINT swp_flag = top_most_changed ? 0 : SWP_NOZORDER; | |
| 1298 | + | |
| 1299 | + // Apply flags and position (since it is affected by flags) | |
| 1300 | + vd->DwStyle = new_style; | |
| 1301 | + vd->DwExStyle = new_ex_style; | |
| 1302 | + ::SetWindowLong(vd->Hwnd, GWL_STYLE, vd->DwStyle); | |
| 1303 | + ::SetWindowLong(vd->Hwnd, GWL_EXSTYLE, vd->DwExStyle); | |
| 1304 | + RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) }; | |
| 1305 | + ImGui_ImplWin32_AdjustWindowRect(viewport, &rect, vd->DwStyle, vd->DwExStyle); // Client to Screen | |
| 1306 | + ::SetWindowPos(vd->Hwnd, insert_after, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, swp_flag | SWP_NOACTIVATE | SWP_FRAMECHANGED); | |
| 1307 | + ::ShowWindow(vd->Hwnd, SW_SHOWNA); // This is necessary when we alter the style | |
| 1308 | + viewport->PlatformRequestMove = viewport->PlatformRequestResize = true; | |
| 1309 | + } | |
| 1310 | +} | |
| 1311 | + | |
| 1312 | +static ImVec2 ImGui_ImplWin32_GetWindowPos(ImGuiViewport* viewport) | |
| 1313 | +{ | |
| 1314 | + ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; | |
| 1315 | + IM_ASSERT(vd->Hwnd != 0); | |
| 1316 | + POINT pos = { 0, 0 }; | |
| 1317 | + ::ClientToScreen(vd->Hwnd, &pos); | |
| 1318 | + return ImVec2((float)pos.x, (float)pos.y); | |
| 1319 | +} | |
| 1320 | + | |
| 1321 | +static void ImGui_ImplWin32_UpdateWin32StyleFromWindow(ImGuiViewport* viewport) | |
| 1322 | +{ | |
| 1323 | + ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; | |
| 1324 | + vd->DwStyle = ::GetWindowLongW(vd->Hwnd, GWL_STYLE); | |
| 1325 | + vd->DwExStyle = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE); | |
| 1326 | +} | |
| 1327 | + | |
| 1328 | +static void ImGui_ImplWin32_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos) | |
| 1329 | +{ | |
| 1330 | + ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; | |
| 1331 | + IM_ASSERT(vd->Hwnd != 0); | |
| 1332 | + RECT rect = { (LONG)pos.x, (LONG)pos.y, (LONG)pos.x, (LONG)pos.y }; | |
| 1333 | + if (viewport->Flags & ImGuiViewportFlags_OwnedByApp) | |
| 1334 | + ImGui_ImplWin32_UpdateWin32StyleFromWindow(viewport); // Not our window, poll style before using | |
| 1335 | + ImGui_ImplWin32_AdjustWindowRect(viewport, &rect, vd->DwStyle, vd->DwExStyle); | |
| 1336 | + ::SetWindowPos(vd->Hwnd, nullptr, rect.left, rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); | |
| 1337 | +} | |
| 1338 | + | |
| 1339 | +static ImVec2 ImGui_ImplWin32_GetWindowSize(ImGuiViewport* viewport) | |
| 1340 | +{ | |
| 1341 | + ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; | |
| 1342 | + IM_ASSERT(vd->Hwnd != 0); | |
| 1343 | + RECT rect; | |
| 1344 | + ::GetClientRect(vd->Hwnd, &rect); | |
| 1345 | + return ImVec2(float(rect.right - rect.left), float(rect.bottom - rect.top)); | |
| 1346 | +} | |
| 1347 | + | |
| 1348 | +static void ImGui_ImplWin32_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) | |
| 1349 | +{ | |
| 1350 | + ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; | |
| 1351 | + IM_ASSERT(vd->Hwnd != 0); | |
| 1352 | + RECT rect = { 0, 0, (LONG)size.x, (LONG)size.y }; | |
| 1353 | + if (viewport->Flags & ImGuiViewportFlags_OwnedByApp) | |
| 1354 | + ImGui_ImplWin32_UpdateWin32StyleFromWindow(viewport); // Not our window, poll style before using | |
| 1355 | + ImGui_ImplWin32_AdjustWindowRect(viewport, &rect, vd->DwStyle, vd->DwExStyle); // Client to Screen | |
| 1356 | + ::SetWindowPos(vd->Hwnd, nullptr, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); | |
| 1357 | +} | |
| 1358 | + | |
| 1359 | +static void ImGui_ImplWin32_SetWindowFocus(ImGuiViewport* viewport) | |
| 1360 | +{ | |
| 1361 | + ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; | |
| 1362 | + IM_ASSERT(vd->Hwnd != 0); | |
| 1363 | + ::BringWindowToTop(vd->Hwnd); | |
| 1364 | + ::SetForegroundWindow(vd->Hwnd); | |
| 1365 | + ::SetFocus(vd->Hwnd); | |
| 1366 | +} | |
| 1367 | + | |
| 1368 | +static bool ImGui_ImplWin32_GetWindowFocus(ImGuiViewport* viewport) | |
| 1369 | +{ | |
| 1370 | + ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; | |
| 1371 | + IM_ASSERT(vd->Hwnd != 0); | |
| 1372 | + return ::GetForegroundWindow() == vd->Hwnd; | |
| 1373 | +} | |
| 1374 | + | |
| 1375 | +static bool ImGui_ImplWin32_GetWindowMinimized(ImGuiViewport* viewport) | |
| 1376 | +{ | |
| 1377 | + ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; | |
| 1378 | + IM_ASSERT(vd->Hwnd != 0); | |
| 1379 | + return ::IsIconic(vd->Hwnd) != 0; | |
| 1380 | +} | |
| 1381 | + | |
| 1382 | +static void ImGui_ImplWin32_SetWindowTitle(ImGuiViewport* viewport, const char* title) | |
| 1383 | +{ | |
| 1384 | + // ::SetWindowTextA() doesn't properly handle UTF-8 so we explicitely convert our string. | |
| 1385 | + ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; | |
| 1386 | + IM_ASSERT(vd->Hwnd != 0); | |
| 1387 | + int n = ::MultiByteToWideChar(CP_UTF8, 0, title, -1, nullptr, 0); | |
| 1388 | + ImVector<wchar_t> title_w; | |
| 1389 | + title_w.resize(n); | |
| 1390 | + ::MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w.Data, n); | |
| 1391 | + | |
| 1392 | + // Calling SetWindowTextW() in a project where UNICODE is not set doesn't work but there's a trick | |
| 1393 | + // which is to pass it directly to the DefWindowProcW() handler. | |
| 1394 | + // See: https://stackoverflow.com/questions/9410681/setwindowtextw-in-an-ansi-project | |
| 1395 | + //::SetWindowTextW(vd->Hwnd, title_w.Data); | |
| 1396 | + ::DefWindowProcW(vd->Hwnd, WM_SETTEXT, 0, (LPARAM)title_w.Data); | |
| 1397 | +} | |
| 1398 | + | |
| 1399 | +static void ImGui_ImplWin32_SetWindowAlpha(ImGuiViewport* viewport, float alpha) | |
| 1400 | +{ | |
| 1401 | + ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; | |
| 1402 | + IM_ASSERT(vd->Hwnd != 0); | |
| 1403 | + IM_ASSERT(alpha >= 0.0f && alpha <= 1.0f); | |
| 1404 | + if (alpha < 1.0f) | |
| 1405 | + { | |
| 1406 | + DWORD ex_style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) | WS_EX_LAYERED; | |
| 1407 | + ::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, ex_style); | |
| 1408 | + ::SetLayeredWindowAttributes(vd->Hwnd, 0, (BYTE)(255 * alpha), LWA_ALPHA); | |
| 1409 | + } | |
| 1410 | + else | |
| 1411 | + { | |
| 1412 | + DWORD ex_style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED; | |
| 1413 | + ::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, ex_style); | |
| 1414 | + } | |
| 1415 | +} | |
| 1416 | + | |
| 1417 | +static float ImGui_ImplWin32_GetWindowDpiScale(ImGuiViewport* viewport) | |
| 1418 | +{ | |
| 1419 | + ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData; | |
| 1420 | + IM_ASSERT(vd->Hwnd != 0); | |
| 1421 | + return ImGui_ImplWin32_GetDpiScaleForHwnd(vd->Hwnd); | |
| 1422 | +} | |
| 1423 | + | |
| 1424 | +// FIXME-DPI: Testing DPI related ideas | |
| 1425 | +static void ImGui_ImplWin32_OnChangedViewport(ImGuiViewport* viewport) | |
| 1426 | +{ | |
| 1427 | + (void)viewport; | |
| 1428 | +#if 0 | |
| 1429 | + ImGuiStyle default_style; | |
| 1430 | + //default_style.WindowPadding = ImVec2(0, 0); | |
| 1431 | + //default_style.WindowBorderSize = 0.0f; | |
| 1432 | + //default_style.ItemSpacing.y = 3.0f; | |
| 1433 | + //default_style.FramePadding = ImVec2(0, 0); | |
| 1434 | + default_style.ScaleAllSizes(viewport->DpiScale); | |
| 1435 | + ImGuiStyle& style = ImGui::GetStyle(); | |
| 1436 | + style = default_style; | |
| 1437 | +#endif | |
| 1438 | +} | |
| 1439 | + | |
| 1440 | +namespace ImGui { extern ImGuiIO& GetIO(ImGuiContext*); extern ImGuiPlatformIO& GetPlatformIO(ImGuiContext*); } | |
| 1441 | + | |
| 1442 | +static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) | |
| 1443 | +{ | |
| 1444 | + // Allow secondary viewport WndProc to be called regardless of current context | |
| 1445 | + ImGuiContext* ctx = (ImGuiContext*)::GetPropA(hWnd, "IMGUI_CONTEXT"); | |
| 1446 | + if (ctx == NULL) | |
| 1447 | + return ::DefWindowProcW(hWnd, msg, wParam, lParam); // unlike ImGui_ImplWin32_WndProcHandler() we are called directly by Windows, we can't just return 0. | |
| 1448 | + | |
| 1449 | + ImGuiIO& io = ImGui::GetIO(ctx); | |
| 1450 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(ctx); | |
| 1451 | + LRESULT result = 0; | |
| 1452 | + if (ImGui_ImplWin32_WndProcHandlerEx(hWnd, msg, wParam, lParam, io)) | |
| 1453 | + result = 1; | |
| 1454 | + else if (ImGuiViewport* viewport = ImGui_ImplWin32_FindViewportByPlatformHandle(platform_io, hWnd)) | |
| 1455 | + { | |
| 1456 | + switch (msg) | |
| 1457 | + { | |
| 1458 | + case WM_CLOSE: | |
| 1459 | + viewport->PlatformRequestClose = true; | |
| 1460 | + return 0; // 0 = Operating system will ignore the message and not destroy the window. We close ourselves. | |
| 1461 | + case WM_MOVE: | |
| 1462 | + viewport->PlatformRequestMove = true; | |
| 1463 | + break; | |
| 1464 | + case WM_SIZE: | |
| 1465 | + viewport->PlatformRequestResize = true; | |
| 1466 | + break; | |
| 1467 | + case WM_MOUSEACTIVATE: | |
| 1468 | + if (viewport->Flags & ImGuiViewportFlags_NoFocusOnClick) | |
| 1469 | + result = MA_NOACTIVATE; | |
| 1470 | + break; | |
| 1471 | + case WM_NCHITTEST: | |
| 1472 | + // Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() correctly. (which is optional). | |
| 1473 | + // The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging. | |
| 1474 | + // If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in | |
| 1475 | + // your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system. | |
| 1476 | + if (viewport->Flags & ImGuiViewportFlags_NoInputs) | |
| 1477 | + result = HTTRANSPARENT; | |
| 1478 | + break; | |
| 1479 | + } | |
| 1480 | + } | |
| 1481 | + if (result == 0) | |
| 1482 | + result = ::DefWindowProcW(hWnd, msg, wParam, lParam); | |
| 1483 | + return result; | |
| 1484 | +} | |
| 1485 | + | |
| 1486 | +static void ImGui_ImplWin32_InitMultiViewportSupport(bool platform_has_own_dc) | |
| 1487 | +{ | |
| 1488 | + WNDCLASSEXW wcex; | |
| 1489 | + wcex.cbSize = sizeof(WNDCLASSEXW); | |
| 1490 | + wcex.style = CS_HREDRAW | CS_VREDRAW | (platform_has_own_dc ? CS_OWNDC : 0); | |
| 1491 | + wcex.lpfnWndProc = ImGui_ImplWin32_WndProcHandler_PlatformWindow; | |
| 1492 | + wcex.cbClsExtra = 0; | |
| 1493 | + wcex.cbWndExtra = 0; | |
| 1494 | + wcex.hInstance = ::GetModuleHandle(nullptr); | |
| 1495 | + wcex.hIcon = nullptr; | |
| 1496 | + wcex.hCursor = nullptr; | |
| 1497 | + wcex.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1); | |
| 1498 | + wcex.lpszMenuName = nullptr; | |
| 1499 | + wcex.lpszClassName = L"ImGui Platform"; | |
| 1500 | + wcex.hIconSm = nullptr; | |
| 1501 | + ::RegisterClassExW(&wcex); | |
| 1502 | + | |
| 1503 | + ImGui_ImplWin32_UpdateMonitors(); | |
| 1504 | + | |
| 1505 | + // Register platform interface (will be coupled with a renderer interface) | |
| 1506 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 1507 | + platform_io.Platform_CreateWindow = ImGui_ImplWin32_CreateWindow; | |
| 1508 | + platform_io.Platform_DestroyWindow = ImGui_ImplWin32_DestroyWindow; | |
| 1509 | + platform_io.Platform_ShowWindow = ImGui_ImplWin32_ShowWindow; | |
| 1510 | + platform_io.Platform_SetWindowPos = ImGui_ImplWin32_SetWindowPos; | |
| 1511 | + platform_io.Platform_GetWindowPos = ImGui_ImplWin32_GetWindowPos; | |
| 1512 | + platform_io.Platform_SetWindowSize = ImGui_ImplWin32_SetWindowSize; | |
| 1513 | + platform_io.Platform_GetWindowSize = ImGui_ImplWin32_GetWindowSize; | |
| 1514 | + platform_io.Platform_SetWindowFocus = ImGui_ImplWin32_SetWindowFocus; | |
| 1515 | + platform_io.Platform_GetWindowFocus = ImGui_ImplWin32_GetWindowFocus; | |
| 1516 | + platform_io.Platform_GetWindowMinimized = ImGui_ImplWin32_GetWindowMinimized; | |
| 1517 | + platform_io.Platform_SetWindowTitle = ImGui_ImplWin32_SetWindowTitle; | |
| 1518 | + platform_io.Platform_SetWindowAlpha = ImGui_ImplWin32_SetWindowAlpha; | |
| 1519 | + platform_io.Platform_UpdateWindow = ImGui_ImplWin32_UpdateWindow; | |
| 1520 | + platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale; // FIXME-DPI | |
| 1521 | + platform_io.Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport; // FIXME-DPI | |
| 1522 | + | |
| 1523 | + // Register main window handle (which is owned by the main application, not by us) | |
| 1524 | + // This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports. | |
| 1525 | + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); | |
| 1526 | + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); | |
| 1527 | + ImGui_ImplWin32_ViewportData* vd = IM_NEW(ImGui_ImplWin32_ViewportData)(); | |
| 1528 | + vd->Hwnd = bd->hWnd; | |
| 1529 | + vd->HwndOwned = false; | |
| 1530 | + main_viewport->PlatformUserData = vd; | |
| 1531 | +} | |
| 1532 | + | |
| 1533 | +static void ImGui_ImplWin32_ShutdownMultiViewportSupport() | |
| 1534 | +{ | |
| 1535 | + ::UnregisterClassW(L"ImGui Platform", ::GetModuleHandle(nullptr)); | |
| 1536 | + ImGui::DestroyPlatformWindows(); | |
| 990 | 1537 | } |
| 991 | 1538 | |
| 992 | 1539 | //--------------------------------------------------------------------------------------------------------- |
| @@ -7,6 +7,7 @@ | ||
| 7 | 7 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5] |
| 8 | 8 | // [X] Platform: Gamepad support. |
| 9 | 9 | // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. |
| 10 | +// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 10 | 11 | |
| 11 | 12 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. |
| 12 | 13 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. |
| @@ -183,6 +183,7 @@ | ||
| 183 | 183 | - `ImGuiBackendFlags_HasSetMousePos`: supports io.WantSetMousePos requests to reposition the OS mouse position (only used if io.ConfigNavMoveSetMousePos is set). |
| 184 | 184 | - `ImGuiBackendFlags_PlatformHasViewports` supports multiple viewports. (multi-viewports only) |
| 185 | 185 | - `ImGuiBackendFlags_HasMouseHoveredViewport` supports calling io.AddMouseViewportEvent() with the viewport under the mouse. IF POSSIBLE, ignore viewports with the ImGuiViewportFlags_NoInputs flag. If this cannot be done, Dear ImGui needs to use a flawed heuristic to find the viewport under mouse position, as it doesn't know about foreign windows. (multi-viewports only) |
| 186 | + - `ImGuiBackendFlags_HasParentViewport` supports honoring viewport->ParentViewportId value, by applying the corresponding parent/child relation at the Platform level. | |
| 186 | 187 | |
| 187 | 188 | **In your `ImGui_ImplXXX_NewFrame()` function:** |
| 188 | 189 | - Set `io.DeltaTime` to the time elapsed (in seconds) since last frame. |
| @@ -36,6 +36,110 @@ | ||
| 36 | 36 | - Please report any issue! |
| 37 | 37 | |
| 38 | 38 | ----------------------------------------------------------------------- |
| 39 | + VERSION 1.92.9 WIP (In Progress) | |
| 40 | +----------------------------------------------------------------------- | |
| 41 | + | |
| 42 | +Breaking Changes: | |
| 43 | + | |
| 44 | +- TreeNode: commented out legacy name `ImGuiTreeNodeFlags_SpanTextWidth` which | |
| 45 | + was obsoleted in 1.90.7 (May 2024). Use `ImGuiTreeNodeFlags_SpanLabelWidth`. | |
| 46 | + | |
| 47 | +Other Changes: | |
| 48 | + | |
| 49 | +- Windows: | |
| 50 | + - Clicking on a window's empty-space to move/focus a window checks | |
| 51 | + for lack of mouse button ownership. This gives an additional opportunity | |
| 52 | + for user code to bypass it without using a clickable item. (#9382) | |
| 53 | + - Clicking on a window's empty-space to move/focus a window checks | |
| 54 | + for lack of queued focus request. (#9382) | |
| 55 | + - Fixed double-click collapse toggle not owning the mouse button. If a | |
| 56 | + `SetNextWindowPos()` with pivot was queued in the same frame, the second | |
| 57 | + click could trigger another item in the same window. (#9439) [@Cleroth] | |
| 58 | +- InputText: | |
| 59 | + - Added `style.InputTextCursorSize` to configure cursor/caret thickness. (#7031, #9409) | |
| 60 | + This is automatically scaled by `style.ScaleAllSizes()`. | |
| 61 | +- Tables: | |
| 62 | + - Redesigned/rewrote code to reconcile columns and settings on topology changes. (#9108) | |
| 63 | + - When a column label is passed to TableSetupColumn(), the underlying identifier | |
| 64 | + is used to match live columns data and .ini settings data when changing. | |
| 65 | + This makes it possible to add/remove columns from a table without losing | |
| 66 | + neither live data neither .ini settings data. | |
| 67 | + - PS: Note that this is distinct from toggling column visibility or reordering | |
| 68 | + columns, which was always possible. The new matching makes it easier to create | |
| 69 | + tables that are entirely customized by user or code, without losing state. | |
| 70 | + - Columns without identifiers or with duplicate identifiers are matched | |
| 71 | + sequentially, matching old behavior. | |
| 72 | + - Column ID are stored in .ini file. | |
| 73 | + - Code is being tested both for live topology changes and for loading .ini | |
| 74 | + data with mismatched topology. | |
| 75 | + - Context Menu: added a "Reset" sub-menu with a "Reset Visibility" option. | |
| 76 | + (which is greyed out when using default settings) | |
| 77 | + - Headers: fixed label being clipped early to reserve space for a sort marker | |
| 78 | + even when no sort marker is displayed. Auto-fitting a column still accounts | |
| 79 | + for the possible marker, so that sorting after an auto-fit doesn't clip the label. | |
| 80 | +- Multi-Select | |
| 81 | + - Reworked ImGuiMultiSelectFlags_NoAutoSelect as it carried side-effects that | |
| 82 | + were hardcoded/designed to use multi-selection on checkboxes. (#9391) | |
| 83 | + Specifically removed those undocumented behaviors from _NoAutoSelect: | |
| 84 | + - Clicking a selected/checked item always unselect/uncheck. | |
| 85 | + - Shift+Click inverts targets value and copy to range. | |
| 86 | + - Shift+Keyboard copy selection source value to range. | |
| 87 | + Those behaviors are still happening on checkboxes used within multi-selection. | |
| 88 | +- Fonts: | |
| 89 | + - Added `IMGUI_DISABLE_DEFAULT_FONT_BITMAP`/`IMGUI_DISABLE_DEFAULT_FONT_VECTOR` to | |
| 90 | + disable embedding either fonts separately. (#9407) | |
| 91 | + - Tweak `CalcTextSize()` awkward width rounding/ceiling code to reduce floating-point | |
| 92 | + imprecisions altering the result by 1 even at relatively small width. (#791) | |
| 93 | + - Better document the fact that ImFontAtlas::Clear()/ClearFonts() functions are | |
| 94 | + unlikely to be useful nowadays. Better recover to an edge case of mistakenly | |
| 95 | + calling ClearFonts() during rendering. | |
| 96 | + - Fixed an issue where passing a manually created ImFontAtlas to CreateContext() would | |
| 97 | + incorrectly destroy it in DestroyContext() when ref-count gets back to zero. (#9426) | |
| 98 | +- Nav: | |
| 99 | + - Fixed context menu activation with gamepad erroneously testing for _NavEnableKeyboard | |
| 100 | + instead of _NavEnableGamepad. (#9454, #8803, #9270) [@Clownacy] | |
| 101 | +- TreeNode: | |
| 102 | + - Fixed nav cursor rendering with rounding even though tree nodes don't have it. (#7589) | |
| 103 | +- Style: | |
| 104 | + - Added style.MenuItemRounding, ImGuiStyleVar_MenuItemRounding. (#7589, #9375, #9453) | |
| 105 | + - Added style.SelectableRounding, ImGuiStyleVar_SelectableRounding. (#7589, #9375, #9453) | |
| 106 | + The use of this is discouraged because it can easily create problems rendering e.g. | |
| 107 | + contiguous selection. | |
| 108 | + - Scale the NavCursor border thickness when using large values with `ScallAllSizes()`. | |
| 109 | +- DrawList: | |
| 110 | + - Minor optimization to `AddLine()`, `AddLineH()`, `AddLineV()` functions. (#4091) | |
| 111 | + - Added `ImDrawListFlags_TextNoPixelSnap` to disable snapping of AddText() | |
| 112 | + coordinates for a given scope. (#3437, #9417, #2291) | |
| 113 | +- ColorButton: | |
| 114 | + - Small rendering tweak/optimization for the alpha checkerboard. | |
| 115 | +- Demo: | |
| 116 | + - Extract 'Widgets->Tree Nodes->Selectable Nodes' out of the 'Advanced' | |
| 117 | + demo for clarity (manual reimplementation of basic selection). | |
| 118 | +- Misc: | |
| 119 | + - Added IM_DEBUG_BREAK() handler for GCC+AArch64/ARM64. [@tom-seddon] | |
| 120 | +- Backends: | |
| 121 | + - OpenGL3: | |
| 122 | + - GLSL version detection assume GLSL 410 when GL context is 4.1. | |
| 123 | + Fixes an issue running on macOS with Wine. [#9427, #6577) [@perminovVS] | |
| 124 | + - Expose selected render state in ImGui_ImplOpenGL3_RenderState, allowing to | |
| 125 | + dynamically select between use of glBindSampler() and glTexParameter(). (#9378) | |
| 126 | + - Win32: | |
| 127 | + - Uses `SetProcessDpiAwarenessContext()` instead of `SetThreadDpiAwarenessContext()` | |
| 128 | + when available, fixing OpenGL DPI scaling issues as e.g. NVIDIA drivers tends | |
| 129 | + to spawn multiple-thread to manage OpenGL. (#9403) | |
| 130 | + | |
| 131 | +Docking+Viewports Branch: | |
| 132 | + | |
| 133 | +- Viewports: | |
| 134 | + - Fixed an issue where the implicit "Debug" window while hidden would erroneously | |
| 135 | + interfere with merging secondary viewports into the main viewport. | |
| 136 | +- Docking: | |
| 137 | + - Fixed behavior change/regression in 1.92.8 where a window using the | |
| 138 | + ImGuiWindowFlags_AlwaysAutoResize flag would have ItemWidth default | |
| 139 | + change when docked. (#9355, #9443) [@reybits] | |
| 140 | + | |
| 141 | + | |
| 142 | +----------------------------------------------------------------------- | |
| 39 | 143 | VERSION 1.92.8 (Released 2026-05-12) |
| 40 | 144 | ----------------------------------------------------------------------- |
| 41 | 145 | |
| @@ -64,9 +168,13 @@ | ||
| 64 | 168 | The new order is also more convenient as `flags` are less frequently used than `thickness` in real code. |
| 65 | 169 | - As a general policy in Dear ImGui, all our flags default to 0 so ImDrawFlags_None was likely written 0 in some call sites. |
| 66 | 170 | - Consider adding `#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS` in your imconfig.h, even temporarily, to clean up legacy code. |
| 171 | + - Reminder: you do NOT need to specify `ImDrawFlags_RoundCornersAll` for rounding, it is already the default! | |
| 67 | 172 | - DrawList: obsoleted `ImDrawCallback_ResetRenderState` in favor of using `ImGui::GetPlatformIO().DrawCallback_ResetRenderState`, |
| 68 | 173 | which is part of our new standard draw callbacks. (#9378) |
| 69 | 174 | Redirecting the earlier value into the later one when set, so both old and new code should work. |
| 175 | +- DrawList: changed value of `ImDrawFlags_Closed`. It was previously advertised as "always == 1" when introduced | |
| 176 | + in 1.82 (2021/02), in order to facilitate backward compatibility with the legacy `bool closed` flag. This | |
| 177 | + guarantee has been removed. The bit is reserved, and `AddPolyline()`, `PathStroke()` will assert when it is used. | |
| 70 | 178 | - Backends: |
| 71 | 179 | - Vulkan: redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. (#914) |
| 72 | 180 | This change allows us to facilitate changing samplers, in line with other backends. [@yaz0r, @ocornut] |
| @@ -81,6 +189,8 @@ | ||
| 81 | 189 | - DirectX10, DirectX11, SDLGPU3, Vulkan: removed samplers from `ImGui_ImplXXXX_RenderState`. |
| 82 | 190 | Prefer to use backend-agnostic DrawCallback_SetSamplerLinear which works everywhere! (#9378) |
| 83 | 191 | If there is a legit need/request for them or any render state we can always add them back. |
| 192 | + - OpenGL3: the new sampler support system prioritize using glBindSampler() when available, | |
| 193 | + which would override glTexParameter() settings you may have set on custom textures. (#9378) | |
| 84 | 194 | |
| 85 | 195 | Other Changes: |
| 86 | 196 | |
| @@ -97,6 +207,15 @@ | ||
| 97 | 207 | #5999, #6452, #5156, #7342, #7592, #7511) |
| 98 | 208 | - Made `AddCallback()` user data default to Null for convenience. |
| 99 | 209 | - Added `AddLineH()`, `AddLineV()` helpers to draw horizontal and vertical lines. [@memononen] |
| 210 | + The new functions are more optimal and will be part of a larger effort in 1.93 to fix | |
| 211 | + inconsistencies and improve the DrawList API. In the current API, `AddLine()` adds a "magic" +0.5f | |
| 212 | + offset and then center the line, whereas AddLineH()/AddLineV() use the right side of the line to expand. | |
| 213 | + For thickness=1.0f lines this is equivalent: | |
| 214 | + `AddLine({10,3}, {20,3}, ...)` --> `AddLineH(x1=10, x2=20, y=3, ...)`. | |
| 215 | + `AddLine({3,10}, {3,20}, ...)` --> `AddLineV(x=3, y1=10, y2=20, ...)`. | |
| 216 | + For larger integer thickness, AddLine() will center but may be blurry, AddLineH()/AddLineV() | |
| 217 | + will expand "inside" (to the right side) and will always be sharp. | |
| 218 | + A subsequent release will expand on those concepts and add new options. | |
| 100 | 219 | - InputText: |
| 101 | 220 | - InputTextMultiline: fixed an issue processing deactivation logic when an active |
| 102 | 221 | multi-line edit is clipped due to being out of view. |
| @@ -225,7 +344,15 @@ | ||
| 225 | 344 | - `IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE`. |
| 226 | 345 | - `IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_SAMPLER`. |
| 227 | 346 | |
| 347 | +Docking+Viewports Branch: | |
| 228 | 348 | |
| 349 | +- Docking: | |
| 350 | + - Toggling tab bar visibility marks saved settings as dirty. (#9380) | |
| 351 | +- Viewports: | |
| 352 | + - Added opaque `void* PlatformIconData` storage in viewport and `ImGuiWindowClass` | |
| 353 | + to allow passing icon information to a custom backend or hook. (#2715) | |
| 354 | + | |
| 355 | + | |
| 229 | 356 | ----------------------------------------------------------------------- |
| 230 | 357 | VERSION 1.92.7 (Released 2026-04-02) |
| 231 | 358 | ----------------------------------------------------------------------- |
| @@ -294,7 +421,7 @@ | ||
| 294 | 421 | part of the scroll freeze. So if you intentionally hide columns <N, the scroll |
| 295 | 422 | freeze area would start covering the subsequent/following columns (N+1) etc. |
| 296 | 423 | - After: `TableSetupScrollFreeze(N, 0)`: include the N left-most columns (regardless of visibility), |
| 297 | - as part of the scroll freeze. So if you intentionally hide columns <N, the scroll | |
| 424 | + part of the scroll freeze. So if you intentionally hide columns <N, the scroll as | |
| 298 | 425 | freeze area will cover less columns. |
| 299 | 426 | - This is generally more sane and logical. |
| 300 | 427 | - Fixed dragging a header to reorder outside of visible bounds (due to horizontal scrolling) |
| @@ -390,7 +517,24 @@ | ||
| 390 | 517 | - GLFW/SDL2/SDL3+WebGPU: added support for WGVK. (#9316, #9246, #9257) [@r-lyeh, @ocornut] |
| 391 | 518 | - GLFW/SDL2/SDL3+WebGPU: removed support for Emscripten <4.0.10. (#9281) [@ypujante] |
| 392 | 519 | |
| 520 | +Docking+Viewports Branch: | |
| 393 | 521 | |
| 522 | +- Viewports: | |
| 523 | + - Fixed an issue where the implicit "Debug" window would erroneously be targetted for | |
| 524 | + mouse inputs while hidden if (1) the implicit "Debug" window was used in a previous | |
| 525 | + session and moved to a secondary viewport and (2) the Platform Backend does not | |
| 526 | + support the `ImGuiBackendFlags_HasMouseHoveredViewport` feature. (#9254) | |
| 527 | + - Backends: SDL2, SDL3: fixed an issue dated 2025/04/09 (1.92 WIP) where a refactor | |
| 528 | + and a merge caused `ImGuiBackendFlags_HasMouseHoveredViewport` to never be set, causing | |
| 529 | + foreign windows to be ignored when deciding of hovered viewport. (#9284) [@ravencgg] | |
| 530 | + - Backends: SDL3: use `SDL_HAS_EVENT_DISPLAY_USABLE_BOUNDS_CHANGED` (SDL 3.4.0+) when | |
| 531 | + available to avoid refreshing monitor work area every frame on Windows. (#8415) | |
| 532 | + - Backends: Win32: fixed setting/getting correct size when viewports have OS decorations | |
| 533 | + enabled (e.g. io.ConfigViewportsNoDecoration = false) and process is running in | |
| 534 | + Per-Monitor V2 DPI mode. May be related to incorrect mouse offset when using | |
| 535 | + decorated OS windows. (#8897) [@lailoken] | |
| 536 | + | |
| 537 | + | |
| 394 | 538 | ----------------------------------------------------------------------- |
| 395 | 539 | VERSION 1.92.6 (2026-02-17) |
| 396 | 540 | ----------------------------------------------------------------------- |
| @@ -632,7 +776,38 @@ | ||
| 632 | 776 | - Win32+DirectX12: ignore seemingly incorrect `D3D12_MESSAGE_ID_FENCE_ZERO_WAIT` |
| 633 | 777 | warning on startups on some setups. (#9084, #9093) [@RT2Code, @LeoGautheron] |
| 634 | 778 | |
| 779 | +Docking+Viewports Branch: | |
| 635 | 780 | |
| 781 | +- Docking: | |
| 782 | + - Fixed various rendering issues and ability to have rounded floating dock nodes. | |
| 783 | + (#6993, #6151) - please note that rounding is still disabled on standalone | |
| 784 | + viewports. | |
| 785 | + - Fixed implicit/fallback "Debug" window from staying visible if once docked. (#9151) | |
| 786 | + - Demo: rework 'Dockspace' demo to increase clarity and put more emphasis on the | |
| 787 | + basic path of simply calling `DockSpaceOverViewport()`. | |
| 788 | +- Viewports: | |
| 789 | + - Fixed a regression in 1.92.4 where partially moving a floating docking node | |
| 790 | + with horizontal/vertical split over the main viewport would set the window in | |
| 791 | + an invalid state in some situations, making user unable to further interact | |
| 792 | + with the window. | |
| 793 | + - Fixed a regression in 1.92.4 which could cause combos/popups window from | |
| 794 | + appearing under their parent viewport if their geometry overlapped the main | |
| 795 | + viewport. (#8948, #9172, #9131, #9128) | |
| 796 | + - Fixed an assert in background dimming code, which could trigger after using | |
| 797 | + gamepad/keyboard to move a window to another viewport. (#9053) [@lut0pia, @ocornut] | |
| 798 | +- Backends: | |
| 799 | + - GLFW: dynamically load X11 functions to avoid `-lx11` linking requirement introduced | |
| 800 | + in 1.92.3. (#9116, #9109) [@ramenguy99] | |
| 801 | + - GLFW: improve workarounds for cases where GLFW is unable to provide reliable monitor | |
| 802 | + info. Preserve existing monitor list when none of the new one is valid. (#9195, #7902, #5683) | |
| 803 | + - SDL2, SDL3: adjust IME offset to match other backends and master branch. (#6071, #1953) | |
| 804 | + - Win32: viewports created by backend forcefully direct messages to | |
| 805 | + `DefWindowProcW()` in order to support Unicode text input. (#9099, #3653, #5961) [@ulhc] | |
| 806 | + - Win32: fixed an issue from 1.90.5 where newly appearing windows that are not parented | |
| 807 | + to the main viewport didn't have their task bar icon appear before the window was | |
| 808 | + explicitly refocused. (#7354, #8669) | |
| 809 | + | |
| 810 | + | |
| 636 | 811 | ----------------------------------------------------------------------- |
| 637 | 812 | VERSION 1.92.5 (Released 2025-11-20) |
| 638 | 813 | ----------------------------------------------------------------------- |
| @@ -777,7 +952,23 @@ | ||
| 777 | 952 | - SDL3+WebGPU: added new example (Emscripten + native Dawn/WGPU). (#8381) [@brutpitt] |
| 778 | 953 | - Win32+OpenGL3: enable DPI awareness. (#9083) |
| 779 | 954 | |
| 955 | +Docking+Viewports Branch: | |
| 780 | 956 | |
| 957 | +- Docking, Style: fixed per-window ImGuiCol_UnsavedMarker changes not being latched | |
| 958 | + by docked windows. (#8983, #9064) | |
| 959 | +- Docking: fixed crash loading certain form of invalid .ini settings (e.g. nodes | |
| 960 | + referring to a missing parent, duplicate nodes id). (#9070) | |
| 961 | +- Docking: added io.ConfigDockingNoDockingOver helper config flag to prevent | |
| 962 | + merging windows into a same tab-bar. | |
| 963 | +- Examples: | |
| 964 | + - SDL2+DX11, SDL3+DX11, Win32+DX10, Win32+DX11: fixed one resource leak | |
| 965 | + from the use of MakeWindowAssociation() in 1.92.4. (#9010, #4350) [@o-3-o] | |
| 966 | +- Backends: | |
| 967 | + - DirectX12: Fixed an issue in synchronization logic improving rendering | |
| 968 | + throughput for secondary viewports. (#9025, #8961) | |
| 969 | + - Vulkan: handle viewport surface creation failure without crashing. (#9068) [@zentia] | |
| 970 | + | |
| 971 | + | |
| 781 | 972 | ----------------------------------------------------------------------- |
| 782 | 973 | VERSION 1.92.4 (Released 2025-10-14) |
| 783 | 974 | ----------------------------------------------------------------------- |
| @@ -786,6 +977,10 @@ | ||
| 786 | 977 | |
| 787 | 978 | Breaking Changes: |
| 788 | 979 | |
| 980 | +- Viewports: for consistency with other config flags, renamed | |
| 981 | + io.ConfigViewportPlatformFocusSetsImGuiFocus | |
| 982 | + to io.ConfigViewportsPlatformFocusSetsImGuiFocus. (#6299, #6462) | |
| 983 | + It was really a typo in the first place, and introduced in 1.92.2. | |
| 789 | 984 | - Backends: |
| 790 | 985 | - TreeNode, Selectable, Clipper: commented out legacy names obsoleted in |
| 791 | 986 | 1.89.7 (July 2023) and 1.89.9 (Sept 2023): |
| @@ -887,7 +1082,54 @@ | ||
| 887 | 1082 | - Win32+DirectX12: Rework synchronization logic. (#8961) [@RT2Code] |
| 888 | 1083 | - Made examples's main.cpp consistent with returning 1 on error. |
| 889 | 1084 | |
| 1085 | +Docking+Viewports Branch: | |
| 890 | 1086 | |
| 1087 | +- Nav, Docking, Selection: Fixed tab change from reinitializing navigation state, | |
| 1088 | + which would erroneously clear selection when using ImGuiSelectableFlags_SelectOnNav | |
| 1089 | + or clear multi-selection when not using ImGuiMultiSelectFlags_NoAutoSelect. (#8997) | |
| 1090 | +- Nav: Fixed a crash that could occur when opening a popup following the processing | |
| 1091 | + of a global shortcut while no windows were focused (the fix done in 1.92.3 was | |
| 1092 | + incomplete for docking branch). | |
| 1093 | +- Viewports: | |
| 1094 | + - Added ImGuiBackendFlags_HasParentViewport backend flag for | |
| 1095 | + backend to specify if it can honor the `viewport->ParentViewport`/`ParentViewportId` | |
| 1096 | + value by applying the corresponding parent/child relation at the Platform level. (#8948) | |
| 1097 | + - SDL3, Win32 backends: supported. | |
| 1098 | + - SDL2, GLFW, OSX backends: unsupported. | |
| 1099 | + - Fixed a bug where ImGuiWindowFlags_NoBringToFrontOnFocus would effectively | |
| 1100 | + be ignored when windows first appear and viewports are enabled. (#7008) [@jshofmann] | |
| 1101 | + - Changed default value of io.ConfigViewportsNoDefaultParent to true. (#8948) | |
| 1102 | + As a reminder, for backend honoring ParentViewportID: | |
| 1103 | + - Parented windows will always appear in front of the main viewport. | |
| 1104 | + - Non-parented windows can appear behing the main viewport. | |
| 1105 | + - Fixed an issue inferring Z-order when attempting to merge a viewport | |
| 1106 | + back in the the main/hosting viewport. (#8948) | |
| 1107 | + Note that for GLFW/SDL2/OSX backends, which do not support honoring ParentViewportID. | |
| 1108 | + Setting io.ConfigViewportsNoDefaultParent=true will align imgui's expectation | |
| 1109 | + with what the backend does. | |
| 1110 | + - Storing `ImGuiViewport* ParentViewport` pointer along with ParentViewportID. | |
| 1111 | + - ImGui::DestroyContext() does not call DestroyPlatformWindows() anymore at it | |
| 1112 | + is assumed to be unnecessary as backends should have done it and we check that | |
| 1113 | + backends have been shutdown since 1.90.4. Changed into asserts. (#7175, #8945) | |
| 1114 | +- Backends: | |
| 1115 | + - DirectX10, DirectX11, DirectX12: Disabled DXGI's Alt+Enter default behavior on | |
| 1116 | + secondary viewports managed by the backend. (#4350) [@PathogenDavid] | |
| 1117 | + - DirectX10, DirectX11: avoid ImGui_ImplXXXX_SwapBuffers() handlers for secondary | |
| 1118 | + viewports crashing if SwapChain could not be created. | |
| 1119 | + - Vulkan: Added a way to configure secondary viewport pipeline creation by | |
| 1120 | + setting init_info.PipelineInfoForViewports fields. (#8946, #8110, #8111, #8686) | |
| 1121 | + - Vulkan: Added a way to configure secondary viewport swapchain VkImageUsageFlags | |
| 1122 | + to e.g. capture rendering. (#8946, #8940) [@olivier-gerard, @ocornut] | |
| 1123 | + Usage example: `init_info.PipelineInfoForViewports.SwapChainImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;` | |
| 1124 | + - Vulkan: pipeline created for secondary viewport automatically match | |
| 1125 | + surface format. (#8686) [@sylmroz] | |
| 1126 | + - Vulkan: Added ImGui_ImplVulkanH_GetWindowDataFromViewport() accessor/helper. (#8946, #8940) [@olivier-gerard] | |
| 1127 | +- Docs: improve docking API comments and demo. (#9000) | |
| 1128 | +- Examples: DX10, DX11: Disabled DXGI's Alt+Enter default behavior in examples. | |
| 1129 | + Applications are free to leave this enabled, but it does not work properly with | |
| 1130 | + multiple viewports. (#4350, #8979) [@PathogenDavid] | |
| 1131 | + | |
| 1132 | + | |
| 891 | 1133 | ----------------------------------------------------------------------- |
| 892 | 1134 | VERSION 1.92.3 (Released 2025-09-17) |
| 893 | 1135 | ----------------------------------------------------------------------- |
| @@ -981,7 +1223,23 @@ | ||
| 981 | 1223 | - Backends: Vulkan: added ImGui_ImplVulkan_CreateMainPipeline() to recreate pipeline |
| 982 | 1224 | without reinitializing backend. (#8110, #8111) [@SuperRonan] |
| 983 | 1225 | |
| 1226 | +Docking+Viewports Branch: | |
| 984 | 1227 | |
| 1228 | +- DPI: fixed io.ConfigDpiScaleFonts from ever working since 1.92 (the irony | |
| 1229 | + being that it is when it started to make sense!). As a reminder, the option | |
| 1230 | + automatically copy the _current_ viewport DpiScale to style.FontScaleDpi. | |
| 1231 | + This is why we separated the style.FontScaleMain and style.FontScaleDpi scaling | |
| 1232 | + factor, as the later is meant to be overwritten. (#8832, #8465) | |
| 1233 | +- DPI: Fixed obsoleted ImGuiConfigFlags_DpiEnableScaleFonts/_DpiEnableScaleViewports | |
| 1234 | + names from setting the equivalent io.ConfigDpiScaleFonts/io.ConfigDpiScaleViewports | |
| 1235 | + flag correctly (regression in 1.92). | |
| 1236 | +- Docking, Style: added style.DockingNodeHasCloseButton option to hide the | |
| 1237 | + Close Button attached to each docking node. (#8933) | |
| 1238 | +- Backends: GLFW: improve multi-viewport behavior in tiling WMs on X11. | |
| 1239 | + Note: using GLFW backend on Linux/BSD etc. requires linking with `-lX11`. | |
| 1240 | + (#8884, #8474, #8289, #2117) [@Ikos3k, @Madman10K] | |
| 1241 | + | |
| 1242 | + | |
| 985 | 1243 | ----------------------------------------------------------------------- |
| 986 | 1244 | VERSION 1.92.2b (Released 2025-08-13) |
| 987 | 1245 | ----------------------------------------------------------------------- |
| @@ -1002,7 +1260,13 @@ | ||
| 1002 | 1260 | - Backends: Allegro5: Fixed missing support for ImGuiKey_PrintScreen |
| 1003 | 1261 | under Windows, as raw Allegro 5 does not receive it. |
| 1004 | 1262 | |
| 1263 | +Docking+Viewports Branch: | |
| 1005 | 1264 | |
| 1265 | +- Fixed a bug where closing a viewport using OS facility (e.g. ALT+F4, Close Button) | |
| 1266 | + would erroneously close all windows located in the viewport, even ones docked | |
| 1267 | + into nested dockspaces. Only top-most windows should be closed. (#8887) [@lailoken] | |
| 1268 | + | |
| 1269 | + | |
| 1006 | 1270 | ----------------------------------------------------------------------- |
| 1007 | 1271 | VERSION 1.92.2 (Released 2025-08-11) |
| 1008 | 1272 | ----------------------------------------------------------------------- |
| @@ -1089,7 +1353,20 @@ | ||
| 1089 | 1353 | - Backends: Vulkan: Avoid calling vkCmdBindDescriptorSets() when texture |
| 1090 | 1354 | has not changed. (#8666) [@micb25] |
| 1091 | 1355 | |
| 1356 | +Docking+Viewports Branch: | |
| 1092 | 1357 | |
| 1358 | +- Windows, Viewport: fixed an issue where interrupting a viewport move with | |
| 1359 | + e.g. a ClearActiveID() call would leave the dragged viewport with the | |
| 1360 | + normally temporary ImGuiViewportFlags_NoInputs flag, preventing further | |
| 1361 | + interactions with the viewport. (#5324) (thanks @mdelaharpe) | |
| 1362 | +- Viewports: added io.ConfigViewportPlatformFocusSetsImGuiFocus to opt-out | |
| 1363 | + of focusing imgui windows When a platform window is focused (e.g. using Alt+Tab, | |
| 1364 | + clicking Platform Title Bar). In principle this is better enabled but we | |
| 1365 | + provide an opt-out because some Linux window managers tend to eagerly focus | |
| 1366 | + windows (on e.g. mouse hover, or even on a simple window pos/size change). | |
| 1367 | + (#6299, #6462) | |
| 1368 | + | |
| 1369 | + | |
| 1093 | 1370 | ----------------------------------------------------------------------- |
| 1094 | 1371 | VERSION 1.92.1 (Released 2025-07-09) |
| 1095 | 1372 | ----------------------------------------------------------------------- |
| @@ -1138,7 +1415,11 @@ | ||
| 1138 | 1415 | - Backends: Vulkan: fixed texture synchronization issue introduced in 1.92.0, |
| 1139 | 1416 | leading to validation layers reacting. (#8772) [@Majora320] |
| 1140 | 1417 | |
| 1418 | +Docking+Viewports Branch: | |
| 1141 | 1419 | |
| 1420 | +- Backends: OSX: Fixed multi-viewport handling broken in 1.92.0. (#8644, #8777) [@cfillion] | |
| 1421 | + | |
| 1422 | + | |
| 1142 | 1423 | ----------------------------------------------------------------------- |
| 1143 | 1424 | VERSION 1.92.0 (Released 2025-06-25) |
| 1144 | 1425 | ----------------------------------------------------------------------- |
| @@ -1365,6 +1646,9 @@ | ||
| 1365 | 1646 | - Imgui_ImplSDLGPU3_PrepareDrawData() --> ImGui_ImplSDLGPU3_PrepareDrawData() |
| 1366 | 1647 | - Internals: RenderTextEllipsis() function removed the 'float clip_max_x' parameter directly |
| 1367 | 1648 | preceding 'float ellipsis_max_x'. Values were identical for a vast majority of users. (#8387) |
| 1649 | +- [Docking] renamed/moved ImGuiConfigFlags_DpiEnableScaleFonts -> bool io.ConfigDpiScaleFonts. | |
| 1650 | +- [Docking] renamed/moved ImGuiConfigFlags_DpiEnableScaleViewports -> bool io.ConfigDpiScaleViewports. | |
| 1651 | + **Neither of those flags are very useful in current code. They will be useful once we merge font changes.** | |
| 1368 | 1652 | |
| 1369 | 1653 | Non-breaking Fonts/Textures related changes: |
| 1370 | 1654 | |
| @@ -1598,7 +1882,36 @@ | ||
| 1598 | 1882 | - Examples: DirectX12+Win32: also test for IsIconic() for sleeping since we don't seem to |
| 1599 | 1883 | get a DXGI_STATUS_OCCLUDED signal when minimized. (#8603) [@dooann] |
| 1600 | 1884 | |
| 1885 | +Docking+Viewports Branch: | |
| 1601 | 1886 | |
| 1887 | +- Viewports: added per-viewport FramebufferScale for Retina display multi-monitor support. | |
| 1888 | + Backend must provide platform_io.platform_io.Platform_GetWindowFramebufferScale handler. | |
| 1889 | + This effectively fixes clipping/rendering on multi-monitors with varying Retina scale. | |
| 1890 | + (#1065, #1542, #1676, #1786, #2826, #3757, #5081, #5580, #5592, #6465, #7273, #7779 etc.) | |
| 1891 | +- Viewports: fixed handling of simultaneous move + resize (e.g. toggling maximized) | |
| 1892 | + when ImGuiConfigFlags_DpiEnableScaleViewports is enabled. | |
| 1893 | +- Backends: Win32: Viewports: fixed an issue when closing a window from | |
| 1894 | + the OS close button (with io.ConfigViewportsNoDecoration=false) while | |
| 1895 | + user code is discarding the 'bool *p_open=false output' from Begin(). | |
| 1896 | + Because we allowed the Win32 window to close early, Windows destroyed | |
| 1897 | + it and our imgui window became not visible even though user code was | |
| 1898 | + still submitting it. (#8670) | |
| 1899 | +- Backends: Win32: Viewports: handle WM_DPICHANGED in backend when | |
| 1900 | + ImGuiConfigFlags_DpiEnableScaleViewports is enabled. | |
| 1901 | +- Backends: GLFW, SDL2, SDL3, Apple: provide Platform_GetWindowFramebufferScale handler, | |
| 1902 | + (#1065, #1542, #1676, #1786, #2826, #3757, #5081, #5580, #5592, #6465, #7273, #7779 etc.) | |
| 1903 | +- Backends: SDLGPU3 for SDL3: added multi-viewport support. (#8573) [@Lekoopapaul] | |
| 1904 | +- Backends: SDL2, SDL3: revert updating monitors and work areas info every | |
| 1905 | + frame. Only do it on Windows to detect task-bar resize until we get an | |
| 1906 | + adequate event for it. (#8415, #8558) | |
| 1907 | +- Backends: SDL3: macOS: Fixed secondary-viewports not appearing on a different | |
| 1908 | + monitor than the main viewport. Because SDL_SetWindowParent() seems to restrict it. | |
| 1909 | +- Backends: GLFW: Disable multi-viewports under Wayland (require GLFW 3.4). (#8587) | |
| 1910 | +- Backends: GLFW: Fixed an issue where Win32 specific WndProc hook was not installed | |
| 1911 | + for all GLFW version, preventing mouse vs touch detection from working on | |
| 1912 | + secondary viewports. | |
| 1913 | + | |
| 1914 | + | |
| 1602 | 1915 | ----------------------------------------------------------------------- |
| 1603 | 1916 | VERSION 1.91.9b (Released 2025-03-17) |
| 1604 | 1917 | ----------------------------------------------------------------------- |
| @@ -1730,6 +2043,8 @@ | ||
| 1730 | 2043 | with asserts enabled. (#8452) |
| 1731 | 2044 | - Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn |
| 1732 | 2045 | handler. (#7660) [@achabense] |
| 2046 | +- Backends: SDL2, SDL3: Use display bounds when SDL_GetDisplayUsableBounds() | |
| 2047 | + fails or return a zero size. (#8415, #3457) | |
| 1733 | 2048 | - Backends: SDL2, SDL3, Win32, Allegro5: Added support for ImGuiMouseCursor_Wait |
| 1734 | 2049 | and ImGuiMouseCursor_Progress cursors. |
| 1735 | 2050 | - Backends: SDL2, SDL3: Avoid calling SDL_GetGlobalMouseState() when mouse is in |
| @@ -1752,7 +2067,23 @@ | ||
| 1752 | 2067 | [@PhantomCloak] (#8369) |
| 1753 | 2068 | - Backends: WebGPU: Fix for webgpu-native API changes. (#8426) [@pplux] |
| 1754 | 2069 | |
| 2070 | +Docking+Viewports Branch: | |
| 1755 | 2071 | |
| 2072 | +- Docking: Removed legacy assert preventing to call DockBuilderSplitNode() on an existing | |
| 2073 | + split node. This makes using DockBuilder a little more flexible and bearable! (#8472) [@MegaMech] | |
| 2074 | +- Viewports: fixed an issue where in certain cases, a window repositioning leading | |
| 2075 | + to a monitor change could have the window incorrectly get clamped within the boundaries | |
| 2076 | + of its previous monitor. Would happen e.g. when loading .ini data during runtime. (#8484) | |
| 2077 | +- Viewports: fixed an assert when a window load settings with a position outside | |
| 2078 | + monitor bounds, when there are multiple monitors. (#8393, #8385) [@gaborodriguez] | |
| 2079 | +- Viewports + Backends: Win32: Fixed setting title bar text when application | |
| 2080 | + is compiled without UNICODE. (#7979, #5725) [@lailoken] | |
| 2081 | +- Backends: GLFW, SDL2/SDL3: Update monitors and work areas information every frame, | |
| 2082 | + as the later may change regardless of monitor/display changes. (#8415) | |
| 2083 | +- Backends: Win32: WM_SETTINGCHANGE's SPI_SETWORKAREA message also triggers a refresh | |
| 2084 | + of monitor list, as they contain work area information. (#8415) [@PathogenDavid, @lailoken] | |
| 2085 | + | |
| 2086 | + | |
| 1756 | 2087 | ----------------------------------------------------------------------- |
| 1757 | 2088 | VERSION 1.91.8 (Released 2025-01-31) |
| 1758 | 2089 | ----------------------------------------------------------------------- |
| @@ -1814,7 +2145,7 @@ | ||
| 1814 | 2145 | one without the other is never correct. (#8174, #6556, #6336, #4723) |
| 1815 | 2146 | - Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in |
| 1816 | 2147 | provided example, to reduce latency. |
| 1817 | -- Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by | |
| 2148 | +- Backends+Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by | |
| 1818 | 2149 | vkAcquireNextImageKHR() or vkQueuePresentKHR(). (#7825, #7831) [@NostraMagister] |
| 1819 | 2150 | - Backends: SDL2: removed assert preventing using ImGui_ImplSDL2_SetGamepadMode() |
| 1820 | 2151 | with ImGui_ImplSDL2_GamepadMode_Manual and an empty array. (#8329) |
| @@ -1828,7 +2159,15 @@ | ||
| 1828 | 2159 | ImGui_ImplDX12_InitInfo instead of creating its own. |
| 1829 | 2160 | - Backends: OSX: Removed notification observer when shutting down. (#8331) [@jrachele] |
| 1830 | 2161 | |
| 2162 | +Docking+Viewports Branch: | |
| 1831 | 2163 | |
| 2164 | +- Docking: Fixed an issue in 1.91.7 where using legacy ImGuiWindowFlags_NavFlattened | |
| 2165 | + flag (instead of ImGuiChildFlags_NavFlattened) in docking branch would conflict | |
| 2166 | + with internal docking flags. (#8357) [@DanielGibson] | |
| 2167 | +- Backends: SDL3: new viewport windows are created with the SDL_WINDOW_HIDDEN flag | |
| 2168 | + before calling SDL_ShowWindow(). (#8328) [@PathogenDavid] | |
| 2169 | + | |
| 2170 | + | |
| 1832 | 2171 | ----------------------------------------------------------------------- |
| 1833 | 2172 | VERSION 1.91.7 (Released 2025-01-14) |
| 1834 | 2173 | ----------------------------------------------------------------------- |
| @@ -1962,7 +2301,16 @@ | ||
| 1962 | 2301 | - Examples: Win32+DX12: Using a basic free-list allocator to manage multiple |
| 1963 | 2302 | SRV descriptors. |
| 1964 | 2303 | |
| 2304 | +Docking+Viewports Branch: | |
| 1965 | 2305 | |
| 2306 | +- Docking: Added an assert to clarify that ImGuiDockNodeFlags_CentralNode flag | |
| 2307 | + (from internals) does not need to be passed to DockSpace(), as it causes general | |
| 2308 | + havoc. (#8145) | |
| 2309 | +- Backends: Win32: Fixed a crash/regression in 1.91.5 when running two processes | |
| 2310 | + with multi-viewports (was using GetProp() to query property which could have | |
| 2311 | + belonged to another process). (#8162, #8069) [@sammyfreg, @ocornut] | |
| 2312 | + | |
| 2313 | + | |
| 1966 | 2314 | ----------------------------------------------------------------------- |
| 1967 | 2315 | VERSION 1.91.5 (Released 2024-11-07) |
| 1968 | 2316 | ----------------------------------------------------------------------- |
| @@ -2021,7 +2369,16 @@ | ||
| 2021 | 2369 | - Examples: Android+OpenGL: Using ALooper_pollOnce() instead of ALooper_pollAll() |
| 2022 | 2370 | which has been deprecated. (#8013) [@feather179] |
| 2023 | 2371 | |
| 2372 | +Docking+Viewports Branch: | |
| 2024 | 2373 | |
| 2374 | +- Backends: GLFW: added Linux workaround for spurious mouse up events emitted while dragging | |
| 2375 | + and creating new viewports. Generally they would be interrupting a dragging operations. | |
| 2376 | + (#3158, #7733, #7922) [@rokups, @ocornut] | |
| 2377 | +- Docking: fixed using ImGuiDockNodeFlags_KeepAliveOnly with DockSpaceOverViewport(): | |
| 2378 | + the normally invisible space did erroneously claim mouse hover and could be potentially | |
| 2379 | + focused. (#8125) [@kcbanner] | |
| 2380 | + | |
| 2381 | + | |
| 2025 | 2382 | ----------------------------------------------------------------------- |
| 2026 | 2383 | VERSION 1.91.4 (Released 2024-10-18) |
| 2027 | 2384 | ----------------------------------------------------------------------- |
| @@ -2110,7 +2467,12 @@ | ||
| 2110 | 2467 | - Backends: DX9, DX10, DX11, DX12, OpenGL, Vulkan, WGPU: Changed default texture sampler |
| 2111 | 2468 | to Clamp instead of Repeat/Wrap. (#7468, #7511, #5999, #5502, #7230) |
| 2112 | 2469 | |
| 2470 | +Docking+Viewports Branch: | |
| 2113 | 2471 | |
| 2472 | +- Backends: changed all backends to allow enabling ImGuiConfigFlags_ViewportsEnable | |
| 2473 | + after initialization. (#5371) | |
| 2474 | + | |
| 2475 | + | |
| 2114 | 2476 | ----------------------------------------------------------------------- |
| 2115 | 2477 | VERSION 1.91.3 (Released 2024-10-04) |
| 2116 | 2478 | ----------------------------------------------------------------------- |
| @@ -2173,6 +2535,13 @@ | ||
| 2173 | 2535 | - Backends: WebGPU: Fixed DAWN api change using WGPUStringView in WGPUShaderSourceWGSL. |
| 2174 | 2536 | (#8009, #8010) [@blitz-research] |
| 2175 | 2537 | |
| 2538 | +Docking+Viewports Branch: | |
| 2539 | + | |
| 2540 | +- Backends: SDL2, SDL3: Fixed building for UWP platforms. (#8008) | |
| 2541 | +- Backends: Win32: Use ResisterClassW()/CreateWindowExW() for secondary viewports, to | |
| 2542 | + ensure correct IME input even if the backend was compiled in MBCS mode. (#7979, #5725) | |
| 2543 | + | |
| 2544 | + | |
| 2176 | 2545 | ----------------------------------------------------------------------- |
| 2177 | 2546 | VERSION 1.91.2 (Released 2024-09-19) |
| 2178 | 2547 | ----------------------------------------------------------------------- |
| @@ -2233,6 +2602,18 @@ | ||
| 2233 | 2602 | - Backends: WebGPU: Added support for optional IMGUI_IMPL_WEBGPU_BACKEND_DAWN / IMGUI_IMPL_WEBGPU_BACKEND_WGPU |
| 2234 | 2603 | defines to handle ever-changing native implementations. (#7977, #7969, #6602, #6188, #7523) [@acgaudette] |
| 2235 | 2604 | |
| 2605 | +Docking+Viewports Branch: | |
| 2606 | + | |
| 2607 | +- Viewports: fixed an issue where a window manually constrained to the main viewport while crossing | |
| 2608 | + over main viewport bounds isn't translated properly. (#7985) | |
| 2609 | +- Backends: SDL2, SDL3, Win32: ensure that ImGuiPlatformMonitor list is available after backend Init call. (#7995) | |
| 2610 | +- Backends: Win32: fixed direct calls to platform_io.Platform_SetWindowPos()/Platform_SetWindowSize() | |
| 2611 | + on windows created by application (typically main viewport). | |
| 2612 | +- Backends: Win32: fixed an issue where a viewport destroyed while clicking would hog | |
| 2613 | + mouse tracking and temporary lead to incorrect update of HoveredWindow. (#7971) | |
| 2614 | +- Backends: SDL3: added support for viewport->ParentViewportId field to support parenting | |
| 2615 | + windows at OS level. (#7973, #7989) [@RT2code] | |
| 2616 | + | |
| 2236 | 2617 | ----------------------------------------------------------------------- |
| 2237 | 2618 | VERSION 1.91.1 (Released 2024-09-04) |
| 2238 | 2619 | ----------------------------------------------------------------------- |
| @@ -2316,6 +2697,16 @@ | ||
| 2316 | 2697 | to handle minimization without burning CPU or GPU by running unthrottled code. (#7844) |
| 2317 | 2698 | - Examples: SDL3: Update for API changes: SDL_Init() returns 0 on failure. |
| 2318 | 2699 | |
| 2700 | +Docking+Viewports Branch: | |
| 2701 | + | |
| 2702 | +- Viewports: added optional platform_io.Platform_GetWindowWorkAreaInsets() hook | |
| 2703 | + to allow backends to alter the default per-viewport work-area. (#7823) | |
| 2704 | +- Backends: don't report monitors with DpiScale of 0, which seemed to be reported for | |
| 2705 | + virtual monitors instead by accessibility drivers. (#7902) [@nicolasnoble, @ocornut] | |
| 2706 | +- Backends: SDL2, SDL3: using SDL_HINT_WINDOW_NO_ACTIVATION_WHEN_SHOWN to support the | |
| 2707 | + ImGuiViewportFlags_NoFocusOnAppearing flag, instead of using a Win32-specific hack. | |
| 2708 | + (#7896) [@RT2Code] | |
| 2709 | + | |
| 2319 | 2710 | ----------------------------------------------------------------------- |
| 2320 | 2711 | VERSION 1.91.0 (Released 2024-07-30) |
| 2321 | 2712 | ----------------------------------------------------------------------- |
| @@ -2475,7 +2866,17 @@ | ||
| 2475 | 2866 | - Backends: GLFW+Emscripten: Fixed Emscripten warning when using mouse wheel on some setups |
| 2476 | 2867 | "Unable to preventDefault inside passive event listener". (#7647, #7600) [@ypujante] |
| 2477 | 2868 | |
| 2869 | +Docking+Viewports Branch: | |
| 2478 | 2870 | |
| 2871 | +- Viewports: Always update fallback monitor to primary monitor if there's one. | |
| 2872 | +- Backends: OSX: Fixed NSAppKitVersion version limit for setWantsBestResolutionOpenGLSurface | |
| 2873 | + usage. (#7814) [@YGXXD] | |
| 2874 | +- Backends: SDL3: Fixed a bug preventing ImGuiViewportFlags_NoFocusOnAppearing support from | |
| 2875 | + working (Windows only). | |
| 2876 | +- Backends: Vulkan: ImGui_ImplVulkan_SwapBuffers() used by secondary viewports still proceeds | |
| 2877 | + increasing frame counters on VK_SUBOPTIMAL_KHR. (#7825, #3881) [@NostraMagister] | |
| 2878 | + | |
| 2879 | + | |
| 2479 | 2880 | ----------------------------------------------------------------------- |
| 2480 | 2881 | VERSION 1.90.9 (Released 2024-07-01) |
| 2481 | 2882 | ----------------------------------------------------------------------- |
| @@ -2556,7 +2957,20 @@ | ||
| 2556 | 2957 | returning VK_SUBOPTIMAL_KHR, which doesn't seem to happen on Wayland. (#7671) |
| 2557 | 2958 | [@AndreiNego, @ocornut] |
| 2558 | 2959 | |
| 2960 | +Docking+Viewports Branch: | |
| 2559 | 2961 | |
| 2962 | +- Windows, Menus: Fixed an issue where the size of sub-menu in their own viewport | |
| 2963 | + would be erroneously clamped to the size of main viewport. (#7730) | |
| 2964 | +- Merged GetBackgroundDrawList() and GetBackgroundDrawList(ImGuiViewport* viewport) | |
| 2965 | + api entry points into a same one GetBackgroundDrawList(ImGuiViewport* viewport = NULL); | |
| 2966 | +- Merged GetForegroundDrawList() and GetForegroundDrawList(ImGuiViewport* viewport) | |
| 2967 | + api entry points into a same one GetForegroundDrawList(ImGuiViewport* viewport = NULL); | |
| 2968 | +- Backends: SDL3: Update for introduction of SDL_GLContext from void*. (#7701, #7702) | |
| 2969 | + [@bcsanches] | |
| 2970 | +- Backends: Win32: Secondary viewports WndProc handler retrieve/set imgui context from | |
| 2971 | + the HWND, allowing WndProc dispatch to work in multi-context setups. | |
| 2972 | + | |
| 2973 | + | |
| 2560 | 2974 | ----------------------------------------------------------------------- |
| 2561 | 2975 | VERSION 1.90.8 (Released 2024-06-06) |
| 2562 | 2976 | ----------------------------------------------------------------------- |
| @@ -2706,7 +3120,16 @@ | ||
| 2706 | 3120 | those API public. Only past users of imgui_internal.h with the extra parameters will be affected. |
| 2707 | 3121 | Added asserts for valid flags in various functions to detect _some_ misuses, BUT NOT ALL. |
| 2708 | 3122 | |
| 3123 | +Docking+Viewports Branch: | |
| 2709 | 3124 | |
| 3125 | +- Docking: *BREAKING* changed signature of DockSpaceOverViewport() to allow passing | |
| 3126 | + an explicit dockspace id if desired. (#7611) | |
| 3127 | + Before: DockSpaceOverViewport(const ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags flags = 0, ...); | |
| 3128 | + After: DockSpaceOverViewport(ImGuiID dockspace_id = 0, const ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags flags = 0, ...); | |
| 3129 | + Simply add a leading 0 to your existing calls to DockSpaceOverViewport() if you have any. | |
| 3130 | +- Tables: resizing border hit-rect scales according to current monitor dpi scale. | |
| 3131 | + | |
| 3132 | + | |
| 2710 | 3133 | ----------------------------------------------------------------------- |
| 2711 | 3134 | VERSION 1.90.6 (Released 2024-05-08) |
| 2712 | 3135 | ----------------------------------------------------------------------- |
| @@ -2764,7 +3187,19 @@ | ||
| 2764 | 3187 | - Examples: GLFW+WebGPU: Added support for WebGPU-native/Dawn (#7435, #7132) [@eliasdaler, @Zelif] |
| 2765 | 3188 | - Examples: GLFW+WebGPU: Renamed example_emscripten_wgpu/ to example_glfw_wgpu/. (#7435, #7132) |
| 2766 | 3189 | |
| 3190 | +Docking+Viewports Branch: | |
| 2767 | 3191 | |
| 3192 | +- Docking: when io.ConfigDockingWithShift is enabled, fixed help tooltip erroneously | |
| 3193 | + reading SetNextWindowXXX() data. (#6709, #4643, #7491) [@ocornut, @cfillion] | |
| 3194 | +- Viewports: fixed outer-right edge of MenuBar clipping rectangle off by one when window | |
| 3195 | + is located on a monitor with negative coordinates. (#6861, #2884) [@cfillion] | |
| 3196 | +- Backends: Vulkan: reworked swap-chain resize handling for secondary viewports, fix for | |
| 3197 | + typical Linux setups. (#2626, #3390, #3758, #7508, #7513) [@RoryO, @InsideBSITheSecond] | |
| 3198 | +- Backends: Vulkan: create a custom pipeline for secondary viewports. Fixes issues | |
| 3199 | + when user created main viewport uses a different renderpass. (#6325, #6305, #7398, | |
| 3200 | + #3459, #3253, #3522) [@skaman, @FunMiles] | |
| 3201 | + | |
| 3202 | + | |
| 2768 | 3203 | ----------------------------------------------------------------------- |
| 2769 | 3204 | VERSION 1.90.5 (Released 2024-04-11) |
| 2770 | 3205 | ----------------------------------------------------------------------- |
| @@ -2820,7 +3255,12 @@ | ||
| 2820 | 3255 | Adding a link to the crawlable version, even though it is not intended for humans, |
| 2821 | 3256 | to increase its search rank. |
| 2822 | 3257 | |
| 3258 | +Docking+Viewports Branch: | |
| 2823 | 3259 | |
| 3260 | +- Backends: Win32: made it so that an appearing viewport showing up doesn't bring | |
| 3261 | + its parent to front. (#7354) | |
| 3262 | + | |
| 3263 | + | |
| 2824 | 3264 | ----------------------------------------------------------------------- |
| 2825 | 3265 | VERSION 1.90.4 (Released 2024-02-22) |
| 2826 | 3266 | ----------------------------------------------------------------------- |
| @@ -2853,7 +3293,14 @@ | ||
| 2853 | 3293 | - Demo: Custom Rendering: better demonstrate PathArcTo(), PathBezierQuadraticCurveTo(), |
| 2854 | 3294 | PathBezierCubicCurveTo(), PathStroke(), PathFillConvex() functions. |
| 2855 | 3295 | |
| 3296 | +Docking+Viewports Branch: | |
| 2856 | 3297 | |
| 3298 | +- Backends: GLFW: enable ImGuiBackendFlags_HasMouseHoveredViewport support with GLFW 3.3.x, | |
| 3299 | + as required specs for it was relaxed in 1.87. This enable better viewport hovering detection | |
| 3300 | + without GLFW 3.4's GLFW_MOUSE_PASSTHROUGH, with less reliance on dear imgui's own heuristic | |
| 3301 | + of platform windows order. (#7316) | |
| 3302 | + | |
| 3303 | + | |
| 2857 | 3304 | ----------------------------------------------------------------------- |
| 2858 | 3305 | VERSION 1.90.3 (Released 2024-02-14) |
| 2859 | 3306 | ----------------------------------------------------------------------- |
| @@ -2941,7 +3388,19 @@ | ||
| 2941 | 3388 | Often requested in some form (#6962, #5219, #3290, #4627, #5054, #3878, #2881, #1506, #1216, #968), |
| 2942 | 3389 | and useful for interactive completion/suggestions popups (#2057, #718) |
| 2943 | 3390 | |
| 3391 | +Docking+Viewports Branch: | |
| 2944 | 3392 | |
| 3393 | +- Added ImGuiWindowClass::FocusRouteParentWindowId as a way to connect the focus route between | |
| 3394 | + a tool window to a parent document window, so that Shortcuts in the documents are routed when the | |
| 3395 | + tool is focused (regardless of whether the tool is docked or in a floating viewport, etc.) (#6798) | |
| 3396 | +- Added ImGuiDockNodeFlags_DockedWindowsInFocusRoute to automatically make a dockspace connect | |
| 3397 | + the focus route of its docked window. This is provided a convenience in case you have windows | |
| 3398 | + where a connection is not explicit. (#6798) | |
| 3399 | +- Viewports: Fixed moving accross monitors when io.ConfigWindowsMoveFromTitleBarOnly is set. (#7299, #3071) | |
| 3400 | +- Backends: OSX: Fixed not submitting Monitors info when viewports are not enabled, leading to | |
| 3401 | + missing e.g. DpiScale info. (#7257) [@actboy168] | |
| 3402 | + | |
| 3403 | + | |
| 2945 | 3404 | ----------------------------------------------------------------------- |
| 2946 | 3405 | VERSION 1.90.1 (Released 2024-01-10) |
| 2947 | 3406 | ----------------------------------------------------------------------- |
| @@ -3045,7 +3504,16 @@ | ||
| 3045 | 3504 | (#6751) [@Traveller23, @ypujante] |
| 3046 | 3505 | - Examples: SDL3: Minor fixes following recent SDL3 in-progress development. |
| 3047 | 3506 | |
| 3507 | +Docking+Viewports Branch: | |
| 3048 | 3508 | |
| 3509 | +- Windows: Fixed ImGuiCol_TitleBg/Active alpha being used for viewport-owned windows. (#7181) [@PathogenDavid] | |
| 3510 | +- Backends: DX12: Changed swapchain scaling mode to DXGI_SCALING_NONE to reduce artifacts as | |
| 3511 | + queued frames aren't synchronized with platform window resizes. (#7152, #7153) [@SuperWangKai] | |
| 3512 | +- Backends: OSX: Fixed monitor and window position by correctly transforming Y origin on multi-viewports | |
| 3513 | + multi-monitor setups. (#7028, #7101, #6009, #6432) [@dmirty-kuzmenko, @734vin] | |
| 3514 | +- Backends: OSX: Fixed IME position in multi-monitor multi-viewports setups. (#7028) [@734vin] | |
| 3515 | + | |
| 3516 | + | |
| 3049 | 3517 | ----------------------------------------------------------------------- |
| 3050 | 3518 | VERSION 1.90.0 (Released 2023-11-15) |
| 3051 | 3519 | ----------------------------------------------------------------------- |
| @@ -3239,6 +3707,8 @@ | ||
| 3239 | 3707 | Fixed leaks, and added ImGui_ImplVulkan_DestroyFontsTexture() (probably no need to call this directly). |
| 3240 | 3708 | (#6943, #6715, #6327, #3743, #4618) |
| 3241 | 3709 | [@helynranta, @thomasherzog, @guybrush77, @albin-johansson, @MiroKaku, @benbatya-fb, @ocornut] |
| 3710 | +- Backends: Vulkan: use specified ColorAttachmentFormat when creating a secondary window when enabling | |
| 3711 | + UseDynamicRendering option. (#6999, #5446, #5037) [@raaaviol] | |
| 3242 | 3712 | - Backends: GLFW: Clear emscripten's MouseWheel callback before shutdown. (#6790, #6096, #4019) [@halx99] |
| 3243 | 3713 | - Backends: GLFW: Added support for F13 to F24 function keys. (#6891) |
| 3244 | 3714 | - Backends: SDL2, SDL3: Added support for F13 to F24 function keys, AppBack, AppForward. (#6891) |
| @@ -3256,7 +3726,32 @@ | ||
| 3256 | 3726 | - Examples: GLFW+Vulkan, SDL+Vulkan: Simplified and removed code due to backend improvements. |
| 3257 | 3727 | - Internals: Renamed ImFloor() to ImTrunc(). Renamed ImFloorSigned() to ImFloor(). (#6861) |
| 3258 | 3728 | |
| 3729 | +Docking+Viewports Branch: | |
| 3259 | 3730 | |
| 3731 | +- Viewports: Fixed window inner clipping rectangle off by one when window is located on a monitor | |
| 3732 | + with negative coordinates. While it is expected that other small issues with arise from this | |
| 3733 | + situation, at the moment we are fixing the most noticeable one. (#6861, #2884) [@Vuhdo, @alektron] | |
| 3734 | +- Docking: revised undocking to reduce accidental whole-node undocking: | |
| 3735 | + - cannot undock a whole node by dragging from empty space in tab-bar. | |
| 3736 | + - can undock whole node by dragging from window/collapse menu button. | |
| 3737 | + - can undock single window by dragging from its tab. | |
| 3738 | + - can still move (but not undock) whole node or whole hierarchy when node is part of a | |
| 3739 | + floating hierarchy. | |
| 3740 | + - added tooltip when hovering the collapse/window menu button, to faciliate understanding | |
| 3741 | + that whole dock node may be undocked or grabbed from here. | |
| 3742 | +- Docking: Fixed an issue leading to incorrect restoration of selected tab in dock nodes that | |
| 3743 | + don't carry the currently focused window. (#2304) | |
| 3744 | +- Docking: added ImGuiDockNodeFlags_NoUndocking. (#2999, #6823, #6780, #3492) | |
| 3745 | +- Docking: renamed ImGuiDockNodeFlags_NoSplit to ImGuiDockNodeFlags_NoDockingSplit. | |
| 3746 | +- Docking: renamed ImGuiDockNodeFlags_NoDockingInCentralNode to ImGuiDockNodeFlags_NoDockingOverCentralNode. | |
| 3747 | +- Docking: Internals: renamed ImGuiDockNodeFlags_NoDockingSplitMe to ImGuiDockNodeFlags_NoDockingSplit. | |
| 3748 | +- Docking: Fixed a bug where ClassId compare tests (when using SetNextWindowClass) on success would | |
| 3749 | + prevent further filter from running, namely the one that prevent docking over a popup. | |
| 3750 | +- Backends: GLFW: Fixed an assertion in situation where the WndProc handler is different between | |
| 3751 | + main and secondary viewport (may happen due to third-party hooks). (#6889) | |
| 3752 | +- Backends: DX9: Fixed incorrect assert triggering on reopening session with minimized windows. (#3424) | |
| 3753 | + | |
| 3754 | + | |
| 3260 | 3755 | ----------------------------------------------------------------------- |
| 3261 | 3756 | VERSION 1.89.9 (Released 2023-09-04) |
| 3262 | 3757 | ----------------------------------------------------------------------- |
| @@ -3313,7 +3808,12 @@ | ||
| 3313 | 3808 | - Examples: Emscripten+WebGPU: Fixed WGPUInstance creation process + use preferred |
| 3314 | 3809 | framebuffer format. (#6640, #6748) [@smileorigin] |
| 3315 | 3810 | |
| 3811 | +Docking+Viewports Branch: | |
| 3316 | 3812 | |
| 3813 | +- Docking: when io.ConfigDockingWithShift is enabled, staying stationary while moving | |
| 3814 | + a window displays an help tooltip to increase affordance. (#6709, #4643) | |
| 3815 | + | |
| 3816 | + | |
| 3317 | 3817 | ----------------------------------------------------------------------- |
| 3318 | 3818 | VERSION 1.89.8 (Released 2023-08-01) |
| 3319 | 3819 | ----------------------------------------------------------------------- |
| @@ -3381,7 +3881,17 @@ | ||
| 3381 | 3881 | - Examples: Vulkan: Creating minimal descriptor pools to fit only what is needed by |
| 3382 | 3882 | example. (#6642) [@SaschaWillem] |
| 3383 | 3883 | |
| 3884 | +Docking+Viewports Branch: | |
| 3384 | 3885 | |
| 3886 | +- Docking, Style: resizing separators use same colors as window borders (ImGuiCol_Border) | |
| 3887 | + for consistency. With default styles it doesn't make a big difference. (#2522) [@rmitton] | |
| 3888 | + In the future if we promote using thick value for inner/outer docking padding we may | |
| 3889 | + need to introduce new colors for it. | |
| 3890 | +- Docking: added style.DockingSeparatorSize, ImGuiStyleVar_DockingSeparatorSize. Now | |
| 3891 | + also scaled by style.ScaleAllSizes(). (#3481, #4721, #2522) [@PossiblyAShrub, @wobbier] | |
| 3892 | +- Docking: fixed rendering of docked-window scrollbar above outer border. (#2522) | |
| 3893 | + | |
| 3894 | + | |
| 3385 | 3895 | ----------------------------------------------------------------------- |
| 3386 | 3896 | VERSION 1.89.7 (Released 2023-07-04) |
| 3387 | 3897 | ----------------------------------------------------------------------- |
| @@ -3476,7 +3986,24 @@ | ||
| 3476 | 3986 | - Examples: Win32+OpenGL3: Changed DefWindowProc() to DefWindowProcW() to match other examples |
| 3477 | 3987 | and support the example app being compiled without UNICODE. (#6516, #5725, #5961, #5975) [@yenixing] |
| 3478 | 3988 | |
| 3989 | +Docking+Viewports Branch: | |
| 3479 | 3990 | |
| 3991 | +- Viewports+Docking: Fixed extraneous viewport+platform-window recreation in various | |
| 3992 | + combination of showing or hiding windows, docking with/without split, undocking. | |
| 3993 | + While with some backends and without OS decorations, some extraneous window recreation | |
| 3994 | + were visibly not noticeable, they would typically become noticeable when enabling | |
| 3995 | + OS decorations on those windows (e.g. Windows title bar fade-in/animation). | |
| 3996 | +- Viewports: Closing a viewport via OS/platform means (e.g. OS close button or task-bar menu), | |
| 3997 | + mark all windows in this viewport as closed. | |
| 3998 | +- Docking: Fixed one-frame flickering on reappearing windows binding to a dock node | |
| 3999 | + where a later-submitted window was already bound. | |
| 4000 | +- Docking: Fixed dragging from title-bar empty space (regression from 1.88 related to | |
| 4001 | + keeping ID alive when calling low-level ButtonBehavior() directly). (#5181, #2645) | |
| 4002 | +- Docking: [Internal] DockBuilderDockWindow() API calls don't clear docking order | |
| 4003 | + if the target node is same as existing one. | |
| 4004 | +- Backends: Win32: Added support for changing ParentViewportID after viewport creation. | |
| 4005 | + | |
| 4006 | + | |
| 3480 | 4007 | ----------------------------------------------------------------------- |
| 3481 | 4008 | VERSION 1.89.6 (Released 2023-05-31) |
| 3482 | 4009 | ----------------------------------------------------------------------- |
| @@ -3545,7 +4072,24 @@ | ||
| 3545 | 4072 | - Examples: Added SDL3+SDL_Renderer example. (#6286) |
| 3546 | 4073 | - Examples: Updated all Visual Studio projects and batches to use /utf-8 argument. |
| 3547 | 4074 | |
| 4075 | +Docking+Viewports Branch: | |
| 3548 | 4076 | |
| 4077 | +- Viewports: Fixed platform-side focus (e.g. Alt+Tab) from leading to accidental | |
| 4078 | + closure of Modal windows. Regression from 1.89.5. (#6357, #6299) | |
| 4079 | +- Viewports: Fixed loss of imgui-side focus when dragging a secondary viewport back in | |
| 4080 | + main viewport, due to platform-side handling changes. Regression from 1.89.5 (#6299) | |
| 4081 | +- Viewports: Avoid applying imgui-side focus when focus change is due to a viewport | |
| 4082 | + destruction. Fixes erroneous popup closure on closing a previous popup. (#6462, #6299) | |
| 4083 | +- Viewports: Added void* ImGuiPlatformMonitor::PlatformHandle field (backend-dependant), | |
| 4084 | + for usage by user code. | |
| 4085 | +- Backends: GLFW: Preserve monitor list when there are no monitor, may briefly | |
| 4086 | + happen when recovering from macOS sleeping mode. (#5683) [@Guistac] | |
| 4087 | +- Backends: SDL2: Update monitor list when receiving a display event. (#6348) | |
| 4088 | + Note however that SDL2 currently doesn't have an event for a DPI/Scaling change, | |
| 4089 | + so monitor data won't be updated in this situation. | |
| 4090 | +- Backends: SDL3: Update monitor list when receiving a display event. (#6348) | |
| 4091 | + | |
| 4092 | + | |
| 3549 | 4093 | ----------------------------------------------------------------------- |
| 3550 | 4094 | VERSION 1.89.5 (Released 2023-04-13) |
| 3551 | 4095 | ----------------------------------------------------------------------- |
| @@ -3602,7 +4146,6 @@ | ||
| 3602 | 4146 | is to other IME function such as SDL_SetTextInputRect(). (#6306, #6071, #1953) |
| 3603 | 4147 | - Backends: GLFW: Added support on Win32 only for io.AddMouseSourceEvent() to discriminate |
| 3604 | 4148 | Mouse/TouchScreen/Pen. (#2334, #2702) |
| 3605 | -- Backends: GLFW: Fixed key modifiers handling on secondary viewports. (#6248, #6034) [@aiekick] | |
| 3606 | 4149 | - Backends: Android: Added support for io.AddMouseSourceEvent() to discriminate Mouse/TouchScreen/Pen. |
| 3607 | 4150 | (#6315) [@PathogenDavid] |
| 3608 | 4151 | - Backends: OSX: Added support for io.AddMouseSourceEvent() to discriminate Mouse/Pen. |
| @@ -3618,7 +4161,17 @@ | ||
| 3618 | 4161 | - TestSuite: Added variety of new regression tests and improved/amended existing ones |
| 3619 | 4162 | in imgui_test_engine/ repo. [@PathogenDavid, @ocornut] |
| 3620 | 4163 | |
| 4164 | +Docking+Viewports Branch: | |
| 3621 | 4165 | |
| 4166 | +- Viewports: Setting focus from Platform/OS (e.g. via decoration, or Alt-Tab) sets corresponding | |
| 4167 | + focus at Dear ImGui level (generally last focused window in the viewport). (#6299) | |
| 4168 | +- Docking: Fixed using GetItemXXX() or IsItemXXX() functions after a DockSpace(). (#6217) | |
| 4169 | +- Backends: GLFW: Fixed key modifiers handling on secondary viewports. (#6248, #6034) [@aiekick] | |
| 4170 | +- Backends: GLFW: Fixed Emscripten erroneously enabling multi-viewport support, leading to assert. (#5683) | |
| 4171 | +- Backends: SDL2/SDL3: Fixed IME text input rectangle position with viewports. (#6071, #1953) | |
| 4172 | +- Backends: SDL3: Fixed for compilation with multi-viewports. (#6255) [@P3RK4N] | |
| 4173 | + | |
| 4174 | + | |
| 3622 | 4175 | ----------------------------------------------------------------------- |
| 3623 | 4176 | VERSION 1.89.4 (Released 2023-03-14) |
| 3624 | 4177 | ----------------------------------------------------------------------- |
| @@ -3692,7 +4245,6 @@ | ||
| 3692 | 4245 | and ImGuiConfigFlags_NavEnableGamepad by default. (#787) |
| 3693 | 4246 | - Internals: Misc tweaks to facilitate applying an explicit-context patch. (#5856) [@Dragnalith] |
| 3694 | 4247 | |
| 3695 | - | |
| 3696 | 4248 | ----------------------------------------------------------------------- |
| 3697 | 4249 | VERSION 1.89.3 (Released 2023-02-14) |
| 3698 | 4250 | ----------------------------------------------------------------------- |
| @@ -3793,7 +4345,11 @@ | ||
| 3793 | 4345 | - Examples: SDL2+SDL_Renderer: Added call to SDL_RenderSetScale() to fix display on a |
| 3794 | 4346 | Retina display (albeit lower-res as our other unmodified examples). (#6121, #6065, #5931). |
| 3795 | 4347 | |
| 4348 | +Docking+Viewports Branch: | |
| 3796 | 4349 | |
| 4350 | +- Backends: GLFW: Handle unsupported glfwGetVideoMode() for Emscripten. (#6096) | |
| 4351 | + | |
| 4352 | + | |
| 3797 | 4353 | ----------------------------------------------------------------------- |
| 3798 | 4354 | VERSION 1.89.2 (Released 2023-01-05) |
| 3799 | 4355 | ----------------------------------------------------------------------- |
| @@ -3843,7 +4399,18 @@ | ||
| 3843 | 4399 | - Backends: Vulkan: Fixed sampler passed to ImGui_ImplVulkan_AddTexture() not being honored as we were using |
| 3844 | 4400 | an immutable sampler. (#5502, #6001, #914) [@martin-ejdestig, @rytisss] |
| 3845 | 4401 | |
| 4402 | +Docking+Viewports Branch: | |
| 3846 | 4403 | |
| 4404 | +- Docking: Internals: fixed DockBuilderCopyDockSpace() crashing when windows not in the | |
| 4405 | + remapping list are docked on the left or top side of a split. (#6035) | |
| 4406 | +- Docking: fixed DockSpace() with ImGuiDockNodeFlags_KeepAliveOnly marking current window | |
| 4407 | + as written to, even if it doesn't technically submit an item. This allow using KeepAliveOnly | |
| 4408 | + from any window location. (#6037) | |
| 4409 | +- Backends: OSX: fixed typo in ImGui_ImplOSX_GetWindowSize that would cause issues when resiing | |
| 4410 | + from OS decorations, if they are enabled on secondary viewports. (#6009) [@sivu] | |
| 4411 | +- Backends: Metal: fixed secondary viewport rendering. (#6015) [@dmirty-kuzmenko] | |
| 4412 | + | |
| 4413 | + | |
| 3847 | 4414 | ----------------------------------------------------------------------- |
| 3848 | 4415 | VERSION 1.89.1 (Released 2022-11-24) |
| 3849 | 4416 | ----------------------------------------------------------------------- |
| @@ -3869,7 +4436,14 @@ | ||
| 3869 | 4436 | - Backends: GLFW: cancel out errors emitted by glfwGetKeyName() when a name is missing. (#5908) |
| 3870 | 4437 | - Backends: WebGPU: fixed validation error with default depth buffer settings. (#5869, #5914) [@kdchambers] |
| 3871 | 4438 | |
| 4439 | +Docking+Viewports Branch: | |
| 3872 | 4440 | |
| 4441 | +- Viewports: Fixed collapsed windows setting ImGuiViewportFlags_NoRendererClear without | |
| 4442 | + making title bar color opaque, leading to potential texture/fb garbage being visible. | |
| 4443 | + Right now as we don't fully support transparent viewports (#2766), so we turn that | |
| 4444 | + 'TitleBgCollapsed' color opaque just lke we do for 'WindowBG' on uncollapsed windows. | |
| 4445 | + | |
| 4446 | + | |
| 3873 | 4447 | ----------------------------------------------------------------------- |
| 3874 | 4448 | VERSION 1.89 (Released 2022-11-15) |
| 3875 | 4449 | ----------------------------------------------------------------------- |
| @@ -4060,7 +4634,24 @@ | ||
| 4060 | 4634 | - Backends: Vulkan: Added experimental ImGui_ImplVulkan_RemoveTexture() for api symmetry. (#914, #5738). |
| 4061 | 4635 | - Backends: WebGPU: fixed rendering when a depth buffer is enabled. (#5869) [@brainlag] |
| 4062 | 4636 | |
| 4637 | +Docking+Viewports Branch: | |
| 4063 | 4638 | |
| 4639 | +- Docking: Fixed incorrect focus highlight on docking node when focusing a menu. (#5702) | |
| 4640 | +- Docking, Nav: Fixed using gamepad/keyboard navigation not being able enter menu layer when | |
| 4641 | + it only contained the standard Collapse/Close buttons and no actual menu. (#5463, #4792) | |
| 4642 | +- Docking: Fixed regression introduced in v1.87 when docked window content not rendered | |
| 4643 | + while switching between with CTRL+Tab. [@rokups] | |
| 4644 | +- Docking: Fixed amending into an existing tab bar from rendering invisible items. (#5515) | |
| 4645 | +- Docking: Made spacing between dock nodes not a dropping gap. When hovering it only | |
| 4646 | + outer-docking drop markers are visible. | |
| 4647 | +- Docking+Viewports: Fixed undocking window node causing parent viewports to become unresponsive | |
| 4648 | + in certain situation (e.g. hidden tab bar). (#5503) [@rokups] | |
| 4649 | +- Backends: SDL: Fixed building backend under non-OSX Apple targets (e.g. iPhone). (#5665) | |
| 4650 | +- Backends: SDL: Fixed drag'n drop crossing a viewport border losing mouse coordinates. (#5710, #5012) | |
| 4651 | +- Backends: GLFW: Fixed leftover static variable preventing from changing or | |
| 4652 | + reinitializing backend while application is running. (#4616, #5434) [@rtoumazet] | |
| 4653 | + | |
| 4654 | + | |
| 4064 | 4655 | ----------------------------------------------------------------------- |
| 4065 | 4656 | VERSION 1.88 (Released 2022-06-21) |
| 4066 | 4657 | ----------------------------------------------------------------------- |
| @@ -4194,7 +4785,27 @@ | ||
| 4194 | 4785 | - Examples: Emscripten+WebGPU: Fix building for latest WebGPU specs. (#3632) |
| 4195 | 4786 | - Examples: OSX+Metal, OSX+OpenGL: Removed now-unnecessary calls to ImGui_ImplOSX_HandleEvent(). (#4821) |
| 4196 | 4787 | |
| 4788 | +Docking+Viewports Branch: | |
| 4197 | 4789 | |
| 4790 | +- Docking: Fixed floating docked nodes not being clamped into viewport workrect to stay reachable | |
| 4791 | + when io.ConfigWindowsMoveFromTitleBarOnly is true and multi-viewports are disabled. (#5044) | |
| 4792 | +- Docking: Fixed a regression where moving window would be interrupted after undocking a tab | |
| 4793 | + when io.ConfigDockingAlwaysTabBar is true. (#5324) [@rokups] | |
| 4794 | +- Docking: Fixed incorrect focus highlight on docking node when focusing empty central node | |
| 4795 | + or a child window which was manually injected into a dockspace window. | |
| 4796 | +- Docking, Modal: Fixed a crash when opening popup from a parent which is being docked on the same frame. (#5401) | |
| 4797 | +- Viewports: Fixed an issue where MouseViewport was lagging by a frame when using 1.87 Input Queue. | |
| 4798 | + A common side-effect would be that when releasing a window drag the underlying window would highlight | |
| 4799 | + for a frame. (#5837, #4921) [@cfillion] | |
| 4800 | +- Viewports: Fixed translating a host viewport from briefly altering the size of AlwaysAutoResize windows. (#5057) | |
| 4801 | +- Viewports: Fixed main viewport size not matching ImDrawData::DisplaySize for one frame during resize | |
| 4802 | + when multi-viewports are disabled. (#4900) | |
| 4803 | +- Backends: SDL: Fixed dragging out main viewport broken on some SDL setups. (#5012) [@rokups] | |
| 4804 | +- Backends: OSX: Added support for multi-viewports. [@stuartcarnie, @metarutaiga] (#4821, #2778) | |
| 4805 | +- Backends: Metal: Added support for multi-viewports. [@stuartcarnie, @metarutaiga] (#4821, #2778) | |
| 4806 | +- Examples: OSX+Metal, SDL+Metal, GLFW+Metal: Added support for multi-viewports. [@rokups] | |
| 4807 | + | |
| 4808 | + | |
| 4198 | 4809 | ----------------------------------------------------------------------- |
| 4199 | 4810 | VERSION 1.87 (Released 2022-02-07) |
| 4200 | 4811 | ----------------------------------------------------------------------- |
| @@ -4337,7 +4948,30 @@ | ||
| 4337 | 4948 | - Backends: WebGPU: Fixed incorrect size parameters in wgpuRenderPassEncoderSetIndexBuffer() and |
| 4338 | 4949 | wgpuRenderPassEncoderSetVertexBuffer() calls. (#4891) [@FeepsDev] |
| 4339 | 4950 | |
| 4951 | +Docking+Viewports Branch: | |
| 4340 | 4952 | |
| 4953 | +- Docking: Fixed a CTRL+TAB crash when aiming at an empty docked window. (#4792) | |
| 4954 | +- Docking: Tabs use their own identifier instead of the Window identifier. | |
| 4955 | + (This will invalidate some stored .ini data such as last selected tab, sorry!) | |
| 4956 | +- Docking: Fixed size constraints not working on single window holding on a dock id (still doesn't work on docked windows). | |
| 4957 | +- Docking: Fixed CTRL+TAB back into a docked window not selecting menu layer when no item are on main layer. | |
| 4958 | +- Viewports, IO: Added io.AddMouseViewportEvent() function to queue hovered viewport change (when known by backend). | |
| 4959 | +- Viewports: Relaxed specs for backend supporting ImGuiBackendFlags_HasMouseHoveredViewport: it is now _optional_ | |
| 4960 | + for the backend to have to ignore viewports with the _NoInputs flag when call io.AddMouseViewportEvent(). It is | |
| 4961 | + much better if they can (Win32 and GLFW 3.3+ backends can, SDL and GLFW 3.2 backends cannot, they are lacking data). | |
| 4962 | + A concrete example is: when dragging a viewport for docking, the viewport is marked with _NoInputs to allow us | |
| 4963 | + to pick the target viewports for docking. If the backend reports a viewport with _NoInputs when calling the | |
| 4964 | + io.AddMouseViewportEvent() function, then Dear ImGui will revert to its flawed heuristic to find the viewport under. | |
| 4965 | + By lowering those specs, we allow the SDL and more backend to support this, only relying on the heuristic in a few | |
| 4966 | + drag and drop situations rather that relying on it everywhere. | |
| 4967 | +- Viewports: Fixed a CTRL+TAB crash with viewports enabled when the window list needs to appears in | |
| 4968 | + its own viewport (regression from 1.86). (#4023, #787) | |
| 4969 | +- Viewports: Fixed active InputText() from preventing viewports to merge. (#4212) | |
| 4970 | +- Backends: SDL: Added support for ImGuiBackendFlags_HasMouseHoveredViewport now that its specs have been lowered. | |
| 4971 | +- (Breaking) Removed ImGuiPlatformIO::Platform_SetImeInputPos() in favor of newly standardized | |
| 4972 | + io.SetPlatformImeDataFn() function. Should not affect more than default backends. | |
| 4973 | + | |
| 4974 | + | |
| 4341 | 4975 | ----------------------------------------------------------------------- |
| 4342 | 4976 | VERSION 1.86 (Released 2021-12-22) |
| 4343 | 4977 | ----------------------------------------------------------------------- |
| @@ -4435,7 +5069,25 @@ | ||
| 4435 | 5069 | wgpuRenderPassEncoderSetIndexBuffer() functions as validation layers appears to not do what the |
| 4436 | 5070 | in-flux specs says. (#4766) [@meshula] |
| 4437 | 5071 | |
| 5072 | +Docking+Viewports Branch: | |
| 4438 | 5073 | |
| 5074 | +- Docking: Revert removal of io.ConfigDockingWithShift config option (removed in 1.83). (#4643) | |
| 5075 | +- Docking: Fixed a bug undocking windows docked into a non-visible or _KeepAliveOnly dockspace | |
| 5076 | + when unrelated windows submitted before the dockspace have dynamic visibility. (#4757) | |
| 5077 | +- Docking, Style: Docked windows honor ImGuiCol_WindowBg. (#2700, #2539) | |
| 5078 | +- Docking, Style: Docked windows honor display their border properly. (#2522) | |
| 5079 | +- Docking: Fixed incorrectly rounded tab bars for dock node that are not at the top of their dock tree. | |
| 5080 | +- Docking: Fixed single-frame node pos/size inconsistencies when window stop or start being submitted. | |
| 5081 | +- Docking: Prevent docking any window created above a popup/modal. (#4317) | |
| 5082 | +- Viewports: Made it possible to explicitly assign ImGuiWindowClass::ParentViewportId to 0 in order | |
| 5083 | + to ensure a window is not parented. Previously this would use the global default (which might be 0, | |
| 5084 | + but not always as it would depend on io.ConfigViewportsNoDefaultParent). (#3152, #2871) | |
| 5085 | +- Viewports: Fixed tooltip in own viewport over modal from being incorrectly dimmed. (#4729) | |
| 5086 | +- Viewports: Fixed CTRL+TAB highlight outline on docked windows not always fitting in host viewport. | |
| 5087 | +- Backends: Made it possible to shutdown default Platform Backends before the Renderer backends. (#4656) | |
| 5088 | +- Disabled: Fixed nested BeginDisabled()/EndDisabled() bug in Docking branch due to bad merge. (#4655, #4452, #4453, #4462) | |
| 5089 | + | |
| 5090 | + | |
| 4439 | 5091 | ----------------------------------------------------------------------- |
| 4440 | 5092 | VERSION 1.85 (Released 2021-10-12) |
| 4441 | 5093 | ----------------------------------------------------------------------- |
| @@ -4453,6 +5105,10 @@ | ||
| 4453 | 5105 | Can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead but it's not |
| 4454 | 5106 | very useful in practice, and the only use of it in the demo was illfit. |
| 4455 | 5107 | Using 'GetContentRegionAvail().x' is generally a better choice. |
| 5108 | +- (Docking branch) IsWindowFocused() and IsWindowHovered() with only the _ChildWindows flag | |
| 5109 | + and without the _RootWindow flag used to leak docking hierarchy, so a docked window would | |
| 5110 | + return as the child of the window hosting the dockspace. This was inconsistent and incorrect | |
| 5111 | + with other behaviors so we fixed it. Added a new _DockHierarchy flag to opt-in this behavior. | |
| 4456 | 5112 | |
| 4457 | 5113 | Other Changes: |
| 4458 | 5114 | |
| @@ -4526,7 +5182,30 @@ | ||
| 4526 | 5182 | - Backends: All renderers: Normalize clipping rect handling across backends. (#4464) |
| 4527 | 5183 | - Examples: Added SDL + SDL_Renderer example in "examples/example_sdl_sdlrenderer/" folder. (#3926) [@1bsyl] |
| 4528 | 5184 | |
| 5185 | +Docking+Viewports Branch: | |
| 4529 | 5186 | |
| 5187 | +- IsWindowFocused: Fixed using ImGuiFocusedFlags_ChildWindows (without _RootWindow) from leaking the | |
| 5188 | + docking hierarchy. Added ImGuiFocusedFlags_DockHierarchy flag to consider docking hierarchy in the test. | |
| 5189 | +- IsWindowHovered: Fixed using ImGuiHoveredFlags_ChildWindows (without _RootWindow) from leaking the | |
| 5190 | + docking hierarchy. Added ImGuiHoveredFlags_DockHierarchy flag to consider docking hierarchy in the test. | |
| 5191 | +- Nav: Fixed an issue with losing focus on docked windows when pressing Alt while keyboard navigation | |
| 5192 | + is disabled. (#4547, #4439) [@PathogenDavid] | |
| 5193 | +- Docking: Fixed IsItemHovered() and functions depending on it (e.g. BeginPopupContextItem()) when | |
| 5194 | + called after Begin() on a docked window (broken 2021/03/04). (#3851) | |
| 5195 | +- Docking: Improved resizing system so that non-central zone are better at keeping their fixed size. | |
| 5196 | + The algorithm is still not handling the allocation of size ideally for nested sibling, but it got better. | |
| 5197 | +- Docking: Fixed settings load issue when mouse wheeling. (#4310) | |
| 5198 | +- Docking: Fixed manually created floating node with a central node from not hiding when windows are gone. | |
| 5199 | +- Docking + Drag and Drop: Fixed using BeginDragDropSource() or BeginDragDropTarget() inside a Begin() | |
| 5200 | + that returned false because the window is docked. (#4515) | |
| 5201 | +- Viewports: Fixed a crash while a window owning its viewport disappear while being dragged. | |
| 5202 | + It would manifest when e.g. reconfiguring dock nodes while dragging. | |
| 5203 | +- Viewports: Fixed unnecessary creation of temporary viewports when multiple docked windows | |
| 5204 | + got reassigned to a new node (created mid-frame) which already has a HostWindow. | |
| 5205 | +- Viewports: Fixed window with viewport ini data immediately merged into a host viewport from | |
| 5206 | + leaving a temporary viewport alive for a frame (would leak into backend). | |
| 5207 | + | |
| 5208 | + | |
| 4530 | 5209 | ----------------------------------------------------------------------- |
| 4531 | 5210 | VERSION 1.84.2 (Released 2021-08-23) |
| 4532 | 5211 | ----------------------------------------------------------------------- |
| @@ -4662,7 +5341,26 @@ | ||
| 4662 | 5341 | - Examples: Updated all .vcxproj to VS2015 (toolset v140) to facilitate usage with vcpkg. |
| 4663 | 5342 | - Examples: SDL2: Accommodate for vcpkg install having headers in SDL2/SDL.h vs SDL.h. |
| 4664 | 5343 | |
| 5344 | +Docking+Viewports Branch: | |
| 4665 | 5345 | |
| 5346 | +- Docking: Clicking on the right-most close button of a docking node closes all windows. (#4186) | |
| 5347 | +- Docking: Fix IsWindowAppearing() and ImGuiCond_Appearing on docked windows. (#4177, #3982, #1497, #1061) | |
| 5348 | +- Docking: Fix crash using DockBuilderRemoveNode() in some situations. (#3111, #3179, #3203, #4295) [@hsimyu] | |
| 5349 | +- Docking: Fix crash when a dock node gets re-qualified as dockspace>floating>dockspace, which tends to happen | |
| 5350 | + when incorrectly calling DockBuilderAddNode() without ImGuiDockNodeFlags_Dockspace and using it as a Dockspace | |
| 5351 | + on the next frame after the floating window hosting the node has been automatically created. (#3203, #4295) | |
| 5352 | +- Docking: Reworked node flags saving/inheritance so that flags enforced by docked windows via the | |
| 5353 | + DockNodeFlagsOverrideSet mechanism are are not left in empty dockspace nodes once the windows gets undocked. | |
| 5354 | + (#4292, #3834, #3633, #3521, #3492, #3335, #2999, #2648) | |
| 5355 | +- Docking: (Internal/Experimental) Removed DockNodeFlagsOverrideClear flags from ImGuiWindowClass as | |
| 5356 | + it is ambiguous how to apply them and we haven't got a use out of them yet. | |
| 5357 | +- Docking: Fixed ImGuiWindowFlags_UnsavedDocument clipping label in docked windows when there are | |
| 5358 | + no close button. (#5745) | |
| 5359 | +- Viewports: Fix popup/tooltip created without a parent window from being given a ParentViewportId value | |
| 5360 | + from the implicit/fallback window. (#4236, #2409) | |
| 5361 | +- Backends: Vulkan: Fix the use of the incorrect fence for secondary viewports. (#4208) [@FunMiles] | |
| 5362 | + | |
| 5363 | + | |
| 4666 | 5364 | ----------------------------------------------------------------------- |
| 4667 | 5365 | VERSION 1.83 (Released 2021-05-24) |
| 4668 | 5366 | ----------------------------------------------------------------------- |
| @@ -4746,7 +5444,23 @@ | ||
| 4746 | 5444 | - Docs: Improvements to description of using colored glyphs/emojis. (#4169, #3369) |
| 4747 | 5445 | - Docs: Improvements to minor mistakes in documentation comments (#3923) [@ANF-Studios] |
| 4748 | 5446 | |
| 5447 | +Docking+Viewports Branch: | |
| 4749 | 5448 | |
| 5449 | +- [Breaking] Removed io.ConfigDockingWithShift config option. Behavior always equivalent to having the | |
| 5450 | + option set to false (dock/undock by default, hold shift to avoid docking). (#2109) | |
| 5451 | +- Docking: DockSpace() returns its node ID. | |
| 5452 | +- Docking: Dockspace() never draws a background. (#3924) | |
| 5453 | +- Docking: Undocking nodes/windows covering most of the monitor max their size down to 90% to ease manipulations. | |
| 5454 | +- Docking: Docking node tab bar honors ItemInnerSpacing.x before first tab. (#4130) | |
| 5455 | +- Docking: Tweak rendering and alignment of dock node menu marker. (#4130) | |
| 5456 | +- Docking: Fixed restoring of tab order within a dockspace or a split node. | |
| 5457 | +- Docking: Fixed reappearing docked windows with no close button showing a tab with extraneous space for one frame. | |
| 5458 | +- Docking: Fixed multiple simultaneously reappearing window from appearing undocked for one frame. | |
| 5459 | +- Viewports: Hotfix for crash in monitor array access, caused by 4b9bc4902. (#3967) | |
| 5460 | +- Backends, Viewports: GLFW: Add a workaround for stuck keys after closing a GLFW window (#3837). | |
| 5461 | +- Backends, Viewports: Vulkan: Rebuild swapchain on VK_SUBOPTIMAL_KHR. (#3881) | |
| 5462 | + | |
| 5463 | + | |
| 4750 | 5464 | ----------------------------------------------------------------------- |
| 4751 | 5465 | VERSION 1.82 (Released 2021-02-15) |
| 4752 | 5466 | ----------------------------------------------------------------------- |
| @@ -4841,7 +5555,14 @@ | ||
| 4841 | 5555 | scheduled builds builds are not required. [@rokups] |
| 4842 | 5556 | - Log/Capture: Added LogTextV, a va_list variant of LogText. [@PathogenDavid] |
| 4843 | 5557 | |
| 5558 | +Docking+Viewports Branch: | |
| 4844 | 5559 | |
| 5560 | +- Viewports: Fix setting of ImGuiViewportFlags_NoRendererClear. (#3213) | |
| 5561 | +- Viewports: Added GetViewportPlatformMonitor() with a safety net to keep code portable. | |
| 5562 | +- Viewports, Backends: SDL: Fix missing ImGuiBackendFlags_HasSetMousePos flag in docking branch. | |
| 5563 | +- Viewports, Backends: GLFW: Fix application of WantSetMousePos. (#1542, #787) | |
| 5564 | + | |
| 5565 | + | |
| 4845 | 5566 | ----------------------------------------------------------------------- |
| 4846 | 5567 | VERSION 1.81 (Released 2021-02-10) |
| 4847 | 5568 | ----------------------------------------------------------------------- |
| @@ -4922,7 +5643,18 @@ | ||
| 4922 | 5643 | - Examples: WebGPU: Added Emscripten+WebGPU example. (#3632) [@bfierz] |
| 4923 | 5644 | - Backends: GLFW: Added ImGui_ImplGlfw_InitForOther() initialization call to use with non OpenGL API. (#3632) |
| 4924 | 5645 | |
| 5646 | +Docking+Viewports Branch: | |
| 4925 | 5647 | |
| 5648 | +- Docking: Fix losing docking information on closed windows for which the hosting node was split. (#3716) [@GamingMinds-DanielC] | |
| 5649 | +- Docking: Fix gap in hit test hole when using ImGuiDockNodeFlags_PassthruCentralNode touching the edge of a viewport. (#3733) | |
| 5650 | +- Viewports: (Breaking) removed ImGuiPlatformIO::MainViewport which is now pretty much unused and duplicate | |
| 5651 | + (and misleading as we will evolve the concept). | |
| 5652 | +- Viewports: (Breaking) turned ImGuiViewport::GetWorkPos(), ImGuiViewport::GetWorkSize() into regular fields | |
| 5653 | + (WorkPos, WorkSize) before exposing in master branch. | |
| 5654 | +- Viewports: Fix issue inferring viewport z-order when new popups gets created. (#3734) + Metrics updates. | |
| 5655 | +- Viewports, Backends: Vulkan: handle VK_ERROR_OUT_OF_DATE_KHR when resizing secondary viewport (#3766, #3758) | |
| 5656 | + | |
| 5657 | + | |
| 4926 | 5658 | ----------------------------------------------------------------------- |
| 4927 | 5659 | VERSION 1.80 (Released 2021-01-21) |
| 4928 | 5660 | ----------------------------------------------------------------------- |
| @@ -5041,7 +5773,15 @@ | ||
| 5041 | 5773 | - Docs: Split examples/README.txt into docs/BACKENDS.md and docs/EXAMPLES.md, and improved them. |
| 5042 | 5774 | - Docs: Consistently renamed all occurrences of "binding" and "back-end" to "backend" in comments and docs. |
| 5043 | 5775 | |
| 5776 | +Docking+Viewports Branch: | |
| 5044 | 5777 | |
| 5778 | +- Docking: Docked windows honor change of tab and text colors. (#2771) | |
| 5779 | +- Docking: Support for appending into existing tab-bar made to work with Docking + internal helper DockNodeBeginAmendTabBar(). | |
| 5780 | +- Docking: Added experimental TabItemFlagsOverrideSet to ImGuiWindowClass. | |
| 5781 | +- Viewports: Fixed incorrect whitening of popups above a modal if both use their own viewport. | |
| 5782 | +- Viewports: Backends: Vulkan: Fixed build, removed extraneous pipeline creation. (#3459, #3579) | |
| 5783 | + | |
| 5784 | + | |
| 5045 | 5785 | ----------------------------------------------------------------------- |
| 5046 | 5786 | VERSION 1.79 (Released 2020-10-08) |
| 5047 | 5787 | ----------------------------------------------------------------------- |
| @@ -5135,7 +5875,22 @@ | ||
| 5135 | 5875 | - Examples: DX12: Added '#define ImTextureID ImU64' in project and build files to also allow building |
| 5136 | 5876 | on 32-bit systems. Added project to default Visual Studio solution file. (#301) |
| 5137 | 5877 | |
| 5878 | +Docking+Viewports Branch: | |
| 5138 | 5879 | |
| 5880 | +- Docking: DockSpace() emits ItemSize() properly (useful when not filling all space). | |
| 5881 | +- Docking: Fixed docking while hovering a child window. (#3420) broken by 85a661d. Improve metrics debugging. | |
| 5882 | +- Docking: Fix honoring payload filter with overlapping nodes (we incorrectly over-relied on g.HoveredDockNode | |
| 5883 | + when making change for #3398). | |
| 5884 | +- Docking: Fix handling of WindowMenuButtonPosition == ImGuiDir_None in Docking Nodes. (#3499) | |
| 5885 | +- Viewports: Fixed a rare edge-case if the window targeted by CTRL+Tab stops being rendered. | |
| 5886 | +- Viewports, Backends: DX12: Make secondary viewport format match main viewport one (#3462) {@BeastLe9enD] | |
| 5887 | +- Viewports: Backends: Vulkan: Removed unused shader code. Fix leaks. Avoid unnecessary pipeline creation for main | |
| 5888 | + viewport. (#3459) + Add ImGui_ImplVulkanH_CreateWindowSwapChain in ImGui_ImplVulkanH_CreateOrResizeWindow(). | |
| 5889 | +- Viewports: Backends: DirectX9: Recover from D3DERR_DEVICELOST on secondary viewports. (#3424) | |
| 5890 | +- Viewports, Backends: Win32: Fix toggling of ImGuiViewportFlags_TopMost (#3477) [@Kodokuna] | |
| 5891 | +- Viewports: Backends: GLFW: Workaround for cases where glfwGetMonitorWorkarea fails (#3457) [@dougbinks] | |
| 5892 | + | |
| 5893 | + | |
| 5139 | 5894 | ----------------------------------------------------------------------- |
| 5140 | 5895 | VERSION 1.78 (Released 2020-08-18) |
| 5141 | 5896 | ----------------------------------------------------------------------- |
| @@ -5236,7 +5991,24 @@ | ||
| 5236 | 5991 | - Examples: Vulkan: Fixed GLFW+Vulkan and SDL+Vulkan clear color not being set. (#3390) [@RoryO] |
| 5237 | 5992 | - CI: Emscripten has stopped their support for their fastcomp backend, switching to latest sdk [@Xipiryon] |
| 5238 | 5993 | |
| 5994 | +Docking+Viewports Branch: | |
| 5239 | 5995 | |
| 5996 | +- Docking: Made DockBuilderAddNode() automatically call DockBuilderRemoveNode(). (#3399, #2109) | |
| 5997 | +- Docking: Storing HoveredDockNode in context which can be useful for easily detecting e.g. hovering an | |
| 5998 | + empty node. (#3398) | |
| 5999 | +- Docking: Fixed docking overlay bits appearing at (0,0), because of 43bd80a. Most typically noticeable | |
| 6000 | + when disabling multi-viewport. | |
| 6001 | +- Docking: Workaround recovery for node created without the _DockSpace flags later becoming a DockSpace. (#3340) | |
| 6002 | +- Docking: Rework size allocations to recover when there's no enough room for nodes + do not hold on | |
| 6003 | + _WantLockSizeOnce forever. (#3328) | |
| 6004 | +- Docking: Rework size allocation to allow user code to override node sizes. Not all edge cases will be | |
| 6005 | + properly handled but this is a step toward toolbar emitting size constraints. | |
| 6006 | +- Docking: Added experimental flags to perform more docking filtering and disable resize per axis. | |
| 6007 | + Designed for toolbar patterns. | |
| 6008 | +- Viewports, Backends, GLFW: Use GLFW_MOUSE_PASSTHROUGH when available. | |
| 6009 | +- Viewports, Backends: DX12: Fixed issue on shutdown when viewports are disabled. (#3347) | |
| 6010 | + | |
| 6011 | + | |
| 5240 | 6012 | ----------------------------------------------------------------------- |
| 5241 | 6013 | VERSION 1.77 (Released 2020-06-29) |
| 5242 | 6014 | ----------------------------------------------------------------------- |
| @@ -5327,7 +6099,18 @@ | ||
| 5327 | 6099 | - Examples: Apple: Fixed example_apple_metal and example_apple_opengl2 using imgui_impl_osx.mm |
| 5328 | 6100 | not forwarding right and center mouse clicks. (#3260) [@nburrus] |
| 5329 | 6101 | |
| 6102 | +Docking+Viewports Branch: | |
| 5330 | 6103 | |
| 6104 | +- Viewports: Don't set ImGuiViewportFlags_NoRendererClear when ImGuiWindowFlags_NoBackground is set. (#3213) | |
| 6105 | +- Viewports: Report minimized viewports as zero DisplaySize to be consistent with main branch. (#1542) | |
| 6106 | +- Docking, Settings: Allow reload of settings data at runtime. (#2573) | |
| 6107 | +- Backends, GLFW: Fix windows resizing incorrectly on Linux due to GLFW firing window positioning | |
| 6108 | + callbacks on next frame after window is resized manually. (#2117) | |
| 6109 | +- Backends: DX12: Fix OBJECT_DELETED_WHILE_STILL_IN_USE on viewport resizing. (#3210) | |
| 6110 | +- Backends: DX12: Fix for crash caused by early resource release. (#3121) | |
| 6111 | +- Backends, Win32: Request monitor update when DPI awareness is enabled to make sure they have the correct DPI settings. | |
| 6112 | + | |
| 6113 | + | |
| 5331 | 6114 | ----------------------------------------------------------------------- |
| 5332 | 6115 | VERSION 1.76 (Released 2020-04-12) |
| 5333 | 6116 | ----------------------------------------------------------------------- |
| @@ -5399,7 +6182,21 @@ | ||
| 5399 | 6182 | - Examples: SDL+DX11: Fixed resizing main window. (#3057) [@joeslay] |
| 5400 | 6183 | - Examples: Added SDL+Metal example application. (#3017) [@coding-jackalope] |
| 5401 | 6184 | |
| 6185 | +Docking+Viewports Branch: | |
| 5402 | 6186 | |
| 6187 | +- Docking: Fixed assert preventing dockspace from being created instead a hidden tab. (#3101) | |
| 6188 | +- Viewports: Fixed secondary viewports accidentally merging into a minimized host viewport. (#3118) | |
| 6189 | +- Viewports, Docking: Added per-viewport work area system for e.g. menu-bars. Fixed DockspaceOverViewport() | |
| 6190 | + and demo code (overlay etc) accordingly. (#3035, #2889, #2474, #1542, #2109) | |
| 6191 | +- Viewports: Improve menu positioning in multi-monitor setups. [@rokups] | |
| 6192 | +- Viewports: Software mouse cursor is also scaled by current DpiScale. (amend #939) | |
| 6193 | +- Viewports: Avoid manually clipping resize grips and borders, which messes up with automation ability | |
| 6194 | + to locate those items. Also simpler and more standard. | |
| 6195 | +- Viewports: Fix for UWP in the imgui_impl_win32.cpp IME handler. (#2895, #2892). | |
| 6196 | +- Viewports: Bunch of extra of comments to facilitate setting up multi-viewports. | |
| 6197 | +- Viewports, GLFW: Avoid using window positioning workaround for GLFW 3.3+ versions that have it fixed. | |
| 6198 | + | |
| 6199 | + | |
| 5403 | 6200 | ----------------------------------------------------------------------- |
| 5404 | 6201 | VERSION 1.75 (Released 2020-02-10) |
| 5405 | 6202 | ----------------------------------------------------------------------- |
| @@ -5497,7 +6294,22 @@ | ||
| 5497 | 6294 | - Examples: Metal: Wrapped main loop in @autoreleasepool block to ensure allocations get freed |
| 5498 | 6295 | even if underlying system event loop gets paused due to app nap. (#2910, #2917) [@bear24rw] |
| 5499 | 6296 | |
| 6297 | +Docking+Viewports Branch: | |
| 5500 | 6298 | |
| 6299 | +- Docking + Nav: Fixed messed up Ctrl+Tab order with docked windows. | |
| 6300 | +- Docking + Nav: Fixed failing to restore NavId when refocusing a child within a docked window. | |
| 6301 | +- Docking + Nav: Fixed failing to restore NavId when refocusing due to missing nav window (when | |
| 6302 | + it stops being submitted). | |
| 6303 | +- Docking: Fixed a bug where the tab bar of a hidden dockspace would keep requesting focus. (#2960) | |
| 6304 | +- Docking: Added experimental DockNodeFlagsOverrideSet/DockNodeFlagsOverrideClear flags in ImGuiWindowClass | |
| 6305 | + (currently experimenting with toolbar idioms). | |
| 6306 | +- Viewports: Fix resizing viewport-owning windows when mouse pos is outside the InnerClipRect | |
| 6307 | + (can happen with OS decoration enabled). | |
| 6308 | +- Viewports: Preserve last known size for minimized main viewport to be consistent with secondary viewports. | |
| 6309 | +- Backends: SDL: Honor NoTaskBarIcon flag under non Win32 OS. (#2117) | |
| 6310 | +- Backends: GLFW, SDL: Platform monitors declared properly even if multi-viewport is not enabled. | |
| 6311 | + | |
| 6312 | + | |
| 5501 | 6313 | ----------------------------------------------------------------------- |
| 5502 | 6314 | VERSION 1.74 (Released 2019-11-25) |
| 5503 | 6315 | ----------------------------------------------------------------------- |
| @@ -5576,7 +6388,15 @@ | ||
| 5576 | 6388 | - CI: Set up a bunch of continuous-integration tests using GitHub Actions. We now compile many of the example |
| 5577 | 6389 | applications on Windows, Linux, MacOS, iOS, Emscripten. Removed Travis integration. (#2865) [@rokups] |
| 5578 | 6390 | |
| 6391 | +Docking+Viewports Branch: | |
| 5579 | 6392 | |
| 6393 | +- Docking: Can undock from the small triangle button. (#2109,. #2645) | |
| 6394 | +- Docking: Fixed node->HasCloseButton not honoring ImGuiDockNodeFlags_NoCloseButton in a floating node, | |
| 6395 | + leading to empty space at the right of tab-bars with those flags. (#2109) | |
| 6396 | +- Docking: Made docked windows not use style.ChildRounding. | |
| 6397 | +- Multi-viewports: Added multi-viewport support in the DX12 back-end. (#2851) [@obfuscate] | |
| 6398 | + | |
| 6399 | + | |
| 5580 | 6400 | ----------------------------------------------------------------------- |
| 5581 | 6401 | VERSION 1.73 (Released 2019-09-24) |
| 5582 | 6402 | ----------------------------------------------------------------------- |
| @@ -5638,7 +6458,29 @@ | ||
| 5638 | 6458 | - Misc: Updated stb_rect_pack.h from 0.99 to 1.00 (fixes by @rygorous: off-by-1 bug in best-fit heuristic, |
| 5639 | 6459 | fix handling of rectangles too large to fit inside texture). (#2762) [@tido64] |
| 5640 | 6460 | |
| 6461 | +Docking+Viewports Branch: | |
| 5641 | 6462 | |
| 6463 | +- Docking: Fix BeginDocked() path that creates node so that SetNextWindowDockID() doesn't immediately discard the node. (#2109) | |
| 6464 | +- Docking: Fix for node created at the same time as windows that are still resizing (typically with | |
| 6465 | + io.ConfigDockingAlwaysTabBar) to not be zero/min sized. (#2109). The fix delays their visibility by one frame, | |
| 6466 | + which is not ideal but not very problematic as the .ini data gets populated after that. | |
| 6467 | +- Docking: Fix a crash that could occur with a malformed ini file (DockNode Parent value pointing to a missing node). | |
| 6468 | +- Viewport: Fix modal/popup window being stuck in unowned hidden viewport associated to fallback window without stealing | |
| 6469 | + it back. Fix modal reference viewport when opened outside of another window. (#1542) | |
| 6470 | +- Viewport: Modals don't need to set ImGuiViewportFlags_NoFocusOnClick, this also mitigate the issue described by #2445, | |
| 6471 | + which becomes particularly bad with unfocused modal. (#1542) | |
| 6472 | +- Viewport: better case case where host window gets moved and resized simultaneous (toggling maximized state). | |
| 6473 | + There's no perfect solution there, than using io.ConfigViewportsNoAutoMerge = false. (#1542) | |
| 6474 | +- Viewport, Docking: Fixed incorrect assignment of IsFallbackWindow which would tag dock node host windows created | |
| 6475 | + in NewFrame() as such, messing with popup viewport inheritance. | |
| 6476 | +- Viewport: Fixed issue where resize grip would display as hovered while mouse is still off the OS bounds so a click | |
| 6477 | + would miss it and focus the OS window behind expected one. (#1542) | |
| 6478 | +- Viewport: Fix to allow multiple shutdown / calls to DestroyPlatformWindows(). (#2769) | |
| 6479 | +- Viewport: Backends: GLFW: Fix setting window size on macOS (#2767, #2117) [@rokups] | |
| 6480 | +- Viewport: Backends: GLFW+Linux: Fix window having incorrect size after uncollapse. (#2756, #2117) [@rokups] | |
| 6481 | +- Viewport: Backends: DirectX9: Workaround for windows not refreshing when main viewport has no draw call. (#2560) | |
| 6482 | + | |
| 6483 | + | |
| 5642 | 6484 | ----------------------------------------------------------------------- |
| 5643 | 6485 | VERSION 1.72b (Released 2019-07-31) |
| 5644 | 6486 | ----------------------------------------------------------------------- |
| @@ -5740,7 +6582,26 @@ | ||
| 5740 | 6582 | (#2482, #2632) [@josiahmanson] |
| 5741 | 6583 | - Examples: Added SDL2+DirectX11 example application. (#2632, #2612, #2482) [@vincenthamm] |
| 5742 | 6584 | |
| 6585 | +Docking+Viewports Branch: | |
| 5743 | 6586 | |
| 6587 | +- Docking: Making it possible to undock a node by clicking on the tab bar / title bar for the node. (#2645). | |
| 6588 | +- Docking: Explicitly inhibit constraint when docked for now. Fix clipping issue related to constraints. (#2690). | |
| 6589 | +- Docking: Fixed dragging/resizing from OS decoration not marking settings as dirty. | |
| 6590 | +- Docking: Renamed io.ConfigDockingTabBarOnSingleWindows to io.ConfigDockingAlwaysTabBar. | |
| 6591 | + Added ImGuiWindowClass::DockingAlwaysTabBar to set on individual windows. | |
| 6592 | +- Docking: Perform simple check: assert if Docking or Viewport are enabled exactly on frame 1 (instead of frame 0 | |
| 6593 | + or later), which is a common user error leading to loss of .ini data on load. | |
| 6594 | +- Docking: Fix so that an appearing window making a dock node reappear won't have a zero-size on its first frame. | |
| 6595 | +- Docking: Fixed using ImGuiDockNodeFlags_AutoHideTabBar with io.ConfigDockingTabBarOnSingleWindows. | |
| 6596 | +- Docking: Added ImGuiDockNode to .natvis file. | |
| 6597 | +- Docking: Fixed support for large meshes in GetBackgroundDrawList(), GetForegroundDrawList(). (#2638) | |
| 6598 | +- Viewport: Fix monitor dpi info not being copied to main viewport when multi-viewports are not enabled. (#2621, #1676) | |
| 6599 | +- Viewport: Refactored ImGuiWindowClass's ViewportFlagsOverrideMask + ViewportFlagsOverrideValue into | |
| 6600 | + ViewportFlagsOverrideSet + ViewportFlagsOverrideClear which appears easier to grasp. (#1542) | |
| 6601 | +- Viewport: Added ImGuiViewportFlags_NoAutoMerge to prevent merging into host viewport in a per-window basis | |
| 6602 | + via the ImGuiWindowClass override mechanism. (#1542) | |
| 6603 | + | |
| 6604 | + | |
| 5744 | 6605 | ----------------------------------------------------------------------- |
| 5745 | 6606 | VERSION 1.71 (Released 2019-06-12) |
| 5746 | 6607 | ----------------------------------------------------------------------- |
| @@ -6079,6 +6940,7 @@ | ||
| 6079 | 6940 | - Renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete). |
| 6080 | 6941 | |
| 6081 | 6942 | Other Changes: |
| 6943 | + | |
| 6082 | 6944 | - Added BETA api for Tab Bar/Tabs widgets: (#261, #351) |
| 6083 | 6945 | - Added BeginTabBar(), EndTabBar(), BeginTabItem(), EndTabItem(), SetTabItemClosed() API. |
| 6084 | 6946 | - Added ImGuiTabBarFlags flags for BeginTabBar(). |
| @@ -77,6 +77,17 @@ | ||
| 77 | 77 | You can use the `ImFontGlyphRangesBuilder` for this purpose and rebuilding your atlas between frames when new characters are needed. This will be the biggest win! |
| 78 | 78 | - Set `io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;` to disable rounding the texture height to the next power of two. |
| 79 | 79 | |
| 80 | +### (5) Reduce texture resizes/copy on startup | |
| 81 | + | |
| 82 | +🆕 Since 1.92, the ImFontAtlas is initially created using a 512x128 texture, then grows as glyphs and fonts are used. Atlas growth leads to alloc+copy, and both the old and new sized textures are present in memory for a short time (typically one frame). If you use known fonts and want to reduce initial growth, you may set `TexMinWidth` and `TexMinHeight` during initializaton. | |
| 83 | + | |
| 84 | +```cpp | |
| 85 | +ImFontAtlas* atlas = io.Fonts; | |
| 86 | +atlas->TexMinWidth = 1024; | |
| 87 | +atlas->TexMinHeight = 1024; | |
| 88 | +atlas->AddFont(...); | |
| 89 | +``` | |
| 90 | + | |
| 80 | 91 | ##### [Return to Index](#index) |
| 81 | 92 | |
| 82 | 93 | --------------------------------------- |
| @@ -43,7 +43,7 @@ | ||
| 43 | 43 | |
| 44 | 44 | **Backends for a variety of graphics API and rendering platforms** are provided in the [backends/](https://github.com/ocornut/imgui/tree/master/backends) folder, along with example applications in the [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder. You may also create your own backend. Anywhere where you can render textured triangles, you can render Dear ImGui. |
| 45 | 45 | |
| 46 | -C++20 users wishing to use a module may the use [stripe2933/imgui-module](https://github.com/stripe2933/imgui-module) third-party extension. | |
| 46 | +C++20 users wishing to use a module may use the [stripe2933/imgui-module](https://github.com/stripe2933/imgui-module) third-party extension. | |
| 47 | 47 | |
| 48 | 48 | See the [Getting Started & Integration](#getting-started--integration) section of this document for more details. |
| 49 | 49 |
| @@ -115,7 +115,35 @@ | ||
| 115 | 115 | - separator: width, thickness, centering (#1643, #2657) |
| 116 | 116 | - splitter: formalize the splitter idiom into an official api (we want to handle n-way split) (#319) |
| 117 | 117 | |
| 118 | - - docking: merge docking branch (#2109) | |
| 118 | + - docking: B: ordering currently held in tab bar should be implicitly held by windows themselves (also see #2304) | |
| 119 | + - docking: B- tab bar: the order/focus restoring code could be part of TabBar and not DockNode? (#8) | |
| 120 | + - docking: B~ rework code to be able to lazily create tab bar instance in a single place. The _Unsorted tab flag could be replacing a trailing-counter in DockNode? | |
| 121 | + - docking: B~ fully track windows/settings reference in dock nodes. perhaps find a representation that allows facilitate use of dock builder functions. | |
| 122 | + - docking: B~ Unreal style document system (requires low-level controls of dockspace serialization fork/copy/delete). this is mostly working but the DockBuilderXXX api are not exposed/finished. | |
| 123 | + - docking: B: when docking outer, perform size locking on neighbors nodes the same way we do it with splitters, so other nodes are not resized. | |
| 124 | + - docking: B~ central node resizing behavior incorrect. | |
| 125 | + - docking: B: changing title font/style per-window is not supported as dock nodes are created in NewFrame. | |
| 126 | + - docking: B- dock node inside its own viewports creates 1 temporary viewport per window on startup before ditching them (doesn't affect the user nor request platform windows to be created, but unnecessary) | |
| 127 | + - docking: B- resize sibling locking behavior may be less desirable if we merged same-axis sibling in a same node level? | |
| 128 | + - docking: B- single visible node part of a hidden split hierarchy (OnlyNodeWithWindows != NULL) should show a normal title bar (not a tab bar) | |
| 129 | + - docking: B~ SetNextWindowDock() calls (with conditional) -> defer everything to DockContextUpdate (repro: Documents->[X]Windows->Dock 1 elsewhere->Click Redock All | |
| 130 | + - docking: B~ tidy up tab list popup buttons features (available with manual tab-bar, see ImGuiTabBarFlags_NoTabListPopupButton code, not used by docking nodes) | |
| 131 | + - docking: B- SetNextWindowDockId(0) with a second Begin() in the frame will asserts | |
| 132 | + - docking: B: resize grip drawn in host window typically appears under scrollbar. | |
| 133 | + - docking: B: resize grip auto-resize on multiple node hierarchy doesn't make much sense or should be improved? | |
| 134 | + - docking: B- SetNextWindowFocus() doesn't seem to apply if the window is hidden this frame, need repro (#4) | |
| 135 | + - docking: B- resizing a dock tree small currently has glitches (overlapping collapse and close button, etc.) | |
| 136 | + - docking: B- dpi: look at interaction with the hi-dpi and multi-dpi stuff. | |
| 137 | + - docking: B- tab bar: appearing on first frame with a dumb layout would do less harm that not appearing? (when behind dynamic branch) or store titles + render in EndTabBar() | |
| 138 | + - docking: B- tab bar: make selected tab always shows its full title? | |
| 139 | + - docking: B- hide close button on single tab bar? | |
| 140 | + - docking: B- nav: design interactions so nav controls can dock/undock | |
| 141 | + - docking: B- dockspace: flag to lock the dock tree and/or sizes (ImGuiDockNodeFlags_Locked?) | |
| 142 | + - docking: B- reintroduce collapsing a floating dock node. also collapsing a docked dock node! | |
| 143 | + - docking: B- allow dragging a non-floating dock node by clicking on the title-bar-looking section (not just the collapse/menu button) | |
| 144 | + - docking: B- option to remember undocked window size? (instead of keeping their docked size) (relate to #2104) | |
| 145 | + - docking: C- nav: CTRL+TAB highlighting tabs shows the mismatch between focus-stack and tab-order (not visible in VS because it doesn't highlight the tabs) | |
| 146 | + - docking: C- after a dock/undock, the Scrollbar Status update in Begin() should use an updated e.g. size_y_for_scrollbars to avoid a 1 frame scrollbar flicker. | |
| 119 | 147 | |
| 120 | 148 | - tabs: "there is currently a problem because TabItem() will try to submit their own tooltip after 0.50 second, and this will have the effect of making your tooltip flicker once." -> tooltip priority work (WIP branch) |
| 121 | 149 | - tabs: make EndTabBar fail if users doesn't respect BeginTabBar return value, for consistency/future-proofing. |
| @@ -271,6 +299,21 @@ | ||
| 271 | 299 | - nav/windowing: when CTRL+Tab/windowing is active, the HoveredWindow detection doesn't take account of the window display re-ordering. |
| 272 | 300 | - nav/windowing: Resizing window will currently fail with certain types of resizing constraints/callback applied |
| 273 | 301 | - focus: preserve ActiveId/focus stack state, e.g. when opening a menu and close it, previously selected InputText() focus gets restored (#622) |
| 302 | + | |
| 303 | + - viewport: make it possible to have no main/hosting viewport (see #8268) | |
| 304 | + - viewport: We set ImGuiViewportFlags_NoFocusOnAppearing in a way that is required for GLFW/SDL binding, but could be handled better without | |
| 305 | + on a custom e.g. Win32 bindings. It prevents newly dragged-out viewports from taking the focus, which makes ALT+F4 more ambiguous. | |
| 306 | + - viewport: not focusing newly undocked viewport means clicking back on previous one doesn't bring OS window to front. | |
| 307 | + - viewport: with platform decoration enabled, platform may force constraint (e.g. minimum size) | |
| 308 | + - viewport: use getfocus/setfocus api to synchronize imgui<>platform focus better (e.g imgui-side ctrl-tab can focus os window, OS initial setup and alt-tab can focus imgui window etc.) | |
| 309 | + - viewport: store per-viewport/monitor DPI in .ini file so an application reload or main window changing DPI on reload can be properly patched for. | |
| 310 | + - viewport: implicit/fallback Debug window can hog a zombie viewport (harmless, noisy?) > could at least clear out the reference on a per session basis? | |
| 311 | + - viewport: need to clarify how to use GetMousePos() from a user point of view. | |
| 312 | + - viewport: could apply monitor boundaries to cliprect to coarse clip things out of monitor? (#8698) | |
| 313 | + - platform: glfw: no support for ImGuiBackendFlags_HasMouseHoveredViewport. | |
| 314 | + - platform: sdl: no support for ImGuiBackendFlags_HasMouseHoveredViewport. maybe we could use SDL_GetMouseFocus() / SDL_WINDOW_MOUSE_FOCUS if imgui could fallback on its heuristic when NoInputs is set | |
| 315 | + - platform: sdl: no refresh of monitor/display (SDL doesn't seem to have an event for it). | |
| 316 | + - platform: sdl: multi-viewport + minimized window seems to break mouse wheel events (at least under Win32). | |
| 274 | 317 | |
| 275 | 318 | - inputs: support track pad style scrolling & slider edit. |
| 276 | 319 | - inputs/io: backspace and arrows in the context of a text input could use system repeat rate. |
| @@ -40,6 +40,7 @@ | ||
| 40 | 40 | ImGui::CreateContext(); |
| 41 | 41 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 42 | 42 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 43 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 43 | 44 | |
| 44 | 45 | // Setup Dear ImGui style |
| 45 | 46 | ImGui::StyleColorsDark(); |
| @@ -7,7 +7,10 @@ | ||
| 7 | 7 | objects = { |
| 8 | 8 | |
| 9 | 9 | /* Begin PBXBuildFile section */ |
| 10 | + 050450AB2768052600AB6805 /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; }; | |
| 11 | + 050450AD276863B000AB6805 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 050450AC276863B000AB6805 /* QuartzCore.framework */; }; | |
| 10 | 12 | 05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05318E0E274C397200A8DE2E /* GameController.framework */; }; |
| 13 | + 05A275442773BEA20084EF39 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05A275432773BEA20084EF39 /* QuartzCore.framework */; }; | |
| 11 | 14 | 07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; }; |
| 12 | 15 | 07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; }; |
| 13 | 16 | 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; }; |
| @@ -33,7 +36,11 @@ | ||
| 33 | 36 | /* End PBXBuildFile section */ |
| 34 | 37 | |
| 35 | 38 | /* Begin PBXFileReference section */ |
| 39 | + 050450AC276863B000AB6805 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; | |
| 36 | 40 | 05318E0E274C397200A8DE2E /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; }; |
| 41 | + 05A2754027728F5B0084EF39 /* imgui_impl_metal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_impl_metal.h; path = ../../backends/imgui_impl_metal.h; sourceTree = "<group>"; }; | |
| 42 | + 05A2754127728F5B0084EF39 /* imgui_impl_osx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_impl_osx.h; path = ../../backends/imgui_impl_osx.h; sourceTree = "<group>"; }; | |
| 43 | + 05A275432773BEA20084EF39 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; }; | |
| 37 | 44 | 07A82ED62139413C0078D120 /* imgui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = ../../imgui_internal.h; sourceTree = "<group>"; }; |
| 38 | 45 | 07A82ED72139413C0078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = ../../imgui_widgets.cpp; sourceTree = "<group>"; }; |
| 39 | 46 | 5079822D257677DB0038A28D /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = ../../imgui_tables.cpp; sourceTree = "<group>"; }; |
| @@ -66,6 +73,7 @@ | ||
| 66 | 73 | isa = PBXFrameworksBuildPhase; |
| 67 | 74 | buildActionMask = 2147483647; |
| 68 | 75 | files = ( |
| 76 | + 05A275442773BEA20084EF39 /* QuartzCore.framework in Frameworks */, | |
| 69 | 77 | 8309BD8F253CCAAA0045E2A1 /* UIKit.framework in Frameworks */, |
| 70 | 78 | 83BBE9E720EB46BD00295997 /* MetalKit.framework in Frameworks */, |
| 71 | 79 | 83BBE9E520EB46B900295997 /* Metal.framework in Frameworks */, |
| @@ -76,6 +84,7 @@ | ||
| 76 | 84 | isa = PBXFrameworksBuildPhase; |
| 77 | 85 | buildActionMask = 2147483647; |
| 78 | 86 | files = ( |
| 87 | + 050450AD276863B000AB6805 /* QuartzCore.framework in Frameworks */, | |
| 79 | 88 | 8309BDC6253CCCFE0045E2A1 /* AppKit.framework in Frameworks */, |
| 80 | 89 | 83BBE9EC20EB471700295997 /* MetalKit.framework in Frameworks */, |
| 81 | 90 | 05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */, |
| @@ -136,6 +145,8 @@ | ||
| 136 | 145 | 83BBE9E320EB46B800295997 /* Frameworks */ = { |
| 137 | 146 | isa = PBXGroup; |
| 138 | 147 | children = ( |
| 148 | + 050450AC276863B000AB6805 /* QuartzCore.framework */, | |
| 149 | + 05A275432773BEA20084EF39 /* QuartzCore.framework */, | |
| 139 | 150 | 05318E0E274C397200A8DE2E /* GameController.framework */, |
| 140 | 151 | 8309BDC5253CCCFE0045E2A1 /* AppKit.framework */, |
| 141 | 152 | 8309BD8E253CCAAA0045E2A1 /* UIKit.framework */, |
| @@ -153,7 +164,9 @@ | ||
| 153 | 164 | isa = PBXGroup; |
| 154 | 165 | children = ( |
| 155 | 166 | 5079822D257677DB0038A28D /* imgui_tables.cpp */, |
| 167 | + 05A2754027728F5B0084EF39 /* imgui_impl_metal.h */, | |
| 156 | 168 | 8309BDB5253CCC9D0045E2A1 /* imgui_impl_metal.mm */, |
| 169 | + 05A2754127728F5B0084EF39 /* imgui_impl_osx.h */, | |
| 157 | 170 | 8309BDB6253CCC9D0045E2A1 /* imgui_impl_osx.mm */, |
| 158 | 171 | 83BBEA0420EB54E700295997 /* imconfig.h */, |
| 159 | 172 | 83BBEA0320EB54E700295997 /* imgui.cpp */, |
| @@ -285,7 +298,7 @@ | ||
| 285 | 298 | 83BBEA0A20EB54E700295997 /* imgui.cpp in Sources */, |
| 286 | 299 | 83BBEA0820EB54E700295997 /* imgui_demo.cpp in Sources */, |
| 287 | 300 | 83BBEA0620EB54E700295997 /* imgui_draw.cpp in Sources */, |
| 288 | - 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */, | |
| 301 | + 050450AB2768052600AB6805 /* imgui_tables.cpp in Sources */, | |
| 289 | 302 | 07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */, |
| 290 | 303 | 8309BDA8253CCC080045E2A1 /* main.mm in Sources */, |
| 291 | 304 | ); |
| @@ -60,11 +60,21 @@ | ||
| 60 | 60 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 61 | 61 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 62 | 62 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 63 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 64 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 63 | 65 | |
| 64 | 66 | // Setup Dear ImGui style |
| 65 | 67 | ImGui::StyleColorsDark(); |
| 66 | 68 | //ImGui::StyleColorsLight(); |
| 67 | 69 | |
| 70 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 71 | + ImGuiStyle& style = ImGui::GetStyle(); | |
| 72 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 73 | + { | |
| 74 | + style.WindowRounding = 0.0f; | |
| 75 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 76 | + } | |
| 77 | + | |
| 68 | 78 | // Setup Renderer backend |
| 69 | 79 | ImGui_ImplMetal_Init(_device); |
| 70 | 80 | |
| @@ -197,6 +207,13 @@ | ||
| 197 | 207 | // Present |
| 198 | 208 | [commandBuffer presentDrawable:view.currentDrawable]; |
| 199 | 209 | [commandBuffer commit]; |
| 210 | + | |
| 211 | + // Update and Render additional Platform Windows | |
| 212 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 213 | + { | |
| 214 | + ImGui::UpdatePlatformWindows(); | |
| 215 | + ImGui::RenderPlatformWindowsDefault(); | |
| 216 | + } | |
| 200 | 217 | } |
| 201 | 218 | |
| 202 | 219 | -(void)mtkView:(MTKView*)view drawableSizeWillChange:(CGSize)size |
| @@ -6,6 +6,8 @@ | ||
| 6 | 6 | // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). |
| 7 | 7 | // - Introduction, links and more at the top of imgui.cpp |
| 8 | 8 | |
| 9 | +// FIXME: Multi-viewports is not yet functional in this example. May need backend rework/coordination. | |
| 10 | + | |
| 9 | 11 | #import <Cocoa/Cocoa.h> |
| 10 | 12 | #import <OpenGL/gl.h> |
| 11 | 13 | #import <OpenGL/glu.h> |
| @@ -47,11 +49,21 @@ | ||
| 47 | 49 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 48 | 50 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 49 | 51 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 52 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 53 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 50 | 54 | |
| 51 | 55 | // Setup Dear ImGui style |
| 52 | 56 | ImGui::StyleColorsDark(); |
| 53 | 57 | //ImGui::StyleColorsLight(); |
| 54 | 58 | |
| 59 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 60 | + ImGuiStyle& style = ImGui::GetStyle(); | |
| 61 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 62 | + { | |
| 63 | + style.WindowRounding = 0.0f; | |
| 64 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 65 | + } | |
| 66 | + | |
| 55 | 67 | // Setup Platform/Renderer backends |
| 56 | 68 | ImGui_ImplOSX_Init(self); |
| 57 | 69 | ImGui_ImplOpenGL2_Init(); |
| @@ -137,6 +149,13 @@ | ||
| 137 | 149 | glClear(GL_COLOR_BUFFER_BIT); |
| 138 | 150 | |
| 139 | 151 | ImGui_ImplOpenGL2_RenderDrawData(draw_data); |
| 152 | + | |
| 153 | + // Update and Render additional Platform Windows | |
| 154 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 155 | + { | |
| 156 | + ImGui::UpdatePlatformWindows(); | |
| 157 | + ImGui::RenderPlatformWindowsDefault(); | |
| 158 | + } | |
| 140 | 159 | |
| 141 | 160 | // Present |
| 142 | 161 | [[self openGLContext] flushBuffer]; |
| @@ -44,6 +44,8 @@ | ||
| 44 | 44 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 45 | 45 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 46 | 46 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 47 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 48 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 47 | 49 | |
| 48 | 50 | // Setup Dear ImGui style |
| 49 | 51 | ImGui::StyleColorsDark(); |
| @@ -53,7 +55,16 @@ | ||
| 53 | 55 | ImGuiStyle& style = ImGui::GetStyle(); |
| 54 | 56 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 55 | 57 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 58 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 59 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 56 | 60 | |
| 61 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 62 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 63 | + { | |
| 64 | + style.WindowRounding = 0.0f; | |
| 65 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 66 | + } | |
| 67 | + | |
| 57 | 68 | id <MTLDevice> device = MTLCreateSystemDefaultDevice(); |
| 58 | 69 | id <MTLCommandQueue> commandQueue = [device newCommandQueue]; |
| 59 | 70 | |
| @@ -163,6 +174,13 @@ | ||
| 163 | 174 | // Rendering |
| 164 | 175 | ImGui::Render(); |
| 165 | 176 | ImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), commandBuffer, renderEncoder); |
| 177 | + | |
| 178 | + // Update and Render additional Platform Windows | |
| 179 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 180 | + { | |
| 181 | + ImGui::UpdatePlatformWindows(); | |
| 182 | + ImGui::RenderPlatformWindowsDefault(); | |
| 183 | + } | |
| 166 | 184 | |
| 167 | 185 | [renderEncoder popDebugGroup]; |
| 168 | 186 | [renderEncoder endEncoding]; |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{9CDA7840-B7A5-496D-A527-E95571496D18}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_glfw_opengl2</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>MultiByte</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>MultiByte</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>MultiByte</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>MultiByte</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -53,6 +53,10 @@ | ||
| 53 | 53 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 54 | 54 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 55 | 55 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 56 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 57 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 58 | + //io.ConfigViewportsNoAutoMerge = true; | |
| 59 | + //io.ConfigViewportsNoTaskBarIcon = true; | |
| 56 | 60 | |
| 57 | 61 | // Setup Dear ImGui style |
| 58 | 62 | ImGui::StyleColorsDark(); |
| @@ -62,7 +66,16 @@ | ||
| 62 | 66 | ImGuiStyle& style = ImGui::GetStyle(); |
| 63 | 67 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 64 | 68 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 69 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 70 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 65 | 71 | |
| 72 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 73 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 74 | + { | |
| 75 | + style.WindowRounding = 0.0f; | |
| 76 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 77 | + } | |
| 78 | + | |
| 66 | 79 | // Setup Platform/Renderer backends |
| 67 | 80 | ImGui_ImplGlfw_InitForOpenGL(window, true); |
| 68 | 81 | ImGui_ImplOpenGL2_Init(); |
| @@ -162,6 +175,17 @@ | ||
| 162 | 175 | //glUseProgram(0); |
| 163 | 176 | ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); |
| 164 | 177 | //glUseProgram(last_program); |
| 178 | + | |
| 179 | + // Update and Render additional Platform Windows | |
| 180 | + // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere. | |
| 181 | + // For this specific demo app we could also call glfwMakeContextCurrent(window) directly) | |
| 182 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 183 | + { | |
| 184 | + GLFWwindow* backup_current_context = glfwGetCurrentContext(); | |
| 185 | + ImGui::UpdatePlatformWindows(); | |
| 186 | + ImGui::RenderPlatformWindowsDefault(); | |
| 187 | + glfwMakeContextCurrent(backup_current_context); | |
| 188 | + } | |
| 165 | 189 | |
| 166 | 190 | glfwMakeContextCurrent(window); |
| 167 | 191 | glfwSwapBuffers(window); |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{4a1fb5ea-22f5-42a8-ab92-1d2df5d47fb9}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_glfw_opengl3</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>MultiByte</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>MultiByte</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>MultiByte</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>MultiByte</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -84,6 +84,10 @@ | ||
| 84 | 84 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 85 | 85 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 86 | 86 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 87 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 88 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 89 | + //io.ConfigViewportsNoAutoMerge = true; | |
| 90 | + //io.ConfigViewportsNoTaskBarIcon = true; | |
| 87 | 91 | |
| 88 | 92 | // Setup Dear ImGui style |
| 89 | 93 | ImGui::StyleColorsDark(); |
| @@ -93,7 +97,18 @@ | ||
| 93 | 97 | ImGuiStyle& style = ImGui::GetStyle(); |
| 94 | 98 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 95 | 99 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 100 | +#if GLFW_VERSION_MAJOR >= 3 && GLFW_VERSION_MINOR >= 3 | |
| 101 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 102 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 103 | +#endif | |
| 96 | 104 | |
| 105 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 106 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 107 | + { | |
| 108 | + style.WindowRounding = 0.0f; | |
| 109 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 110 | + } | |
| 111 | + | |
| 97 | 112 | // Setup Platform/Renderer backends |
| 98 | 113 | ImGui_ImplGlfw_InitForOpenGL(window, true); |
| 99 | 114 | #ifdef __EMSCRIPTEN__ |
| @@ -197,6 +212,17 @@ | ||
| 197 | 212 | glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); |
| 198 | 213 | glClear(GL_COLOR_BUFFER_BIT); |
| 199 | 214 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); |
| 215 | + | |
| 216 | + // Update and Render additional Platform Windows | |
| 217 | + // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere. | |
| 218 | + // For this specific demo app we could also call glfwMakeContextCurrent(window) directly) | |
| 219 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 220 | + { | |
| 221 | + GLFWwindow* backup_current_context = glfwGetCurrentContext(); | |
| 222 | + ImGui::UpdatePlatformWindows(); | |
| 223 | + ImGui::RenderPlatformWindowsDefault(); | |
| 224 | + glfwMakeContextCurrent(backup_current_context); | |
| 225 | + } | |
| 200 | 226 | |
| 201 | 227 | glfwSwapBuffers(window); |
| 202 | 228 | } |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{57E2DF5A-6FC8-45BB-99DD-91A18C646E80}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_glfw_vulkan</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>MultiByte</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>MultiByte</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>MultiByte</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>MultiByte</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -390,6 +390,10 @@ | ||
| 390 | 390 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 391 | 391 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 392 | 392 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 393 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 394 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 395 | + //io.ConfigViewportsNoAutoMerge = true; | |
| 396 | + //io.ConfigViewportsNoTaskBarIcon = true; | |
| 393 | 397 | |
| 394 | 398 | // Setup Dear ImGui style |
| 395 | 399 | ImGui::StyleColorsDark(); |
| @@ -399,7 +403,16 @@ | ||
| 399 | 403 | ImGuiStyle& style = ImGui::GetStyle(); |
| 400 | 404 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 401 | 405 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 406 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 407 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 402 | 408 | |
| 409 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 410 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 411 | + { | |
| 412 | + style.WindowRounding = 0.0f; | |
| 413 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 414 | + } | |
| 415 | + | |
| 403 | 416 | // Setup Platform/Renderer backends |
| 404 | 417 | ImGui_ImplGlfw_InitForVulkan(window, true); |
| 405 | 418 | ImGui_ImplVulkan_InitInfo init_info = {}; |
| @@ -513,17 +526,25 @@ | ||
| 513 | 526 | |
| 514 | 527 | // Rendering |
| 515 | 528 | ImGui::Render(); |
| 516 | - ImDrawData* draw_data = ImGui::GetDrawData(); | |
| 517 | - const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f); | |
| 518 | - if (!is_minimized) | |
| 529 | + ImDrawData* main_draw_data = ImGui::GetDrawData(); | |
| 530 | + const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f); | |
| 531 | + wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w; | |
| 532 | + wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w; | |
| 533 | + wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w; | |
| 534 | + wd->ClearValue.color.float32[3] = clear_color.w; | |
| 535 | + if (!main_is_minimized) | |
| 536 | + FrameRender(wd, main_draw_data); | |
| 537 | + | |
| 538 | + // Update and Render additional Platform Windows | |
| 539 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 519 | 540 | { |
| 520 | - wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w; | |
| 521 | - wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w; | |
| 522 | - wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w; | |
| 523 | - wd->ClearValue.color.float32[3] = clear_color.w; | |
| 524 | - FrameRender(wd, draw_data); | |
| 525 | - FramePresent(wd); | |
| 541 | + ImGui::UpdatePlatformWindows(); | |
| 542 | + ImGui::RenderPlatformWindowsDefault(); | |
| 526 | 543 | } |
| 544 | + | |
| 545 | + // Present Main Platform Window | |
| 546 | + if (!main_is_minimized) | |
| 547 | + FramePresent(wd); | |
| 527 | 548 | } |
| 528 | 549 | |
| 529 | 550 | // Cleanup |
| @@ -14,7 +14,7 @@ | ||
| 14 | 14 | # * build/example_glfw_wgpu[.exe] or build/Debug/example_glfw_wgpu[.exe] |
| 15 | 15 | |
| 16 | 16 | # Building for desktop with WGVK (MUCH EASIER) |
| 17 | -# 1. git clone https://github.com/manuel5975p/WGVK dawn | |
| 17 | +# 1. git clone https://github.com/manuel5975p/WGVK wgvk | |
| 18 | 18 | # 2. cmake -B build -DIMGUI_WGVK_DIR=wgvk |
| 19 | 19 | # 3. cmake --build build |
| 20 | 20 | # The resulting binary will be found at one of the following locations: |
| @@ -37,7 +37,7 @@ | ||
| 37 | 37 | set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE) |
| 38 | 38 | endif() |
| 39 | 39 | |
| 40 | -set(CMAKE_CXX_STANDARD 17) # Dawn requires C++17 | |
| 40 | +set(CMAKE_CXX_STANDARD 20) # Dawn requires C++20 | |
| 41 | 41 | |
| 42 | 42 | # Dear ImGui |
| 43 | 43 | set(IMGUI_DIR ../../) |
| @@ -87,6 +87,7 @@ | ||
| 87 | 87 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 88 | 88 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 89 | 89 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 90 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 90 | 91 | |
| 91 | 92 | // Setup Dear ImGui style |
| 92 | 93 | ImGui::StyleColorsDark(); |
| @@ -61,6 +61,7 @@ | ||
| 61 | 61 | ImGui::CreateContext(); |
| 62 | 62 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 63 | 63 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 64 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 64 | 65 | |
| 65 | 66 | // Setup Dear ImGui style |
| 66 | 67 | ImGui::StyleColorsDark(); |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{1A0BF63C-18EF-4BAE-A8DA-055481B11F5D}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_win32_directx11</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>Unicode</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>Unicode</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>Unicode</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>Unicode</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -21,7 +21,7 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{9E1987E3-1F19-45CA-B9C9-D31E791836D8}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_sdl2_directx11</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | <ProjectName>example_sdl2_directx11</ProjectName> |
| 26 | 26 | </PropertyGroup> |
| 27 | 27 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| @@ -29,27 +29,27 @@ | ||
| 29 | 29 | <ConfigurationType>Application</ConfigurationType> |
| 30 | 30 | <UseDebugLibraries>true</UseDebugLibraries> |
| 31 | 31 | <CharacterSet>MultiByte</CharacterSet> |
| 32 | - <PlatformToolset>v143</PlatformToolset> | |
| 32 | + <PlatformToolset>v141</PlatformToolset> | |
| 33 | 33 | </PropertyGroup> |
| 34 | 34 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 35 | 35 | <ConfigurationType>Application</ConfigurationType> |
| 36 | 36 | <UseDebugLibraries>true</UseDebugLibraries> |
| 37 | 37 | <CharacterSet>MultiByte</CharacterSet> |
| 38 | - <PlatformToolset>v143</PlatformToolset> | |
| 38 | + <PlatformToolset>v141</PlatformToolset> | |
| 39 | 39 | </PropertyGroup> |
| 40 | 40 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 41 | 41 | <ConfigurationType>Application</ConfigurationType> |
| 42 | 42 | <UseDebugLibraries>false</UseDebugLibraries> |
| 43 | 43 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 44 | 44 | <CharacterSet>MultiByte</CharacterSet> |
| 45 | - <PlatformToolset>v143</PlatformToolset> | |
| 45 | + <PlatformToolset>v141</PlatformToolset> | |
| 46 | 46 | </PropertyGroup> |
| 47 | 47 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 48 | 48 | <ConfigurationType>Application</ConfigurationType> |
| 49 | 49 | <UseDebugLibraries>false</UseDebugLibraries> |
| 50 | 50 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 51 | 51 | <CharacterSet>MultiByte</CharacterSet> |
| 52 | - <PlatformToolset>v143</PlatformToolset> | |
| 52 | + <PlatformToolset>v141</PlatformToolset> | |
| 53 | 53 | </PropertyGroup> |
| 54 | 54 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 55 | 55 | <ImportGroup Label="ExtensionSettings"> |
| @@ -75,6 +75,10 @@ | ||
| 75 | 75 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 76 | 76 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 77 | 77 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 78 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 79 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 80 | + //io.ConfigViewportsNoAutoMerge = true; | |
| 81 | + //io.ConfigViewportsNoTaskBarIcon = true; | |
| 78 | 82 | |
| 79 | 83 | // Setup Dear ImGui style |
| 80 | 84 | ImGui::StyleColorsDark(); |
| @@ -84,7 +88,16 @@ | ||
| 84 | 88 | ImGuiStyle& style = ImGui::GetStyle(); |
| 85 | 89 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 86 | 90 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 91 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 92 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 87 | 93 | |
| 94 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 95 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 96 | + { | |
| 97 | + style.WindowRounding = 0.0f; | |
| 98 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 99 | + } | |
| 100 | + | |
| 88 | 101 | // Setup Platform/Renderer backends |
| 89 | 102 | ImGui_ImplSDL2_InitForD3D(window); |
| 90 | 103 | ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); |
| @@ -192,6 +205,13 @@ | ||
| 192 | 205 | g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha); |
| 193 | 206 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); |
| 194 | 207 | |
| 208 | + // Update and Render additional Platform Windows | |
| 209 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 210 | + { | |
| 211 | + ImGui::UpdatePlatformWindows(); | |
| 212 | + ImGui::RenderPlatformWindowsDefault(); | |
| 213 | + } | |
| 214 | + | |
| 195 | 215 | g_pSwapChain->Present(1, 0); // Present with vsync |
| 196 | 216 | //g_pSwapChain->Present(0, 0); // Present without vsync |
| 197 | 217 | } |
| @@ -238,6 +258,16 @@ | ||
| 238 | 258 | res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); |
| 239 | 259 | if (res != S_OK) |
| 240 | 260 | return false; |
| 261 | + | |
| 262 | + // Disable DXGI's default Alt+Enter fullscreen behavior. | |
| 263 | + // - You are free to leave this enabled, but it will not work properly with multiple viewports. | |
| 264 | + // - This must be done for all windows associated to the device. Our DX11 backend does this automatically for secondary viewports that it creates. | |
| 265 | + IDXGIFactory* pSwapChainFactory; | |
| 266 | + if (SUCCEEDED(g_pSwapChain->GetParent(IID_PPV_ARGS(&pSwapChainFactory)))) | |
| 267 | + { | |
| 268 | + pSwapChainFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER); | |
| 269 | + pSwapChainFactory->Release(); | |
| 270 | + } | |
| 241 | 271 | |
| 242 | 272 | CreateRenderTarget(); |
| 243 | 273 | return true; |
| @@ -24,11 +24,21 @@ | ||
| 24 | 24 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 25 | 25 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 26 | 26 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 27 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 28 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 27 | 29 | |
| 28 | 30 | // Setup style |
| 29 | 31 | ImGui::StyleColorsDark(); |
| 30 | 32 | //ImGui::StyleColorsLight(); |
| 31 | 33 | |
| 34 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 35 | + ImGuiStyle& style = ImGui::GetStyle(); | |
| 36 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 37 | + { | |
| 38 | + style.WindowRounding = 0.0f; | |
| 39 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 40 | + } | |
| 41 | + | |
| 32 | 42 | // Load Fonts |
| 33 | 43 | // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). |
| 34 | 44 | // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. |
| @@ -169,6 +179,13 @@ | ||
| 169 | 179 | // Rendering |
| 170 | 180 | ImGui::Render(); |
| 171 | 181 | ImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), commandBuffer, renderEncoder); |
| 182 | + | |
| 183 | + // Update and Render additional Platform Windows | |
| 184 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 185 | + { | |
| 186 | + ImGui::UpdatePlatformWindows(); | |
| 187 | + ImGui::RenderPlatformWindowsDefault(); | |
| 188 | + } | |
| 172 | 189 | |
| 173 | 190 | [renderEncoder popDebugGroup]; |
| 174 | 191 | [renderEncoder endEncoding]; |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{2AE17FDE-F7F3-4CAC-ADAB-0710EDA4F741}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_sdl2_opengl2</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>MultiByte</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>MultiByte</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>MultiByte</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>MultiByte</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -64,6 +64,10 @@ | ||
| 64 | 64 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 65 | 65 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 66 | 66 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 67 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 68 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 69 | + //io.ConfigViewportsNoAutoMerge = true; | |
| 70 | + //io.ConfigViewportsNoTaskBarIcon = true; | |
| 67 | 71 | |
| 68 | 72 | // Setup Dear ImGui style |
| 69 | 73 | ImGui::StyleColorsDark(); |
| @@ -73,7 +77,16 @@ | ||
| 73 | 77 | ImGuiStyle& style = ImGui::GetStyle(); |
| 74 | 78 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 75 | 79 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 80 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 81 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 76 | 82 | |
| 83 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 84 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 85 | + { | |
| 86 | + style.WindowRounding = 0.0f; | |
| 87 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 88 | + } | |
| 89 | + | |
| 77 | 90 | // Setup Platform/Renderer backends |
| 78 | 91 | ImGui_ImplSDL2_InitForOpenGL(window, gl_context); |
| 79 | 92 | ImGui_ImplOpenGL2_Init(); |
| @@ -174,6 +187,19 @@ | ||
| 174 | 187 | glClear(GL_COLOR_BUFFER_BIT); |
| 175 | 188 | //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound |
| 176 | 189 | ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); |
| 190 | + | |
| 191 | + // Update and Render additional Platform Windows | |
| 192 | + // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere. | |
| 193 | + // For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly) | |
| 194 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 195 | + { | |
| 196 | + SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow(); | |
| 197 | + SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext(); | |
| 198 | + ImGui::UpdatePlatformWindows(); | |
| 199 | + ImGui::RenderPlatformWindowsDefault(); | |
| 200 | + SDL_GL_MakeCurrent(backup_current_window, backup_current_context); | |
| 201 | + } | |
| 202 | + | |
| 177 | 203 | SDL_GL_SwapWindow(window); |
| 178 | 204 | } |
| 179 | 205 |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{BBAEB705-1669-40F3-8567-04CF6A991F4C}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_sdl2_opengl3</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>MultiByte</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>MultiByte</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>MultiByte</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>MultiByte</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -104,6 +104,10 @@ | ||
| 104 | 104 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 105 | 105 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 106 | 106 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 107 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 108 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 109 | + //io.ConfigViewportsNoAutoMerge = true; | |
| 110 | + //io.ConfigViewportsNoTaskBarIcon = true; | |
| 107 | 111 | |
| 108 | 112 | // Setup Dear ImGui style |
| 109 | 113 | ImGui::StyleColorsDark(); |
| @@ -113,7 +117,16 @@ | ||
| 113 | 117 | ImGuiStyle& style = ImGui::GetStyle(); |
| 114 | 118 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 115 | 119 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 120 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 121 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 116 | 122 | |
| 123 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 124 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 125 | + { | |
| 126 | + style.WindowRounding = 0.0f; | |
| 127 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 128 | + } | |
| 129 | + | |
| 117 | 130 | // Setup Platform/Renderer backends |
| 118 | 131 | ImGui_ImplSDL2_InitForOpenGL(window, gl_context); |
| 119 | 132 | ImGui_ImplOpenGL3_Init(glsl_version); |
| @@ -221,6 +234,19 @@ | ||
| 221 | 234 | glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); |
| 222 | 235 | glClear(GL_COLOR_BUFFER_BIT); |
| 223 | 236 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); |
| 237 | + | |
| 238 | + // Update and Render additional Platform Windows | |
| 239 | + // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere. | |
| 240 | + // For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly) | |
| 241 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 242 | + { | |
| 243 | + SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow(); | |
| 244 | + SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext(); | |
| 245 | + ImGui::UpdatePlatformWindows(); | |
| 246 | + ImGui::RenderPlatformWindowsDefault(); | |
| 247 | + SDL_GL_MakeCurrent(backup_current_window, backup_current_context); | |
| 248 | + } | |
| 249 | + | |
| 224 | 250 | SDL_GL_SwapWindow(window); |
| 225 | 251 | } |
| 226 | 252 | #ifdef __EMSCRIPTEN__ |
| @@ -21,7 +21,7 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{0C0B2BEA-311F-473C-9652-87923EF639E3}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_sdl2_sdlrenderer2</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | <ProjectName>example_sdl2_sdlrenderer2</ProjectName> |
| 26 | 26 | </PropertyGroup> |
| 27 | 27 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| @@ -29,27 +29,27 @@ | ||
| 29 | 29 | <ConfigurationType>Application</ConfigurationType> |
| 30 | 30 | <UseDebugLibraries>true</UseDebugLibraries> |
| 31 | 31 | <CharacterSet>MultiByte</CharacterSet> |
| 32 | - <PlatformToolset>v143</PlatformToolset> | |
| 32 | + <PlatformToolset>v141</PlatformToolset> | |
| 33 | 33 | </PropertyGroup> |
| 34 | 34 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 35 | 35 | <ConfigurationType>Application</ConfigurationType> |
| 36 | 36 | <UseDebugLibraries>true</UseDebugLibraries> |
| 37 | 37 | <CharacterSet>MultiByte</CharacterSet> |
| 38 | - <PlatformToolset>v143</PlatformToolset> | |
| 38 | + <PlatformToolset>v141</PlatformToolset> | |
| 39 | 39 | </PropertyGroup> |
| 40 | 40 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 41 | 41 | <ConfigurationType>Application</ConfigurationType> |
| 42 | 42 | <UseDebugLibraries>false</UseDebugLibraries> |
| 43 | 43 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 44 | 44 | <CharacterSet>MultiByte</CharacterSet> |
| 45 | - <PlatformToolset>v143</PlatformToolset> | |
| 45 | + <PlatformToolset>v141</PlatformToolset> | |
| 46 | 46 | </PropertyGroup> |
| 47 | 47 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 48 | 48 | <ConfigurationType>Application</ConfigurationType> |
| 49 | 49 | <UseDebugLibraries>false</UseDebugLibraries> |
| 50 | 50 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 51 | 51 | <CharacterSet>MultiByte</CharacterSet> |
| 52 | - <PlatformToolset>v143</PlatformToolset> | |
| 52 | + <PlatformToolset>v141</PlatformToolset> | |
| 53 | 53 | </PropertyGroup> |
| 54 | 54 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 55 | 55 | <ImportGroup Label="ExtensionSettings"> |
| @@ -66,6 +66,7 @@ | ||
| 66 | 66 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 67 | 67 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 68 | 68 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 69 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 69 | 70 | |
| 70 | 71 | // Setup Dear ImGui style |
| 71 | 72 | ImGui::StyleColorsDark(); |
| @@ -75,6 +76,8 @@ | ||
| 75 | 76 | ImGuiStyle& style = ImGui::GetStyle(); |
| 76 | 77 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 77 | 78 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 79 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 80 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 78 | 81 | |
| 79 | 82 | // Setup Platform/Renderer backends |
| 80 | 83 | ImGui_ImplSDL2_InitForSDLRenderer(window, renderer); |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{BAE3D0B5-9695-4EB1-AD0F-75890EB4A3B3}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_sdl2_vulkan</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>MultiByte</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>MultiByte</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>MultiByte</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>MultiByte</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -396,6 +396,10 @@ | ||
| 396 | 396 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 397 | 397 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 398 | 398 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 399 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 400 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 401 | + //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons; | |
| 402 | + //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge; | |
| 399 | 403 | |
| 400 | 404 | // Setup Dear ImGui style |
| 401 | 405 | ImGui::StyleColorsDark(); |
| @@ -405,7 +409,16 @@ | ||
| 405 | 409 | ImGuiStyle& style = ImGui::GetStyle(); |
| 406 | 410 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 407 | 411 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 412 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 413 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 408 | 414 | |
| 415 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 416 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 417 | + { | |
| 418 | + style.WindowRounding = 0.0f; | |
| 419 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 420 | + } | |
| 421 | + | |
| 409 | 422 | // Setup Platform/Renderer backends |
| 410 | 423 | ImGui_ImplSDL2_InitForVulkan(window); |
| 411 | 424 | ImGui_ImplVulkan_InitInfo init_info = {}; |
| @@ -528,17 +541,25 @@ | ||
| 528 | 541 | |
| 529 | 542 | // Rendering |
| 530 | 543 | ImGui::Render(); |
| 531 | - ImDrawData* draw_data = ImGui::GetDrawData(); | |
| 532 | - const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f); | |
| 533 | - if (!is_minimized) | |
| 544 | + ImDrawData* main_draw_data = ImGui::GetDrawData(); | |
| 545 | + const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f); | |
| 546 | + wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w; | |
| 547 | + wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w; | |
| 548 | + wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w; | |
| 549 | + wd->ClearValue.color.float32[3] = clear_color.w; | |
| 550 | + if (!main_is_minimized) | |
| 551 | + FrameRender(wd, main_draw_data); | |
| 552 | + | |
| 553 | + // Update and Render additional Platform Windows | |
| 554 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 534 | 555 | { |
| 535 | - wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w; | |
| 536 | - wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w; | |
| 537 | - wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w; | |
| 538 | - wd->ClearValue.color.float32[3] = clear_color.w; | |
| 539 | - FrameRender(wd, draw_data); | |
| 540 | - FramePresent(wd); | |
| 556 | + ImGui::UpdatePlatformWindows(); | |
| 557 | + ImGui::RenderPlatformWindowsDefault(); | |
| 541 | 558 | } |
| 559 | + | |
| 560 | + // Present Main Platform Window | |
| 561 | + if (!main_is_minimized) | |
| 562 | + FramePresent(wd); | |
| 542 | 563 | } |
| 543 | 564 | |
| 544 | 565 | // Cleanup |
| @@ -14,7 +14,7 @@ | ||
| 14 | 14 | # * build/example_sdl2_wgpu[.exe] or build/Debug/example_sdl2_wgpu[.exe] |
| 15 | 15 | |
| 16 | 16 | # Building for desktop with WGVK (MUCH EASIER) |
| 17 | -# 1. git clone https://github.com/manuel5975p/WGVK dawn | |
| 17 | +# 1. git clone https://github.com/manuel5975p/WGVK wgvk | |
| 18 | 18 | # 2. cmake -B build -DIMGUI_WGVK_DIR=wgvk |
| 19 | 19 | # 3. cmake --build build |
| 20 | 20 | # The resulting binary will be found at one of the following locations: |
| @@ -37,7 +37,7 @@ | ||
| 37 | 37 | set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE) |
| 38 | 38 | endif() |
| 39 | 39 | |
| 40 | -set(CMAKE_CXX_STANDARD 17) # Dawn requires C++17 | |
| 40 | +set(CMAKE_CXX_STANDARD 10) # Dawn requires C++20 | |
| 41 | 41 | |
| 42 | 42 | # Dear ImGui |
| 43 | 43 | set(IMGUI_DIR ../../) |
| @@ -21,7 +21,7 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{009DAC16-1A9C-47BE-9770-A30A046E8090}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_sdl3_directx11</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | <ProjectName>example_sdl3_directx11</ProjectName> |
| 26 | 26 | </PropertyGroup> |
| 27 | 27 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| @@ -29,27 +29,27 @@ | ||
| 29 | 29 | <ConfigurationType>Application</ConfigurationType> |
| 30 | 30 | <UseDebugLibraries>true</UseDebugLibraries> |
| 31 | 31 | <CharacterSet>MultiByte</CharacterSet> |
| 32 | - <PlatformToolset>v143</PlatformToolset> | |
| 32 | + <PlatformToolset>v141</PlatformToolset> | |
| 33 | 33 | </PropertyGroup> |
| 34 | 34 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 35 | 35 | <ConfigurationType>Application</ConfigurationType> |
| 36 | 36 | <UseDebugLibraries>true</UseDebugLibraries> |
| 37 | 37 | <CharacterSet>MultiByte</CharacterSet> |
| 38 | - <PlatformToolset>v143</PlatformToolset> | |
| 38 | + <PlatformToolset>v141</PlatformToolset> | |
| 39 | 39 | </PropertyGroup> |
| 40 | 40 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 41 | 41 | <ConfigurationType>Application</ConfigurationType> |
| 42 | 42 | <UseDebugLibraries>false</UseDebugLibraries> |
| 43 | 43 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 44 | 44 | <CharacterSet>MultiByte</CharacterSet> |
| 45 | - <PlatformToolset>v143</PlatformToolset> | |
| 45 | + <PlatformToolset>v141</PlatformToolset> | |
| 46 | 46 | </PropertyGroup> |
| 47 | 47 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 48 | 48 | <ConfigurationType>Application</ConfigurationType> |
| 49 | 49 | <UseDebugLibraries>false</UseDebugLibraries> |
| 50 | 50 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 51 | 51 | <CharacterSet>MultiByte</CharacterSet> |
| 52 | - <PlatformToolset>v143</PlatformToolset> | |
| 52 | + <PlatformToolset>v141</PlatformToolset> | |
| 53 | 53 | </PropertyGroup> |
| 54 | 54 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 55 | 55 | <ImportGroup Label="ExtensionSettings"> |
| @@ -66,6 +66,10 @@ | ||
| 66 | 66 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 67 | 67 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 68 | 68 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 69 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 70 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 71 | + //io.ConfigViewportsNoAutoMerge = true; | |
| 72 | + //io.ConfigViewportsNoTaskBarIcon = true; | |
| 69 | 73 | |
| 70 | 74 | // Setup Dear ImGui style |
| 71 | 75 | ImGui::StyleColorsDark(); |
| @@ -75,7 +79,16 @@ | ||
| 75 | 79 | ImGuiStyle& style = ImGui::GetStyle(); |
| 76 | 80 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 77 | 81 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 82 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 83 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 78 | 84 | |
| 85 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 86 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 87 | + { | |
| 88 | + style.WindowRounding = 0.0f; | |
| 89 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 90 | + } | |
| 91 | + | |
| 79 | 92 | // Setup Platform/Renderer backends |
| 80 | 93 | ImGui_ImplSDL3_InitForD3D(window); |
| 81 | 94 | ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); |
| @@ -186,6 +199,13 @@ | ||
| 186 | 199 | g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha); |
| 187 | 200 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); |
| 188 | 201 | |
| 202 | + // Update and Render additional Platform Windows | |
| 203 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 204 | + { | |
| 205 | + ImGui::UpdatePlatformWindows(); | |
| 206 | + ImGui::RenderPlatformWindowsDefault(); | |
| 207 | + } | |
| 208 | + | |
| 189 | 209 | g_pSwapChain->Present(1, 0); // Present with vsync |
| 190 | 210 | //g_pSwapChain->Present(0, 0); // Present without vsync |
| 191 | 211 | } |
| @@ -233,6 +253,16 @@ | ||
| 233 | 253 | res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); |
| 234 | 254 | if (res != S_OK) |
| 235 | 255 | return false; |
| 256 | + | |
| 257 | + // Disable DXGI's default Alt+Enter fullscreen behavior. | |
| 258 | + // - You are free to leave this enabled, but it will not work properly with multiple viewports. | |
| 259 | + // - This must be done for all windows associated to the device. Our DX11 backend does this automatically for secondary viewports that it creates. | |
| 260 | + IDXGIFactory* pSwapChainFactory; | |
| 261 | + if (SUCCEEDED(g_pSwapChain->GetParent(IID_PPV_ARGS(&pSwapChainFactory)))) | |
| 262 | + { | |
| 263 | + pSwapChainFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER); | |
| 264 | + pSwapChainFactory->Release(); | |
| 265 | + } | |
| 236 | 266 | |
| 237 | 267 | CreateRenderTarget(); |
| 238 | 268 | return true; |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{84AAA301-84FE-428B-9E3E-817BC8123C0C}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_sdl3_opengl3</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>MultiByte</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>MultiByte</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>MultiByte</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>MultiByte</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -94,6 +94,10 @@ | ||
| 94 | 94 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 95 | 95 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 96 | 96 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 97 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 98 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 99 | + //io.ConfigViewportsNoAutoMerge = true; | |
| 100 | + //io.ConfigViewportsNoTaskBarIcon = true; | |
| 97 | 101 | |
| 98 | 102 | // Setup Dear ImGui style |
| 99 | 103 | ImGui::StyleColorsDark(); |
| @@ -103,7 +107,16 @@ | ||
| 103 | 107 | ImGuiStyle& style = ImGui::GetStyle(); |
| 104 | 108 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 105 | 109 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 110 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 111 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 106 | 112 | |
| 113 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 114 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 115 | + { | |
| 116 | + style.WindowRounding = 0.0f; | |
| 117 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 118 | + } | |
| 119 | + | |
| 107 | 120 | // Setup Platform/Renderer backends |
| 108 | 121 | ImGui_ImplSDL3_InitForOpenGL(window, gl_context); |
| 109 | 122 | ImGui_ImplOpenGL3_Init(glsl_version); |
| @@ -214,6 +227,19 @@ | ||
| 214 | 227 | glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); |
| 215 | 228 | glClear(GL_COLOR_BUFFER_BIT); |
| 216 | 229 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); |
| 230 | + | |
| 231 | + // Update and Render additional Platform Windows | |
| 232 | + // (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere. | |
| 233 | + // For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly) | |
| 234 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 235 | + { | |
| 236 | + SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow(); | |
| 237 | + SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext(); | |
| 238 | + ImGui::UpdatePlatformWindows(); | |
| 239 | + ImGui::RenderPlatformWindowsDefault(); | |
| 240 | + SDL_GL_MakeCurrent(backup_current_window, backup_current_context); | |
| 241 | + } | |
| 242 | + | |
| 217 | 243 | SDL_GL_SwapWindow(window); |
| 218 | 244 | } |
| 219 | 245 | #ifdef __EMSCRIPTEN__ |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{c22cb6f8-39a5-4dda-90ed-4aca4e81e1e5}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_sdl3_sdlgpu3</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>MultiByte</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>MultiByte</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>MultiByte</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>MultiByte</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -68,6 +68,8 @@ | ||
| 68 | 68 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 69 | 69 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 70 | 70 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 71 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 72 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 71 | 73 | |
| 72 | 74 | // Setup Dear ImGui style |
| 73 | 75 | ImGui::StyleColorsDark(); |
| @@ -77,7 +79,16 @@ | ||
| 77 | 79 | ImGuiStyle& style = ImGui::GetStyle(); |
| 78 | 80 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 79 | 81 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 82 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 83 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 80 | 84 | |
| 85 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 86 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 87 | + { | |
| 88 | + style.WindowRounding = 0.0f; | |
| 89 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 90 | + } | |
| 91 | + | |
| 81 | 92 | // Setup Platform/Renderer backends |
| 82 | 93 | ImGui_ImplSDL3_InitForSDLGPU(window); |
| 83 | 94 | ImGui_ImplSDLGPU3_InitInfo init_info = {}; |
| @@ -210,6 +221,13 @@ | ||
| 210 | 221 | ImGui_ImplSDLGPU3_RenderDrawData(draw_data, command_buffer, render_pass); |
| 211 | 222 | |
| 212 | 223 | SDL_EndGPURenderPass(render_pass); |
| 224 | + } | |
| 225 | + | |
| 226 | + // Update and Render additional Platform Windows | |
| 227 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 228 | + { | |
| 229 | + ImGui::UpdatePlatformWindows(); | |
| 230 | + ImGui::RenderPlatformWindowsDefault(); | |
| 213 | 231 | } |
| 214 | 232 | |
| 215 | 233 | // Submit the command buffer |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_sdl3_opengl3</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>MultiByte</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>MultiByte</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>MultiByte</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>MultiByte</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -56,6 +56,7 @@ | ||
| 56 | 56 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 57 | 57 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 58 | 58 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 59 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 59 | 60 | |
| 60 | 61 | // Setup Dear ImGui style |
| 61 | 62 | ImGui::StyleColorsDark(); |
| @@ -65,6 +66,8 @@ | ||
| 65 | 66 | ImGuiStyle& style = ImGui::GetStyle(); |
| 66 | 67 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 67 | 68 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 69 | + //io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 70 | + //io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 68 | 71 | |
| 69 | 72 | // Setup Platform/Renderer backends |
| 70 | 73 | ImGui_ImplSDL3_InitForSDLRenderer(window, renderer); |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{663A7E89-1E42-4222-921C-177F5B5910DF}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_sdl3_vulkan</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>MultiByte</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>MultiByte</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>MultiByte</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>MultiByte</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -395,6 +395,10 @@ | ||
| 395 | 395 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 396 | 396 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 397 | 397 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 398 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 399 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 400 | + //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons; | |
| 401 | + //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge; | |
| 398 | 402 | |
| 399 | 403 | // Setup Dear ImGui style |
| 400 | 404 | ImGui::StyleColorsDark(); |
| @@ -404,7 +408,16 @@ | ||
| 404 | 408 | ImGuiStyle& style = ImGui::GetStyle(); |
| 405 | 409 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 406 | 410 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 411 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 412 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 407 | 413 | |
| 414 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 415 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 416 | + { | |
| 417 | + style.WindowRounding = 0.0f; | |
| 418 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 419 | + } | |
| 420 | + | |
| 408 | 421 | // Setup Platform/Renderer backends |
| 409 | 422 | ImGui_ImplSDL3_InitForVulkan(window); |
| 410 | 423 | ImGui_ImplVulkan_InitInfo init_info = {}; |
| @@ -530,17 +543,25 @@ | ||
| 530 | 543 | |
| 531 | 544 | // Rendering |
| 532 | 545 | ImGui::Render(); |
| 533 | - ImDrawData* draw_data = ImGui::GetDrawData(); | |
| 534 | - const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f); | |
| 535 | - if (!is_minimized) | |
| 546 | + ImDrawData* main_draw_data = ImGui::GetDrawData(); | |
| 547 | + const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f); | |
| 548 | + wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w; | |
| 549 | + wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w; | |
| 550 | + wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w; | |
| 551 | + wd->ClearValue.color.float32[3] = clear_color.w; | |
| 552 | + if (!main_is_minimized) | |
| 553 | + FrameRender(wd, main_draw_data); | |
| 554 | + | |
| 555 | + // Update and Render additional Platform Windows | |
| 556 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 536 | 557 | { |
| 537 | - wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w; | |
| 538 | - wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w; | |
| 539 | - wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w; | |
| 540 | - wd->ClearValue.color.float32[3] = clear_color.w; | |
| 541 | - FrameRender(wd, draw_data); | |
| 542 | - FramePresent(wd); | |
| 558 | + ImGui::UpdatePlatformWindows(); | |
| 559 | + ImGui::RenderPlatformWindowsDefault(); | |
| 543 | 560 | } |
| 561 | + | |
| 562 | + // Present Main Platform Window | |
| 563 | + if (!main_is_minimized) | |
| 564 | + FramePresent(wd); | |
| 544 | 565 | } |
| 545 | 566 | |
| 546 | 567 | // Cleanup |
| @@ -14,7 +14,7 @@ | ||
| 14 | 14 | # * build/example_sdl3_wgpu[.exe] or build/Debug/example_sdl3_wgpu[.exe] |
| 15 | 15 | |
| 16 | 16 | # Building for desktop with WGVK (MUCH EASIER) |
| 17 | -# 1. git clone https://github.com/manuel5975p/WGVK dawn | |
| 17 | +# 1. git clone https://github.com/manuel5975p/WGVK wgvk | |
| 18 | 18 | # 2. cmake -B build -DIMGUI_WGVK_DIR=wgvk |
| 19 | 19 | # 3. cmake --build build |
| 20 | 20 | # The resulting binary will be found at one of the following locations: |
| @@ -37,7 +37,7 @@ | ||
| 37 | 37 | set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE) |
| 38 | 38 | endif() |
| 39 | 39 | |
| 40 | -set(CMAKE_CXX_STANDARD 17) # Dawn requires C++17 | |
| 40 | +set(CMAKE_CXX_STANDARD 20) # Dawn requires C++20 | |
| 41 | 41 | |
| 42 | 42 | # Dear ImGui |
| 43 | 43 | set(IMGUI_DIR ../../) |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{345A953E-A004-4648-B442-DC5F9F11068C}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_win32_directx10</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>Unicode</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>Unicode</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>Unicode</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>Unicode</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -57,6 +57,10 @@ | ||
| 57 | 57 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 58 | 58 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 59 | 59 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 60 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 61 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 62 | + //io.ConfigViewportsNoAutoMerge = true; | |
| 63 | + //io.ConfigViewportsNoTaskBarIcon = true; | |
| 60 | 64 | |
| 61 | 65 | // Setup Dear ImGui style |
| 62 | 66 | ImGui::StyleColorsDark(); |
| @@ -66,7 +70,16 @@ | ||
| 66 | 70 | ImGuiStyle& style = ImGui::GetStyle(); |
| 67 | 71 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 68 | 72 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 73 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 74 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 69 | 75 | |
| 76 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 77 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 78 | + { | |
| 79 | + style.WindowRounding = 0.0f; | |
| 80 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 81 | + } | |
| 82 | + | |
| 70 | 83 | // Setup Platform/Renderer backends |
| 71 | 84 | ImGui_ImplWin32_Init(hwnd); |
| 72 | 85 | ImGui_ImplDX10_Init(g_pd3dDevice); |
| @@ -177,6 +190,13 @@ | ||
| 177 | 190 | g_pd3dDevice->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha); |
| 178 | 191 | ImGui_ImplDX10_RenderDrawData(ImGui::GetDrawData()); |
| 179 | 192 | |
| 193 | + // Update and Render additional Platform Windows | |
| 194 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 195 | + { | |
| 196 | + ImGui::UpdatePlatformWindows(); | |
| 197 | + ImGui::RenderPlatformWindowsDefault(); | |
| 198 | + } | |
| 199 | + | |
| 180 | 200 | // Present |
| 181 | 201 | HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync |
| 182 | 202 | //HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync |
| @@ -196,7 +216,6 @@ | ||
| 196 | 216 | } |
| 197 | 217 | |
| 198 | 218 | // Helper functions |
| 199 | - | |
| 200 | 219 | bool CreateDeviceD3D(HWND hWnd) |
| 201 | 220 | { |
| 202 | 221 | // Setup swap chain |
| @@ -224,6 +243,16 @@ | ||
| 224 | 243 | res = D3D10CreateDeviceAndSwapChain(nullptr, D3D10_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice); |
| 225 | 244 | if (res != S_OK) |
| 226 | 245 | return false; |
| 246 | + | |
| 247 | + // Disable DXGI's default Alt+Enter fullscreen behavior. | |
| 248 | + // - You are free to leave this enabled, but it will not work properly with multiple viewports. | |
| 249 | + // - This must be done for all windows associated to the device. Our DX11 backend does this automatically for secondary viewports that it creates. | |
| 250 | + IDXGIFactory* pSwapChainFactory; | |
| 251 | + if (SUCCEEDED(g_pSwapChain->GetParent(IID_PPV_ARGS(&pSwapChainFactory)))) | |
| 252 | + { | |
| 253 | + pSwapChainFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER); | |
| 254 | + pSwapChainFactory->Release(); | |
| 255 | + } | |
| 227 | 256 | |
| 228 | 257 | CreateRenderTarget(); |
| 229 | 258 | return true; |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{9F316E83-5AE5-4939-A723-305A94F48005}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_win32_directx11</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>Unicode</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>Unicode</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>Unicode</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>Unicode</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -57,6 +57,12 @@ | ||
| 57 | 57 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 58 | 58 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 59 | 59 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 60 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 61 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 62 | + //io.ConfigViewportsNoAutoMerge = true; | |
| 63 | + //io.ConfigViewportsNoTaskBarIcon = true; | |
| 64 | + //io.ConfigDockingAlwaysTabBar = true; | |
| 65 | + //io.ConfigDockingTransparentPayload = true; | |
| 60 | 66 | |
| 61 | 67 | // Setup Dear ImGui style |
| 62 | 68 | ImGui::StyleColorsDark(); |
| @@ -66,7 +72,16 @@ | ||
| 66 | 72 | ImGuiStyle& style = ImGui::GetStyle(); |
| 67 | 73 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 68 | 74 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 75 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 76 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 69 | 77 | |
| 78 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 79 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 80 | + { | |
| 81 | + style.WindowRounding = 0.0f; | |
| 82 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 83 | + } | |
| 84 | + | |
| 70 | 85 | // Setup Platform/Renderer backends |
| 71 | 86 | ImGui_ImplWin32_Init(hwnd); |
| 72 | 87 | ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); |
| @@ -177,6 +192,13 @@ | ||
| 177 | 192 | g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha); |
| 178 | 193 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); |
| 179 | 194 | |
| 195 | + // Update and Render additional Platform Windows | |
| 196 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 197 | + { | |
| 198 | + ImGui::UpdatePlatformWindows(); | |
| 199 | + ImGui::RenderPlatformWindowsDefault(); | |
| 200 | + } | |
| 201 | + | |
| 180 | 202 | // Present |
| 181 | 203 | HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync |
| 182 | 204 | //HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync |
| @@ -196,7 +218,6 @@ | ||
| 196 | 218 | } |
| 197 | 219 | |
| 198 | 220 | // Helper functions |
| 199 | - | |
| 200 | 221 | bool CreateDeviceD3D(HWND hWnd) |
| 201 | 222 | { |
| 202 | 223 | // Setup swap chain |
| @@ -226,6 +247,16 @@ | ||
| 226 | 247 | res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); |
| 227 | 248 | if (res != S_OK) |
| 228 | 249 | return false; |
| 250 | + | |
| 251 | + // Disable DXGI's default Alt+Enter fullscreen behavior. | |
| 252 | + // - You are free to leave this enabled, but it will not work properly with multiple viewports. | |
| 253 | + // - This must be done for all windows associated to the device. Our DX11 backend does this automatically for secondary viewports that it creates. | |
| 254 | + IDXGIFactory* pSwapChainFactory; | |
| 255 | + if (SUCCEEDED(g_pSwapChain->GetParent(IID_PPV_ARGS(&pSwapChainFactory)))) | |
| 256 | + { | |
| 257 | + pSwapChainFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER); | |
| 258 | + pSwapChainFactory->Release(); | |
| 259 | + } | |
| 229 | 260 | |
| 230 | 261 | CreateRenderTarget(); |
| 231 | 262 | return true; |
| @@ -28,27 +28,27 @@ | ||
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>Unicode</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v142</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>Unicode</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v142</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>Unicode</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v142</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>Unicode</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v142</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -137,6 +137,10 @@ | ||
| 137 | 137 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 138 | 138 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 139 | 139 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 140 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 141 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 142 | + //io.ConfigViewportsNoAutoMerge = true; | |
| 143 | + //io.ConfigViewportsNoTaskBarIcon = true; | |
| 140 | 144 | |
| 141 | 145 | // Setup Dear ImGui style |
| 142 | 146 | ImGui::StyleColorsDark(); |
| @@ -146,7 +150,16 @@ | ||
| 146 | 150 | ImGuiStyle& style = ImGui::GetStyle(); |
| 147 | 151 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 148 | 152 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 153 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 154 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 149 | 155 | |
| 156 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 157 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 158 | + { | |
| 159 | + style.WindowRounding = 0.0f; | |
| 160 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 161 | + } | |
| 162 | + | |
| 150 | 163 | // Setup Platform/Renderer backends |
| 151 | 164 | ImGui_ImplWin32_Init(hwnd); |
| 152 | 165 | |
| @@ -285,6 +298,14 @@ | ||
| 285 | 298 | g_pd3dCommandList->Close(); |
| 286 | 299 | |
| 287 | 300 | g_pd3dCommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&g_pd3dCommandList); |
| 301 | + | |
| 302 | + // Update and Render additional Platform Windows | |
| 303 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 304 | + { | |
| 305 | + ImGui::UpdatePlatformWindows(); | |
| 306 | + ImGui::RenderPlatformWindowsDefault(); | |
| 307 | + } | |
| 308 | + | |
| 288 | 309 | g_pd3dCommandQueue->Signal(g_fence, ++g_fenceLastSignaledValue); |
| 289 | 310 | frameCtx->FenceValue = g_fenceLastSignaledValue; |
| 290 | 311 | |
| @@ -310,7 +331,6 @@ | ||
| 310 | 331 | } |
| 311 | 332 | |
| 312 | 333 | // Helper functions |
| 313 | - | |
| 314 | 334 | bool CreateDeviceD3D(HWND hWnd) |
| 315 | 335 | { |
| 316 | 336 | // Setup swap chain |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{4165A294-21F2-44CA-9B38-E3F935ABADF5}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_win32_directx9</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>Unicode</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>Unicode</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>Unicode</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>Unicode</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -55,6 +55,10 @@ | ||
| 55 | 55 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 56 | 56 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 57 | 57 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 58 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 59 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 60 | + //io.ConfigViewportsNoAutoMerge = true; | |
| 61 | + //io.ConfigViewportsNoTaskBarIcon = true; | |
| 58 | 62 | |
| 59 | 63 | // Setup Dear ImGui style |
| 60 | 64 | ImGui::StyleColorsDark(); |
| @@ -64,7 +68,16 @@ | ||
| 64 | 68 | ImGuiStyle& style = ImGui::GetStyle(); |
| 65 | 69 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 66 | 70 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 71 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 72 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 67 | 73 | |
| 74 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 75 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 76 | + { | |
| 77 | + style.WindowRounding = 0.0f; | |
| 78 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 79 | + } | |
| 80 | + | |
| 68 | 81 | // Setup Platform/Renderer backends |
| 69 | 82 | ImGui_ImplWin32_Init(hwnd); |
| 70 | 83 | ImGui_ImplDX9_Init(g_pd3dDevice); |
| @@ -187,6 +200,14 @@ | ||
| 187 | 200 | ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData()); |
| 188 | 201 | g_pd3dDevice->EndScene(); |
| 189 | 202 | } |
| 203 | + | |
| 204 | + // Update and Render additional Platform Windows | |
| 205 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 206 | + { | |
| 207 | + ImGui::UpdatePlatformWindows(); | |
| 208 | + ImGui::RenderPlatformWindowsDefault(); | |
| 209 | + } | |
| 210 | + | |
| 190 | 211 | HRESULT result = g_pd3dDevice->Present(nullptr, nullptr, nullptr, nullptr); |
| 191 | 212 | if (result == D3DERR_DEVICELOST) |
| 192 | 213 | g_DeviceLost = true; |
| @@ -205,7 +226,6 @@ | ||
| 205 | 226 | } |
| 206 | 227 | |
| 207 | 228 | // Helper functions |
| 208 | - | |
| 209 | 229 | bool CreateDeviceD3D(HWND hWnd) |
| 210 | 230 | { |
| 211 | 231 | if ((g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == nullptr) |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{C624E5FF-D4FE-4D35-9164-B8A91864F98E}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_win32_opengl2</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>Unicode</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>Unicode</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>Unicode</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>Unicode</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -33,6 +33,42 @@ | ||
| 33 | 33 | void ResetDeviceWGL(); |
| 34 | 34 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); |
| 35 | 35 | |
| 36 | +// Support function for multi-viewports | |
| 37 | +// Unlike most other backend combination, we need specific hooks to combine Win32+OpenGL. | |
| 38 | +// We could in theory decide to support Win32-specific code in OpenGL backend via e.g. an hypothetical ImGui_ImplOpenGL3_InitForRawWin32(). | |
| 39 | +static void Hook_Renderer_CreateWindow(ImGuiViewport* viewport) | |
| 40 | +{ | |
| 41 | + assert(viewport->RendererUserData == NULL); | |
| 42 | + | |
| 43 | + WGL_WindowData* data = IM_NEW(WGL_WindowData); | |
| 44 | + CreateDeviceWGL((HWND)viewport->PlatformHandle, data); | |
| 45 | + viewport->RendererUserData = data; | |
| 46 | +} | |
| 47 | + | |
| 48 | +static void Hook_Renderer_DestroyWindow(ImGuiViewport* viewport) | |
| 49 | +{ | |
| 50 | + if (viewport->RendererUserData != NULL) | |
| 51 | + { | |
| 52 | + WGL_WindowData* data = (WGL_WindowData*)viewport->RendererUserData; | |
| 53 | + CleanupDeviceWGL((HWND)viewport->PlatformHandle, data); | |
| 54 | + IM_DELETE(data); | |
| 55 | + viewport->RendererUserData = NULL; | |
| 56 | + } | |
| 57 | +} | |
| 58 | + | |
| 59 | +static void Hook_Platform_RenderWindow(ImGuiViewport* viewport, void*) | |
| 60 | +{ | |
| 61 | + // Activate the platform window DC in the OpenGL rendering context | |
| 62 | + if (WGL_WindowData* data = (WGL_WindowData*)viewport->RendererUserData) | |
| 63 | + wglMakeCurrent(data->hDC, g_hRC); | |
| 64 | +} | |
| 65 | + | |
| 66 | +static void Hook_Renderer_SwapBuffers(ImGuiViewport* viewport, void*) | |
| 67 | +{ | |
| 68 | + if (WGL_WindowData* data = (WGL_WindowData*)viewport->RendererUserData) | |
| 69 | + ::SwapBuffers(data->hDC); | |
| 70 | +} | |
| 71 | + | |
| 36 | 72 | // Main code |
| 37 | 73 | int main(int, char**) |
| 38 | 74 | { |
| @@ -65,6 +101,8 @@ | ||
| 65 | 101 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 66 | 102 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 67 | 103 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 104 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 105 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 68 | 106 | |
| 69 | 107 | // Setup Dear ImGui style |
| 70 | 108 | ImGui::StyleColorsDark(); |
| @@ -74,11 +112,34 @@ | ||
| 74 | 112 | ImGuiStyle& style = ImGui::GetStyle(); |
| 75 | 113 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 76 | 114 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 115 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 116 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 77 | 117 | |
| 118 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 119 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 120 | + { | |
| 121 | + style.WindowRounding = 0.0f; | |
| 122 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 123 | + } | |
| 124 | + | |
| 78 | 125 | // Setup Platform/Renderer backends |
| 79 | 126 | ImGui_ImplWin32_InitForOpenGL(hwnd); |
| 80 | 127 | ImGui_ImplOpenGL3_Init(); |
| 81 | 128 | |
| 129 | + // Win32+GL needs specific hooks for viewport, as there are specific things needed to tie Win32 and GL api. | |
| 130 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 131 | + { | |
| 132 | + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); | |
| 133 | + IM_ASSERT(platform_io.Renderer_CreateWindow == NULL); | |
| 134 | + IM_ASSERT(platform_io.Renderer_DestroyWindow == NULL); | |
| 135 | + IM_ASSERT(platform_io.Renderer_SwapBuffers == NULL); | |
| 136 | + IM_ASSERT(platform_io.Platform_RenderWindow == NULL); | |
| 137 | + platform_io.Renderer_CreateWindow = Hook_Renderer_CreateWindow; | |
| 138 | + platform_io.Renderer_DestroyWindow = Hook_Renderer_DestroyWindow; | |
| 139 | + platform_io.Renderer_SwapBuffers = Hook_Renderer_SwapBuffers; | |
| 140 | + platform_io.Platform_RenderWindow = Hook_Platform_RenderWindow; | |
| 141 | + } | |
| 142 | + | |
| 82 | 143 | // Load Fonts |
| 83 | 144 | // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap(). |
| 84 | 145 | // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold. |
| @@ -172,6 +233,16 @@ | ||
| 172 | 233 | glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); |
| 173 | 234 | glClear(GL_COLOR_BUFFER_BIT); |
| 174 | 235 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); |
| 236 | + | |
| 237 | + // Update and Render additional Platform Windows | |
| 238 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 239 | + { | |
| 240 | + ImGui::UpdatePlatformWindows(); | |
| 241 | + ImGui::RenderPlatformWindowsDefault(); | |
| 242 | + | |
| 243 | + // Restore the OpenGL rendering context to the main window DC, since platform windows might have changed it. | |
| 244 | + wglMakeCurrent(g_MainWindow.hDC, g_hRC); | |
| 245 | + } | |
| 175 | 246 | |
| 176 | 247 | // Present |
| 177 | 248 | ::SwapBuffers(g_MainWindow.hDC); |
| @@ -21,34 +21,34 @@ | ||
| 21 | 21 | <PropertyGroup Label="Globals"> |
| 22 | 22 | <ProjectGuid>{0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}</ProjectGuid> |
| 23 | 23 | <RootNamespace>example_win32_directx11</RootNamespace> |
| 24 | - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> | |
| 24 | + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> | |
| 25 | 25 | </PropertyGroup> |
| 26 | 26 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
| 27 | 27 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |
| 28 | 28 | <ConfigurationType>Application</ConfigurationType> |
| 29 | 29 | <UseDebugLibraries>true</UseDebugLibraries> |
| 30 | 30 | <CharacterSet>Unicode</CharacterSet> |
| 31 | - <PlatformToolset>v143</PlatformToolset> | |
| 31 | + <PlatformToolset>v141</PlatformToolset> | |
| 32 | 32 | </PropertyGroup> |
| 33 | 33 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |
| 34 | 34 | <ConfigurationType>Application</ConfigurationType> |
| 35 | 35 | <UseDebugLibraries>true</UseDebugLibraries> |
| 36 | 36 | <CharacterSet>Unicode</CharacterSet> |
| 37 | - <PlatformToolset>v143</PlatformToolset> | |
| 37 | + <PlatformToolset>v141</PlatformToolset> | |
| 38 | 38 | </PropertyGroup> |
| 39 | 39 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |
| 40 | 40 | <ConfigurationType>Application</ConfigurationType> |
| 41 | 41 | <UseDebugLibraries>false</UseDebugLibraries> |
| 42 | 42 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 43 | 43 | <CharacterSet>Unicode</CharacterSet> |
| 44 | - <PlatformToolset>v143</PlatformToolset> | |
| 44 | + <PlatformToolset>v141</PlatformToolset> | |
| 45 | 45 | </PropertyGroup> |
| 46 | 46 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
| 47 | 47 | <ConfigurationType>Application</ConfigurationType> |
| 48 | 48 | <UseDebugLibraries>false</UseDebugLibraries> |
| 49 | 49 | <WholeProgramOptimization>true</WholeProgramOptimization> |
| 50 | 50 | <CharacterSet>Unicode</CharacterSet> |
| 51 | - <PlatformToolset>v143</PlatformToolset> | |
| 51 | + <PlatformToolset>v141</PlatformToolset> | |
| 52 | 52 | </PropertyGroup> |
| 53 | 53 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
| 54 | 54 | <ImportGroup Label="ExtensionSettings"> |
| @@ -340,6 +340,16 @@ | ||
| 340 | 340 | |
| 341 | 341 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); |
| 342 | 342 | |
| 343 | +// FIXME: This code would ideally be inside imgui_impl_win32.cpp, it would create a dependency on Vulkan headers in imgui_impl_win32.cpp | |
| 344 | +static int ImGui_ImplWin32_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface) | |
| 345 | +{ | |
| 346 | + VkWin32SurfaceCreateInfoKHR createInfo = {}; | |
| 347 | + createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; | |
| 348 | + createInfo.hwnd = (HWND)viewport->PlatformHandleRaw; | |
| 349 | + createInfo.hinstance = ::GetModuleHandle(nullptr); | |
| 350 | + return (int)vkCreateWin32SurfaceKHR((VkInstance)vk_instance, &createInfo, (VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface); | |
| 351 | +} | |
| 352 | + | |
| 343 | 353 | // Main code |
| 344 | 354 | int main(int, char**) |
| 345 | 355 | { |
| @@ -383,6 +393,10 @@ | ||
| 383 | 393 | ImGuiIO& io = ImGui::GetIO(); (void)io; |
| 384 | 394 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls |
| 385 | 395 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls |
| 396 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking | |
| 397 | + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows | |
| 398 | + //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons; | |
| 399 | + //io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge; | |
| 386 | 400 | |
| 387 | 401 | // Setup Dear ImGui style |
| 388 | 402 | ImGui::StyleColorsDark(); |
| @@ -392,9 +406,20 @@ | ||
| 392 | 406 | ImGuiStyle& style = ImGui::GetStyle(); |
| 393 | 407 | style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) |
| 394 | 408 | style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor) |
| 409 | + io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 410 | + io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 395 | 411 | |
| 412 | + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. | |
| 413 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 414 | + { | |
| 415 | + style.WindowRounding = 0.0f; | |
| 416 | + style.Colors[ImGuiCol_WindowBg].w = 1.0f; | |
| 417 | + } | |
| 418 | + | |
| 396 | 419 | // Setup Platform/Renderer backends |
| 397 | 420 | ImGui_ImplWin32_Init(hwnd); |
| 421 | + ImGui::GetPlatformIO().Platform_CreateVkSurface = ImGui_ImplWin32_CreateVkSurface; | |
| 422 | + | |
| 398 | 423 | ImGui_ImplVulkan_InitInfo init_info = {}; |
| 399 | 424 | //init_info.ApiVersion = VK_API_VERSION_1_3; // Pass in your value of VkApplicationInfo::apiVersion, otherwise will default to header version. |
| 400 | 425 | init_info.Instance = g_Instance; |
| @@ -497,17 +522,25 @@ | ||
| 497 | 522 | |
| 498 | 523 | // Rendering |
| 499 | 524 | ImGui::Render(); |
| 500 | - ImDrawData* draw_data = ImGui::GetDrawData(); | |
| 501 | - const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f); | |
| 502 | - if (!is_minimized) | |
| 525 | + ImDrawData* main_draw_data = ImGui::GetDrawData(); | |
| 526 | + const bool main_is_minimized = (main_draw_data->DisplaySize.x <= 0.0f || main_draw_data->DisplaySize.y <= 0.0f); | |
| 527 | + wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w; | |
| 528 | + wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w; | |
| 529 | + wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w; | |
| 530 | + wd->ClearValue.color.float32[3] = clear_color.w; | |
| 531 | + if (!main_is_minimized) | |
| 532 | + FrameRender(wd, main_draw_data); | |
| 533 | + | |
| 534 | + // Update and Render additional Platform Windows | |
| 535 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 503 | 536 | { |
| 504 | - wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w; | |
| 505 | - wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w; | |
| 506 | - wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w; | |
| 507 | - wd->ClearValue.color.float32[3] = clear_color.w; | |
| 508 | - FrameRender(wd, draw_data); | |
| 509 | - FramePresent(wd); | |
| 537 | + ImGui::UpdatePlatformWindows(); | |
| 538 | + ImGui::RenderPlatformWindowsDefault(); | |
| 510 | 539 | } |
| 540 | + | |
| 541 | + // Present Main Platform Window | |
| 542 | + if (!main_is_minimized) | |
| 543 | + FramePresent(wd); | |
| 511 | 544 | } |
| 512 | 545 | |
| 513 | 546 | // Cleanup |
| @@ -49,11 +49,13 @@ | ||
| 49 | 49 | //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) |
| 50 | 50 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. |
| 51 | 51 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). |
| 52 | -//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded fonts (ProggyClean/ProggyForever), remove ~9 KB + ~14 KB from output binary. AddFontDefaultXXX() functions will assert. | |
| 52 | +//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded fonts (ProggyClean + ProggyForever). Remove ~9 KB + ~14 KB from output binary. AddFontDefaultXXX() functions will assert. | |
| 53 | +//#define IMGUI_DISABLE_DEFAULT_FONT_BITMAP // Disable default embedded bitmap font (ProggyClean). Remove ~9 KB from output binary. AddFontDefaultBitmap() will assert. | |
| 54 | +//#define IMGUI_DISABLE_DEFAULT_FONT_VECTOR // Disable default embedded vector font (ProggyForever), Remove ~14 KB from output binary. AddFontDefaultVector() will assert. | |
| 53 | 55 | //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available |
| 54 | 56 | |
| 55 | 57 | //---- Enable Test Engine / Automation features. |
| 56 | -//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details. | |
| 58 | +//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_imconfig.h", see Test Engine for details. | |
| 57 | 59 | |
| 58 | 60 | //---- Include imgui_user.h at the end of imgui.h as a convenience |
| 59 | 61 | // May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included. |
大き過ぎるので表示しません
| @@ -1,4 +1,4 @@ | ||
| 1 | -// dear imgui, v1.92.8 | |
| 1 | +// dear imgui, v1.92.9 WIP | |
| 2 | 2 | // (headers) |
| 3 | 3 | |
| 4 | 4 | // Help: |
| @@ -29,10 +29,12 @@ | ||
| 29 | 29 | |
| 30 | 30 | // Library Version |
| 31 | 31 | // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') |
| 32 | -#define IMGUI_VERSION "1.92.8" | |
| 33 | -#define IMGUI_VERSION_NUM 19280 | |
| 32 | +#define IMGUI_VERSION "1.92.9 WIP" | |
| 33 | +#define IMGUI_VERSION_NUM 19284 | |
| 34 | 34 | #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 |
| 35 | 35 | #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 |
| 36 | +#define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch. | |
| 37 | +#define IMGUI_HAS_DOCK // In 'docking' WIP branch. | |
| 36 | 38 | |
| 37 | 39 | /* |
| 38 | 40 | |
| @@ -46,14 +48,14 @@ | ||
| 46 | 48 | // [SECTION] Helpers: Debug log, Memory allocations macros, ImVector<> |
| 47 | 49 | // [SECTION] ImGuiStyle |
| 48 | 50 | // [SECTION] ImGuiIO |
| 49 | -// [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload) | |
| 51 | +// [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiWindowClass, ImGuiPayload) | |
| 50 | 52 | // [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor) |
| 51 | 53 | // [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiMultiSelectIO, ImGuiSelectionRequest, ImGuiSelectionBasicStorage, ImGuiSelectionExternalStorage) |
| 52 | 54 | // [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) |
| 53 | 55 | // [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureRect, ImTextureData) |
| 54 | 56 | // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFontBaked, ImFont) |
| 55 | 57 | // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) |
| 56 | -// [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformImeData) | |
| 58 | +// [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformMonitor, ImGuiPlatformImeData) | |
| 57 | 59 | // [SECTION] Obsolete functions and types |
| 58 | 60 | |
| 59 | 61 | */ |
| @@ -197,8 +199,9 @@ | ||
| 197 | 199 | struct ImGuiMultiSelectIO; // Structure to interact with a BeginMultiSelect()/EndMultiSelect() block |
| 198 | 200 | struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame |
| 199 | 201 | struct ImGuiPayload; // User data payload for drag and drop operations |
| 200 | -struct ImGuiPlatformIO; // Interface between platform/renderer backends and ImGui (e.g. Clipboard, IME hooks). Extends ImGuiIO. In docking branch, this gets extended to support multi-viewports. | |
| 202 | +struct ImGuiPlatformIO; // Interface between platform/renderer backends and ImGui (e.g. Clipboard, IME, Multi-Viewport support). Extends ImGuiIO. | |
| 201 | 203 | struct ImGuiPlatformImeData; // Platform IME data for io.PlatformSetImeDataFn() function. |
| 204 | +struct ImGuiPlatformMonitor; // Multi-viewport support: user-provided bounds for each connected monitor/display. Used when positioning popups and tooltips to avoid them straddling monitors | |
| 202 | 205 | struct ImGuiSelectionBasicStorage; // Optional helper to store multi-selection state + apply multi-selection requests. |
| 203 | 206 | struct ImGuiSelectionExternalStorage;//Optional helper to apply multi-selection requests to existing randomly accessible storage. |
| 204 | 207 | struct ImGuiSelectionRequest; // A selection request (stored in ImGuiMultiSelectIO) |
| @@ -210,7 +213,8 @@ | ||
| 210 | 213 | struct ImGuiTableColumnSortSpecs; // Sorting specification for one column of a table |
| 211 | 214 | struct ImGuiTextBuffer; // Helper to hold and append into a text buffer (~string builder) |
| 212 | 215 | struct ImGuiTextFilter; // Helper to parse and apply text filters (e.g. "aaaaa[,bbbbb][,ccccc]") |
| 213 | -struct ImGuiViewport; // A Platform Window (always only one in 'master' branch), in the future may represent Platform Monitor | |
| 216 | +struct ImGuiViewport; // A Platform Window (always 1 unless multi-viewport are enabled. One per platform window to output to). In the future may represent Platform Monitor | |
| 217 | +struct ImGuiWindowClass; // Window class (rare/advanced uses: provide hints to the platform backend via altered viewport flags and parent/child info) | |
| 214 | 218 | |
| 215 | 219 | // Enumerations |
| 216 | 220 | // - We don't use strongly typed enums much because they add constraints (can't extend in private code, can't store typed in bit fields, extra casting on iteration) |
| @@ -246,6 +250,7 @@ | ||
| 246 | 250 | typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4() etc. |
| 247 | 251 | typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags |
| 248 | 252 | typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo() |
| 253 | +typedef int ImGuiDockNodeFlags; // -> enum ImGuiDockNodeFlags_ // Flags: for DockSpace() | |
| 249 | 254 | typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for BeginDragDropSource(), AcceptDragDropPayload() |
| 250 | 255 | typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused() |
| 251 | 256 | typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc. |
| @@ -466,10 +471,12 @@ | ||
| 466 | 471 | IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options. |
| 467 | 472 | IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered and hoverable (e.g. not blocked by a popup/modal)? See ImGuiHoveredFlags_ for options. IMPORTANT: If you are trying to check whether your mouse should be dispatched to Dear ImGui or to your underlying app, you should not use this function! Use the 'io.WantCaptureMouse' boolean for that! Refer to FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" for details. |
| 468 | 473 | IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives |
| 474 | + IMGUI_API float GetWindowDpiScale(); // get DPI scale currently associated to the current window's viewport. | |
| 469 | 475 | IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider always using GetCursorScreenPos() and GetContentRegionAvail() instead) |
| 470 | 476 | IMGUI_API ImVec2 GetWindowSize(); // get current window size (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider always using GetCursorScreenPos() and GetContentRegionAvail() instead) |
| 471 | 477 | IMGUI_API float GetWindowWidth(); // get current window width (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for GetWindowSize().x. |
| 472 | 478 | IMGUI_API float GetWindowHeight(); // get current window height (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for GetWindowSize().y. |
| 479 | + IMGUI_API ImGuiViewport*GetWindowViewport(); // get viewport currently associated to the current window. | |
| 473 | 480 | |
| 474 | 481 | // Window manipulation |
| 475 | 482 | // - Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin). |
| @@ -481,6 +488,7 @@ | ||
| 481 | 488 | IMGUI_API void SetNextWindowFocus(); // set next window to be focused / top-most. call before Begin() |
| 482 | 489 | IMGUI_API void SetNextWindowScroll(const ImVec2& scroll); // set next window scrolling value (use < 0.0f to not affect a given axis). |
| 483 | 490 | IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily override the Alpha component of ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground. |
| 491 | + IMGUI_API void SetNextWindowViewport(ImGuiID viewport_id); // set next window viewport | |
| 484 | 492 | IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects. |
| 485 | 493 | IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0, 0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. |
| 486 | 494 | IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). |
| @@ -613,7 +621,8 @@ | ||
| 613 | 621 | IMGUI_API ImGuiID GetID(int int_id); |
| 614 | 622 | |
| 615 | 623 | // Widgets: Text |
| 616 | - IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text. | |
| 624 | + // - Note that all functions taking format strings in the API may be passed ("%s", text) or ("%.*s", text_len, text): which will automatically bypass the formatter. | |
| 625 | + IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Practically equivalent to 'Text("%s", text)' but doesn't require null terminated string if 'text_end' is specified. | |
| 617 | 626 | IMGUI_API void Text(const char* fmt, ...) IM_FMTARGS(1); // formatted text |
| 618 | 627 | IMGUI_API void TextV(const char* fmt, va_list args) IM_FMTLIST(1); |
| 619 | 628 | IMGUI_API void TextColored(const ImVec4& col, const char* fmt, ...) IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor(); |
| @@ -648,7 +657,7 @@ | ||
| 648 | 657 | // Widgets: Images |
| 649 | 658 | // - Read about ImTextureID/ImTextureRef here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples |
| 650 | 659 | // - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above. |
| 651 | - // - Image() pads adds style.ImageBorderSize on each side, ImageButton() adds style.FramePadding on each side. | |
| 660 | + // - Image() adds style.ImageBorderSize on each side, ImageButton() adds style.FramePadding on each side. | |
| 652 | 661 | // - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. |
| 653 | 662 | // - An obsolete version of Image(), before 1.91.9 (March 2025), had a 'tint_col' parameter which is now supported by the ImageWithBg() function. |
| 654 | 663 | IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1)); |
| @@ -808,7 +817,7 @@ | ||
| 808 | 817 | // - Use BeginMenuBar() on a window ImGuiWindowFlags_MenuBar to append to its menu bar. |
| 809 | 818 | // - Use BeginMainMenuBar() to create a menu bar at the top of the screen and append to it. |
| 810 | 819 | // - Use BeginMenu() to create a menu. You can call BeginMenu() multiple time with the same identifier to append more items to it. |
| 811 | - // - Not that MenuItem() keyboardshortcuts are displayed as a convenience but _not processed_ by Dear ImGui at the moment. | |
| 820 | + // - Note that MenuItem() keyboard shortcuts are displayed as a convenience but _not processed_ by Dear ImGui at the moment. | |
| 812 | 821 | IMGUI_API bool BeginMenuBar(); // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window). |
| 813 | 822 | IMGUI_API void EndMenuBar(); // only call EndMenuBar() if BeginMenuBar() returns true! |
| 814 | 823 | IMGUI_API bool BeginMainMenuBar(); // create and append to a full screen menu-bar. |
| @@ -837,7 +846,7 @@ | ||
| 837 | 846 | |
| 838 | 847 | // Popups, Modals |
| 839 | 848 | // - They block normal mouse hovering detection (and therefore most mouse interactions) behind them. |
| 840 | - // - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE. | |
| 849 | + // - If not modal: they can be closed by clicking anywhere outside them, or by pressing Escape (call 'Shortcut(ImGuiKey_Escape)' to claim a higher-priority shortcut). | |
| 841 | 850 | // - Their visibility state (~bool) is held internally instead of being held by the programmer as we are used to with regular Begin*() calls. |
| 842 | 851 | // - The 3 properties above are related: we need to retain popup visibility state in the library because popups may be closed as any time. |
| 843 | 852 | // - You can bypass the hovering restriction by using ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling IsItemHovered() or IsWindowHovered(). |
| @@ -908,14 +917,15 @@ | ||
| 908 | 917 | IMGUI_API bool TableSetColumnIndex(int column_n); // append into the specified column. Return true when column is visible. |
| 909 | 918 | |
| 910 | 919 | // Tables: Headers & Columns declaration |
| 911 | - // - Use TableSetupColumn() to specify label, resizing policy, default width/weight, id, various other flags etc. | |
| 920 | + // - Use TableSetupColumn() to specify label, resizing policy, default width/weight, various other flags etc. | |
| 921 | + // (the trailing 'ImGuiID user_data', which used to be referred to as 'ImGuiID user_id', is merely user data that is blindly copied in ImGuiTableColumnSortSpecs). | |
| 912 | 922 | // - Use TableHeadersRow() to create a header row and automatically submit a TableHeader() for each column. |
| 913 | 923 | // Headers are required to perform: reordering, sorting, and opening the context menu. |
| 914 | 924 | // The context menu can also be made available in columns body using ImGuiTableFlags_ContextMenuInBody. |
| 915 | 925 | // - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in |
| 916 | 926 | // some advanced use cases (e.g. adding custom widgets in header row). |
| 917 | 927 | // - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled. When freezing columns you would usually also use ImGuiTableColumnFlags_NoHide on them. |
| 918 | - IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_id = 0); | |
| 928 | + IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_data = 0); | |
| 919 | 929 | IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled. |
| 920 | 930 | IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used) |
| 921 | 931 | IMGUI_API void TableHeadersRow(); // submit a row with headers cells based on data provided to TableSetupColumn() + submit context menu |
| @@ -957,6 +967,34 @@ | ||
| 957 | 967 | IMGUI_API bool TabItemButton(const char* label, ImGuiTabItemFlags flags = 0); // create a Tab behaving like a button. return true when clicked. cannot be selected in the tab bar. |
| 958 | 968 | IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name. |
| 959 | 969 | |
| 970 | + // Docking | |
| 971 | + // - Read https://github.com/ocornut/imgui/wiki/Docking for details. | |
| 972 | + // - Enable with io.ConfigFlags |= ImGuiConfigFlags_DockingEnable. | |
| 973 | + // - You can use many Docking facilities without calling any API. | |
| 974 | + // - Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking. | |
| 975 | + // - Drag from window menu button (upper-left button) to undock an entire node (all windows). | |
| 976 | + // - When io.ConfigDockingWithShift == true, you instead need to hold SHIFT to enable docking. | |
| 977 | + // - DockSpaceOverViewport: | |
| 978 | + // - This is a helper to create an invisible window covering a viewport, then submit a DockSpace() into it. | |
| 979 | + // - Most applications can simply call DockSpaceOverViewport() once to allow docking windows into e.g. the edge of your screen. | |
| 980 | + // e.g. ImGui::NewFrame(); ImGui::DockSpaceOverViewport(); // Create a dockspace in main viewport. | |
| 981 | + // or: ImGui::NewFrame(); ImGui::DockSpaceOverViewport(0, nullptr, ImGuiDockNodeFlags_PassthruCentralNode); // Create a dockspace in main viewport, central node is transparent. | |
| 982 | + // - Dockspaces: | |
| 983 | + // - A dockspace is an explicit dock node within an existing window. | |
| 984 | + // - IMPORTANT: Dockspaces need to be submitted _before_ any window they can host. Submit them early in your frame! | |
| 985 | + // - IMPORTANT: Dockspaces need to be kept alive if hidden, otherwise windows docked into it will be undocked. | |
| 986 | + // If you have e.g. multiple tabs with a dockspace inside each tab: submit the non-visible dockspaces with ImGuiDockNodeFlags_KeepAliveOnly. | |
| 987 | + // - See 'Demo->Examples->Dockspace' or 'Demo->Examples->Documents' for more detailed demos. | |
| 988 | + // - Programmatic docking: | |
| 989 | + // - There is no public API yet other than the very limited SetNextWindowDockID() function. Sorry for that! | |
| 990 | + // - Read https://github.com/ocornut/imgui/wiki/Docking for examples of how to use current internal API. | |
| 991 | + IMGUI_API ImGuiID DockSpace(ImGuiID dockspace_id, const ImVec2& size = ImVec2(0, 0), ImGuiDockNodeFlags flags = 0, const ImGuiWindowClass* window_class = NULL); | |
| 992 | + IMGUI_API ImGuiID DockSpaceOverViewport(ImGuiID dockspace_id = 0, const ImGuiViewport* viewport = NULL, ImGuiDockNodeFlags flags = 0, const ImGuiWindowClass* window_class = NULL); | |
| 993 | + IMGUI_API void SetNextWindowDockID(ImGuiID dock_id, ImGuiCond cond = 0); // set next window dock id | |
| 994 | + IMGUI_API void SetNextWindowClass(const ImGuiWindowClass* window_class); // set next window class (control docking compatibility + provide hints to platform backend via custom viewport flags and platform parent/child relationship) | |
| 995 | + IMGUI_API ImGuiID GetWindowDockID(); // get dock id of current window, or 0 if not associated to any docking node. | |
| 996 | + IMGUI_API bool IsWindowDocked(); // is current window docked into another window? | |
| 997 | + | |
| 960 | 998 | // Logging/Capture |
| 961 | 999 | // - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are automatically opened during logging. |
| 962 | 1000 | IMGUI_API void LogToTTY(int auto_open_depth = -1); // start logging to tty (stdout) |
| @@ -1032,8 +1070,8 @@ | ||
| 1032 | 1070 | IMGUI_API ImGuiViewport* GetMainViewport(); // return primary/default viewport. This can never be NULL. |
| 1033 | 1071 | |
| 1034 | 1072 | // Background/Foreground Draw Lists |
| 1035 | - IMGUI_API ImDrawList* GetBackgroundDrawList(); // this draw list will be the first rendered one. Useful to quickly draw shapes/text behind dear imgui contents. | |
| 1036 | - IMGUI_API ImDrawList* GetForegroundDrawList(); // this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. | |
| 1073 | + IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport = NULL); // get background draw list for the given viewport or viewport associated to the current window. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. | |
| 1074 | + IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport = NULL); // get foreground draw list for the given viewport or viewport associated to the current window. this draw list will be the top-most rendered one. Useful to quickly draw shapes/text over dear imgui contents. | |
| 1037 | 1075 | |
| 1038 | 1076 | // Miscellaneous Utilities |
| 1039 | 1077 | IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped. |
| @@ -1156,6 +1194,15 @@ | ||
| 1156 | 1194 | IMGUI_API void* MemAlloc(size_t size); |
| 1157 | 1195 | IMGUI_API void MemFree(void* ptr); |
| 1158 | 1196 | |
| 1197 | + // (Optional) Platform/OS interface for multi-viewport support | |
| 1198 | + // Read comments around the ImGuiPlatformIO structure for more details. | |
| 1199 | + // Note: You may use GetWindowViewport() to get the current viewport of the current window. | |
| 1200 | + IMGUI_API void UpdatePlatformWindows(); // call in main loop. will call CreateWindow/ResizeWindow/etc. platform functions for each secondary viewport, and DestroyWindow for each inactive viewport. | |
| 1201 | + IMGUI_API void RenderPlatformWindowsDefault(void* platform_render_arg = NULL, void* renderer_render_arg = NULL); // call in main loop. will call RenderWindow/SwapBuffers platform functions for each secondary viewport which doesn't have the ImGuiViewportFlags_Minimized flag set. May be reimplemented by user for custom rendering needs. | |
| 1202 | + IMGUI_API void DestroyPlatformWindows(); // call DestroyWindow platform functions for all viewports. call from backend Shutdown() if you need to close platform windows before imgui shutdown. otherwise will be called by DestroyContext(). | |
| 1203 | + IMGUI_API ImGuiViewport* FindViewportByID(ImGuiID viewport_id); // this is a helper for backends. | |
| 1204 | + IMGUI_API ImGuiViewport* FindViewportByPlatformHandle(void* platform_handle); // this is a helper for backends. the type platform_handle is decided by the backend (e.g. HWND, MyWindow*, GLFWwindow* etc.) | |
| 1205 | + | |
| 1159 | 1206 | } // namespace ImGui |
| 1160 | 1207 | |
| 1161 | 1208 | //----------------------------------------------------------------------------- |
| @@ -1186,11 +1233,13 @@ | ||
| 1186 | 1233 | ImGuiWindowFlags_NoNavInputs = 1 << 16, // No keyboard/gamepad navigation within the window |
| 1187 | 1234 | ImGuiWindowFlags_NoNavFocus = 1 << 17, // No focusing toward this window with keyboard/gamepad navigation (e.g. skipped by Ctrl+Tab) |
| 1188 | 1235 | ImGuiWindowFlags_UnsavedDocument = 1 << 18, // Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar. |
| 1236 | + ImGuiWindowFlags_NoDocking = 1 << 19, // Disable docking of this window | |
| 1189 | 1237 | ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, |
| 1190 | 1238 | ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse, |
| 1191 | 1239 | ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus, |
| 1192 | 1240 | |
| 1193 | 1241 | // [Internal] |
| 1242 | + ImGuiWindowFlags_DockNodeHost = 1 << 23, // Don't use! For internal use by Begin()/NewFrame() | |
| 1194 | 1243 | ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild() |
| 1195 | 1244 | ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip() |
| 1196 | 1245 | ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup() |
| @@ -1330,7 +1379,7 @@ | ||
| 1330 | 1379 | |
| 1331 | 1380 | #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS |
| 1332 | 1381 | ImGuiTreeNodeFlags_NavLeftJumpsBackHere = ImGuiTreeNodeFlags_NavLeftJumpsToParent, // Renamed in 1.92.0 |
| 1333 | - ImGuiTreeNodeFlags_SpanTextWidth = ImGuiTreeNodeFlags_SpanLabelWidth, // Renamed in 1.90.7 | |
| 1382 | + //ImGuiTreeNodeFlags_SpanTextWidth = ImGuiTreeNodeFlags_SpanLabelWidth, // Renamed in 1.90.7 | |
| 1334 | 1383 | //ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7 |
| 1335 | 1384 | #endif |
| 1336 | 1385 | }; |
| @@ -1436,7 +1485,7 @@ | ||
| 1436 | 1485 | ImGuiFocusedFlags_RootWindow = 1 << 1, // Test from root window (top most parent of the current hierarchy) |
| 1437 | 1486 | ImGuiFocusedFlags_AnyWindow = 1 << 2, // Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use 'io.WantCaptureMouse' instead! Please read the FAQ! |
| 1438 | 1487 | ImGuiFocusedFlags_NoPopupHierarchy = 1 << 3, // Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow) |
| 1439 | - //ImGuiFocusedFlags_DockHierarchy = 1 << 4, // Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow) | |
| 1488 | + ImGuiFocusedFlags_DockHierarchy = 1 << 4, // Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow) | |
| 1440 | 1489 | ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows, |
| 1441 | 1490 | }; |
| 1442 | 1491 | |
| @@ -1450,7 +1499,7 @@ | ||
| 1450 | 1499 | ImGuiHoveredFlags_RootWindow = 1 << 1, // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy) |
| 1451 | 1500 | ImGuiHoveredFlags_AnyWindow = 1 << 2, // IsWindowHovered() only: Return true if any window is hovered |
| 1452 | 1501 | ImGuiHoveredFlags_NoPopupHierarchy = 1 << 3, // IsWindowHovered() only: Do not consider popup hierarchy (do not treat popup emitter as parent of popup) (when used with _ChildWindows or _RootWindow) |
| 1453 | - //ImGuiHoveredFlags_DockHierarchy = 1 << 4, // IsWindowHovered() only: Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow) | |
| 1502 | + ImGuiHoveredFlags_DockHierarchy = 1 << 4, // IsWindowHovered() only: Consider docking hierarchy (treat dockspace host as parent of docked window) (when used with _ChildWindows or _RootWindow) | |
| 1454 | 1503 | ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 5, // Return true even if a popup window is normally blocking access to this item/window |
| 1455 | 1504 | //ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 6, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet. |
| 1456 | 1505 | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 7, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns. |
| @@ -1480,6 +1529,27 @@ | ||
| 1480 | 1529 | ImGuiHoveredFlags_NoSharedDelay = 1 << 17, // IsItemHovered() only: Disable shared delay system where moving from one item to the next keeps the previous timer for a short time (standard for tooltips with long delays) |
| 1481 | 1530 | }; |
| 1482 | 1531 | |
| 1532 | +// Flags for ImGui::DockSpace(), shared/inherited by child nodes. | |
| 1533 | +// (Some flags can be applied to individual nodes directly) | |
| 1534 | +// FIXME-DOCK: Also see ImGuiDockNodeFlagsPrivate_ which may involve using the WIP and internal DockBuilder api. | |
| 1535 | +enum ImGuiDockNodeFlags_ | |
| 1536 | +{ | |
| 1537 | + ImGuiDockNodeFlags_None = 0, | |
| 1538 | + ImGuiDockNodeFlags_KeepAliveOnly = 1 << 0, // // Don't display the dockspace node but keep it alive. Windows docked into this dockspace node won't be undocked. | |
| 1539 | + //ImGuiDockNodeFlags_NoCentralNode = 1 << 1, // // Disable Central Node (the node which can stay empty) | |
| 1540 | + ImGuiDockNodeFlags_NoDockingOverCentralNode = 1 << 2, // // Disable docking over the Central Node, which will be always kept empty. | |
| 1541 | + ImGuiDockNodeFlags_PassthruCentralNode = 1 << 3, // // Enable passthru dockspace: 1) DockSpace() will render a ImGuiCol_WindowBg background covering everything excepted the Central Node when empty. Meaning the host window should probably use SetNextWindowBgAlpha(0.0f) prior to Begin() when using this. 2) When Central Node is empty: let inputs pass-through + won't display a DockingEmptyBg background. See demo for details. | |
| 1542 | + ImGuiDockNodeFlags_NoDockingSplit = 1 << 4, // // Disable other windows/nodes from splitting this node. | |
| 1543 | + ImGuiDockNodeFlags_NoResize = 1 << 5, // Saved // Disable resizing node using the splitter/separators. Useful with programmatically setup dockspaces. | |
| 1544 | + ImGuiDockNodeFlags_AutoHideTabBar = 1 << 6, // // Tab bar will automatically hide when there is a single window in the dock node. | |
| 1545 | + ImGuiDockNodeFlags_NoUndocking = 1 << 7, // // Disable undocking this node. | |
| 1546 | + | |
| 1547 | +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS | |
| 1548 | + ImGuiDockNodeFlags_NoSplit = ImGuiDockNodeFlags_NoDockingSplit, // Renamed in 1.90 | |
| 1549 | + ImGuiDockNodeFlags_NoDockingInCentralNode = ImGuiDockNodeFlags_NoDockingOverCentralNode, // Renamed in 1.90 | |
| 1550 | +#endif | |
| 1551 | +}; | |
| 1552 | + | |
| 1483 | 1553 | // Flags for ImGui::BeginDragDropSource(), ImGui::AcceptDragDropPayload() |
| 1484 | 1554 | enum ImGuiDragDropFlags_ |
| 1485 | 1555 | { |
| @@ -1714,12 +1784,21 @@ | ||
| 1714 | 1784 | ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct backend to not alter mouse cursor shape and visibility. Use if the backend cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead. |
| 1715 | 1785 | ImGuiConfigFlags_NoKeyboard = 1 << 6, // Instruct dear imgui to disable keyboard inputs and interactions. This is done by ignoring keyboard events and clearing existing states. |
| 1716 | 1786 | |
| 1787 | + // [BETA] Docking | |
| 1788 | + ImGuiConfigFlags_DockingEnable = 1 << 7, // Docking enable flags. | |
| 1789 | + | |
| 1790 | + // [BETA] Viewports | |
| 1791 | + // When using viewports it is recommended that your default value for ImGuiCol_WindowBg is opaque (Alpha=1.0) so transition to a viewport won't be noticeable. | |
| 1792 | + ImGuiConfigFlags_ViewportsEnable = 1 << 10, // Viewport enable flags (require both ImGuiBackendFlags_PlatformHasViewports + ImGuiBackendFlags_RendererHasViewports set by the respective backends) | |
| 1793 | + | |
| 1717 | 1794 | // [Unused] User storage (to allow your backend/engine to communicate to code that may be shared between multiple projects. Those flags are NOT used by core Dear ImGui) |
| 1718 | 1795 | ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware. |
| 1719 | 1796 | ImGuiConfigFlags_IsTouchScreen = 1 << 21, // Application is using a touch screen instead of a mouse. |
| 1720 | 1797 | #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS |
| 1721 | 1798 | ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavMoveSetMousePos |
| 1722 | 1799 | ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // [moved/renamed in 1.91.4] -> use bool io.ConfigNavCaptureKeyboard |
| 1800 | + ImGuiConfigFlags_DpiEnableScaleFonts = 1 << 14, // [moved/renamed in 1.92.0] -> use bool io.ConfigDpiScaleFonts | |
| 1801 | + ImGuiConfigFlags_DpiEnableScaleViewports= 1 << 15, // [moved/renamed in 1.92.0] -> use bool io.ConfigDpiScaleViewports | |
| 1723 | 1802 | #endif |
| 1724 | 1803 | }; |
| 1725 | 1804 | |
| @@ -1732,6 +1811,12 @@ | ||
| 1732 | 1811 | ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Backend Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if io.ConfigNavMoveSetMousePos is set). |
| 1733 | 1812 | ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3, // Backend Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices. |
| 1734 | 1813 | ImGuiBackendFlags_RendererHasTextures = 1 << 4, // Backend Renderer supports ImTextureData requests to create/update/destroy textures. This enables incremental texture updates and texture reloads. See https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md for instructions on how to upgrade your custom backend. |
| 1814 | + | |
| 1815 | + // [BETA] Multi-Viewports | |
| 1816 | + ImGuiBackendFlags_RendererHasViewports = 1 << 10, // Backend Renderer supports multiple viewports. | |
| 1817 | + ImGuiBackendFlags_PlatformHasViewports = 1 << 11, // Backend Platform supports multiple viewports. | |
| 1818 | + ImGuiBackendFlags_HasMouseHoveredViewport=1 << 12, // Backend Platform supports calling io.AddMouseViewportEvent() with the viewport under the mouse. IF POSSIBLE, ignore viewports with the ImGuiViewportFlags_NoInputs flag (Win32 backend, GLFW 3.30+ backend can do this, SDL backend cannot). If this cannot be done, Dear ImGui needs to use a flawed heuristic to find the viewport under. | |
| 1819 | + ImGuiBackendFlags_HasParentViewport = 1 << 13, // Backend Platform supports honoring viewport->ParentViewport/ParentViewportId value, by applying the corresponding parent/child relationship at the Platform level. Child windows always appear in front of their parent window. | |
| 1735 | 1820 | }; |
| 1736 | 1821 | |
| 1737 | 1822 | // Enumeration for PushStyleColor() / PopStyleColor() |
| @@ -1779,6 +1864,8 @@ | ||
| 1779 | 1864 | ImGuiCol_TabDimmed, // Tab background, when tab-bar is unfocused & tab is unselected |
| 1780 | 1865 | ImGuiCol_TabDimmedSelected, // Tab background, when tab-bar is unfocused & tab is selected |
| 1781 | 1866 | ImGuiCol_TabDimmedSelectedOverline,//..horizontal overline, when tab-bar is unfocused & tab is selected |
| 1867 | + ImGuiCol_DockingPreview, // Preview overlay color when about to docking something | |
| 1868 | + ImGuiCol_DockingEmptyBg, // Background color for empty node (e.g. CentralNode with no window docked into it) | |
| 1782 | 1869 | ImGuiCol_PlotLines, |
| 1783 | 1870 | ImGuiCol_PlotLinesHovered, |
| 1784 | 1871 | ImGuiCol_PlotHistogram, |
| @@ -1854,6 +1941,8 @@ | ||
| 1854 | 1941 | ImGuiStyleVar_TableAngledHeadersTextAlign,// ImVec2 TableAngledHeadersTextAlign |
| 1855 | 1942 | ImGuiStyleVar_TreeLinesSize, // float TreeLinesSize |
| 1856 | 1943 | ImGuiStyleVar_TreeLinesRounding, // float TreeLinesRounding |
| 1944 | + ImGuiStyleVar_MenuItemRounding, // float MenuItemRounding | |
| 1945 | + ImGuiStyleVar_SelectableRounding, // float SelectableRounding | |
| 1857 | 1946 | ImGuiStyleVar_DragDropTargetRounding, // float DragDropTargetRounding |
| 1858 | 1947 | ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign |
| 1859 | 1948 | ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign |
| @@ -1861,6 +1950,7 @@ | ||
| 1861 | 1950 | ImGuiStyleVar_SeparatorTextBorderSize, // float SeparatorTextBorderSize |
| 1862 | 1951 | ImGuiStyleVar_SeparatorTextAlign, // ImVec2 SeparatorTextAlign |
| 1863 | 1952 | ImGuiStyleVar_SeparatorTextPadding, // ImVec2 SeparatorTextPadding |
| 1953 | + ImGuiStyleVar_DockingSeparatorSize, // float DockingSeparatorSize | |
| 1864 | 1954 | ImGuiStyleVar_COUNT |
| 1865 | 1955 | }; |
| 1866 | 1956 | |
| @@ -2158,7 +2248,7 @@ | ||
| 2158 | 2248 | // Sorting specification for one column of a table (sizeof == 12 bytes) |
| 2159 | 2249 | struct ImGuiTableColumnSortSpecs |
| 2160 | 2250 | { |
| 2161 | - ImGuiID ColumnUserID; // User id of the column (if specified by a TableSetupColumn() call) | |
| 2251 | + ImGuiID ColumnUserID; // User data for the column (if specified by a TableSetupColumn() call in the 'ImGuiID user_data' field). FIXME: Should be called 'UserData'.. | |
| 2162 | 2252 | ImS16 ColumnIndex; // Index of the column |
| 2163 | 2253 | ImS16 SortOrder; // Index within parent ImGuiTableSortSpecs (always stored in order starting from 0, tables sorted on a single criteria will always have a 0 here) |
| 2164 | 2254 | ImGuiSortDirection SortDirection; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending |
| @@ -2331,6 +2421,8 @@ | ||
| 2331 | 2421 | ImGuiTreeNodeFlags TreeLinesFlags; // Default way to draw lines connecting TreeNode hierarchy. ImGuiTreeNodeFlags_DrawLinesNone or ImGuiTreeNodeFlags_DrawLinesFull or ImGuiTreeNodeFlags_DrawLinesToNodes. |
| 2332 | 2422 | float TreeLinesSize; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines. |
| 2333 | 2423 | float TreeLinesRounding; // Radius of lines connecting child nodes to the vertical line. |
| 2424 | + float MenuItemRounding; // Radius of MenuItem, BeginMenu rounding. | |
| 2425 | + float SelectableRounding; // Radius of Selectable rounding. MODIFYING THIS IS DISCOURAGED. CONTIGUOUS SELECTIONS WILL NOT LOOK RIGHT. (#7589) | |
| 2334 | 2426 | float DragDropTargetRounding; // Radius of the drag and drop target frame. When <0.0f: use FrameRounding. |
| 2335 | 2427 | float DragDropTargetBorderSize; // Thickness of the drag and drop target border. |
| 2336 | 2428 | float DragDropTargetPadding; // Size to expand the drag and drop target from actual target item size. |
| @@ -2338,12 +2430,15 @@ | ||
| 2338 | 2430 | ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. |
| 2339 | 2431 | ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). |
| 2340 | 2432 | 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. |
| 2433 | + float InputTextCursorSize; // Thickness of cursor/caret in InputText(). | |
| 2341 | 2434 | float SeparatorSize; // Thickness of border in Separator(). Must be >= 1.0f. |
| 2342 | 2435 | float SeparatorTextBorderSize; // Thickness of border in SeparatorText() |
| 2343 | 2436 | ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center). |
| 2344 | 2437 | 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. |
| 2345 | 2438 | ImVec2 DisplayWindowPadding; // Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen. |
| 2346 | 2439 | ImVec2 DisplaySafeAreaPadding; // Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured). |
| 2440 | + bool DockingNodeHasCloseButton; // Docking node has their own CloseButton() to close all docked windows. | |
| 2441 | + float DockingSeparatorSize; // Thickness of resizing border between docked windows | |
| 2347 | 2442 | float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). We apply per-monitor DPI scaling over this scale. May be removed later. |
| 2348 | 2443 | bool AntiAliasedLines; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). |
| 2349 | 2444 | bool AntiAliasedLinesUseTex; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). Latched at the beginning of the frame (copied to ImDrawList). |
| @@ -2428,6 +2523,26 @@ | ||
| 2428 | 2523 | bool ConfigNavCursorVisibleAuto; // = true // Using directional navigation key makes the cursor visible. Mouse click hides the cursor. |
| 2429 | 2524 | bool ConfigNavCursorVisibleAlways; // = false // Navigation cursor is always visible. |
| 2430 | 2525 | |
| 2526 | + // Docking options (when ImGuiConfigFlags_DockingEnable is set) | |
| 2527 | + bool ConfigDockingNoSplit; // = false // Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars. | |
| 2528 | + bool ConfigDockingNoDockingOver; // = false // Simplified docking mode: disable window merging into a same tab-bar, so docking is limited to splitting windows. | |
| 2529 | + bool ConfigDockingWithShift; // = false // Enable docking with holding Shift key (reduce visual noise, allows dropping in wider space) | |
| 2530 | + bool ConfigDockingAlwaysTabBar; // = false // [BETA] [FIXME: This currently creates regression with auto-sizing and general overhead] Make every single floating window display within a docking node. | |
| 2531 | + bool ConfigDockingTransparentPayload;// = false // [BETA] Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge. | |
| 2532 | + | |
| 2533 | + // Viewport options (when ImGuiConfigFlags_ViewportsEnable is set) | |
| 2534 | + // (sorry for the amount of "NoXXXX" flags, which may be harder to reason about! may rework someday) | |
| 2535 | + bool ConfigViewportsNoAutoMerge; // = false; // Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it. May also set ImGuiViewportFlags_NoAutoMerge on individual viewport. | |
| 2536 | + bool ConfigViewportsNoTaskBarIcon; // = false // Disable default OS task bar icon flag for secondary viewports. When a viewport doesn't want a task bar icon, ImGuiViewportFlags_NoTaskBarIcon will be set on it. | |
| 2537 | + bool ConfigViewportsNoDecoration; // = true // Disable default OS window decoration flag for secondary viewports. When a viewport doesn't want window decorations, ImGuiViewportFlags_NoDecoration will be set on it. Enabling decoration can create subsequent issues at OS levels (e.g. minimum window size). | |
| 2538 | + bool ConfigViewportsNoDefaultParent; // = true // Disable setting OS window parent to main viewport by default. The platform backend is expected to honor `viewport->ParentViewportID` to setup a parent/child relationship between the OS windows (supported if ImGuiBackendFlags_HasParentViewport is set). When parented: child windows always appear in front of their parent. Set to false if you want viewports to automatically be parent of main viewport, otherwise all viewports will be top-level OS windows. Parent/child relationship may be set on a per-window basis using ImGuiWindowClass. | |
| 2539 | + bool ConfigViewportsPlatformFocusSetsImGuiFocus;//= true // When a platform window is focused (e.g. using Alt+Tab, clicking Platform Title Bar), apply corresponding focus on imgui windows (may clear focus/active id from imgui windows location in other platform windows). In principle this is better enabled but we provide an opt-out, because some Linux window managers tend to eagerly focus windows (e.g. on mouse hover, or even a simple window pos/size change). | |
| 2540 | + | |
| 2541 | + // DPI/Scaling options | |
| 2542 | + // This may keep evolving during 1.92.x releases. Expect some turbulence. | |
| 2543 | + bool ConfigDpiScaleFonts; // = false // [EXPERIMENTAL] Automatically overwrite style.FontScaleDpi when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. | |
| 2544 | + bool ConfigDpiScaleViewports; // = false // [EXPERIMENTAL] Scale Dear ImGui and Platform Windows when Monitor DPI changes. | |
| 2545 | + | |
| 2431 | 2546 | // Miscellaneous options |
| 2432 | 2547 | // (you can visualize and interact with all options in 'Demo->Configuration') |
| 2433 | 2548 | bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations. |
| @@ -2525,6 +2640,7 @@ | ||
| 2525 | 2640 | IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change |
| 2526 | 2641 | IMGUI_API void AddMouseWheelEvent(float wheel_x, float wheel_y); // Queue a mouse wheel update. wheel_y<0: scroll down, wheel_y>0: scroll up, wheel_x<0: scroll right, wheel_x>0: scroll left. |
| 2527 | 2642 | IMGUI_API void AddMouseSourceEvent(ImGuiMouseSource source); // Queue a mouse source change (Mouse/TouchScreen/Pen) |
| 2643 | + IMGUI_API void AddMouseViewportEvent(ImGuiID id); // Queue a mouse hovered viewport. Requires backend to set ImGuiBackendFlags_HasMouseHoveredViewport to call this (for multi-viewport support). | |
| 2528 | 2644 | IMGUI_API void AddFocusEvent(bool focused); // Queue a gain/loss of focus for the application (generally based on OS/platform focus of your window) |
| 2529 | 2645 | IMGUI_API void AddInputCharacter(unsigned int c); // Queue a new character input |
| 2530 | 2646 | IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue a new character input from a UTF-16 character, it can be a surrogate |
| @@ -2570,6 +2686,7 @@ | ||
| 2570 | 2686 | float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold Shift to turn vertical scroll into horizontal scroll. |
| 2571 | 2687 | float MouseWheelH; // Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends. |
| 2572 | 2688 | ImGuiMouseSource MouseSource; // Mouse actual input peripheral (Mouse/TouchScreen/Pen). |
| 2689 | + ImGuiID MouseHoveredViewport; // (Optional) Modify using io.AddMouseViewportEvent(). With multi-viewports: viewport the OS mouse is hovering. If possible _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag is much better (few backends can handle that). Set io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport if you can provide this info. If you don't imgui will infer the value using the rectangles and last focused time of the viewports it knows about (ignoring other OS windows). | |
| 2573 | 2690 | bool KeyCtrl; // Keyboard modifier down: Ctrl (non-macOS), Cmd (macOS) |
| 2574 | 2691 | bool KeyShift; // Keyboard modifier down: Shift |
| 2575 | 2692 | bool KeyAlt; // Keyboard modifier down: Alt |
| @@ -2594,6 +2711,7 @@ | ||
| 2594 | 2711 | bool MouseCtrlLeftAsRightClick; // (OSX) Set to true when the current click was a Ctrl+Click that spawned a simulated right click |
| 2595 | 2712 | float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) |
| 2596 | 2713 | float MouseDownDurationPrev[5]; // Previous time the mouse button has been down |
| 2714 | + ImVec2 MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point | |
| 2597 | 2715 | float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds) |
| 2598 | 2716 | float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui. |
| 2599 | 2717 | bool AppFocusLost; // Only modify via AddFocusEvent() |
| @@ -2612,7 +2730,7 @@ | ||
| 2612 | 2730 | //void* ImeWindowHandle; // [Obsoleted in 1.87] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning. |
| 2613 | 2731 | |
| 2614 | 2732 | #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS |
| 2615 | - float FontGlobalScale; // Moved io.FontGlobalScale to style.FontScaleMain in 1.92 (June 2025) | |
| 2733 | + float FontGlobalScale; // Moved io.FontGlobalScale to style.FontScaleMain in 1.92.0 (June 2025) | |
| 2616 | 2734 | |
| 2617 | 2735 | // Legacy: before 1.91.1, clipboard functions were stored in ImGuiIO instead of ImGuiPlatformIO. |
| 2618 | 2736 | // As this is will affect all users of custom engines/backends, we are providing proper legacy redirection (will obsolete). |
| @@ -2684,6 +2802,29 @@ | ||
| 2684 | 2802 | ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. |
| 2685 | 2803 | }; |
| 2686 | 2804 | |
| 2805 | +// [ALPHA] Rarely used / very advanced uses only. Use with SetNextWindowClass() and DockSpace() functions. | |
| 2806 | +// Important: the content of this class is still highly WIP and likely to change and be refactored | |
| 2807 | +// before we stabilize Docking features. Please be mindful if using this. | |
| 2808 | +// Provide hints: | |
| 2809 | +// - To the platform backend via altered viewport flags (enable/disable OS decoration, OS task bar icons, etc.) | |
| 2810 | +// - To the platform backend for OS level parent/child relationships of viewport (otherwise: default is configured via io.ConfigViewportsNoDefaultParent) | |
| 2811 | +// - To the docking system for various options and filtering. | |
| 2812 | +struct ImGuiWindowClass | |
| 2813 | +{ | |
| 2814 | + ImGuiID ClassId; // User data. 0 = Default class (unclassed). Windows of different classes cannot be docked with each others. | |
| 2815 | + ImGuiID ParentViewportId; // Hint for the platform backend. -1: use default. 0: request platform backend to not parent the platform. != 0: request platform backend to create a parent<>child relationship between the platform windows. Not conforming backends are free to e.g. parent every viewport to the main viewport or not. | |
| 2816 | + ImGuiID FocusRouteParentWindowId; // ID of parent window for shortcut focus route evaluation, e.g. Shortcut() call from Parent Window will succeed when this window is focused. | |
| 2817 | + ImGuiViewportFlags ViewportFlagsOverrideSet; // Viewport flags to set when a window of this class owns a viewport. This allows you to enforce OS decoration or task bar icon, override the defaults on a per-window basis. | |
| 2818 | + ImGuiViewportFlags ViewportFlagsOverrideClear; // Viewport flags to clear when a window of this class owns a viewport. This allows you to enforce OS decoration or task bar icon, override the defaults on a per-window basis. | |
| 2819 | + ImGuiTabItemFlags TabItemFlagsOverrideSet; // [EXPERIMENTAL] TabItem flags to set when a window of this class gets submitted into a dock node tab bar. May use with ImGuiTabItemFlags_Leading or ImGuiTabItemFlags_Trailing. | |
| 2820 | + ImGuiDockNodeFlags DockNodeFlagsOverrideSet; // [EXPERIMENTAL] Dock node flags to set when a window of this class is hosted by a dock node (it doesn't have to be selected!) | |
| 2821 | + bool DockingAlwaysTabBar; // Set to true to enforce single floating windows of this class always having their own docking node (equivalent of setting the global io.ConfigDockingAlwaysTabBar) | |
| 2822 | + bool DockingAllowUnclassed; // Set to true to allow windows of this class to be docked/merged with an unclassed window. // FIXME-DOCK: Move to DockNodeFlags override? | |
| 2823 | + void* PlatformIconData; // [EXPERIMENTAL] Pass opaque data for Platform backend to handle. | |
| 2824 | + | |
| 2825 | + ImGuiWindowClass() { memset((void*)this, 0, sizeof(*this)); ParentViewportId = (ImGuiID)-1; DockingAllowUnclassed = true; } | |
| 2826 | +}; | |
| 2827 | + | |
| 2687 | 2828 | // Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload() |
| 2688 | 2829 | struct ImGuiPayload |
| 2689 | 2830 | { |
| @@ -3049,6 +3190,7 @@ | ||
| 3049 | 3190 | ImGuiMultiSelectFlags_NavWrapX = 1 << 16, // [Temporary] Enable navigation wrapping on X axis. Provided as a convenience because we don't have a design for the general Nav API for this yet. When the more general feature be public we may obsolete this flag in favor of new one. |
| 3050 | 3191 | ImGuiMultiSelectFlags_NoSelectOnRightClick = 1 << 17, // Disable default right-click processing, which selects item on mouse down, and is designed for context-menus. |
| 3051 | 3192 | ImGuiMultiSelectFlags_SelectOnMask_ = ImGuiMultiSelectFlags_SelectOnAuto | ImGuiMultiSelectFlags_SelectOnClickAlways | ImGuiMultiSelectFlags_SelectOnClickRelease, |
| 3193 | + ImGuiMultiSelectFlags_CheckboxMode_ = 1 << 20, // [Internal] | |
| 3052 | 3194 | |
| 3053 | 3195 | // Obsolete names |
| 3054 | 3196 | #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS |
| @@ -3245,20 +3387,27 @@ | ||
| 3245 | 3387 | enum ImDrawFlags_ |
| 3246 | 3388 | { |
| 3247 | 3389 | ImDrawFlags_None = 0, |
| 3248 | - ImDrawFlags_RoundCornersTopLeft = 1 << 4, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-left corner only (when rounding > 0.0f, we default to all corners). Was 0x01. | |
| 3249 | - ImDrawFlags_RoundCornersTopRight = 1 << 5, // AddRect(), AddRectFilled(), PathRect(): enable rounding top-right corner only (when rounding > 0.0f, we default to all corners). Was 0x02. | |
| 3250 | - ImDrawFlags_RoundCornersBottomLeft = 1 << 6, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-left corner only (when rounding > 0.0f, we default to all corners). Was 0x04. | |
| 3251 | - ImDrawFlags_RoundCornersBottomRight = 1 << 7, // AddRect(), AddRectFilled(), PathRect(): enable rounding bottom-right corner only (when rounding > 0.0f, we default to all corners). Wax 0x08. | |
| 3252 | - ImDrawFlags_RoundCornersNone = 1 << 8, // AddRect(), AddRectFilled(), PathRect(): disable rounding on all corners (when rounding > 0.0f). This is NOT zero, NOT an implicit flag! | |
| 3253 | - ImDrawFlags_Closed = 1 << 9, // PathStroke(), AddPolyline(): specify that shape should be closed (Important: this is always == 1 for legacy reason) | |
| 3390 | + | |
| 3391 | + // Rounding for AddRect(), AddRectFilled(), PathRect() | |
| 3392 | + // - When not specified, we defaults to ImDrawFlags_RoundCornersAll! So you only need to use those flags if you want another configuration. | |
| 3393 | + ImDrawFlags_RoundCornersTopLeft = 1 << 4, // Round top-left corner only (when rounding > 0.0f, we default to all corners). | |
| 3394 | + ImDrawFlags_RoundCornersTopRight = 1 << 5, // Round top-right corner only (when rounding > 0.0f, we default to all corners). | |
| 3395 | + ImDrawFlags_RoundCornersBottomLeft = 1 << 6, // Round bottom-left corner only (when rounding > 0.0f, we default to all corners). | |
| 3396 | + ImDrawFlags_RoundCornersBottomRight = 1 << 7, // Round bottom-right corner only (when rounding > 0.0f, we default to all corners). | |
| 3397 | + ImDrawFlags_RoundCornersNone = 1 << 8, // Disable rounding even if `float rounding > 0.0f`. This is NOT zero, NOT an implicit flag! | |
| 3398 | + ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, // (Default!!) | |
| 3399 | + ImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, // Default to ALL corners if none of the _RoundCornersXX flags are specified! | |
| 3254 | 3400 | ImDrawFlags_RoundCornersTop = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight, |
| 3255 | 3401 | ImDrawFlags_RoundCornersBottom = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, |
| 3256 | 3402 | ImDrawFlags_RoundCornersLeft = ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersTopLeft, |
| 3257 | 3403 | ImDrawFlags_RoundCornersRight = ImDrawFlags_RoundCornersBottomRight | ImDrawFlags_RoundCornersTopRight, |
| 3258 | - ImDrawFlags_RoundCornersAll = ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight, | |
| 3259 | - ImDrawFlags_RoundCornersDefault_ = ImDrawFlags_RoundCornersAll, // Default to ALL corners if none of the _RoundCornersXX flags are specified. | |
| 3260 | 3404 | ImDrawFlags_RoundCornersMask_ = ImDrawFlags_RoundCornersAll | ImDrawFlags_RoundCornersNone, |
| 3261 | - ImDrawFlags_InvalidMask_ = (ImDrawFlags)0x8000000F, | |
| 3405 | + | |
| 3406 | + // Stroke options | |
| 3407 | + ImDrawFlags_Closed = 1 << 9, // PathStroke(), AddPolyline(): specify that shape should be closed. | |
| 3408 | + //ImDrawFlags_Closed = 1 << 0, // Prior to 1.92.8 (May 2026), ImDrawFlags_Closed was guaranteed to be == 1<<0 == 1 for legacy compatibility reason. Hardcoded use of 1 or true should be replaced. | |
| 3409 | + | |
| 3410 | + ImDrawFlags_InvalidMask_ = ~0x7FFFFFF0, // == 0x8000000F, | |
| 3262 | 3411 | }; |
| 3263 | 3412 | |
| 3264 | 3413 | // Flags for ImDrawList instance. Those are set automatically by ImGui:: functions from ImGuiIO settings, and generally not manipulated directly. |
| @@ -3270,6 +3419,7 @@ | ||
| 3270 | 3419 | ImDrawListFlags_AntiAliasedLinesUseTex = 1 << 1, // Enable anti-aliased lines/borders using textures when possible. Require backend to render with bilinear filtering (NOT point/nearest filtering). |
| 3271 | 3420 | ImDrawListFlags_AntiAliasedFill = 1 << 2, // Enable anti-aliased edge around filled shapes (rounded rectangles, circles). |
| 3272 | 3421 | ImDrawListFlags_AllowVtxOffset = 1 << 3, // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled. |
| 3422 | + ImDrawListFlags_TextNoPixelSnap = 1 << 4, // Disable automatically snapping AddText() calls to pixel boundaries. | |
| 3273 | 3423 | }; |
| 3274 | 3424 | |
| 3275 | 3425 | // Draw command list |
| @@ -3421,8 +3571,8 @@ | ||
| 3421 | 3571 | inline void PushTextureID(ImTextureRef tex_ref) { PushTexture(tex_ref); } // RENAMED in 1.92.0 |
| 3422 | 3572 | inline void PopTextureID() { PopTexture(); } // RENAMED in 1.92.0 |
| 3423 | 3573 | #else |
| 3424 | - IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding /*= 0.0f*/, ImDrawFlags flags /*= 0*/, float thickness /*= 1.0f*/) = delete; | |
| 3425 | - IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness) = delete; | |
| 3574 | + void AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding /*= 0.0f*/, ImDrawFlags flags /*= 0*/, float thickness /*= 1.0f*/) = delete; | |
| 3575 | + void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness) = delete; | |
| 3426 | 3576 | inline void PathStroke(ImU32 col, ImDrawFlags flags /*= 0*/, float thickness /*= 1.0f*/) = delete; |
| 3427 | 3577 | #endif |
| 3428 | 3578 | //inline void AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f) { AddEllipse(center, ImVec2(radius_x, radius_y), col, rot, num_segments, thickness); } // OBSOLETED in 1.90.5 (Mar 2024) |
| @@ -3503,7 +3653,7 @@ | ||
| 3503 | 3653 | // You may use ImTextureData::Updates[] for the list, or ImTextureData::UpdateBox for a single bounding box. |
| 3504 | 3654 | struct ImTextureRect |
| 3505 | 3655 | { |
| 3506 | - unsigned short x, y; // Upper-left coordinates of rectangle to update | |
| 3656 | + unsigned short x, y; // Upper-left coordinates of rectangle to update, within the parent Pixels[] array. | |
| 3507 | 3657 | unsigned short w, h; // Size of rectangle to update (in pixels) |
| 3508 | 3658 | }; |
| 3509 | 3659 | |
| @@ -3525,7 +3675,7 @@ | ||
| 3525 | 3675 | int Width; // w r // Texture width |
| 3526 | 3676 | int Height; // w r // Texture height |
| 3527 | 3677 | int BytesPerPixel; // w r // 4 or 1 |
| 3528 | - unsigned char* Pixels; // w r // Pointer to buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. | |
| 3678 | + unsigned char* Pixels; // w r // Pointer to whole texture buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. | |
| 3529 | 3679 | ImTextureRect UsedRect; // w r // Bounding box encompassing all past and queued Updates[]. |
| 3530 | 3680 | ImTextureRect UpdateRect; // w r // Bounding box encompassing all queued Updates[]. |
| 3531 | 3681 | ImVector<ImTextureRect> Updates; // w r // Array of individual updates. |
| @@ -3535,7 +3685,7 @@ | ||
| 3535 | 3685 | bool WantDestroyNextFrame; // rw - // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame. |
| 3536 | 3686 | |
| 3537 | 3687 | // Functions |
| 3538 | - // - If GetPixels() functions asserts while being called by your render loop, it could be caused by calling ImFontAtlas::Clear() instead of ClearFonts()? | |
| 3688 | + // - If GetPixels() functions asserts while being called by your render loop, it could be caused by calling ImFontAtlas::Clear()/ClearFonts()? | |
| 3539 | 3689 | ImTextureData() { memset((void*)this, 0, sizeof(*this)); Status = ImTextureStatus_Destroyed; TexID = ImTextureID_Invalid; } |
| 3540 | 3690 | ~ImTextureData() { DestroyPixels(); } |
| 3541 | 3691 | IMGUI_API void Create(ImTextureFormat format, int w, int h); |
| @@ -3689,14 +3839,16 @@ | ||
| 3689 | 3839 | IMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed. |
| 3690 | 3840 | IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_data_size, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. |
| 3691 | 3841 | IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. |
| 3692 | - IMGUI_API void RemoveFont(ImFont* font); | |
| 3693 | - | |
| 3694 | - IMGUI_API void Clear(); // Clear everything (fonts + textures). Don't call mid-frame! | |
| 3695 | - IMGUI_API void ClearFonts(); // Clear input+output font data/glyphs. You can call this mid-frame if you load new fonts afterwards! | |
| 3696 | - IMGUI_API void CompactCache(); // Compact cached glyphs and texture. | |
| 3842 | + IMGUI_API void RemoveFont(ImFont* font); // Remove a font | |
| 3843 | + IMGUI_API void CompactCache(); // Compact cached glyphs and texture. | |
| 3697 | 3844 | IMGUI_API void SetFontLoader(const ImFontLoader* font_loader); // Change font loader at runtime. |
| 3698 | 3845 | |
| 3699 | - // As we are transitioning toward a new font system, we expect to obsolete those soon: | |
| 3846 | + // Clearing the atlas/fonts has little use nowadays, unless you want to batch remove all fonts. | |
| 3847 | + // - Since 1.92, you can call ClearFonts() mid-frame, if you load new fonts afterwards. | |
| 3848 | + // - As we are transitioning toward our new font system the semantic for those functions gets increasingly misleading and are often a source of issues. | |
| 3849 | + // TL;DR; most likely, don't use any of those functions. We expect to obsolete/rework them. | |
| 3850 | + IMGUI_API void Clear(); // Clear everything (fonts + textures). Don't call mid-frame! | |
| 3851 | + IMGUI_API void ClearFonts(); // Clear input+output font data/glyphs. New fonts and textures will be recreated afterwards. | |
| 3700 | 3852 | IMGUI_API void ClearInputData(); // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. |
| 3701 | 3853 | IMGUI_API void ClearTexData(); // [OBSOLETE] Clear CPU-side copy of the texture data. Saves RAM once the texture has been copied to graphics memory. |
| 3702 | 3854 | |
| @@ -3915,7 +4067,7 @@ | ||
| 3915 | 4067 | IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip = NULL); |
| 3916 | 4068 | IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, ImDrawTextFlags flags = 0); |
| 3917 | 4069 | #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS |
| 3918 | - inline const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(LegacySize * scale, text, text_end, wrap_width); } | |
| 4070 | + inline const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(LegacySize * scale, text, text_end, wrap_width); } // Obsoleted old name in 1.92.0. Note how `scale` was to `size`. | |
| 3919 | 4071 | #endif |
| 3920 | 4072 | |
| 3921 | 4073 | // [Internal] Don't use! |
| @@ -3954,11 +4106,24 @@ | ||
| 3954 | 4106 | ImGuiViewportFlags_None = 0, |
| 3955 | 4107 | ImGuiViewportFlags_IsPlatformWindow = 1 << 0, // Represent a Platform Window |
| 3956 | 4108 | ImGuiViewportFlags_IsPlatformMonitor = 1 << 1, // Represent a Platform Monitor (unused yet) |
| 3957 | - ImGuiViewportFlags_OwnedByApp = 1 << 2, // Platform Window: Is created/managed by the application (rather than a dear imgui backend) | |
| 4109 | + ImGuiViewportFlags_OwnedByApp = 1 << 2, // Platform Window: Is created/managed by the user application? (rather than our backend) | |
| 4110 | + ImGuiViewportFlags_NoDecoration = 1 << 3, // Platform Window: Disable platform decorations: title bar, borders, etc. (generally set all windows, but if ImGuiConfigFlags_ViewportsDecoration is set we only set this on popups/tooltips) | |
| 4111 | + ImGuiViewportFlags_NoTaskBarIcon = 1 << 4, // Platform Window: Disable platform task bar icon (generally set on popups/tooltips, or all windows if ImGuiConfigFlags_ViewportsNoTaskBarIcon is set) | |
| 4112 | + ImGuiViewportFlags_NoFocusOnAppearing = 1 << 5, // Platform Window: Don't take focus when created. | |
| 4113 | + ImGuiViewportFlags_NoFocusOnClick = 1 << 6, // Platform Window: Don't take focus when clicked on. | |
| 4114 | + ImGuiViewportFlags_NoInputs = 1 << 7, // Platform Window: Make mouse pass through so we can drag this window while peaking behind it. | |
| 4115 | + ImGuiViewportFlags_NoRendererClear = 1 << 8, // Platform Window: Renderer doesn't need to clear the framebuffer ahead (because we will fill it entirely). | |
| 4116 | + ImGuiViewportFlags_NoAutoMerge = 1 << 9, // Platform Window: Avoid merging this window into another host window. This can only be set via ImGuiWindowClass viewport flags override (because we need to now ahead if we are going to create a viewport in the first place!). | |
| 4117 | + ImGuiViewportFlags_TopMost = 1 << 10, // Platform Window: Display on top (for tooltips only). | |
| 4118 | + ImGuiViewportFlags_CanHostOtherWindows = 1 << 11, // Viewport can host multiple imgui windows (secondary viewports are associated to a single window). // FIXME: In practice there's still probably code making the assumption that this is always and only on the MainViewport. Will fix once we add support for "no main viewport". | |
| 4119 | + | |
| 4120 | + // Output status flags (from Platform) | |
| 4121 | + ImGuiViewportFlags_IsMinimized = 1 << 12, // Platform Window: Window is minimized, can skip render. When minimized we tend to avoid using the viewport pos/size for clipping window or testing if they are contained in the viewport. | |
| 4122 | + ImGuiViewportFlags_IsFocused = 1 << 13, // Platform Window: Window is focused (last call to Platform_GetWindowFocus() returned true) | |
| 3958 | 4123 | }; |
| 3959 | 4124 | |
| 3960 | 4125 | // - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows. |
| 3961 | -// - In 'docking' branch with multi-viewport enabled, we extend this concept to have multiple active viewports. | |
| 4126 | +// - With multi-viewport enabled, we extend this concept to have multiple active viewports. | |
| 3962 | 4127 | // - In the future we will extend this concept further to also represent Platform Monitor and support a "no main platform window" operation mode. |
| 3963 | 4128 | // - About Main Area vs Work Area: |
| 3964 | 4129 | // - Main Area = entire viewport. |
| @@ -3973,22 +4138,85 @@ | ||
| 3973 | 4138 | ImVec2 FramebufferScale; // Density of the viewport for Retina display (always 1,1 on Windows, may be 2,2 etc on macOS/iOS). This will affect font rasterizer density. |
| 3974 | 4139 | ImVec2 WorkPos; // Work Area: Position of the viewport minus task bars, menus bars, status bars (>= Pos) |
| 3975 | 4140 | ImVec2 WorkSize; // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size) |
| 4141 | + float DpiScale; // 1.0f = 96 DPI = No extra scale. | |
| 4142 | + ImGuiID ParentViewportId; // (Advanced) 0: no parent. Instruct the platform backend to setup a parent/child relationship between platform windows. | |
| 4143 | + ImGuiViewport* ParentViewport; // (Advanced) Direct shortcut to ImGui::FindViewportByID(ParentViewportId). NULL: no parent. | |
| 4144 | + ImDrawData* DrawData; // The ImDrawData corresponding to this viewport. Valid after Render() and until the next call to NewFrame(). | |
| 3976 | 4145 | |
| 3977 | 4146 | // Platform/Backend Dependent Data |
| 3978 | - void* PlatformHandle; // void* to hold higher-level, platform window handle (e.g. HWND, GLFWWindow*, SDL_Window*) | |
| 3979 | - void* PlatformHandleRaw; // void* to hold lower-level, platform-native window handle (under Win32 this is expected to be a HWND, unused for other platforms) | |
| 4147 | + // Our design separate the Renderer and Platform backends to facilitate combining default backends with each others. | |
| 4148 | + // When our create your own backend for a custom engine, it is possible that both Renderer and Platform will be handled | |
| 4149 | + // by the same system and you may not need to use all the UserData/Handle fields. | |
| 4150 | + // The library never uses those fields, they are merely storage to facilitate backend implementation. | |
| 4151 | + void* RendererUserData; // void* to hold custom data structure for the renderer (e.g. swap chain, framebuffers etc.). generally set by your Renderer_CreateWindow function. | |
| 4152 | + void* PlatformUserData; // void* to hold custom data structure for the OS / platform (e.g. windowing info, render context). generally set by your Platform_CreateWindow function. | |
| 4153 | + void* PlatformIconData; // void* to hold custom data structure for the OS / platform to specify an icon. Currently unused for exposed to allow experiments. | |
| 4154 | + void* PlatformHandle; // void* to hold higher-level, platform window handle (e.g. HWND for Win32 backend, Uint32 WindowID for SDL, GLFWWindow* for GLFW), for FindViewportByPlatformHandle(). | |
| 4155 | + void* PlatformHandleRaw; // void* to hold lower-level, platform-native window handle (always HWND on Win32 platform, unused for other platforms). | |
| 4156 | + bool PlatformWindowCreated; // Platform window has been created (Platform_CreateWindow() has been called). This is false during the first frame where a viewport is being created. | |
| 4157 | + bool PlatformRequestMove; // Platform window requested move (e.g. window was moved by the OS / host window manager, authoritative position will be OS window position) | |
| 4158 | + bool PlatformRequestResize; // Platform window requested resize (e.g. window was resized by the OS / host window manager, authoritative size will be OS window size) | |
| 4159 | + bool PlatformRequestClose; // Platform window requested closure (e.g. window was moved by the OS / host window manager, e.g. pressing ALT-F4) | |
| 3980 | 4160 | |
| 3981 | 4161 | ImGuiViewport() { memset((void*)this, 0, sizeof(*this)); } |
| 4162 | + ~ImGuiViewport() { IM_ASSERT(PlatformUserData == NULL && RendererUserData == NULL); } | |
| 3982 | 4163 | |
| 3983 | 4164 | // Helpers |
| 3984 | 4165 | ImVec2 GetCenter() const { return ImVec2(Pos.x + Size.x * 0.5f, Pos.y + Size.y * 0.5f); } |
| 3985 | 4166 | ImVec2 GetWorkCenter() const { return ImVec2(WorkPos.x + WorkSize.x * 0.5f, WorkPos.y + WorkSize.y * 0.5f); } |
| 4167 | + IMGUI_API const char* GetDebugName() const; | |
| 3986 | 4168 | }; |
| 3987 | 4169 | |
| 3988 | 4170 | //----------------------------------------------------------------------------- |
| 3989 | -// [SECTION] Platform Dependent Interfaces | |
| 4171 | +// [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformMonitor, ImGuiPlatformImeData) | |
| 3990 | 4172 | //----------------------------------------------------------------------------- |
| 3991 | 4173 | |
| 4174 | +// [BETA] (Optional) Multi-Viewport Support! | |
| 4175 | +// If you are new to Dear ImGui and trying to integrate it into your engine, you can probably ignore this for now. | |
| 4176 | +// | |
| 4177 | +// This feature allows you to seamlessly drag Dear ImGui windows outside of your application viewport. | |
| 4178 | +// This is achieved by creating new Platform/OS windows on the fly, and rendering into them. | |
| 4179 | +// Dear ImGui manages the viewport structures, and the backend create and maintain one Platform/OS window for each of those viewports. | |
| 4180 | +// | |
| 4181 | +// See Recap: https://github.com/ocornut/imgui/wiki/Multi-Viewports | |
| 4182 | +// See Glossary https://github.com/ocornut/imgui/wiki/Glossary for details about some of the terminology. | |
| 4183 | +// | |
| 4184 | +// About the coordinates system: | |
| 4185 | +// - When multi-viewports are enabled, all Dear ImGui coordinates become absolute coordinates (same as OS coordinates!) | |
| 4186 | +// - So e.g. ImGui::SetNextWindowPos(ImVec2(0,0)) will position a window relative to your primary monitor! | |
| 4187 | +// - If you want to position windows relative to your main application viewport, use ImGui::GetMainViewport()->Pos as a base position. | |
| 4188 | +// | |
| 4189 | +// Steps to use multi-viewports in your application, when using a default backend from the examples/ folder: | |
| 4190 | +// - Application: Enable feature with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 4191 | +// - Backend: The backend initialization will setup all necessary ImGuiPlatformIO's functions and update monitors info every frame. | |
| 4192 | +// - Application: In your main loop, call ImGui::UpdatePlatformWindows(), ImGui::RenderPlatformWindowsDefault() after EndFrame() or Render(). | |
| 4193 | +// - Application: Fix absolute coordinates used in ImGui::SetWindowPos() or ImGui::SetNextWindowPos() calls. | |
| 4194 | +// | |
| 4195 | +// Steps to use multi-viewports in your application, when using a custom backend: | |
| 4196 | +// - Important: THIS IS NOT EASY TO DO and comes with many subtleties not described here! | |
| 4197 | +// It's also an experimental feature, so some of the requirements may evolve. | |
| 4198 | +// Consider using default backends if you can. Either way, carefully follow and refer to examples/ backends for details. | |
| 4199 | +// - Application: Enable feature with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. | |
| 4200 | +// - Backend: Hook ImGuiPlatformIO's Platform_* and Renderer_* callbacks (see below). | |
| 4201 | +// Set 'io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports' and 'io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports'. | |
| 4202 | +// Update ImGuiPlatformIO's Monitors list every frame. | |
| 4203 | +// Update MousePos every frame, in absolute coordinates. | |
| 4204 | +// - Application: In your main loop, call ImGui::UpdatePlatformWindows(), ImGui::RenderPlatformWindowsDefault() after EndFrame() or Render(). | |
| 4205 | +// You may skip calling RenderPlatformWindowsDefault() if its API is not convenient for your needs. Read comments below. | |
| 4206 | +// - Application: Fix absolute coordinates used in ImGui::SetWindowPos() or ImGui::SetNextWindowPos() calls. | |
| 4207 | +// | |
| 4208 | +// About ImGui::RenderPlatformWindowsDefault(): | |
| 4209 | +// - This function is a mostly a _helper_ for the common-most cases, and to facilitate using default backends. | |
| 4210 | +// - You can check its simple source code to understand what it does. | |
| 4211 | +// It basically iterates secondary viewports and call 4 functions that are setup in ImGuiPlatformIO, if available: | |
| 4212 | +// Platform_RenderWindow(), Renderer_RenderWindow(), Platform_SwapBuffers(), Renderer_SwapBuffers() | |
| 4213 | +// Those functions pointers exists only for the benefit of RenderPlatformWindowsDefault(). | |
| 4214 | +// - If you have very specific rendering needs (e.g. flipping multiple swap-chain simultaneously, unusual sync/threading issues, etc.), | |
| 4215 | +// you may be tempted to ignore RenderPlatformWindowsDefault() and write customized code to perform your renderingg. | |
| 4216 | +// You may decide to setup the platform_io's *RenderWindow and *SwapBuffers pointers and call your functions through those pointers, | |
| 4217 | +// or you may decide to never setup those pointers and call your code directly. They are a convenience, not an obligatory interface. | |
| 4218 | +//----------------------------------------------------------------------------- | |
| 4219 | + | |
| 3992 | 4220 | // Access via ImGui::GetPlatformIO() |
| 3993 | 4221 | struct ImGuiPlatformIO |
| 3994 | 4222 | { |
| @@ -4037,6 +4265,56 @@ | ||
| 4037 | 4265 | //ImDrawCallback DrawCallback_SetSamplerCustom; // Request backend to set texture sampling using Backend Specific data. |
| 4038 | 4266 | |
| 4039 | 4267 | //------------------------------------------------------------------ |
| 4268 | + // Input - Interface with Platform & Renderer backends for Multi-Viewport support | |
| 4269 | + //------------------------------------------------------------------ | |
| 4270 | + | |
| 4271 | + // For reference, the second column shows which function are generally calling the Platform Functions: | |
| 4272 | + // N = ImGui::NewFrame() ~ beginning of the dear imgui frame: read info from platform/OS windows (latest size/position) | |
| 4273 | + // F = ImGui::Begin(), ImGui::EndFrame() ~ during the dear imgui frame | |
| 4274 | + // U = ImGui::UpdatePlatformWindows() ~ after the dear imgui frame: create and update all platform/OS windows | |
| 4275 | + // R = ImGui::RenderPlatformWindowsDefault() ~ render | |
| 4276 | + // D = ImGui::DestroyPlatformWindows() ~ shutdown | |
| 4277 | + // The general idea is that NewFrame() we will read the current Platform/OS state, and UpdatePlatformWindows() will write to it. | |
| 4278 | + | |
| 4279 | + // The handlers are designed so we can mix and match two imgui_impl_xxxx files, one Platform backend and one Renderer backend. | |
| 4280 | + // Custom engine backends will often provide both Platform and Renderer interfaces together and so may not need to use all functions. | |
| 4281 | + // Platform functions are typically called _before_ their Renderer counterpart, apart from Destroy which are called the other way. | |
| 4282 | + | |
| 4283 | + // Platform Backend functions (e.g. Win32, GLFW, SDL) ------------------- Called by ----- | |
| 4284 | + void (*Platform_CreateWindow)(ImGuiViewport* vp); // . . U . . // Create a new platform window for the given viewport | |
| 4285 | + void (*Platform_DestroyWindow)(ImGuiViewport* vp); // N . U . D // | |
| 4286 | + void (*Platform_ShowWindow)(ImGuiViewport* vp); // . . U . . // Newly created windows are initially hidden so SetWindowPos/Size/Title can be called on them before showing the window | |
| 4287 | + void (*Platform_SetWindowPos)(ImGuiViewport* vp, ImVec2 pos); // . . U . . // Set platform window position (given the upper-left corner of client area) | |
| 4288 | + ImVec2 (*Platform_GetWindowPos)(ImGuiViewport* vp); // N . . . . // | |
| 4289 | + void (*Platform_SetWindowSize)(ImGuiViewport* vp, ImVec2 size); // . . U . . // Set platform window client area size (ignoring OS decorations such as OS title bar etc.) | |
| 4290 | + ImVec2 (*Platform_GetWindowSize)(ImGuiViewport* vp); // N . . . . // Get platform window client area size | |
| 4291 | + ImVec2 (*Platform_GetWindowFramebufferScale)(ImGuiViewport* vp); // N . . . . // Return viewport density. Always 1,1 on Windows, often 2,2 on Retina display on macOS/iOS. MUST BE INTEGER VALUES. | |
| 4292 | + void (*Platform_SetWindowFocus)(ImGuiViewport* vp); // N . . . . // Move window to front and set input focus | |
| 4293 | + bool (*Platform_GetWindowFocus)(ImGuiViewport* vp); // . . U . . // | |
| 4294 | + bool (*Platform_GetWindowMinimized)(ImGuiViewport* vp); // N . . . . // Get platform window minimized state. When minimized, we generally won't attempt to get/set size and contents will be culled more easily | |
| 4295 | + void (*Platform_SetWindowTitle)(ImGuiViewport* vp, const char* str); // . . U . . // Set platform window title (given an UTF-8 string) | |
| 4296 | + void (*Platform_SetWindowAlpha)(ImGuiViewport* vp, float alpha); // . . U . . // (Optional) Setup global transparency (not per-pixel transparency) | |
| 4297 | + void (*Platform_UpdateWindow)(ImGuiViewport* vp); // . . U . . // (Optional) Called by UpdatePlatformWindows(). Optional hook to allow the platform backend from doing general book-keeping every frame. | |
| 4298 | + void (*Platform_RenderWindow)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Main rendering (platform side! This is often unused, or just setting a "current" context for OpenGL bindings). 'render_arg' is the value passed to RenderPlatformWindowsDefault(). | |
| 4299 | + void (*Platform_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Call Present/SwapBuffers (platform side! This is often unused!). 'render_arg' is the value passed to RenderPlatformWindowsDefault(). | |
| 4300 | + float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // N . . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI. | |
| 4301 | + void (*Platform_OnChangedViewport)(ImGuiViewport* vp); // . F . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Called during Begin() every time the viewport we are outputting into changes, so backend has a chance to swap fonts to adjust style. | |
| 4302 | + ImVec4 (*Platform_GetWindowWorkAreaInsets)(ImGuiViewport* vp); // N . . . . // (Optional) [BETA] Get initial work area inset for the viewport (won't be covered by main menu bar, dockspace over viewport etc.). Default to (0,0),(0,0). 'safeAreaInsets' in iOS land, 'DisplayCutout' in Android land. | |
| 4303 | + int (*Platform_CreateVkSurface)(ImGuiViewport* vp, ImU64 vk_inst, const void* vk_allocators, ImU64* out_vk_surface); // (Optional) For a Vulkan Renderer to call into Platform code (since the surface creation needs to tie them both). | |
| 4304 | + | |
| 4305 | + // Renderer Backend functions (e.g. DirectX, OpenGL, Vulkan) ------------ Called by ----- | |
| 4306 | + void (*Renderer_CreateWindow)(ImGuiViewport* vp); // . . U . . // Create swap chain, frame buffers etc. (called after Platform_CreateWindow) | |
| 4307 | + void (*Renderer_DestroyWindow)(ImGuiViewport* vp); // N . U . D // Destroy swap chain, frame buffers etc. (called before Platform_DestroyWindow) | |
| 4308 | + void (*Renderer_SetWindowSize)(ImGuiViewport* vp, ImVec2 size); // . . U . . // Resize swap chain, frame buffers etc. (called after Platform_SetWindowSize) | |
| 4309 | + void (*Renderer_RenderWindow)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Clear framebuffer, setup render target, then render the viewport->DrawData. 'render_arg' is the value passed to RenderPlatformWindowsDefault(). | |
| 4310 | + void (*Renderer_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Call Present/SwapBuffers. 'render_arg' is the value passed to RenderPlatformWindowsDefault(). | |
| 4311 | + | |
| 4312 | + // (Optional) Monitor list | |
| 4313 | + // - Updated by: app/backend. Update every frame to dynamically support changing monitor or DPI configuration. | |
| 4314 | + // - Used by: dear imgui to query DPI info, clamp popups/tooltips within same monitor and not have them straddle monitors. | |
| 4315 | + ImVector<ImGuiPlatformMonitor> Monitors; | |
| 4316 | + | |
| 4317 | + //------------------------------------------------------------------ | |
| 4040 | 4318 | // Output |
| 4041 | 4319 | //------------------------------------------------------------------ |
| 4042 | 4320 | |
| @@ -4044,12 +4322,27 @@ | ||
| 4044 | 4322 | // The ImGui_ImplXXXX_RenderDrawData() function of each backend generally access this via ImDrawData::Textures which points to this. The array is available here mostly because backends will want to destroy textures on shutdown. |
| 4045 | 4323 | ImVector<ImTextureData*> Textures; // List of textures used by Dear ImGui (most often 1) + contents of external texture list is automatically appended into this. |
| 4046 | 4324 | |
| 4325 | + // Viewports list (the list is updated by calling ImGui::EndFrame or ImGui::Render) | |
| 4326 | + // (in the future we will attempt to organize this feature to remove the need for a "main viewport") | |
| 4327 | + ImVector<ImGuiViewport*> Viewports; // Main viewports, followed by all secondary viewports. | |
| 4328 | + | |
| 4047 | 4329 | //------------------------------------------------------------------ |
| 4048 | 4330 | // Functions |
| 4049 | 4331 | //------------------------------------------------------------------ |
| 4050 | 4332 | |
| 4051 | 4333 | IMGUI_API void ClearPlatformHandlers(); // Clear all Platform_XXX fields. Typically called on Platform Backend shutdown. |
| 4052 | 4334 | IMGUI_API void ClearRendererHandlers(); // Clear all Renderer_XXX fields. Typically called on Renderer Backend shutdown. |
| 4335 | +}; | |
| 4336 | + | |
| 4337 | +// (Optional) This is required when enabling multi-viewport. Represent the bounds of each connected monitor/display and their DPI. | |
| 4338 | +// We use this information for multiple DPI support + clamping the position of popups and tooltips so they don't straddle multiple monitors. | |
| 4339 | +struct ImGuiPlatformMonitor | |
| 4340 | +{ | |
| 4341 | + ImVec2 MainPos, MainSize; // Coordinates of the area displayed on this monitor (Min = upper left, Max = bottom right) | |
| 4342 | + ImVec2 WorkPos, WorkSize; // Coordinates without task bars / side bars / menu bars. Used to avoid positioning popups/tooltips inside this region. If you don't have this info, please copy the value for MainPos/MainSize. | |
| 4343 | + float DpiScale; // 1.0f = 96 DPI | |
| 4344 | + void* PlatformHandle; // Backend dependant data (e.g. HMONITOR, GLFWmonitor*, SDL Display Index, NSScreen*) | |
| 4345 | + ImGuiPlatformMonitor() { MainPos = MainSize = WorkPos = WorkSize = ImVec2(0, 0); DpiScale = 1.0f; PlatformHandle = NULL; } | |
| 4053 | 4346 | }; |
| 4054 | 4347 | |
| 4055 | 4348 | // (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. Handler is called during EndFrame(). |
| @@ -1,4 +1,4 @@ | ||
| 1 | -// dear imgui, v1.92.8 | |
| 1 | +// dear imgui, v1.92.9 WIP | |
| 2 | 2 | // (demo code) |
| 3 | 3 | |
| 4 | 4 | // Help: |
| @@ -120,6 +120,7 @@ | ||
| 120 | 120 | // [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() |
| 121 | 121 | // [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles() |
| 122 | 122 | // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() |
| 123 | +// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() | |
| 123 | 124 | // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() |
| 124 | 125 | // [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser() |
| 125 | 126 | |
| @@ -239,6 +240,7 @@ | ||
| 239 | 240 | static void ShowExampleAppAssetsBrowser(bool* p_open); |
| 240 | 241 | static void ShowExampleAppConsole(bool* p_open); |
| 241 | 242 | static void ShowExampleAppCustomRendering(bool* p_open); |
| 243 | +static void ShowExampleAppDockSpace(bool* p_open); | |
| 242 | 244 | static void ShowExampleAppDocuments(bool* p_open); |
| 243 | 245 | static void ShowExampleAppImageViewer(bool* p_open); |
| 244 | 246 | static void ShowExampleAppLog(bool* p_open); |
| @@ -285,6 +287,16 @@ | ||
| 285 | 287 | } |
| 286 | 288 | } |
| 287 | 289 | |
| 290 | +static void ShowDockingDisabledMessage() | |
| 291 | +{ | |
| 292 | + ImGuiIO& io = ImGui::GetIO(); | |
| 293 | + ImGui::Text("ERROR: Docking is not enabled! See Demo > Configuration."); | |
| 294 | + ImGui::Text("Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable in your code, or "); | |
| 295 | + ImGui::SameLine(0.0f, 0.0f); | |
| 296 | + if (ImGui::SmallButton("click here")) | |
| 297 | + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; | |
| 298 | +} | |
| 299 | + | |
| 288 | 300 | // Helper to wire demo markers located in code to an interactive browser (e.g. https://pthom.github.io/imgui_explorer) |
| 289 | 301 | #if IMGUI_VERSION_NUM >= 19263 |
| 290 | 302 | namespace ImGui { extern IMGUI_API void DemoMarker(const char* file, int line, const char* section); } |
| @@ -311,6 +323,7 @@ | ||
| 311 | 323 | bool ShowAppConsole = false; |
| 312 | 324 | bool ShowAppCustomRendering = false; |
| 313 | 325 | bool ShowAppDocuments = false; |
| 326 | + bool ShowAppDockSpace = false; | |
| 314 | 327 | bool ShowAppImageViewer = false; |
| 315 | 328 | bool ShowAppLog = false; |
| 316 | 329 | bool ShowAppLayout = false; |
| @@ -353,7 +366,8 @@ | ||
| 353 | 366 | |
| 354 | 367 | // Examples Apps (accessible from the "Examples" menu) |
| 355 | 368 | if (demo_data.ShowMainMenuBar) { ShowExampleAppMainMenuBar(); } |
| 356 | - if (demo_data.ShowAppDocuments) { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); } | |
| 369 | + if (demo_data.ShowAppDockSpace) { ShowExampleAppDockSpace(&demo_data.ShowAppDockSpace); } // Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) | |
| 370 | + if (demo_data.ShowAppDocuments) { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); } // ...process the Document app next, as it may also use a DockSpace() | |
| 357 | 371 | if (demo_data.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); } |
| 358 | 372 | if (demo_data.ShowAppConsole) { ShowExampleAppConsole(&demo_data.ShowAppConsole); } |
| 359 | 373 | if (demo_data.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); } |
| @@ -391,6 +405,7 @@ | ||
| 391 | 405 | static bool no_nav = false; |
| 392 | 406 | static bool no_background = false; |
| 393 | 407 | static bool no_bring_to_front = false; |
| 408 | + static bool no_docking = false; | |
| 394 | 409 | static bool unsaved_document = false; |
| 395 | 410 | |
| 396 | 411 | ImGuiWindowFlags window_flags = 0; |
| @@ -403,6 +418,7 @@ | ||
| 403 | 418 | if (no_nav) window_flags |= ImGuiWindowFlags_NoNav; |
| 404 | 419 | if (no_background) window_flags |= ImGuiWindowFlags_NoBackground; |
| 405 | 420 | if (no_bring_to_front) window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus; |
| 421 | + if (no_docking) window_flags |= ImGuiWindowFlags_NoDocking; | |
| 406 | 422 | if (unsaved_document) window_flags |= ImGuiWindowFlags_UnsavedDocument; |
| 407 | 423 | if (no_close) p_open = NULL; // Don't pass our bool* to Begin |
| 408 | 424 | |
| @@ -518,6 +534,54 @@ | ||
| 518 | 534 | ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways); |
| 519 | 535 | ImGui::SameLine(); HelpMarker("Navigation cursor is always visible."); |
| 520 | 536 | |
| 537 | + ImGui::SeparatorText("Docking"); | |
| 538 | + ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", &io.ConfigFlags, ImGuiConfigFlags_DockingEnable); | |
| 539 | + ImGui::SameLine(); | |
| 540 | + if (io.ConfigDockingWithShift) | |
| 541 | + HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to enable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows)."); | |
| 542 | + else | |
| 543 | + HelpMarker("Drag from window title bar or their tab to dock/undock. Hold SHIFT to disable docking.\n\nDrag from window menu button (upper-left button) to undock an entire node (all windows)."); | |
| 544 | + if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) | |
| 545 | + { | |
| 546 | + ImGui::Indent(); | |
| 547 | + ImGui::Checkbox("io.ConfigDockingNoSplit", &io.ConfigDockingNoSplit); | |
| 548 | + ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window splitting, so docking is limited to merging multiple windows together into tab-bars."); | |
| 549 | + ImGui::Checkbox("io.ConfigDockingNoDockingOver", &io.ConfigDockingNoDockingOver); | |
| 550 | + ImGui::SameLine(); HelpMarker("Simplified docking mode: disable window merging into a same tab-bar, so docking is limited to splitting windows."); | |
| 551 | + ImGui::Checkbox("io.ConfigDockingWithShift", &io.ConfigDockingWithShift); | |
| 552 | + ImGui::SameLine(); HelpMarker("Enable docking when holding Shift only (allow to drop in wider space, reduce visual noise)"); | |
| 553 | + ImGui::Checkbox("io.ConfigDockingAlwaysTabBar", &io.ConfigDockingAlwaysTabBar); | |
| 554 | + ImGui::SameLine(); HelpMarker("Create a docking node and tab-bar on single floating windows."); | |
| 555 | + ImGui::Checkbox("io.ConfigDockingTransparentPayload", &io.ConfigDockingTransparentPayload); | |
| 556 | + ImGui::SameLine(); HelpMarker("Make window or viewport transparent when docking and only display docking boxes on the target viewport. Useful if rendering of multiple viewport cannot be synced. Best used with ConfigViewportsNoAutoMerge."); | |
| 557 | + ImGui::Unindent(); | |
| 558 | + } | |
| 559 | + | |
| 560 | + ImGui::SeparatorText("Multi-viewports"); | |
| 561 | + ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", &io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable); | |
| 562 | + ImGui::SameLine(); HelpMarker("[beta] Enable beta multi-viewports support. See ImGuiPlatformIO for details."); | |
| 563 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) | |
| 564 | + { | |
| 565 | + ImGui::Indent(); | |
| 566 | + ImGui::Checkbox("io.ConfigViewportsNoAutoMerge", &io.ConfigViewportsNoAutoMerge); | |
| 567 | + ImGui::SameLine(); HelpMarker("Set to make all floating imgui windows always create their own viewport. Otherwise, they are merged into the main host viewports when overlapping it."); | |
| 568 | + ImGui::Checkbox("io.ConfigViewportsNoTaskBarIcon", &io.ConfigViewportsNoTaskBarIcon); | |
| 569 | + ImGui::SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)"); | |
| 570 | + ImGui::Checkbox("io.ConfigViewportsNoDecoration", &io.ConfigViewportsNoDecoration); | |
| 571 | + ImGui::SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)"); | |
| 572 | + ImGui::Checkbox("io.ConfigViewportsNoDefaultParent", &io.ConfigViewportsNoDefaultParent); | |
| 573 | + ImGui::SameLine(); HelpMarker("(note: some platform backends may not reflect a change of this value for existing viewports, and may need the viewport to be recreated)"); | |
| 574 | + ImGui::Checkbox("io.ConfigViewportsPlatformFocusSetsImGuiFocus", &io.ConfigViewportsPlatformFocusSetsImGuiFocus); | |
| 575 | + ImGui::SameLine(); HelpMarker("When a platform window is focused (e.g. using Alt+Tab, clicking Platform Title Bar), apply corresponding focus on imgui windows (may clear focus/active id from imgui windows location in other platform windows). In principle this is better enabled but we provide an opt-out, because some Linux window managers tend to eagerly focus windows (e.g. on mouse hover, or even a simple window pos/size change)."); | |
| 576 | + ImGui::Unindent(); | |
| 577 | + } | |
| 578 | + | |
| 579 | + //ImGui::SeparatorText("DPI/Scaling"); | |
| 580 | + //ImGui::Checkbox("io.ConfigDpiScaleFonts", &io.ConfigDpiScaleFonts); | |
| 581 | + //ImGui::SameLine(); HelpMarker("Experimental: Automatically update style.FontScaleDpi when Monitor DPI changes. This will scale fonts but NOT style sizes/padding for now."); | |
| 582 | + //ImGui::Checkbox("io.ConfigDpiScaleViewports", &io.ConfigDpiScaleViewports); | |
| 583 | + //ImGui::SameLine(); HelpMarker("Experimental: Scale Dear ImGui and Platform Windows when Monitor DPI changes."); | |
| 584 | + | |
| 521 | 585 | ImGui::SeparatorText("Windows"); |
| 522 | 586 | ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); |
| 523 | 587 | ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback."); |
| @@ -583,13 +647,18 @@ | ||
| 583 | 647 | "Those flags are set by the backends (imgui_impl_xxx files) to specify their capabilities.\n" |
| 584 | 648 | "Here we expose them as read-only fields to avoid breaking interactions with your backend."); |
| 585 | 649 | |
| 650 | + // Make a local copy to avoid modifying actual backend flags. | |
| 586 | 651 | // FIXME: Maybe we need a BeginReadonly() equivalent to keep label bright? |
| 587 | 652 | ImGui::BeginDisabled(); |
| 588 | - ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad); | |
| 589 | - ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors); | |
| 590 | - ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos); | |
| 591 | - ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset); | |
| 592 | - ImGui::CheckboxFlags("io.BackendFlags: RendererHasTextures", &io.BackendFlags, ImGuiBackendFlags_RendererHasTextures); | |
| 653 | + ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", &io.BackendFlags, ImGuiBackendFlags_HasGamepad); | |
| 654 | + ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors); | |
| 655 | + ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos); | |
| 656 | + ImGui::CheckboxFlags("io.BackendFlags: PlatformHasViewports", &io.BackendFlags, ImGuiBackendFlags_PlatformHasViewports); | |
| 657 | + ImGui::CheckboxFlags("io.BackendFlags: HasMouseHoveredViewport",&io.BackendFlags, ImGuiBackendFlags_HasMouseHoveredViewport); | |
| 658 | + ImGui::CheckboxFlags("io.BackendFlags: HasParentViewport", &io.BackendFlags, ImGuiBackendFlags_HasParentViewport); | |
| 659 | + ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset); | |
| 660 | + ImGui::CheckboxFlags("io.BackendFlags: RendererHasTextures", &io.BackendFlags, ImGuiBackendFlags_RendererHasTextures); | |
| 661 | + ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports", &io.BackendFlags, ImGuiBackendFlags_RendererHasViewports); | |
| 593 | 662 | ImGui::EndDisabled(); |
| 594 | 663 | |
| 595 | 664 | ImGui::TreePop(); |
| @@ -641,6 +710,7 @@ | ||
| 641 | 710 | ImGui::TableNextColumn(); ImGui::Checkbox("No nav", &no_nav); |
| 642 | 711 | ImGui::TableNextColumn(); ImGui::Checkbox("No background", &no_background); |
| 643 | 712 | ImGui::TableNextColumn(); ImGui::Checkbox("No bring to front", &no_bring_to_front); |
| 713 | + ImGui::TableNextColumn(); ImGui::Checkbox("No docking", &no_docking); | |
| 644 | 714 | ImGui::TableNextColumn(); ImGui::Checkbox("Unsaved document", &unsaved_document); |
| 645 | 715 | ImGui::EndTable(); |
| 646 | 716 | } |
| @@ -682,6 +752,7 @@ | ||
| 682 | 752 | ImGui::MenuItem("Console", NULL, &demo_data->ShowAppConsole); |
| 683 | 753 | ImGui::MenuItem("Custom rendering", NULL, &demo_data->ShowAppCustomRendering); |
| 684 | 754 | ImGui::MenuItem("Documents", NULL, &demo_data->ShowAppDocuments); |
| 755 | + ImGui::MenuItem("Dockspace", NULL, &demo_data->ShowAppDockSpace); | |
| 685 | 756 | ImGui::MenuItem("Image Viewer", NULL, &demo_data->ShowAppImageViewer); |
| 686 | 757 | ImGui::MenuItem("Log", NULL, &demo_data->ShowAppLog); |
| 687 | 758 | ImGui::MenuItem("Property editor", NULL, &demo_data->ShowAppPropertyEditor); |
| @@ -2299,18 +2370,24 @@ | ||
| 2299 | 2370 | "IsWindowFocused() = %d\n" |
| 2300 | 2371 | "IsWindowFocused(_ChildWindows) = %d\n" |
| 2301 | 2372 | "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n" |
| 2373 | + "IsWindowFocused(_ChildWindows|_DockHierarchy) = %d\n" | |
| 2302 | 2374 | "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" |
| 2303 | 2375 | "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" |
| 2376 | + "IsWindowFocused(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n" | |
| 2304 | 2377 | "IsWindowFocused(_RootWindow) = %d\n" |
| 2305 | 2378 | "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n" |
| 2379 | + "IsWindowFocused(_RootWindow|_DockHierarchy) = %d\n" | |
| 2306 | 2380 | "IsWindowFocused(_AnyWindow) = %d\n", |
| 2307 | 2381 | ImGui::IsWindowFocused(), |
| 2308 | 2382 | ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), |
| 2309 | 2383 | ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy), |
| 2384 | + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_DockHierarchy), | |
| 2310 | 2385 | ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), |
| 2311 | 2386 | ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy), |
| 2387 | + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy), | |
| 2312 | 2388 | ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), |
| 2313 | 2389 | ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy), |
| 2390 | + ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_DockHierarchy), | |
| 2314 | 2391 | ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); |
| 2315 | 2392 | |
| 2316 | 2393 | // Testing IsWindowHovered() function with its various flags. |
| @@ -2320,10 +2397,13 @@ | ||
| 2320 | 2397 | "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" |
| 2321 | 2398 | "IsWindowHovered(_ChildWindows) = %d\n" |
| 2322 | 2399 | "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n" |
| 2400 | + "IsWindowHovered(_ChildWindows|_DockHierarchy) = %d\n" | |
| 2323 | 2401 | "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" |
| 2324 | 2402 | "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" |
| 2403 | + "IsWindowHovered(_ChildWindows|_RootWindow|_DockHierarchy) = %d\n" | |
| 2325 | 2404 | "IsWindowHovered(_RootWindow) = %d\n" |
| 2326 | 2405 | "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n" |
| 2406 | + "IsWindowHovered(_RootWindow|_DockHierarchy) = %d\n" | |
| 2327 | 2407 | "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" |
| 2328 | 2408 | "IsWindowHovered(_AnyWindow) = %d\n" |
| 2329 | 2409 | "IsWindowHovered(_Stationary) = %d\n", |
| @@ -2332,10 +2412,13 @@ | ||
| 2332 | 2412 | ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), |
| 2333 | 2413 | ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), |
| 2334 | 2414 | ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy), |
| 2415 | + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_DockHierarchy), | |
| 2335 | 2416 | ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), |
| 2336 | 2417 | ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy), |
| 2418 | + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy), | |
| 2337 | 2419 | ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), |
| 2338 | 2420 | ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy), |
| 2421 | + ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_DockHierarchy), | |
| 2339 | 2422 | ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), |
| 2340 | 2423 | ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow), |
| 2341 | 2424 | ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary)); |
| @@ -2348,10 +2431,13 @@ | ||
| 2348 | 2431 | |
| 2349 | 2432 | // Calling IsItemHovered() after begin returns the hovered status of the title bar. |
| 2350 | 2433 | // This is useful in particular if you want to create a context menu associated to the title bar of a window. |
| 2434 | + // This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties). | |
| 2351 | 2435 | static bool test_window = false; |
| 2352 | 2436 | ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); |
| 2353 | 2437 | if (test_window) |
| 2354 | 2438 | { |
| 2439 | + // FIXME-DOCK: This window cannot be docked within the ImGui Demo window, this will cause a feedback loop and get them stuck. | |
| 2440 | + // Could we fix this through an ImGuiWindowClass feature? Or an API call to tag our parent as "don't skip items"? | |
| 2355 | 2441 | ImGui::Begin("Title bar Hovered/Active tests", &test_window); |
| 2356 | 2442 | if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered() |
| 2357 | 2443 | { |
| @@ -4121,7 +4207,7 @@ | ||
| 4121 | 4207 | ImGui::BeginDisabled(); |
| 4122 | 4208 | ImGui::Button("Disabled item", sz); |
| 4123 | 4209 | if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) |
| 4124 | - ImGui::SetTooltip("I am a a tooltip for a disabled item."); | |
| 4210 | + ImGui::SetTooltip("I am a tooltip for a disabled item."); | |
| 4125 | 4211 | ImGui::EndDisabled(); |
| 4126 | 4212 | |
| 4127 | 4213 | ImGui::TreePop(); |
| @@ -4138,9 +4224,9 @@ | ||
| 4138 | 4224 | { |
| 4139 | 4225 | IMGUI_DEMO_MARKER("Widgets/Tree Nodes"); |
| 4140 | 4226 | // See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree. |
| 4141 | - if (ImGui::TreeNode("Basic trees")) | |
| 4227 | + if (ImGui::TreeNode("Basic Trees")) | |
| 4142 | 4228 | { |
| 4143 | - IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees"); | |
| 4229 | + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic Trees"); | |
| 4144 | 4230 | for (int i = 0; i < 5; i++) |
| 4145 | 4231 | { |
| 4146 | 4232 | // Use SetNextItemOpen() so set the default state of a node to be open. We could |
| @@ -4164,9 +4250,9 @@ | ||
| 4164 | 4250 | ImGui::TreePop(); |
| 4165 | 4251 | } |
| 4166 | 4252 | |
| 4167 | - if (ImGui::TreeNode("Hierarchy lines")) | |
| 4253 | + if (ImGui::TreeNode("Hierarchy Lines")) | |
| 4168 | 4254 | { |
| 4169 | - IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Hierarchy lines"); | |
| 4255 | + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Hierarchy Lines"); | |
| 4170 | 4256 | static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DefaultOpen; |
| 4171 | 4257 | HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags"); |
| 4172 | 4258 | ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", &base_flags, ImGuiTreeNodeFlags_DrawLinesNone); |
| @@ -4203,15 +4289,57 @@ | ||
| 4203 | 4289 | ImGui::TreePop(); |
| 4204 | 4290 | } |
| 4205 | 4291 | |
| 4206 | - if (ImGui::TreeNode("Advanced, with Selectable nodes")) | |
| 4292 | + if (ImGui::TreeNode("Selectable Nodes")) | |
| 4207 | 4293 | { |
| 4208 | - IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes"); | |
| 4294 | + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Selectable Nodes"); | |
| 4209 | 4295 | HelpMarker( |
| 4210 | - "This is a more typical looking tree with selectable nodes.\n" | |
| 4211 | - "Click to select, Ctrl+Click to toggle, click on arrows or double-click to open."); | |
| 4296 | + "Manually implemented selectable nodes.\n" | |
| 4297 | + "Click to select, Ctrl+Click to toggle, click on arrows or double-click to open.\n\n" | |
| 4298 | + "You may also use the multi-select API (see 'Demo->Widgets->Selection State & Multi-Select') for more advanced multi-selection features."); | |
| 4299 | + | |
| 4300 | + // Hold in 'selection_mask' a simple representation of what may be user-side selection state. | |
| 4301 | + // - You may retain selection state inside or outside your objects in whatever format you see fit. | |
| 4302 | + // You may use ImGuiSelectionBasicStorage which is conceptually close to a set<> of identifiers. | |
| 4303 | + // - We record which node was clicked and then apply selection at the end of the loop. | |
| 4304 | + // - This is a manual and simplified reimplementation of multi-selection, which the full | |
| 4305 | + // BeginMultiSelect() API implements better, but which is not trivial to wire for trees. | |
| 4306 | + static int selection_mask = 0x00; | |
| 4307 | + int node_clicked_idx = -1; | |
| 4308 | + for (int node_n = 0; node_n < 6; node_n++) | |
| 4309 | + { | |
| 4310 | + // Disable the default "open on single-click behavior" + set Selected flag according to our selection. | |
| 4311 | + // To alter selection we use if 'IsItemClicked() && !IsItemToggledOpen()', so clicking on an arrow doesn't alter selection. | |
| 4312 | + // In a BeginMultiSelect()/EndMultiSelect() we could use IsItemToggledSelection() but here we reimplement and use our own logic. | |
| 4313 | + ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; | |
| 4314 | + if (selection_mask & (1 << node_n)) | |
| 4315 | + flags |= ImGuiTreeNodeFlags_Selected; | |
| 4316 | + | |
| 4317 | + bool is_open = ImGui::TreeNodeEx((void*)(intptr_t)node_n, flags, "Selectable Node %d", node_n); | |
| 4318 | + if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) | |
| 4319 | + node_clicked_idx = node_n; | |
| 4320 | + if (is_open) | |
| 4321 | + { | |
| 4322 | + ImGui::BulletText("<Node contents here>"); | |
| 4323 | + ImGui::TreePop(); | |
| 4324 | + } | |
| 4325 | + } | |
| 4326 | + if (node_clicked_idx != -1) | |
| 4327 | + { | |
| 4328 | + // Update selection state (process outside of tree loop to avoid visual inconsistencies during the clicking frame) | |
| 4329 | + if (ImGui::GetIO().KeyCtrl) | |
| 4330 | + selection_mask ^= (1 << node_clicked_idx); // Ctrl+Click to toggle | |
| 4331 | + else //if (!(selection_mask & (1 << node_clicked_idx))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection | |
| 4332 | + selection_mask = (1 << node_clicked_idx); // Click to single-select | |
| 4333 | + } | |
| 4334 | + ImGui::TreePop(); | |
| 4335 | + } | |
| 4336 | + | |
| 4337 | + if (ImGui::TreeNode("Advanced")) | |
| 4338 | + { | |
| 4339 | + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced"); | |
| 4212 | 4340 | static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; |
| 4213 | 4341 | static bool align_label_with_current_x_position = false; |
| 4214 | - static bool test_drag_and_drop = false; | |
| 4342 | + static bool use_drag_and_drop = false; | |
| 4215 | 4343 | ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow); |
| 4216 | 4344 | ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); |
| 4217 | 4345 | ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node."); |
| @@ -4229,44 +4357,30 @@ | ||
| 4229 | 4357 | ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes); |
| 4230 | 4358 | |
| 4231 | 4359 | ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); |
| 4232 | - ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop); | |
| 4233 | - ImGui::Text("Hello!"); | |
| 4360 | + ImGui::Checkbox("Make Tree Nodes as drag & drop sources", &use_drag_and_drop); | |
| 4234 | 4361 | if (align_label_with_current_x_position) |
| 4235 | 4362 | ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); |
| 4236 | 4363 | |
| 4237 | - // 'selection_mask' is dumb representation of what may be user-side selection state. | |
| 4238 | - // You may retain selection state inside or outside your objects in whatever format you see fit. | |
| 4239 | - // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end | |
| 4240 | - /// of the loop. May be a pointer to your own node type, etc. | |
| 4241 | - static int selection_mask = (1 << 2); | |
| 4242 | - int node_clicked = -1; | |
| 4243 | - for (int i = 0; i < 6; i++) | |
| 4364 | + for (int node_n = 0; node_n < 6; node_n++) | |
| 4244 | 4365 | { |
| 4245 | - // Disable the default "open on single-click behavior" + set Selected flag according to our selection. | |
| 4246 | - // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection. | |
| 4247 | 4366 | ImGuiTreeNodeFlags node_flags = base_flags; |
| 4248 | - const bool is_selected = (selection_mask & (1 << i)) != 0; | |
| 4249 | - if (is_selected) | |
| 4250 | - node_flags |= ImGuiTreeNodeFlags_Selected; | |
| 4251 | - if (i < 3) | |
| 4367 | + if (node_n < 3) | |
| 4252 | 4368 | { |
| 4253 | 4369 | // Items 0..2 are Tree Node |
| 4254 | - bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); | |
| 4255 | - if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) | |
| 4256 | - node_clicked = i; | |
| 4257 | - if (test_drag_and_drop && ImGui::BeginDragDropSource()) | |
| 4370 | + bool is_open = ImGui::TreeNodeEx((void*)(intptr_t)node_n, node_flags, "Selectable Node %d", node_n); | |
| 4371 | + if (use_drag_and_drop && ImGui::BeginDragDropSource()) | |
| 4258 | 4372 | { |
| 4259 | - ImGui::SetDragDropPayload("_TREENODE", NULL, 0); | |
| 4373 | + ImGui::SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", NULL, 0); | |
| 4260 | 4374 | ImGui::Text("This is a drag and drop source"); |
| 4261 | 4375 | ImGui::EndDragDropSource(); |
| 4262 | 4376 | } |
| 4263 | - if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanLabelWidth)) | |
| 4377 | + if (node_n == 2 && (base_flags & ImGuiTreeNodeFlags_SpanLabelWidth)) | |
| 4264 | 4378 | { |
| 4265 | 4379 | // Item 2 has an additional inline button to help demonstrate SpanLabelWidth. |
| 4266 | 4380 | ImGui::SameLine(); |
| 4267 | 4381 | if (ImGui::SmallButton("button")) {} |
| 4268 | 4382 | } |
| 4269 | - if (node_open) | |
| 4383 | + if (is_open) | |
| 4270 | 4384 | { |
| 4271 | 4385 | ImGui::BulletText("Blah blah\nBlah Blah"); |
| 4272 | 4386 | ImGui::SameLine(); |
| @@ -4280,26 +4394,15 @@ | ||
| 4280 | 4394 | // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can |
| 4281 | 4395 | // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). |
| 4282 | 4396 | node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet |
| 4283 | - ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); | |
| 4284 | - if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) | |
| 4285 | - node_clicked = i; | |
| 4286 | - if (test_drag_and_drop && ImGui::BeginDragDropSource()) | |
| 4397 | + ImGui::TreeNodeEx((void*)(intptr_t)node_n, node_flags, "Selectable Leaf %d", node_n); | |
| 4398 | + if (use_drag_and_drop && ImGui::BeginDragDropSource()) | |
| 4287 | 4399 | { |
| 4288 | - ImGui::SetDragDropPayload("_TREENODE", NULL, 0); | |
| 4400 | + ImGui::SetDragDropPayload("MY_TREENODE_PAYLOAD_TYPE", NULL, 0); | |
| 4289 | 4401 | ImGui::Text("This is a drag and drop source"); |
| 4290 | 4402 | ImGui::EndDragDropSource(); |
| 4291 | 4403 | } |
| 4292 | 4404 | } |
| 4293 | 4405 | } |
| 4294 | - if (node_clicked != -1) | |
| 4295 | - { | |
| 4296 | - // Update selection state | |
| 4297 | - // (process outside of tree loop to avoid visual inconsistencies during the clicking frame) | |
| 4298 | - if (ImGui::GetIO().KeyCtrl) | |
| 4299 | - selection_mask ^= (1 << node_clicked); // Ctrl+Click to toggle | |
| 4300 | - else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection | |
| 4301 | - selection_mask = (1 << node_clicked); // Click to single-select | |
| 4302 | - } | |
| 4303 | 4406 | if (align_label_with_current_x_position) |
| 4304 | 4407 | ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); |
| 4305 | 4408 | ImGui::TreePop(); |
| @@ -8333,6 +8436,12 @@ | ||
| 8333 | 8436 | ImGui::Text("Emscripten: %d.%d.%d", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__); |
| 8334 | 8437 | #endif |
| 8335 | 8438 | #endif |
| 8439 | +#ifdef IMGUI_HAS_VIEWPORT | |
| 8440 | + ImGui::Text("define: IMGUI_HAS_VIEWPORT"); | |
| 8441 | +#endif | |
| 8442 | +#ifdef IMGUI_HAS_DOCK | |
| 8443 | + ImGui::Text("define: IMGUI_HAS_DOCK"); | |
| 8444 | +#endif | |
| 8336 | 8445 | #ifdef NDEBUG |
| 8337 | 8446 | ImGui::Text("define: NDEBUG"); |
| 8338 | 8447 | #endif |
| @@ -8361,7 +8470,20 @@ | ||
| 8361 | 8470 | if (io.ConfigFlags & ImGuiConfigFlags_NoMouse) ImGui::Text(" NoMouse"); |
| 8362 | 8471 | if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) ImGui::Text(" NoMouseCursorChange"); |
| 8363 | 8472 | if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) ImGui::Text(" NoKeyboard"); |
| 8473 | + if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) ImGui::Text(" DockingEnable"); | |
| 8474 | + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui::Text(" ViewportsEnable"); | |
| 8364 | 8475 | if (io.MouseDrawCursor) ImGui::Text("io.MouseDrawCursor"); |
| 8476 | + if (io.ConfigDpiScaleFonts) ImGui::Text("io.ConfigDpiScaleFonts"); | |
| 8477 | + if (io.ConfigDpiScaleViewports) ImGui::Text("io.ConfigDpiScaleViewports"); | |
| 8478 | + if (io.ConfigViewportsNoAutoMerge) ImGui::Text("io.ConfigViewportsNoAutoMerge"); | |
| 8479 | + if (io.ConfigViewportsNoTaskBarIcon) ImGui::Text("io.ConfigViewportsNoTaskBarIcon"); | |
| 8480 | + if (io.ConfigViewportsNoDecoration) ImGui::Text("io.ConfigViewportsNoDecoration"); | |
| 8481 | + if (io.ConfigViewportsNoDefaultParent) ImGui::Text("io.ConfigViewportsNoDefaultParent"); | |
| 8482 | + if (io.ConfigDockingNoSplit) ImGui::Text("io.ConfigDockingNoSplit"); | |
| 8483 | + if (io.ConfigDockingNoDockingOver) ImGui::Text("io.ConfigDockingNoDockingOver"); | |
| 8484 | + if (io.ConfigDockingWithShift) ImGui::Text("io.ConfigDockingWithShift"); | |
| 8485 | + if (io.ConfigDockingAlwaysTabBar) ImGui::Text("io.ConfigDockingAlwaysTabBar"); | |
| 8486 | + if (io.ConfigDockingTransparentPayload) ImGui::Text("io.ConfigDockingTransparentPayload"); | |
| 8365 | 8487 | if (io.ConfigMacOSXBehaviors) ImGui::Text("io.ConfigMacOSXBehaviors"); |
| 8366 | 8488 | if (io.ConfigNavMoveSetMousePos) ImGui::Text("io.ConfigNavMoveSetMousePos"); |
| 8367 | 8489 | if (io.ConfigNavCaptureKeyboard) ImGui::Text("io.ConfigNavCaptureKeyboard"); |
| @@ -8373,8 +8495,12 @@ | ||
| 8373 | 8495 | if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad"); |
| 8374 | 8496 | if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); |
| 8375 | 8497 | if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos"); |
| 8498 | + if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports) ImGui::Text(" PlatformHasViewports"); | |
| 8499 | + if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)ImGui::Text(" HasMouseHoveredViewport"); | |
| 8500 | + if (io.BackendFlags & ImGuiBackendFlags_HasParentViewport) ImGui::Text(" HasParentViewport"); | |
| 8376 | 8501 | if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset"); |
| 8377 | 8502 | if (io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) ImGui::Text(" RendererHasTextures"); |
| 8503 | + if (io.BackendFlags & ImGuiBackendFlags_RendererHasViewports) ImGui::Text(" RendererHasViewports"); | |
| 8378 | 8504 | ImGui::Separator(); |
| 8379 | 8505 | ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexData->Width, io.Fonts->TexData->Height); |
| 8380 | 8506 | ImGui::Text("io.Fonts->FontLoaderName: %s", io.Fonts->FontLoaderName ? io.Fonts->FontLoaderName : "NULL"); |
| @@ -8487,10 +8613,10 @@ | ||
| 8487 | 8613 | style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work. |
| 8488 | 8614 | SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize()); |
| 8489 | 8615 | DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 4.0f); |
| 8490 | - //BeginDisabled(GetIO().ConfigDpiScaleFonts); | |
| 8616 | + BeginDisabled(GetIO().ConfigDpiScaleFonts); | |
| 8491 | 8617 | DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 4.0f); |
| 8492 | - //SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten."); | |
| 8493 | - //EndDisabled(); | |
| 8618 | + SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten."); | |
| 8619 | + EndDisabled(); | |
| 8494 | 8620 | |
| 8495 | 8621 | // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) |
| 8496 | 8622 | if (SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) |
| @@ -8539,6 +8665,8 @@ | ||
| 8539 | 8665 | SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); |
| 8540 | 8666 | SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f"); |
| 8541 | 8667 | SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); |
| 8668 | + SliderFloat("MenuItemRounding", &style.MenuItemRounding, 0.0f, 12.0f, "%.0f"); | |
| 8669 | + // NB: SelectableRounding is intentionally NOT made visible here. We don't want to encourage people using that. | |
| 8542 | 8670 | |
| 8543 | 8671 | SeparatorText("Scrollbar"); |
| 8544 | 8672 | SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); |
| @@ -8598,6 +8726,11 @@ | ||
| 8598 | 8726 | SliderFloat("ImageRounding", &style.ImageRounding, 0.0f, 12.0f, "%.0f"); |
| 8599 | 8727 | SliderFloat("ImageBorderSize", &style.ImageBorderSize, 0.0f, max_border_size, "%.0f"); |
| 8600 | 8728 | |
| 8729 | + SeparatorText("Docking"); | |
| 8730 | + //SetCursorPosX(GetCursorPosX() + CalcItemWidth() - GetFrameHeight()); | |
| 8731 | + Checkbox("DockingNodeHasCloseButton", &style.DockingNodeHasCloseButton); | |
| 8732 | + SliderFloat("DockingSeparatorSize", &style.DockingSeparatorSize, 0.0f, 12.0f, "%.0f"); | |
| 8733 | + | |
| 8601 | 8734 | SeparatorText("Tooltips"); |
| 8602 | 8735 | for (int n = 0; n < 2; n++) |
| 8603 | 8736 | if (TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav")) |
| @@ -9985,6 +10118,8 @@ | ||
| 9985 | 10118 | else |
| 9986 | 10119 | { |
| 9987 | 10120 | ImGui::Text("(Hold Shift to display a dummy viewport)"); |
| 10121 | + if (ImGui::IsWindowDocked()) | |
| 10122 | + ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!"); | |
| 9988 | 10123 | if (ImGui::Button("Set 200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); |
| 9989 | 10124 | if (ImGui::Button("Set 500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); |
| 9990 | 10125 | if (ImGui::Button("Set 800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } |
| @@ -10011,7 +10146,7 @@ | ||
| 10011 | 10146 | { |
| 10012 | 10147 | static int location = 0; |
| 10013 | 10148 | ImGuiIO& io = ImGui::GetIO(); |
| 10014 | - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; | |
| 10149 | + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; | |
| 10015 | 10150 | if (location >= 0) |
| 10016 | 10151 | { |
| 10017 | 10152 | const float PAD = 10.0f; |
| @@ -10024,6 +10159,7 @@ | ||
| 10024 | 10159 | window_pos_pivot.x = (location & 1) ? 1.0f : 0.0f; |
| 10025 | 10160 | window_pos_pivot.y = (location & 2) ? 1.0f : 0.0f; |
| 10026 | 10161 | ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); |
| 10162 | + ImGui::SetNextWindowViewport(viewport->ID); | |
| 10027 | 10163 | window_flags |= ImGuiWindowFlags_NoMove; |
| 10028 | 10164 | } |
| 10029 | 10165 | else if (location == -2) |
| @@ -10451,6 +10587,164 @@ | ||
| 10451 | 10587 | } |
| 10452 | 10588 | |
| 10453 | 10589 | //----------------------------------------------------------------------------- |
| 10590 | +// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace() | |
| 10591 | +//----------------------------------------------------------------------------- | |
| 10592 | + | |
| 10593 | +struct ImGuiDemoDockspaceArgs | |
| 10594 | +{ | |
| 10595 | + bool IsFullscreen = true; | |
| 10596 | + bool KeepWindowPadding = false; // Keep WindowPadding to help understand that DockSpace() is a widget inside the window. | |
| 10597 | + ImGuiDockNodeFlags DockSpaceFlags = ImGuiDockNodeFlags_None; | |
| 10598 | +}; | |
| 10599 | + | |
| 10600 | +// THIS IS A DEMO FOR ADVANCED USAGE OF DockSpace(). | |
| 10601 | +// MOST REGULAR APPLICATIONS WANTING TO ALLOW DOCKING WINDOWS ON THE EDGE OF YOUR SCREEN CAN SIMPLY USE: | |
| 10602 | +// ImGui::NewFrame(); + ImGui::DockSpaceOverViewport(); // Create a dockspace in main viewport | |
| 10603 | +// OR: | |
| 10604 | +// ImGui::NewFrame(); + ImGui::DockSpaceOverViewport(0, nullptr, ImGuiDockNodeFlags_PassthruCentralNode); // Create a dockspace in main viewport, where central node is transparent. | |
| 10605 | +// Demonstrate using DockSpace() to create an explicit docking node within an existing window, with various options. | |
| 10606 | +// Read https://github.com/ocornut/imgui/wiki/Docking for details. | |
| 10607 | +// The reasons we do not use DockSpaceOverViewport() in this demo is because: | |
| 10608 | +// - (1) we allow the host window to be floating/moveable instead of filling the viewport (when args->IsFullscreen == false) | |
| 10609 | +// which is mostly to showcase the idea that DockSpace() may be submitted anywhere. | |
| 10610 | +// Also see 'Demo->Examples->Documents' for a less abstract version of this. | |
| 10611 | +// - (2) we allow the host window to have padding (when args->UsePadding == true) | |
| 10612 | +// - (3) we expose variety of other flags. | |
| 10613 | +static void ShowExampleAppDockSpaceAdvanced(ImGuiDemoDockspaceArgs* args, bool* p_open) | |
| 10614 | +{ | |
| 10615 | + ImGuiDockNodeFlags dockspace_flags = args->DockSpaceFlags; | |
| 10616 | + | |
| 10617 | + // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into, | |
| 10618 | + // because it would be confusing to have two docking targets within each others. | |
| 10619 | + ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking; | |
| 10620 | + if (args->IsFullscreen) | |
| 10621 | + { | |
| 10622 | + // Fullscreen dockspace: practically the same as calling DockSpaceOverViewport(); | |
| 10623 | + const ImGuiViewport* viewport = ImGui::GetMainViewport(); | |
| 10624 | + ImGui::SetNextWindowPos(viewport->WorkPos); | |
| 10625 | + ImGui::SetNextWindowSize(viewport->WorkSize); | |
| 10626 | + ImGui::SetNextWindowViewport(viewport->ID); | |
| 10627 | + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); | |
| 10628 | + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); | |
| 10629 | + window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; | |
| 10630 | + window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; | |
| 10631 | + window_flags |= ImGuiWindowFlags_NoBackground; | |
| 10632 | + } | |
| 10633 | + else | |
| 10634 | + { | |
| 10635 | + // Floating dockspace | |
| 10636 | + dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode; | |
| 10637 | + } | |
| 10638 | + | |
| 10639 | + // Important: note that we proceed even if Begin() returns false (aka window is collapsed). | |
| 10640 | + // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive, | |
| 10641 | + // all active windows docked into it will lose their parent and become undocked. | |
| 10642 | + // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise | |
| 10643 | + // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible. | |
| 10644 | + if (!args->KeepWindowPadding) | |
| 10645 | + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); | |
| 10646 | + ImGui::Begin("Window with a DockSpace", p_open, window_flags); | |
| 10647 | + if (!args->KeepWindowPadding) | |
| 10648 | + ImGui::PopStyleVar(); | |
| 10649 | + | |
| 10650 | + if (args->IsFullscreen) | |
| 10651 | + ImGui::PopStyleVar(2); | |
| 10652 | + | |
| 10653 | + // Submit the DockSpace widget inside our window | |
| 10654 | + // - Note that the id here is different from the one used by DockSpaceOverViewport(), so docking state won't get transfered between "Basic" and "Advanced" demos. | |
| 10655 | + // - If we made the ShowExampleAppDockSpaceBasic() calculate its own ID and pass it to DockSpaceOverViewport() the ID could easily match. | |
| 10656 | + ImGuiID dockspace_id = ImGui::GetID("MyDockSpace"); | |
| 10657 | + ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags); | |
| 10658 | + | |
| 10659 | + ImGui::End(); | |
| 10660 | +} | |
| 10661 | + | |
| 10662 | +static void ShowExampleAppDockSpaceBasic(ImGuiDockNodeFlags flags) | |
| 10663 | +{ | |
| 10664 | + // Basic version which you can use in many apps: | |
| 10665 | + // e.g: | |
| 10666 | + // ImGui::DockSpaceOverViewport(); | |
| 10667 | + // or: | |
| 10668 | + // ImGui::DockSpaceOverViewport(0, nullptr, ImGuiDockNodeFlags_PassthruCentralNode); // Central node will be transparent | |
| 10669 | + // or: | |
| 10670 | + // ImGuiViewport* viewport = ImGui::GetMainViewport(); | |
| 10671 | + // ImGui::DockSpaceOverViewport(0, viewport, ImGuiDockNodeFlags_None); | |
| 10672 | + | |
| 10673 | + ImGui::DockSpaceOverViewport(0, nullptr, flags); | |
| 10674 | +} | |
| 10675 | + | |
| 10676 | +void ShowExampleAppDockSpace(bool* p_open) | |
| 10677 | +{ | |
| 10678 | + static int opt_demo_mode = 0; | |
| 10679 | + static bool opt_demo_mode_changed = false; | |
| 10680 | + static ImGuiDemoDockspaceArgs args; | |
| 10681 | + | |
| 10682 | + if (opt_demo_mode == 0) | |
| 10683 | + ShowExampleAppDockSpaceBasic(args.DockSpaceFlags); | |
| 10684 | + else | |
| 10685 | + ShowExampleAppDockSpaceAdvanced(&args, p_open); | |
| 10686 | + | |
| 10687 | + // Refocus our window to minimize perceived loss of focus when changing mode (caused by the fact that each use a different window, which would not happen in a real app) | |
| 10688 | + if (opt_demo_mode_changed) | |
| 10689 | + ImGui::SetNextWindowFocus(); | |
| 10690 | + ImGui::Begin("Examples: Dockspace", p_open, ImGuiWindowFlags_MenuBar); | |
| 10691 | + opt_demo_mode_changed = false; | |
| 10692 | + opt_demo_mode_changed |= ImGui::RadioButton("Basic demo mode", &opt_demo_mode, 0); | |
| 10693 | + opt_demo_mode_changed |= ImGui::RadioButton("Advanced demo mode", &opt_demo_mode, 1); | |
| 10694 | + | |
| 10695 | + ImGui::SeparatorText("Options"); | |
| 10696 | + | |
| 10697 | + if ((ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable) == 0) | |
| 10698 | + { | |
| 10699 | + ShowDockingDisabledMessage(); | |
| 10700 | + } | |
| 10701 | + else if (opt_demo_mode == 0) | |
| 10702 | + { | |
| 10703 | + args.DockSpaceFlags &= ImGuiDockNodeFlags_PassthruCentralNode; // Allowed flags | |
| 10704 | + ImGui::CheckboxFlags("Flag: PassthruCentralNode", &args.DockSpaceFlags, ImGuiDockNodeFlags_PassthruCentralNode); | |
| 10705 | + } | |
| 10706 | + else if (opt_demo_mode == 1) | |
| 10707 | + { | |
| 10708 | + ImGui::Checkbox("Fullscreen", &args.IsFullscreen); | |
| 10709 | + ImGui::Checkbox("Keep Window Padding", &args.KeepWindowPadding); | |
| 10710 | + ImGui::SameLine(); | |
| 10711 | + HelpMarker("This is mostly exposed to facilitate understanding that a DockSpace() is _inside_ a window."); | |
| 10712 | + ImGui::BeginDisabled(args.IsFullscreen == false); | |
| 10713 | + ImGui::CheckboxFlags("Flag: PassthruCentralNode", &args.DockSpaceFlags, ImGuiDockNodeFlags_PassthruCentralNode); | |
| 10714 | + ImGui::EndDisabled(); | |
| 10715 | + ImGui::CheckboxFlags("Flag: NoDockingOverCentralNode", &args.DockSpaceFlags, ImGuiDockNodeFlags_NoDockingOverCentralNode); | |
| 10716 | + ImGui::CheckboxFlags("Flag: NoDockingSplit", &args.DockSpaceFlags, ImGuiDockNodeFlags_NoDockingSplit); | |
| 10717 | + ImGui::CheckboxFlags("Flag: NoUndocking", &args.DockSpaceFlags, ImGuiDockNodeFlags_NoUndocking); | |
| 10718 | + ImGui::CheckboxFlags("Flag: NoResize", &args.DockSpaceFlags, ImGuiDockNodeFlags_NoResize); | |
| 10719 | + ImGui::CheckboxFlags("Flag: AutoHideTabBar", &args.DockSpaceFlags, ImGuiDockNodeFlags_AutoHideTabBar); | |
| 10720 | + } | |
| 10721 | + | |
| 10722 | + // Show demo options and help | |
| 10723 | + if (ImGui::BeginMenuBar()) | |
| 10724 | + { | |
| 10725 | + if (ImGui::BeginMenu("Help")) | |
| 10726 | + { | |
| 10727 | + ImGui::TextUnformatted( | |
| 10728 | + "This demonstrates the use of ImGui::DockSpace() which allows you to manually\ncreate a docking node _within_ another window." "\n" | |
| 10729 | + "The \"Basic\" version uses the ImGui::DockSpaceOverViewport() helper. Most applications can probably use this."); | |
| 10730 | + ImGui::Separator(); | |
| 10731 | + ImGui::TextUnformatted("When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n" | |
| 10732 | + "- Drag from window title bar or their tab to dock/undock." "\n" | |
| 10733 | + "- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n" | |
| 10734 | + "- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" "\n" | |
| 10735 | + "- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)"); | |
| 10736 | + ImGui::Separator(); | |
| 10737 | + ImGui::TextUnformatted("More details:"); ImGui::Bullet(); ImGui::SameLine(); ImGui::TextLinkOpenURL("Docking Wiki page", "https://github.com/ocornut/imgui/wiki/Docking"); | |
| 10738 | + ImGui::BulletText("Read comments in ShowExampleAppDockSpace()"); | |
| 10739 | + ImGui::EndMenu(); | |
| 10740 | + } | |
| 10741 | + ImGui::EndMenuBar(); | |
| 10742 | + } | |
| 10743 | + | |
| 10744 | + ImGui::End(); | |
| 10745 | +} | |
| 10746 | + | |
| 10747 | +//----------------------------------------------------------------------------- | |
| 10454 | 10748 | // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() |
| 10455 | 10749 | //----------------------------------------------------------------------------- |
| 10456 | 10750 | |
| @@ -10575,11 +10869,25 @@ | ||
| 10575 | 10869 | static ExampleAppDocuments app; |
| 10576 | 10870 | |
| 10577 | 10871 | // Options |
| 10872 | + enum Target | |
| 10873 | + { | |
| 10874 | + Target_None, | |
| 10875 | + Target_Tab, // Create documents as local tab into a local tab bar | |
| 10876 | + Target_DockSpaceAndWindow // Create documents as regular windows, and create an embedded dockspace | |
| 10877 | + }; | |
| 10878 | + static Target opt_target = Target_Tab; | |
| 10578 | 10879 | static bool opt_reorderable = true; |
| 10579 | 10880 | static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_; |
| 10580 | 10881 | |
| 10882 | + // When (opt_target == Target_DockSpaceAndWindow) there is the possibily that one of our child Document window (e.g. "Eggplant") | |
| 10883 | + // that we emit gets docked into the same spot as the parent window ("Example: Documents"). | |
| 10884 | + // This would create a problematic feedback loop because selecting the "Eggplant" tab would make the "Example: Documents" tab | |
| 10885 | + // not visible, which in turn would stop submitting the "Eggplant" window. | |
| 10886 | + // We avoid this problem by submitting our documents window even if our parent window is not currently visible. | |
| 10887 | + // Another solution may be to make the "Example: Documents" window use the ImGuiWindowFlags_NoDocking. | |
| 10888 | + | |
| 10581 | 10889 | bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar); |
| 10582 | - if (!window_contents_visible) | |
| 10890 | + if (!window_contents_visible && opt_target != Target_DockSpaceAndWindow) | |
| 10583 | 10891 | { |
| 10584 | 10892 | ImGui::End(); |
| 10585 | 10893 | return; |
| @@ -10624,6 +10932,12 @@ | ||
| 10624 | 10932 | doc.DoForceClose(); |
| 10625 | 10933 | ImGui::PopID(); |
| 10626 | 10934 | } |
| 10935 | + ImGui::PushItemWidth(ImGui::GetFontSize() * 12); | |
| 10936 | + ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0"); | |
| 10937 | + ImGui::PopItemWidth(); | |
| 10938 | + bool redock_all = false; | |
| 10939 | + if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); } | |
| 10940 | + if (opt_target == Target_DockSpaceAndWindow) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); } | |
| 10627 | 10941 | |
| 10628 | 10942 | ImGui::Separator(); |
| 10629 | 10943 | |
| @@ -10637,7 +10951,8 @@ | ||
| 10637 | 10951 | // hole for one-frame, both in the tab-bar and in tab-contents when closing a tab/window. |
| 10638 | 10952 | // The rarely used SetTabItemClosed() function is a way to notify of programmatic closure to avoid the one-frame hole. |
| 10639 | 10953 | |
| 10640 | - // Submit Tab Bar and Tabs | |
| 10954 | + // Tabs | |
| 10955 | + if (opt_target == Target_Tab) | |
| 10641 | 10956 | { |
| 10642 | 10957 | ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0); |
| 10643 | 10958 | tab_bar_flags |= ImGuiTabBarFlags_DrawSelectedOverline; |
| @@ -10679,6 +10994,53 @@ | ||
| 10679 | 10994 | |
| 10680 | 10995 | ImGui::EndTabBar(); |
| 10681 | 10996 | } |
| 10997 | + } | |
| 10998 | + else if (opt_target == Target_DockSpaceAndWindow) | |
| 10999 | + { | |
| 11000 | + if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable) | |
| 11001 | + { | |
| 11002 | + app.NotifyOfDocumentsClosedElsewhere(); | |
| 11003 | + | |
| 11004 | + // Create a DockSpace node where any window can be docked | |
| 11005 | + ImGuiID dockspace_id = ImGui::GetID("MyDockSpace"); | |
| 11006 | + ImGui::DockSpace(dockspace_id); | |
| 11007 | + | |
| 11008 | + // Create Windows | |
| 11009 | + for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) | |
| 11010 | + { | |
| 11011 | + MyDocument* doc = &app.Documents[doc_n]; | |
| 11012 | + if (!doc->Open) | |
| 11013 | + continue; | |
| 11014 | + | |
| 11015 | + ImGui::SetNextWindowDockID(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver); | |
| 11016 | + ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0); | |
| 11017 | + bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags); | |
| 11018 | + | |
| 11019 | + // Cancel attempt to close when unsaved add to save queue so we can display a popup. | |
| 11020 | + if (!doc->Open && doc->Dirty) | |
| 11021 | + { | |
| 11022 | + doc->Open = true; | |
| 11023 | + app.CloseQueue.push_back(doc); | |
| 11024 | + } | |
| 11025 | + | |
| 11026 | + app.DisplayDocContextMenu(doc); | |
| 11027 | + if (visible) | |
| 11028 | + app.DisplayDocContents(doc); | |
| 11029 | + | |
| 11030 | + ImGui::End(); | |
| 11031 | + } | |
| 11032 | + } | |
| 11033 | + else | |
| 11034 | + { | |
| 11035 | + ShowDockingDisabledMessage(); | |
| 11036 | + } | |
| 11037 | + } | |
| 11038 | + | |
| 11039 | + // Early out other contents | |
| 11040 | + if (!window_contents_visible) | |
| 11041 | + { | |
| 11042 | + ImGui::End(); | |
| 11043 | + return; | |
| 10682 | 11044 | } |
| 10683 | 11045 | |
| 10684 | 11046 | // Display renaming UI |
| @@ -1,4 +1,4 @@ | ||
| 1 | -// dear imgui, v1.92.8 | |
| 1 | +// dear imgui, v1.92.9 WIP | |
| 2 | 2 | // (drawing and font code) |
| 3 | 3 | |
| 4 | 4 | /* |
| @@ -231,6 +231,8 @@ | ||
| 231 | 231 | colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); |
| 232 | 232 | colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); |
| 233 | 233 | colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.50f, 0.50f, 0.50f, 0.00f); |
| 234 | + colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_HeaderActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f); | |
| 235 | + colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); | |
| 234 | 236 | colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); |
| 235 | 237 | colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); |
| 236 | 238 | colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); |
| @@ -299,6 +301,8 @@ | ||
| 299 | 301 | colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); |
| 300 | 302 | colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); |
| 301 | 303 | colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.53f, 0.53f, 0.87f, 0.00f); |
| 304 | + colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f); | |
| 305 | + colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); | |
| 302 | 306 | colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); |
| 303 | 307 | colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); |
| 304 | 308 | colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); |
| @@ -368,6 +372,8 @@ | ||
| 368 | 372 | colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); |
| 369 | 373 | colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); |
| 370 | 374 | colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.26f, 0.59f, 1.00f, 0.00f); |
| 375 | + colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f); | |
| 376 | + colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); | |
| 371 | 377 | colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); |
| 372 | 378 | colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); |
| 373 | 379 | colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); |
| @@ -402,7 +408,6 @@ | ||
| 402 | 408 | const float a = ((float)i * 2 * IM_PI) / (float)IM_COUNTOF(ArcFastVtx); |
| 403 | 409 | ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a)); |
| 404 | 410 | } |
| 405 | - ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); | |
| 406 | 411 | } |
| 407 | 412 | |
| 408 | 413 | ImDrawListSharedData::~ImDrawListSharedData() |
| @@ -412,17 +417,17 @@ | ||
| 412 | 417 | |
| 413 | 418 | void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error) |
| 414 | 419 | { |
| 415 | - if (CircleSegmentMaxError == max_error) | |
| 420 | + if (CircleTessellationMaxError == max_error) | |
| 416 | 421 | return; |
| 417 | 422 | |
| 418 | 423 | IM_ASSERT(max_error > 0.0f); |
| 419 | - CircleSegmentMaxError = max_error; | |
| 424 | + CircleTessellationMaxError = max_error; | |
| 420 | 425 | for (int i = 0; i < IM_COUNTOF(CircleSegmentCounts); i++) |
| 421 | 426 | { |
| 422 | 427 | const float radius = (float)i; |
| 423 | - CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : IM_DRAWLIST_ARCFAST_SAMPLE_MAX); | |
| 428 | + CircleSegmentCounts[i] = (ImU8)((i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleTessellationMaxError) : IM_DRAWLIST_ARCFAST_SAMPLE_MAX); | |
| 424 | 429 | } |
| 425 | - ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); | |
| 430 | + ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleTessellationMaxError); | |
| 426 | 431 | } |
| 427 | 432 | |
| 428 | 433 | ImDrawList::ImDrawList(ImDrawListSharedData* shared_data) |
| @@ -656,11 +661,11 @@ | ||
| 656 | 661 | int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const |
| 657 | 662 | { |
| 658 | 663 | // Automatic segment count |
| 659 | - const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy | |
| 664 | + const int radius_idx = (int)(radius + 0.999f); // ceil to never reduce accuracy | |
| 660 | 665 | if (radius_idx >= 0 && radius_idx < IM_COUNTOF(_Data->CircleSegmentCounts)) |
| 661 | 666 | return _Data->CircleSegmentCounts[radius_idx]; // Use cached value |
| 662 | 667 | else |
| 663 | - return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); | |
| 668 | + return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleTessellationMaxError); | |
| 664 | 669 | } |
| 665 | 670 | |
| 666 | 671 | // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) |
| @@ -823,8 +828,13 @@ | ||
| 823 | 828 | const ImVec2 opaque_uv = _Data->TexUvWhitePixel; |
| 824 | 829 | const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw |
| 825 | 830 | const bool thick_line = (thickness > _FringeScale); |
| 826 | - IM_ASSERT((flags & ImDrawFlags_InvalidMask_) == 0 && "Incorrect parameter. Did you swapped 'thickness' and 'flags'?"); | |
| 827 | 831 | |
| 832 | + // If this assert triggers on legacy code: | |
| 833 | + // - 1.92.8 (2025/05): swapped two last parameters order: flags, thickness --> thickness, flags. This should normally be caught by compile-time type-checking. | |
| 834 | + // - 1.92.8 (2025/05): changed value of ImDrawList_Closed which was previously guaranteed to be == 1. Hardcoded use of 1 or true should be replaced. | |
| 835 | + // Read more details near AddRect() + see "API BREAKING CHANGES" section for 1.82, 1.90 and 1.92.8. | |
| 836 | + IM_ASSERT_USER_ERROR_RET((flags & ImDrawFlags_InvalidMask_) == 0, "Incorrect parameter. Did you swap 'thickness' and 'flags'?"); | |
| 837 | + | |
| 828 | 838 | if (Flags & ImDrawListFlags_AntiAliasedLines) |
| 829 | 839 | { |
| 830 | 840 | // Anti-aliased stroke |
| @@ -1475,27 +1485,24 @@ | ||
| 1475 | 1485 | { |
| 1476 | 1486 | if ((col & IM_COL32_A_MASK) == 0) |
| 1477 | 1487 | return; |
| 1478 | - PathLineTo(p1 + ImVec2(0.5f, 0.5f)); | |
| 1479 | - PathLineTo(p2 + ImVec2(0.5f, 0.5f)); | |
| 1480 | - PathStroke(col, thickness); | |
| 1488 | + const ImVec2 points[2] = { ImVec2(p1.x + 0.5f, p1.y + 0.5f), ImVec2(p2.x + 0.5f, p2.y + 0.5f) }; | |
| 1489 | + AddPolyline(points, 2, col, thickness); | |
| 1481 | 1490 | } |
| 1482 | 1491 | |
| 1483 | 1492 | void ImDrawList::AddLineH(float min_x, float max_x, float y, ImU32 col, float thickness) |
| 1484 | 1493 | { |
| 1485 | 1494 | if ((col & IM_COL32_A_MASK) == 0) |
| 1486 | 1495 | return; |
| 1487 | - PathLineTo(ImVec2(min_x + 0.5f, y + 0.5f)); // Same as AddLine() above. | |
| 1488 | - PathLineTo(ImVec2(max_x + 0.5f, y + 0.5f)); | |
| 1489 | - PathStroke(col, thickness); | |
| 1496 | + const ImVec2 points[2] = { ImVec2(min_x + 0.5f, y + 0.5f), ImVec2(max_x + 0.5f, y + 0.5f) }; // Same as AddLine() above. | |
| 1497 | + AddPolyline(points, 2, col, thickness); | |
| 1490 | 1498 | } |
| 1491 | 1499 | |
| 1492 | 1500 | void ImDrawList::AddLineV(float x, float min_y, float max_y, ImU32 col, float thickness) |
| 1493 | 1501 | { |
| 1494 | 1502 | if ((col & IM_COL32_A_MASK) == 0) |
| 1495 | 1503 | return; |
| 1496 | - PathLineTo(ImVec2(x + 0.5f, min_y + 0.5f)); // Same as AddLine() above. | |
| 1497 | - PathLineTo(ImVec2(x + 0.5f, max_y + 0.5f)); | |
| 1498 | - PathStroke(col, thickness); | |
| 1504 | + const ImVec2 points[2] = { ImVec2(x + 0.5f, min_y + 0.5f), ImVec2(x + 0.5f, max_y + 0.5f) }; // Same as AddLine() above. | |
| 1505 | + AddPolyline(points, 2, col, thickness); | |
| 1499 | 1506 | } |
| 1500 | 1507 | |
| 1501 | 1508 | // p_min = upper-left, p_max = lower-right |
| @@ -1503,14 +1510,15 @@ | ||
| 1503 | 1510 | void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, float thickness, ImDrawFlags flags) |
| 1504 | 1511 | { |
| 1505 | 1512 | // If this assert triggers on legacy code: |
| 1506 | - // - 1.92.8 (2025/04): swapped two last parameters order: flags, thickness --> thickness, flags. This should normally be caught by compile-time type-checking. | |
| 1513 | + // - 1.92.8 (2025/05): swapped two last parameters order: flags, thickness --> thickness, flags. This should normally be caught by compile-time type-checking. | |
| 1514 | + // - 1.92.8 (2025/05): changed value of ImDrawList_Closed which was previously guaranteed to be == 1. Hardcoded use of 1 or true should be replaced. | |
| 1507 | 1515 | // - 1.82.0 (2021/03): changed ImDrawCornerFlags to ImDrawFlags_RoundCornersXXX values. |
| 1508 | 1516 | // If you used hard-coded 1 to 15 or ~0 in flags to configure corner rounding use the new flags! |
| 1509 | 1517 | // - Hard coded support for ~0 == ImDrawFlags_RoundCornersAll. |
| 1510 | 1518 | // - Hard coded support for values 0x01 to 0x0F (matching 15 out of 16 old flags combinations) --> see FixRectCornerFlags() in <1.90 code. |
| 1511 | 1519 | // - Hard coded 0x00 with 'float rounding > 0.0f' --> replace with ImDrawFlags_RoundCornersNone or use 'float rounding = 0.0f'. |
| 1512 | - // See "API BREAKING CHANGES" section for 1.82 and 1.90. | |
| 1513 | - IM_ASSERT((flags & ImDrawFlags_InvalidMask_) == 0 && "Incorrect parameter. Did you swapped 'thickness' and 'flags'?"); // Or misuse of legacy hard-coded ImDrawCornerFlags values | |
| 1520 | + // See "API BREAKING CHANGES" section for 1.82, 1.90 and 1.92.8. | |
| 1521 | + IM_ASSERT_USER_ERROR_RET((flags & ImDrawFlags_InvalidMask_) == 0, "Incorrect parameter. Did you swap 'thickness' and 'flags'?"); // Or misuse of legacy hard-coded ImDrawCornerFlags values | |
| 1514 | 1522 | |
| 1515 | 1523 | if ((col & IM_COL32_A_MASK) == 0) |
| 1516 | 1524 | return; |
| @@ -2560,8 +2568,6 @@ | ||
| 2560 | 2568 | // - ImFontAtlasBuildPreloadAllGlyphRanges() |
| 2561 | 2569 | // - ImFontAtlasBuildUpdatePointers() |
| 2562 | 2570 | // - ImFontAtlasBuildRenderBitmapFromString() |
| 2563 | -// - ImFontAtlasBuildUpdateBasicTexData() | |
| 2564 | -// - ImFontAtlasBuildUpdateLinesTexData() | |
| 2565 | 2571 | // - ImFontAtlasBuildAddFont() |
| 2566 | 2572 | // - ImFontAtlasBuildSetupFontBakedEllipsis() |
| 2567 | 2573 | // - ImFontAtlasBuildSetupFontBakedBlanks() |
| @@ -2578,13 +2584,14 @@ | ||
| 2578 | 2584 | // - ImFontAtlasUpdateDrawListsSharedData() |
| 2579 | 2585 | //----------------------------------------------------------------------------- |
| 2580 | 2586 | // - ImFontAtlasBuildSetTexture() |
| 2581 | -// - ImFontAtlasBuildAddTexture() | |
| 2582 | -// - ImFontAtlasBuildMakeSpace() | |
| 2583 | -// - ImFontAtlasBuildRepackTexture() | |
| 2584 | -// - ImFontAtlasBuildGrowTexture() | |
| 2585 | -// - ImFontAtlasBuildRepackOrGrowTexture() | |
| 2586 | -// - ImFontAtlasBuildGetTextureSizeEstimate() | |
| 2587 | -// - ImFontAtlasBuildCompactTexture() | |
| 2587 | +// - ImFontAtlasBuildUpdateTexData() | |
| 2588 | +// - ImFontAtlasTextureAdd() | |
| 2589 | +// - ImFontAtlasTextureRepack() | |
| 2590 | +// - ImFontAtlasTextureGrow() | |
| 2591 | +// - ImFontAtlasTextureMakeSpace() | |
| 2592 | +// - ImFontAtlasTextureGetSizeEstimate() | |
| 2593 | +// - ImFontAtlasBuildClear() | |
| 2594 | +// - ImFontAtlasTextureCompact() | |
| 2588 | 2595 | // - ImFontAtlasBuildInit() |
| 2589 | 2596 | // - ImFontAtlasBuildDestroy() |
| 2590 | 2597 | //----------------------------------------------------------------------------- |
| @@ -2689,6 +2696,7 @@ | ||
| 2689 | 2696 | // Calling this mid-frame will discard the CPU-side copy of the texture data which is generally unreliable as you may have textures queued for creation or updates. |
| 2690 | 2697 | void ImFontAtlas::Clear() |
| 2691 | 2698 | { |
| 2699 | + IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlas::Clear()\n"); | |
| 2692 | 2700 | bool backup_renderer_has_textures = RendererHasTextures; |
| 2693 | 2701 | RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't. |
| 2694 | 2702 | ClearFonts(); |
| @@ -2699,6 +2707,7 @@ | ||
| 2699 | 2707 | void ImFontAtlas::ClearFonts() |
| 2700 | 2708 | { |
| 2701 | 2709 | // FIXME-NEWATLAS: Illegal to remove currently bound font. |
| 2710 | + IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlas::ClearFonts()\n"); | |
| 2702 | 2711 | IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); |
| 2703 | 2712 | for (ImFont* font : Fonts) |
| 2704 | 2713 | ImFontAtlasBuildNotifySetFont(this, font, NULL); |
| @@ -2774,6 +2783,28 @@ | ||
| 2774 | 2783 | IM_ASSERT(atlas->Builder == NULL || atlas->Builder->FrameCount < frame_count); // Protection against being called twice. |
| 2775 | 2784 | atlas->RendererHasTextures = renderer_has_textures; |
| 2776 | 2785 | |
| 2786 | + // Update texture status and discard old textures. | |
| 2787 | + // (we do this first thing to handle an edge case: if user mistakenly calls ClearFonts()+SetStatus(OK) during | |
| 2788 | + // rendering, it would ImFontAtlasBuildMain() rebuilding before tex->Updates[] gets a chance to be cleared) | |
| 2789 | + // (if somehow we need to move this back lower in the function, we could manually call the code to clear Updates[]). | |
| 2790 | + for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) | |
| 2791 | + { | |
| 2792 | + // Update and remove if requested | |
| 2793 | + ImTextureData* tex = atlas->TexList[tex_n]; | |
| 2794 | + if (tex->Status == ImTextureStatus_WantCreate && atlas->RendererHasTextures) | |
| 2795 | + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture's TexID/BackendUserData but did not update Status to OK."); | |
| 2796 | + | |
| 2797 | + bool remove_from_list = ImTextureDataUpdateNewFrame(tex); | |
| 2798 | + if (remove_from_list) | |
| 2799 | + { | |
| 2800 | + IM_ASSERT(atlas->TexData != tex); | |
| 2801 | + tex->DestroyPixels(); | |
| 2802 | + IM_DELETE(tex); | |
| 2803 | + atlas->TexList.erase(atlas->TexList.begin() + tex_n); | |
| 2804 | + tex_n--; | |
| 2805 | + } | |
| 2806 | + } | |
| 2807 | + | |
| 2777 | 2808 | // Check that font atlas was built or backend support texture reload in which case we can build now |
| 2778 | 2809 | if (atlas->RendererHasTextures) |
| 2779 | 2810 | { |
| @@ -2813,61 +2844,49 @@ | ||
| 2813 | 2844 | builder->BakedPool.Size -= builder->BakedDiscardedCount; |
| 2814 | 2845 | builder->BakedDiscardedCount = 0; |
| 2815 | 2846 | } |
| 2847 | +} | |
| 2816 | 2848 | |
| 2817 | - // Update texture status | |
| 2818 | - for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) | |
| 2849 | +bool ImTextureDataUpdateNewFrame(ImTextureData* tex) | |
| 2850 | +{ | |
| 2851 | + bool remove_from_list = false; | |
| 2852 | + if (tex->Status == ImTextureStatus_OK) | |
| 2819 | 2853 | { |
| 2820 | - ImTextureData* tex = atlas->TexList[tex_n]; | |
| 2821 | - bool remove_from_list = false; | |
| 2822 | - if (tex->Status == ImTextureStatus_OK) | |
| 2823 | - { | |
| 2824 | - tex->Updates.resize(0); | |
| 2825 | - tex->UpdateRect.x = tex->UpdateRect.y = (unsigned short)~0; | |
| 2826 | - tex->UpdateRect.w = tex->UpdateRect.h = 0; | |
| 2827 | - } | |
| 2828 | - if (tex->Status == ImTextureStatus_WantCreate && atlas->RendererHasTextures) | |
| 2829 | - IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture's TexID/BackendUserData but did not update Status to OK."); | |
| 2854 | + tex->Updates.resize(0); | |
| 2855 | + tex->UpdateRect.x = tex->UpdateRect.y = (unsigned short)~0; | |
| 2856 | + tex->UpdateRect.w = tex->UpdateRect.h = 0; | |
| 2857 | + } | |
| 2830 | 2858 | |
| 2831 | - // Request destroy | |
| 2832 | - // - Keep bool to true in order to differentiate a planned destroy vs a destroy decided by the backend. | |
| 2833 | - // - We don't destroy pixels right away, as backend may have an in-flight copy from RAM. | |
| 2834 | - if (tex->WantDestroyNextFrame && tex->Status != ImTextureStatus_Destroyed && tex->Status != ImTextureStatus_WantDestroy) | |
| 2835 | - { | |
| 2836 | - IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates); | |
| 2837 | - tex->Status = ImTextureStatus_WantDestroy; | |
| 2838 | - } | |
| 2859 | + // Request destroy | |
| 2860 | + // - Keep bool to true in order to differentiate a planned destroy vs a destroy decided by the backend. | |
| 2861 | + // - We don't destroy pixels right away, as backend may have an in-flight copy from RAM. | |
| 2862 | + if (tex->WantDestroyNextFrame && tex->Status != ImTextureStatus_Destroyed && tex->Status != ImTextureStatus_WantDestroy) | |
| 2863 | + { | |
| 2864 | + IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates); | |
| 2865 | + tex->Status = ImTextureStatus_WantDestroy; | |
| 2866 | + } | |
| 2839 | 2867 | |
| 2840 | - // If a texture has never reached the backend, they don't need to know about it. | |
| 2841 | - // (note: backends between 1.92.0 and 1.92.4 could set an already destroyed texture to ImTextureStatus_WantDestroy | |
| 2842 | - // when invalidating graphics objects twice, which would previously remove it from the list and crash.) | |
| 2843 | - if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL) | |
| 2844 | - tex->Status = ImTextureStatus_Destroyed; | |
| 2868 | + // If a texture has never reached the backend, they don't need to know about it. | |
| 2869 | + // (note: backends between 1.92.0 and 1.92.4 could set an already destroyed texture to ImTextureStatus_WantDestroy | |
| 2870 | + // when invalidating graphics objects twice, which would previously remove it from the list and crash.) | |
| 2871 | + if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL) | |
| 2872 | + tex->Status = ImTextureStatus_Destroyed; | |
| 2845 | 2873 | |
| 2846 | - // Process texture being destroyed | |
| 2847 | - if (tex->Status == ImTextureStatus_Destroyed) | |
| 2848 | - { | |
| 2849 | - IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture Status to Destroyed but did not clear TexID/BackendUserData!"); | |
| 2850 | - if (tex->WantDestroyNextFrame) | |
| 2851 | - remove_from_list = true; // Destroy was scheduled by us | |
| 2852 | - else | |
| 2853 | - tex->Status = ImTextureStatus_WantCreate; // Destroy was done was backend: recreate it (e.g. freed resources mid-run) | |
| 2854 | - } | |
| 2874 | + // Process texture being destroyed | |
| 2875 | + if (tex->Status == ImTextureStatus_Destroyed) | |
| 2876 | + { | |
| 2877 | + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture Status to Destroyed but did not clear TexID/BackendUserData!"); | |
| 2878 | + if (tex->WantDestroyNextFrame) | |
| 2879 | + remove_from_list = true; // Destroy was scheduled by us | |
| 2880 | + else | |
| 2881 | + tex->Status = ImTextureStatus_WantCreate; // Destroy was done was backend: recreate it (e.g. freed resources mid-run) | |
| 2882 | + } | |
| 2855 | 2883 | |
| 2856 | - // The backend may need defer destroying by a few frames, to handle texture used by previous in-flight rendering. | |
| 2857 | - // We allow the texture staying in _WantDestroy state and increment a counter which the backend can use to take its decision. | |
| 2858 | - if (tex->Status == ImTextureStatus_WantDestroy) | |
| 2859 | - tex->UnusedFrames++; | |
| 2884 | + // The backend may need defer destroying by a few frames, to handle texture used by previous in-flight rendering. | |
| 2885 | + // We allow the texture staying in _WantDestroy state and increment a counter which the backend can use to take its decision. | |
| 2886 | + if (tex->Status == ImTextureStatus_WantDestroy) | |
| 2887 | + tex->UnusedFrames++; | |
| 2860 | 2888 | |
| 2861 | - // Destroy and remove | |
| 2862 | - if (remove_from_list) | |
| 2863 | - { | |
| 2864 | - IM_ASSERT(atlas->TexData != tex); | |
| 2865 | - tex->DestroyPixels(); | |
| 2866 | - IM_DELETE(tex); | |
| 2867 | - atlas->TexList.erase(atlas->TexList.begin() + tex_n); | |
| 2868 | - tex_n--; | |
| 2869 | - } | |
| 2870 | - } | |
| 2889 | + return remove_from_list; | |
| 2871 | 2890 | } |
| 2872 | 2891 | |
| 2873 | 2892 | void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h) |
| @@ -3143,8 +3162,10 @@ | ||
| 3143 | 3162 | dst += 4; |
| 3144 | 3163 | } |
| 3145 | 3164 | } |
| 3146 | -#ifndef IMGUI_DISABLE_DEFAULT_FONT | |
| 3165 | +#if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_BITMAP) | |
| 3147 | 3166 | static const char* GetDefaultCompressedFontDataProggyClean(int* out_size); |
| 3167 | +#endif | |
| 3168 | +#if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_VECTOR) | |
| 3148 | 3169 | static const char* GetDefaultCompressedFontDataProggyForever(int* out_size); |
| 3149 | 3170 | #endif |
| 3150 | 3171 | |
| @@ -3169,7 +3190,7 @@ | ||
| 3169 | 3190 | // If you want a similar font which may be better scaled, consider using AddFontDefaultVector(). |
| 3170 | 3191 | ImFont* ImFontAtlas::AddFontDefaultBitmap(const ImFontConfig* font_cfg_template) |
| 3171 | 3192 | { |
| 3172 | -#ifndef IMGUI_DISABLE_DEFAULT_FONT | |
| 3193 | +#if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_BITMAP) | |
| 3173 | 3194 | ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); |
| 3174 | 3195 | if (!font_cfg_template) |
| 3175 | 3196 | font_cfg.PixelSnapH = true; // Prevents sub-integer scaling factors at lower-level layers. |
| @@ -3190,14 +3211,14 @@ | ||
| 3190 | 3211 | IM_ASSERT(0 && "Function is disabled in this build."); |
| 3191 | 3212 | IM_UNUSED(font_cfg_template); |
| 3192 | 3213 | return NULL; |
| 3193 | -#endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT | |
| 3214 | +#endif | |
| 3194 | 3215 | } |
| 3195 | 3216 | |
| 3196 | 3217 | // Load a minimal version of ProggyForever, designed to match our good old ProggyClean, but nicely scalable. |
| 3197 | 3218 | // (See build script in https://github.com/ocornut/proggyforever for details) |
| 3198 | 3219 | ImFont* ImFontAtlas::AddFontDefaultVector(const ImFontConfig* font_cfg_template) |
| 3199 | 3220 | { |
| 3200 | -#ifndef IMGUI_DISABLE_DEFAULT_FONT | |
| 3221 | +#if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_VECTOR) | |
| 3201 | 3222 | ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); |
| 3202 | 3223 | if (!font_cfg_template) |
| 3203 | 3224 | font_cfg.PixelSnapH = true; // Precisely match ProggyClean, but prevents sub-integer scaling factors at lower-level layers. |
| @@ -3218,7 +3239,7 @@ | ||
| 3218 | 3239 | IM_ASSERT(0 && "Function is disabled in this build."); |
| 3219 | 3240 | IM_UNUSED(font_cfg_template); |
| 3220 | 3241 | return NULL; |
| 3221 | -#endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT | |
| 3242 | +#endif | |
| 3222 | 3243 | } |
| 3223 | 3244 | |
| 3224 | 3245 | ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) |
| @@ -3574,7 +3595,7 @@ | ||
| 3574 | 3595 | } |
| 3575 | 3596 | } |
| 3576 | 3597 | |
| 3577 | -static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas) | |
| 3598 | +static void ImFontAtlasBuildUpdateTexDataBasic(ImFontAtlas* atlas) | |
| 3578 | 3599 | { |
| 3579 | 3600 | // Pack and store identifier so we can refresh UV coordinates on texture resize. |
| 3580 | 3601 | // FIXME-NEWATLAS: User/custom rects where user code wants to store UV coordinates will need to do the same thing. |
| @@ -3608,7 +3629,7 @@ | ||
| 3608 | 3629 | atlas->TexUvWhitePixel = ImVec2((r.x + 0.5f) * atlas->TexUvScale.x, (r.y + 0.5f) * atlas->TexUvScale.y); |
| 3609 | 3630 | } |
| 3610 | 3631 | |
| 3611 | -static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas) | |
| 3632 | +static void ImFontAtlasBuildUpdateTexDataLines(ImFontAtlas* atlas) | |
| 3612 | 3633 | { |
| 3613 | 3634 | if (atlas->Flags & ImFontAtlasFlags_NoBakedLines) |
| 3614 | 3635 | return; |
| @@ -4057,6 +4078,12 @@ | ||
| 4057 | 4078 | ImFontAtlasUpdateDrawListsTextures(atlas, old_tex_ref, atlas->TexRef); |
| 4058 | 4079 | } |
| 4059 | 4080 | |
| 4081 | +static void ImFontAtlasBuildUpdateTexData(ImFontAtlas* atlas) | |
| 4082 | +{ | |
| 4083 | + ImFontAtlasBuildUpdateTexDataBasic(atlas); | |
| 4084 | + ImFontAtlasBuildUpdateTexDataLines(atlas); | |
| 4085 | +} | |
| 4086 | + | |
| 4060 | 4087 | // Create a new texture, discard previous one |
| 4061 | 4088 | ImTextureData* ImFontAtlasTextureAdd(ImFontAtlas* atlas, int w, int h) |
| 4062 | 4089 | { |
| @@ -4171,8 +4198,7 @@ | ||
| 4171 | 4198 | } |
| 4172 | 4199 | |
| 4173 | 4200 | // Update other cached UV |
| 4174 | - ImFontAtlasBuildUpdateLinesTexData(atlas); | |
| 4175 | - ImFontAtlasBuildUpdateBasicTexData(atlas); | |
| 4201 | + ImFontAtlasBuildUpdateTexData(atlas); | |
| 4176 | 4202 | |
| 4177 | 4203 | builder->LockDisableResize = false; |
| 4178 | 4204 | ImFontAtlasUpdateDrawListsSharedData(atlas); |
| @@ -4321,8 +4347,7 @@ | ||
| 4321 | 4347 | ImFontAtlasPackInit(atlas); |
| 4322 | 4348 | |
| 4323 | 4349 | // Add required texture data |
| 4324 | - ImFontAtlasBuildUpdateLinesTexData(atlas); | |
| 4325 | - ImFontAtlasBuildUpdateBasicTexData(atlas); | |
| 4350 | + ImFontAtlasBuildUpdateTexData(atlas); | |
| 4326 | 4351 | |
| 4327 | 4352 | // Register fonts |
| 4328 | 4353 | ImFontAtlasBuildUpdatePointers(atlas); |
| @@ -4351,6 +4376,8 @@ | ||
| 4351 | 4376 | atlas->Builder = NULL; |
| 4352 | 4377 | } |
| 4353 | 4378 | |
| 4379 | +//----------------------------------------------------------------------------- | |
| 4380 | + | |
| 4354 | 4381 | void ImFontAtlasPackInit(ImFontAtlas * atlas) |
| 4355 | 4382 | { |
| 4356 | 4383 | ImTextureData* tex = atlas->TexData; |
| @@ -5747,8 +5774,13 @@ | ||
| 5747 | 5774 | if (glyph->Colored) |
| 5748 | 5775 | col |= ~IM_COL32_A_MASK; |
| 5749 | 5776 | float scale = (size >= 0.0f) ? (size / baked->Size) : 1.0f; |
| 5750 | - float x = IM_TRUNC(pos.x); | |
| 5751 | - float y = IM_TRUNC(pos.y); | |
| 5777 | + float x = pos.x; | |
| 5778 | + float y = pos.y; | |
| 5779 | + if ((draw_list->Flags & ImDrawListFlags_TextNoPixelSnap) == 0) | |
| 5780 | + { | |
| 5781 | + x = IM_TRUNC(x); | |
| 5782 | + y = IM_TRUNC(y); | |
| 5783 | + } | |
| 5752 | 5784 | |
| 5753 | 5785 | float x1 = x + glyph->X0 * scale; |
| 5754 | 5786 | float x2 = x + glyph->X1 * scale; |
| @@ -5780,12 +5812,17 @@ | ||
| 5780 | 5812 | // DO NOT CALL DIRECTLY THIS WILL CHANGE WILDLY IN 2026. Use ImDrawList::AddText(). |
| 5781 | 5813 | void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, ImDrawTextFlags flags) |
| 5782 | 5814 | { |
| 5783 | - // Align to be pixel perfect | |
| 5784 | 5815 | begin: |
| 5785 | - float x = IM_TRUNC(pos.x); | |
| 5786 | - float y = IM_TRUNC(pos.y); | |
| 5816 | + // Align to be pixel perfect | |
| 5817 | + float x = pos.x; | |
| 5818 | + float y = pos.y; | |
| 5787 | 5819 | if (y > clip_rect.w) |
| 5788 | 5820 | return; |
| 5821 | + if ((draw_list->Flags & ImDrawListFlags_TextNoPixelSnap) == 0) | |
| 5822 | + { | |
| 5823 | + x = IM_TRUNC(x); | |
| 5824 | + y = IM_TRUNC(y); | |
| 5825 | + } | |
| 5789 | 5826 | |
| 5790 | 5827 | if (!text_end) |
| 5791 | 5828 | text_end = text_begin + ImStrlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. |
| @@ -5990,6 +6027,7 @@ | ||
| 5990 | 6027 | // - RenderArrow() |
| 5991 | 6028 | // - RenderBullet() |
| 5992 | 6029 | // - RenderCheckMark() |
| 6030 | +// - RenderArrowDockMenu() | |
| 5993 | 6031 | // - RenderArrowPointingAt() |
| 5994 | 6032 | // - RenderRectFilledInRangeH() |
| 5995 | 6033 | // - RenderRectFilledWithHole() |
| @@ -6065,6 +6103,14 @@ | ||
| 6065 | 6103 | } |
| 6066 | 6104 | } |
| 6067 | 6105 | |
| 6106 | +// This is less wide than RenderArrow() and we use in dock nodes instead of the regular RenderArrow() to denote a change of functionality, | |
| 6107 | +// and because the saved space means that the left-most tab label can stay at exactly the same position as the label of a loose window. | |
| 6108 | +void ImGui::RenderArrowDockMenu(ImDrawList* draw_list, ImVec2 p_min, float sz, ImU32 col) | |
| 6109 | +{ | |
| 6110 | + draw_list->AddRectFilled(p_min + ImVec2(sz * 0.20f, sz * 0.15f), p_min + ImVec2(sz * 0.80f, sz * 0.30f), col); | |
| 6111 | + RenderArrowPointingAt(draw_list, p_min + ImVec2(sz * 0.50f, sz * 0.85f), ImVec2(sz * 0.30f, sz * 0.40f), ImGuiDir_Down, col); | |
| 6112 | +} | |
| 6113 | + | |
| 6068 | 6114 | static inline float ImAcos01(float x) |
| 6069 | 6115 | { |
| 6070 | 6116 | if (x <= 0.0f) return IM_PI * 0.5f; |
| @@ -6171,8 +6217,8 @@ | ||
| 6171 | 6217 | flags = ImDrawFlags_RoundCornersDefault_; |
| 6172 | 6218 | if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF) |
| 6173 | 6219 | { |
| 6174 | - ImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col)); | |
| 6175 | - ImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col)); | |
| 6220 | + ImU32 col_bg1 = GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col)); | |
| 6221 | + ImU32 col_bg2 = GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col)); | |
| 6176 | 6222 | draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, flags); |
| 6177 | 6223 | |
| 6178 | 6224 | int yi = 0; |
| @@ -6181,12 +6227,12 @@ | ||
| 6181 | 6227 | float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y); |
| 6182 | 6228 | if (y2 <= y1) |
| 6183 | 6229 | continue; |
| 6184 | - for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f) | |
| 6230 | + for (float x = p_min.x + grid_off.x + ((yi ^ 1) & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f) | |
| 6185 | 6231 | { |
| 6186 | 6232 | float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x); |
| 6187 | 6233 | if (x2 <= x1) |
| 6188 | 6234 | continue; |
| 6189 | - ImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone; | |
| 6235 | + ImDrawFlags cell_flags = ImDrawFlags_RoundCornersNone; // FIXME: Could use CalcRoundingFlagsForRectInRect() | |
| 6190 | 6236 | if (y1 <= p_min.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersTopLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersTopRight; } |
| 6191 | 6237 | if (y2 >= p_max.y) { if (x1 <= p_min.x) cell_flags |= ImDrawFlags_RoundCornersBottomLeft; if (x2 >= p_max.x) cell_flags |= ImDrawFlags_RoundCornersBottomRight; } |
| 6192 | 6238 | |
| @@ -6328,7 +6374,7 @@ | ||
| 6328 | 6374 | // Download and more information at https://github.com/bluescan/proggyfonts |
| 6329 | 6375 | //----------------------------------------------------------------------------- |
| 6330 | 6376 | |
| 6331 | -#ifndef IMGUI_DISABLE_DEFAULT_FONT | |
| 6377 | +#if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_BITMAP) | |
| 6332 | 6378 | |
| 6333 | 6379 | // File: 'ProggyClean.ttf' (41208 bytes) |
| 6334 | 6380 | // Exported using binary_to_compressed_c.exe -u8 "ProggyClean.ttf" proggy_clean_ttf |
| @@ -6508,6 +6554,7 @@ | ||
| 6508 | 6554 | *out_size = proggy_clean_ttf_compressed_size; |
| 6509 | 6555 | return (const char*)proggy_clean_ttf_compressed_data; |
| 6510 | 6556 | } |
| 6557 | +#endif // #if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_BITMAP) | |
| 6511 | 6558 | |
| 6512 | 6559 | //----------------------------------------------------------------------------- |
| 6513 | 6560 | // [SECTION] Default font data (ProggyForever-Regular-minimal.ttf) |
| @@ -6516,6 +6563,8 @@ | ||
| 6516 | 6563 | // MIT license / Copyright (c) 2026 Disco Hello, Copyright (c) 2019,2023 Tristan Grimmer |
| 6517 | 6564 | //----------------------------------------------------------------------------- |
| 6518 | 6565 | |
| 6566 | +#if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_VECTOR) | |
| 6567 | + | |
| 6519 | 6568 | // File: 'output/ProggyForever-Regular-minimal.ttf' (18556 bytes) |
| 6520 | 6569 | // Exported using binary_to_compressed_c.exe -u8 "output/ProggyForever-Regular-minimal.ttf" proggy_forever_minimal_ttf |
| 6521 | 6570 | static const unsigned int proggy_forever_minimal_ttf_compressed_size = 14562; |
| @@ -6770,7 +6819,6 @@ | ||
| 6770 | 6819 | *out_size = proggy_forever_minimal_ttf_compressed_size; |
| 6771 | 6820 | return (const char*)proggy_forever_minimal_ttf_compressed_data; |
| 6772 | 6821 | } |
| 6773 | - | |
| 6774 | -#endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT | |
| 6822 | +#endif // #if !defined(IMGUI_DISABLE_DEFAULT_FONT) && !defined(IMGUI_DISABLE_DEFAULT_FONT_VECTOR) | |
| 6775 | 6823 | |
| 6776 | 6824 | #endif // #ifndef IMGUI_DISABLE |
| @@ -1,4 +1,4 @@ | ||
| 1 | -// dear imgui, v1.92.8 | |
| 1 | +// dear imgui, v1.92.9 WIP | |
| 2 | 2 | // (internal structures/api) |
| 3 | 3 | |
| 4 | 4 | // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. |
| @@ -35,7 +35,7 @@ | ||
| 35 | 35 | // [SECTION] ImGuiContext (main imgui context) |
| 36 | 36 | // [SECTION] ImGuiWindowTempData, ImGuiWindow |
| 37 | 37 | // [SECTION] Tab bar, Tab item support |
| 38 | -// [SECTION] Table support | |
| 38 | +// [SECTION] Table support + internal API | |
| 39 | 39 | // [SECTION] ImGui internal API |
| 40 | 40 | // [SECTION] ImFontLoader |
| 41 | 41 | // [SECTION] ImFontAtlas internal API |
| @@ -153,6 +153,10 @@ | ||
| 153 | 153 | struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine |
| 154 | 154 | struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum |
| 155 | 155 | struct ImGuiDeactivatedItemData; // Data for IsItemDeactivated()/IsItemDeactivatedAfterEdit() function. |
| 156 | +struct ImGuiDockContext; // Docking system context | |
| 157 | +struct ImGuiDockRequest; // Docking system dock/undock queued request | |
| 158 | +struct ImGuiDockNode; // Docking system node (hold a list of Windows OR two child dock nodes) | |
| 159 | +struct ImGuiDockNodeSettings; // Storage for a dock node in .ini file (we preserve those even if the associated dock node isn't active during the session) | |
| 156 | 160 | struct ImGuiErrorRecoveryState; // Storage of stack sizes for error handling and recovery |
| 157 | 161 | struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup() |
| 158 | 162 | struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box |
| @@ -185,12 +189,14 @@ | ||
| 185 | 189 | struct ImGuiTypingSelectState; // Storage for GetTypingSelectRequest() |
| 186 | 190 | struct ImGuiTypingSelectRequest; // Storage for GetTypingSelectRequest() (aimed to be public) |
| 187 | 191 | struct ImGuiWindow; // Storage for one window |
| 192 | +struct ImGuiWindowDockStyle; // Storage for window-style data which needs to be stored for docking purpose | |
| 188 | 193 | struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame, in practice we currently keep it for each window) |
| 189 | 194 | struct ImGuiWindowSettings; // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session) |
| 190 | 195 | |
| 191 | 196 | // Enumerations |
| 192 | 197 | // Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. |
| 193 | 198 | enum ImGuiLocKey : int; // -> enum ImGuiLocKey // Enum: a localization entry for translation. |
| 199 | +typedef int ImGuiDataAuthority; // -> enum ImGuiDataAuthority_ // Enum: for storing the source authority (dock node vs window) of a field | |
| 194 | 200 | typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical |
| 195 | 201 | |
| 196 | 202 | // Flags |
| @@ -230,6 +236,9 @@ | ||
| 230 | 236 | // [SECTION] Macros |
| 231 | 237 | //----------------------------------------------------------------------------- |
| 232 | 238 | |
| 239 | +// Internal Drag and Drop payload types. String starting with '_' are reserved for Dear ImGui. | |
| 240 | +#define IMGUI_PAYLOAD_TYPE_WINDOW "_IMWINDOW" // Payload == ImGuiWindow* | |
| 241 | + | |
| 233 | 242 | // Debug Printing Into TTY |
| 234 | 243 | // (since IMGUI_VERSION_NUM >= 18729: IMGUI_DEBUG_LOG was reworked into IMGUI_DEBUG_PRINTF (and removed framecount from it). If you were using a #define IMGUI_DEBUG_LOG please rename) |
| 235 | 244 | #ifndef IMGUI_DEBUG_PRINTF |
| @@ -247,10 +256,13 @@ | ||
| 247 | 256 | #define IMGUI_DEBUG_LOG_POPUP(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) |
| 248 | 257 | #define IMGUI_DEBUG_LOG_NAV(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventNav) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) |
| 249 | 258 | #define IMGUI_DEBUG_LOG_SELECTION(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) |
| 259 | +#define IMGUI_DEBUG_LOG_TABLE(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventTable) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) | |
| 250 | 260 | #define IMGUI_DEBUG_LOG_CLIPPER(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventClipper) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) |
| 251 | 261 | #define IMGUI_DEBUG_LOG_IO(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) |
| 252 | 262 | #define IMGUI_DEBUG_LOG_FONT(...) do { ImGuiContext* g2 = GImGui; if (g2 && g2->DebugLogFlags & ImGuiDebugLogFlags_EventFont) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) // Called from ImFontAtlas function which may operate without a context. |
| 253 | 263 | #define IMGUI_DEBUG_LOG_INPUTROUTING(...) do{if (g.DebugLogFlags & ImGuiDebugLogFlags_EventInputRouting)IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) |
| 264 | +#define IMGUI_DEBUG_LOG_DOCKING(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventDocking) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) | |
| 265 | +#define IMGUI_DEBUG_LOG_VIEWPORT(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventViewport) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) | |
| 254 | 266 | |
| 255 | 267 | // Debug options (also see ones on top of imgui.cpp) |
| 256 | 268 | //#define IMGUI_DEBUG_BOXSELECT |
| @@ -321,6 +333,8 @@ | ||
| 321 | 333 | #define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xde01") |
| 322 | 334 | #elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__) |
| 323 | 335 | #define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xe7f001f0") |
| 336 | +#elif defined(__GNUC__) && defined(__aarch64__) | |
| 337 | +#define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xd4200000") // GDB needs 'set $pc=($pc+4)' to skip this :( | |
| 324 | 338 | #else |
| 325 | 339 | #define IM_DEBUG_BREAK() IM_ASSERT(0) // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger! |
| 326 | 340 | #endif |
| @@ -531,6 +545,7 @@ | ||
| 531 | 545 | inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2(ImFloor(v.x), ImFloor(v.y)); } |
| 532 | 546 | inline float ImTrunc64(float f) { return (float)(ImS64)(f); } |
| 533 | 547 | inline float ImRound64(float f) { return (float)(ImS64)(f + 0.5f); } // FIXME: Positive values only. |
| 548 | +inline float ImCeilFast(float f) { int i = (int)f; return (float)(i + (f > (float)i)); } // Consider using the the bit-hack version (search for "0x1p120f"). | |
| 534 | 549 | inline int ImModPositive(int a, int b) { return (a + b) % b; } |
| 535 | 550 | inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } |
| 536 | 551 | inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } |
| @@ -688,6 +703,8 @@ | ||
| 688 | 703 | |
| 689 | 704 | inline void set(T* data, int size) { Data = data; DataEnd = data + size; } |
| 690 | 705 | inline void set(T* data, T* data_end) { Data = data; DataEnd = data_end; } |
| 706 | + inline void clear() { Data = DataEnd = NULL; } | |
| 707 | + inline bool empty() const { return Data == DataEnd; } | |
| 691 | 708 | inline int size() const { return (int)(ptrdiff_t)(DataEnd - Data); } |
| 692 | 709 | inline int size_in_bytes() const { return (int)(ptrdiff_t)(DataEnd - Data) * (int)sizeof(T); } |
| 693 | 710 | inline T& operator[](int i) { T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } |
| @@ -872,7 +889,7 @@ | ||
| 872 | 889 | float FontSize; // Current font size (used for for simplified AddText overload) |
| 873 | 890 | float FontScale; // Current font scale (== FontSize / Font->FontSize) |
| 874 | 891 | float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() |
| 875 | - float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc | |
| 892 | + float CircleTessellationMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc | |
| 876 | 893 | float InitialFringeScale; // Initial scale to apply to AA fringe |
| 877 | 894 | ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) |
| 878 | 895 | ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() |
| @@ -1021,7 +1038,7 @@ | ||
| 1021 | 1038 | enum ImGuiHoveredFlagsPrivate_ |
| 1022 | 1039 | { |
| 1023 | 1040 | ImGuiHoveredFlags_DelayMask_ = ImGuiHoveredFlags_DelayNone | ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay, |
| 1024 | - ImGuiHoveredFlags_AllowedMaskForIsWindowHovered = ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_Stationary, | |
| 1041 | + ImGuiHoveredFlags_AllowedMaskForIsWindowHovered = ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_DockHierarchy | ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_Stationary, | |
| 1025 | 1042 | ImGuiHoveredFlags_AllowedMaskForIsItemHovered = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped | ImGuiHoveredFlags_AllowWhenDisabled | ImGuiHoveredFlags_NoNavOverride | ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayMask_, |
| 1026 | 1043 | }; |
| 1027 | 1044 | |
| @@ -1319,6 +1336,9 @@ | ||
| 1319 | 1336 | ImGuiNextWindowDataFlags_HasWindowFlags = 1 << 8, |
| 1320 | 1337 | ImGuiNextWindowDataFlags_HasChildFlags = 1 << 9, |
| 1321 | 1338 | ImGuiNextWindowDataFlags_HasRefreshPolicy = 1 << 10, |
| 1339 | + ImGuiNextWindowDataFlags_HasViewport = 1 << 11, | |
| 1340 | + ImGuiNextWindowDataFlags_HasDock = 1 << 12, | |
| 1341 | + ImGuiNextWindowDataFlags_HasWindowClass = 1 << 13, | |
| 1322 | 1342 | }; |
| 1323 | 1343 | |
| 1324 | 1344 | // Storage for SetNexWindow** functions |
| @@ -1330,6 +1350,7 @@ | ||
| 1330 | 1350 | ImGuiCond PosCond; |
| 1331 | 1351 | ImGuiCond SizeCond; |
| 1332 | 1352 | ImGuiCond CollapsedCond; |
| 1353 | + ImGuiCond DockCond; | |
| 1333 | 1354 | ImVec2 PosVal; |
| 1334 | 1355 | ImVec2 PosPivotVal; |
| 1335 | 1356 | ImVec2 SizeVal; |
| @@ -1337,11 +1358,15 @@ | ||
| 1337 | 1358 | ImVec2 ScrollVal; |
| 1338 | 1359 | ImGuiWindowFlags WindowFlags; // Only honored by BeginTable() |
| 1339 | 1360 | ImGuiChildFlags ChildFlags; |
| 1361 | + bool PosUndock; | |
| 1340 | 1362 | bool CollapsedVal; |
| 1341 | 1363 | ImRect SizeConstraintRect; |
| 1342 | 1364 | ImGuiSizeCallback SizeCallback; |
| 1343 | 1365 | void* SizeCallbackUserData; |
| 1344 | 1366 | float BgAlphaVal; // Override background alpha |
| 1367 | + ImGuiID ViewportId; | |
| 1368 | + ImGuiID DockId; | |
| 1369 | + ImGuiWindowClass WindowClass; | |
| 1345 | 1370 | ImVec2 MenuBarOffsetMinVal; // (Always on) This is not exposed publicly, so we don't clear it and it doesn't have a corresponding flag (could we? for consistency?) |
| 1346 | 1371 | ImGuiWindowRefreshFlags RefreshFlagsVal; |
| 1347 | 1372 | |
| @@ -1527,6 +1552,7 @@ | ||
| 1527 | 1552 | ImGuiInputEventType_MousePos, |
| 1528 | 1553 | ImGuiInputEventType_MouseWheel, |
| 1529 | 1554 | ImGuiInputEventType_MouseButton, |
| 1555 | + ImGuiInputEventType_MouseViewport, | |
| 1530 | 1556 | ImGuiInputEventType_Key, |
| 1531 | 1557 | ImGuiInputEventType_Text, |
| 1532 | 1558 | ImGuiInputEventType_Focus, |
| @@ -1547,6 +1573,7 @@ | ||
| 1547 | 1573 | struct ImGuiInputEventMousePos { float PosX, PosY; ImGuiMouseSource MouseSource; }; |
| 1548 | 1574 | struct ImGuiInputEventMouseWheel { float WheelX, WheelY; ImGuiMouseSource MouseSource; }; |
| 1549 | 1575 | struct ImGuiInputEventMouseButton { int Button; bool Down; ImGuiMouseSource MouseSource; }; |
| 1576 | +struct ImGuiInputEventMouseViewport { ImGuiID HoveredViewportID; }; | |
| 1550 | 1577 | struct ImGuiInputEventKey { ImGuiKey Key; bool Down; float AnalogValue; }; |
| 1551 | 1578 | struct ImGuiInputEventText { unsigned int Char; }; |
| 1552 | 1579 | struct ImGuiInputEventAppFocused { bool Focused; }; |
| @@ -1561,6 +1588,7 @@ | ||
| 1561 | 1588 | ImGuiInputEventMousePos MousePos; // if Type == ImGuiInputEventType_MousePos |
| 1562 | 1589 | ImGuiInputEventMouseWheel MouseWheel; // if Type == ImGuiInputEventType_MouseWheel |
| 1563 | 1590 | ImGuiInputEventMouseButton MouseButton; // if Type == ImGuiInputEventType_MouseButton |
| 1591 | + ImGuiInputEventMouseViewport MouseViewport; // if Type == ImGuiInputEventType_MouseViewport | |
| 1564 | 1592 | ImGuiInputEventKey Key; // if Type == ImGuiInputEventType_Key |
| 1565 | 1593 | ImGuiInputEventText Text; // if Type == ImGuiInputEventType_Text |
| 1566 | 1594 | ImGuiInputEventAppFocused AppFocused; // if Type == ImGuiInputEventType_Focus |
| @@ -1702,6 +1730,7 @@ | ||
| 1702 | 1730 | }; |
| 1703 | 1731 | |
| 1704 | 1732 | // Early work-in-progress API for ScrollToItem() |
| 1733 | +// FIXME: Missing flags to request making both edges visible when possible. | |
| 1705 | 1734 | enum ImGuiScrollFlags_ |
| 1706 | 1735 | { |
| 1707 | 1736 | ImGuiScrollFlags_None = 0, |
| @@ -1721,8 +1750,8 @@ | ||
| 1721 | 1750 | ImGuiNavRenderCursorFlags_None = 0, |
| 1722 | 1751 | ImGuiNavRenderCursorFlags_Compact = 1 << 1, // Compact highlight, no padding/distance from focused item |
| 1723 | 1752 | ImGuiNavRenderCursorFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) even when g.NavCursorVisible == false, aka even when using the mouse. |
| 1724 | - ImGuiNavRenderCursorFlags_NoRounding = 1 << 3, | |
| 1725 | 1753 | #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS |
| 1754 | + ImGuiNavRenderCursorFlags_NoRounding = 1 << 3, | |
| 1726 | 1755 | ImGuiNavHighlightFlags_None = ImGuiNavRenderCursorFlags_None, // Renamed in 1.91.4 |
| 1727 | 1756 | ImGuiNavHighlightFlags_Compact = ImGuiNavRenderCursorFlags_Compact, // Renamed in 1.91.4 |
| 1728 | 1757 | ImGuiNavHighlightFlags_AlwaysDraw = ImGuiNavRenderCursorFlags_AlwaysDraw, // Renamed in 1.91.4 |
| @@ -1958,8 +1987,156 @@ | ||
| 1958 | 1987 | // [SECTION] Docking support |
| 1959 | 1988 | //----------------------------------------------------------------------------- |
| 1960 | 1989 | |
| 1990 | +#define DOCKING_HOST_DRAW_CHANNEL_BG 0 // Dock host: background fill | |
| 1991 | +#define DOCKING_HOST_DRAW_CHANNEL_FG 1 // Dock host: decorations and contents | |
| 1992 | + | |
| 1961 | 1993 | #ifdef IMGUI_HAS_DOCK |
| 1962 | -// <this is filled in 'docking' branch> | |
| 1994 | + | |
| 1995 | +// Extend ImGuiDockNodeFlags_ | |
| 1996 | +enum ImGuiDockNodeFlagsPrivate_ | |
| 1997 | +{ | |
| 1998 | + // [Internal] | |
| 1999 | + ImGuiDockNodeFlags_DockSpace = 1 << 10, // Saved // A dockspace is a node that occupy space within an existing user window. Otherwise the node is floating and create its own window. | |
| 2000 | + ImGuiDockNodeFlags_CentralNode = 1 << 11, // Saved // The central node has 2 main properties: stay visible when empty, only use "remaining" spaces from its neighbor. | |
| 2001 | + ImGuiDockNodeFlags_NoTabBar = 1 << 12, // Saved // Tab bar is completely unavailable. No triangle in the corner to enable it back. | |
| 2002 | + ImGuiDockNodeFlags_HiddenTabBar = 1 << 13, // Saved // Tab bar is hidden, with a triangle in the corner to show it again (NB: actual tab-bar instance may be destroyed as this is only used for single-window tab bar) | |
| 2003 | + ImGuiDockNodeFlags_NoWindowMenuButton = 1 << 14, // Saved // Disable window/docking menu (that one that appears instead of the collapse button) | |
| 2004 | + ImGuiDockNodeFlags_NoCloseButton = 1 << 15, // Saved // Disable close button | |
| 2005 | + ImGuiDockNodeFlags_NoResizeX = 1 << 16, // // | |
| 2006 | + ImGuiDockNodeFlags_NoResizeY = 1 << 17, // // | |
| 2007 | + ImGuiDockNodeFlags_DockedWindowsInFocusRoute= 1 << 18, // // Any docked window will be automatically be focus-route chained (window->ParentWindowForFocusRoute set to this) so Shortcut() in this window can run when any docked window is focused. | |
| 2008 | + | |
| 2009 | + // Disable docking/undocking actions in this dockspace or individual node (existing docked nodes will be preserved) | |
| 2010 | + // Those are not exposed in public because the desirable sharing/inheriting/copy-flag-on-split behaviors are quite difficult to design and understand. | |
| 2011 | + // The two public flags ImGuiDockNodeFlags_NoDockingOverCentralNode/ImGuiDockNodeFlags_NoDockingSplit don't have those issues. | |
| 2012 | + ImGuiDockNodeFlags_NoDockingSplitOther = 1 << 19, // // Disable this node from splitting other windows/nodes. | |
| 2013 | + ImGuiDockNodeFlags_NoDockingOverMe = 1 << 20, // // Disable other windows/nodes from being docked over this node. | |
| 2014 | + ImGuiDockNodeFlags_NoDockingOverOther = 1 << 21, // // Disable this node from being docked over another window or non-empty node. | |
| 2015 | + ImGuiDockNodeFlags_NoDockingOverEmpty = 1 << 22, // // Disable this node from being docked over an empty node (e.g. DockSpace with no other windows) | |
| 2016 | + ImGuiDockNodeFlags_NoDocking = ImGuiDockNodeFlags_NoDockingOverMe | ImGuiDockNodeFlags_NoDockingOverOther | ImGuiDockNodeFlags_NoDockingOverEmpty | ImGuiDockNodeFlags_NoDockingSplit | ImGuiDockNodeFlags_NoDockingSplitOther, | |
| 2017 | + | |
| 2018 | + // Masks | |
| 2019 | + ImGuiDockNodeFlags_SharedFlagsInheritMask_ = ~0, | |
| 2020 | + ImGuiDockNodeFlags_NoResizeFlagsMask_ = (int)ImGuiDockNodeFlags_NoResize | ImGuiDockNodeFlags_NoResizeX | ImGuiDockNodeFlags_NoResizeY, | |
| 2021 | + | |
| 2022 | + // When splitting, those local flags are moved to the inheriting child, never duplicated | |
| 2023 | + ImGuiDockNodeFlags_LocalFlagsTransferMask_ = (int)ImGuiDockNodeFlags_NoDockingSplit | ImGuiDockNodeFlags_NoResizeFlagsMask_ | (int)ImGuiDockNodeFlags_AutoHideTabBar | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar | ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_NoCloseButton, | |
| 2024 | + ImGuiDockNodeFlags_SavedFlagsMask_ = ImGuiDockNodeFlags_NoResizeFlagsMask_ | ImGuiDockNodeFlags_DockSpace | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar | ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_NoCloseButton, | |
| 2025 | +}; | |
| 2026 | + | |
| 2027 | +// Store the source authority (dock node vs window) of a field | |
| 2028 | +enum ImGuiDataAuthority_ | |
| 2029 | +{ | |
| 2030 | + ImGuiDataAuthority_Auto, | |
| 2031 | + ImGuiDataAuthority_DockNode, | |
| 2032 | + ImGuiDataAuthority_Window, | |
| 2033 | +}; | |
| 2034 | + | |
| 2035 | +enum ImGuiDockNodeState | |
| 2036 | +{ | |
| 2037 | + ImGuiDockNodeState_Unknown, | |
| 2038 | + ImGuiDockNodeState_HostWindowHiddenBecauseSingleWindow, | |
| 2039 | + ImGuiDockNodeState_HostWindowHiddenBecauseWindowsAreResizing, | |
| 2040 | + ImGuiDockNodeState_HostWindowVisible, | |
| 2041 | +}; | |
| 2042 | + | |
| 2043 | +// sizeof() 176~216 | |
| 2044 | +struct IMGUI_API ImGuiDockNode | |
| 2045 | +{ | |
| 2046 | + ImGuiID ID; | |
| 2047 | + ImGuiDockNodeFlags SharedFlags; // (Write) Flags shared by all nodes of a same dockspace hierarchy (inherited from the root node) | |
| 2048 | + ImGuiDockNodeFlags LocalFlags; // (Write) Flags specific to this node | |
| 2049 | + ImGuiDockNodeFlags LocalFlagsInWindows; // (Write) Flags specific to this node, applied from windows | |
| 2050 | + ImGuiDockNodeFlags MergedFlags; // (Read) Effective flags (== SharedFlags | LocalFlagsInNode | LocalFlagsInWindows) | |
| 2051 | + ImGuiDockNodeState State; | |
| 2052 | + ImGuiDockNode* ParentNode; | |
| 2053 | + ImGuiDockNode* ChildNodes[2]; // [Split node only] Child nodes (left/right or top/bottom). Consider switching to an array. | |
| 2054 | + ImVector<ImGuiWindow*> Windows; // Note: unordered list! Iterate TabBar->Tabs for user-order. | |
| 2055 | + ImGuiTabBar* TabBar; | |
| 2056 | + ImVec2 Pos; // Current position | |
| 2057 | + ImVec2 Size; // Current size | |
| 2058 | + ImVec2 SizeRef; // [Split node only] Last explicitly written-to size (overridden when using a splitter affecting the node), used to calculate Size. | |
| 2059 | + ImGuiAxis SplitAxis; // [Split node only] Split axis (X or Y) | |
| 2060 | + ImU32 LastBgColor; | |
| 2061 | + ImGuiWindowClass WindowClass; // [Root node only] | |
| 2062 | + | |
| 2063 | + ImGuiWindow* HostWindow; | |
| 2064 | + ImGuiWindow* VisibleWindow; // Generally point to window which is ID is == SelectedTabID, but when CTRL+Tabbing this can be a different window. | |
| 2065 | + ImGuiDockNode* CentralNode; // [Root node only] Pointer to central node. | |
| 2066 | + ImGuiDockNode* OnlyNodeWithWindows; // [Root node only] Set when there is a single visible node within the hierarchy. | |
| 2067 | + int CountNodeWithWindows; // [Root node only] | |
| 2068 | + int LastFrameAlive; // Last frame number the node was updated or kept alive explicitly with DockSpace() + ImGuiDockNodeFlags_KeepAliveOnly | |
| 2069 | + int LastFrameActive; // Last frame number the node was updated. | |
| 2070 | + int LastFrameFocused; // Last frame number the node was focused. | |
| 2071 | + ImGuiID LastFocusedNodeId; // [Root node only] Which of our child docking node (any ancestor in the hierarchy) was last focused. | |
| 2072 | + ImGuiID SelectedTabId; // [Leaf node only] Which of our tab/window is selected. | |
| 2073 | + ImGuiID WantCloseTabId; // [Leaf node only] Set when closing a specific tab/window. | |
| 2074 | + ImGuiID RefViewportId; // Reference viewport ID from visible window when HostWindow == NULL. | |
| 2075 | + ImGuiDataAuthority AuthorityForPos :3; | |
| 2076 | + ImGuiDataAuthority AuthorityForSize :3; | |
| 2077 | + ImGuiDataAuthority AuthorityForViewport :3; | |
| 2078 | + bool IsVisible :1; // Set to false when the node is hidden (usually disabled as it has no active window) | |
| 2079 | + bool IsFocused :1; | |
| 2080 | + bool IsBgDrawnThisFrame :1; | |
| 2081 | + bool HasCloseButton :1; // Provide space for a close button (if any of the docked window has one). Note that button may be hidden on window without one. | |
| 2082 | + bool HasWindowMenuButton :1; | |
| 2083 | + bool HasCentralNodeChild :1; | |
| 2084 | + bool WantCloseAll :1; // Set when closing all tabs at once. | |
| 2085 | + bool WantLockSizeOnce :1; | |
| 2086 | + bool WantMouseMove :1; // After a node extraction we need to transition toward moving the newly created host window | |
| 2087 | + bool WantHiddenTabBarUpdate :1; | |
| 2088 | + bool WantHiddenTabBarToggle :1; | |
| 2089 | + | |
| 2090 | + ImGuiDockNode(ImGuiID id); | |
| 2091 | + ~ImGuiDockNode(); | |
| 2092 | + bool IsRootNode() const { return ParentNode == NULL; } | |
| 2093 | + bool IsDockSpace() const { return (MergedFlags & ImGuiDockNodeFlags_DockSpace) != 0; } | |
| 2094 | + bool IsFloatingNode() const { return ParentNode == NULL && (MergedFlags & ImGuiDockNodeFlags_DockSpace) == 0; } | |
| 2095 | + bool IsCentralNode() const { return (MergedFlags & ImGuiDockNodeFlags_CentralNode) != 0; } | |
| 2096 | + bool IsHiddenTabBar() const { return (MergedFlags & ImGuiDockNodeFlags_HiddenTabBar) != 0; } // Hidden tab bar can be shown back by clicking the small triangle | |
| 2097 | + bool IsNoTabBar() const { return (MergedFlags & ImGuiDockNodeFlags_NoTabBar) != 0; } // Never show a tab bar | |
| 2098 | + bool IsSplitNode() const { return ChildNodes[0] != NULL; } | |
| 2099 | + bool IsLeafNode() const { return ChildNodes[0] == NULL; } | |
| 2100 | + bool IsEmpty() const { return ChildNodes[0] == NULL && Windows.Size == 0; } | |
| 2101 | + ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } | |
| 2102 | + | |
| 2103 | + void SetLocalFlags(ImGuiDockNodeFlags flags) { LocalFlags = flags; UpdateMergedFlags(); } | |
| 2104 | + void UpdateMergedFlags() { MergedFlags = SharedFlags | LocalFlags | LocalFlagsInWindows; } | |
| 2105 | +}; | |
| 2106 | + | |
| 2107 | +// List of colors that are stored at the time of Begin() into Docked Windows. | |
| 2108 | +// We currently store the packed colors in a simple array window->DockStyle.Colors[]. | |
| 2109 | +// A better solution may involve appending into a log of colors in ImGuiContext + store offsets into those arrays in ImGuiWindow, | |
| 2110 | +// but it would be more complex as we'd need to double-buffer both as e.g. drop target may refer to window from last frame. | |
| 2111 | +enum ImGuiWindowDockStyleCol | |
| 2112 | +{ | |
| 2113 | + ImGuiWindowDockStyleCol_Text, | |
| 2114 | + ImGuiWindowDockStyleCol_TabHovered, | |
| 2115 | + ImGuiWindowDockStyleCol_TabFocused, | |
| 2116 | + ImGuiWindowDockStyleCol_TabSelected, | |
| 2117 | + ImGuiWindowDockStyleCol_TabSelectedOverline, | |
| 2118 | + ImGuiWindowDockStyleCol_TabDimmed, | |
| 2119 | + ImGuiWindowDockStyleCol_TabDimmedSelected, | |
| 2120 | + ImGuiWindowDockStyleCol_TabDimmedSelectedOverline, | |
| 2121 | + ImGuiWindowDockStyleCol_UnsavedMarker, | |
| 2122 | + ImGuiWindowDockStyleCol_COUNT | |
| 2123 | +}; | |
| 2124 | + | |
| 2125 | +// We don't store style.Alpha: dock_node->LastBgColor embeds it and otherwise it would only affect the docking tab, which intuitively I would say we don't want to. | |
| 2126 | +struct ImGuiWindowDockStyle | |
| 2127 | +{ | |
| 2128 | + ImU32 Colors[ImGuiWindowDockStyleCol_COUNT]; | |
| 2129 | +}; | |
| 2130 | + | |
| 2131 | +struct ImGuiDockContext | |
| 2132 | +{ | |
| 2133 | + ImGuiStorage Nodes; // Map ID -> ImGuiDockNode*: Active nodes | |
| 2134 | + ImVector<ImGuiDockRequest> Requests; | |
| 2135 | + ImVector<ImGuiDockNodeSettings> NodesSettings; | |
| 2136 | + bool WantFullRebuild; | |
| 2137 | + ImGuiDockContext() { memset((void*)this, 0, sizeof(*this)); } | |
| 2138 | +}; | |
| 2139 | + | |
| 1963 | 2140 | #endif // #ifdef IMGUI_HAS_DOCK |
| 1964 | 2141 | |
| 1965 | 2142 | //----------------------------------------------------------------------------- |
| @@ -1970,10 +2147,24 @@ | ||
| 1970 | 2147 | // Every instance of ImGuiViewport is in fact a ImGuiViewportP. |
| 1971 | 2148 | struct ImGuiViewportP : public ImGuiViewport |
| 1972 | 2149 | { |
| 2150 | + ImGuiWindow* Window; // Set when the viewport is owned by a window (and ImGuiViewportFlags_CanHostOtherWindows is NOT set) | |
| 2151 | + int Idx; | |
| 2152 | + int LastFrameActive; // Last frame number this viewport was activated by a window | |
| 2153 | + int LastFocusedStampCount; // Last stamp number from when a window hosted by this viewport was focused (by comparing this value between two viewport we have an implicit viewport z-order we use as fallback) | |
| 2154 | + ImGuiID LastNameHash; | |
| 2155 | + ImVec2 LastPos; | |
| 2156 | + ImVec2 LastSize; | |
| 2157 | + float Alpha; // Window opacity (when dragging dockable windows/viewports we make them transparent) | |
| 2158 | + float LastAlpha; | |
| 2159 | + bool LastFocusedHadNavWindow;// Instead of maintaining a LastFocusedWindow (which may harder to correctly maintain), we merely store weither NavWindow != NULL last time the viewport was focused. | |
| 2160 | + short PlatformMonitor; | |
| 1973 | 2161 | float BgFgDrawListsLastTimeActive[2]; // Last frame number the background (0) and foreground (1) draw lists were used |
| 1974 | 2162 | ImDrawList* BgFgDrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays. |
| 1975 | 2163 | ImDrawData DrawDataP; |
| 1976 | 2164 | ImDrawDataBuilder DrawDataBuilder; // Temporary data while building final ImDrawData |
| 2165 | + ImVec2 LastPlatformPos; | |
| 2166 | + ImVec2 LastPlatformSize; | |
| 2167 | + ImVec2 LastRendererSize; | |
| 1977 | 2168 | |
| 1978 | 2169 | // Per-viewport work area |
| 1979 | 2170 | // - Insets are >= 0.0f values, distance from viewport corners to work area. |
| @@ -1984,8 +2175,9 @@ | ||
| 1984 | 2175 | ImVec2 BuildWorkInsetMin; // Work Area inset accumulator for current frame, to become next frame's WorkInset |
| 1985 | 2176 | ImVec2 BuildWorkInsetMax; // " |
| 1986 | 2177 | |
| 1987 | - ImGuiViewportP() { BgFgDrawListsLastTimeActive[0] = BgFgDrawListsLastTimeActive[1] = -1.0f; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; } | |
| 1988 | - ~ImGuiViewportP() { if (BgFgDrawLists[0]) IM_DELETE(BgFgDrawLists[0]); if (BgFgDrawLists[1]) IM_DELETE(BgFgDrawLists[1]); } | |
| 2178 | + ImGuiViewportP() { Window = NULL; Idx = -1; LastFrameActive = LastFocusedStampCount = -1; BgFgDrawListsLastTimeActive[0] = BgFgDrawListsLastTimeActive[1] = -1.0f; LastNameHash = 0; Alpha = LastAlpha = 1.0f; LastFocusedHadNavWindow = false; PlatformMonitor = -1; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; LastPlatformPos = LastPlatformSize = LastRendererSize = ImVec2(FLT_MAX, FLT_MAX); } | |
| 2179 | + ~ImGuiViewportP() { if (BgFgDrawLists[0]) IM_DELETE(BgFgDrawLists[0]); if (BgFgDrawLists[1]) IM_DELETE(BgFgDrawLists[1]); } | |
| 2180 | + void ClearRequestFlags() { PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; } | |
| 1989 | 2181 | |
| 1990 | 2182 | // Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect) |
| 1991 | 2183 | ImVec2 CalcWorkRectPos(const ImVec2& inset_min) const { return ImVec2(Pos.x + inset_min.x, Pos.y + inset_min.y); } |
| @@ -2008,14 +2200,19 @@ | ||
| 2008 | 2200 | struct ImGuiWindowSettings |
| 2009 | 2201 | { |
| 2010 | 2202 | ImGuiID ID; |
| 2011 | - ImVec2ih Pos; | |
| 2203 | + ImVec2ih Pos; // NB: Settings position are stored RELATIVE to the viewport! Whereas runtime ones are absolute positions. | |
| 2012 | 2204 | ImVec2ih Size; |
| 2205 | + ImVec2ih ViewportPos; | |
| 2206 | + ImGuiID ViewportId; | |
| 2207 | + ImGuiID DockId; // ID of last known DockNode (even if the DockNode is invisible because it has only 1 active window), or 0 if none. | |
| 2208 | + ImGuiID ClassId; // ID of window class if specified | |
| 2209 | + short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible. | |
| 2013 | 2210 | bool Collapsed; |
| 2014 | 2211 | bool IsChild; |
| 2015 | 2212 | bool WantApply; // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context) |
| 2016 | 2213 | bool WantDelete; // Set to invalidate/delete the settings entry |
| 2017 | 2214 | |
| 2018 | - ImGuiWindowSettings() { memset((void*)this, 0, sizeof(*this)); } | |
| 2215 | + ImGuiWindowSettings() { memset((void*)this, 0, sizeof(*this)); DockOrder = -1; } | |
| 2019 | 2216 | char* GetName() { return (char*)(this + 1); } |
| 2020 | 2217 | }; |
| 2021 | 2218 | |
| @@ -2045,12 +2242,18 @@ | ||
| 2045 | 2242 | ImGuiLocKey_TableSizeOne, |
| 2046 | 2243 | ImGuiLocKey_TableSizeAllFit, |
| 2047 | 2244 | ImGuiLocKey_TableSizeAllDefault, |
| 2245 | + ImGuiLocKey_TableReset, | |
| 2246 | + //ImGuiLocKey_TableResetAll, | |
| 2048 | 2247 | ImGuiLocKey_TableResetOrder, |
| 2248 | + ImGuiLocKey_TableResetVisibility, | |
| 2049 | 2249 | ImGuiLocKey_WindowingMainMenuBar, |
| 2050 | 2250 | ImGuiLocKey_WindowingPopup, |
| 2051 | 2251 | ImGuiLocKey_WindowingUntitled, |
| 2052 | 2252 | ImGuiLocKey_OpenLink_s, |
| 2053 | 2253 | ImGuiLocKey_CopyLink, |
| 2254 | + ImGuiLocKey_DockingHideTabBar, | |
| 2255 | + ImGuiLocKey_DockingHoldShiftToDock, | |
| 2256 | + ImGuiLocKey_DockingDragToUndockOrMoveNode, | |
| 2054 | 2257 | ImGuiLocKey_COUNT |
| 2055 | 2258 | }; |
| 2056 | 2259 | |
| @@ -2097,10 +2300,11 @@ | ||
| 2097 | 2300 | ImGuiDebugLogFlags_EventIO = 1 << 7, |
| 2098 | 2301 | ImGuiDebugLogFlags_EventFont = 1 << 8, |
| 2099 | 2302 | ImGuiDebugLogFlags_EventInputRouting = 1 << 9, |
| 2100 | - ImGuiDebugLogFlags_EventDocking = 1 << 10, // Unused in this branch | |
| 2101 | - ImGuiDebugLogFlags_EventViewport = 1 << 11, // Unused in this branch | |
| 2303 | + ImGuiDebugLogFlags_EventDocking = 1 << 10, | |
| 2304 | + ImGuiDebugLogFlags_EventViewport = 1 << 11, | |
| 2305 | + ImGuiDebugLogFlags_EventTable = 1 << 12, | |
| 2102 | 2306 | |
| 2103 | - ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventIO | ImGuiDebugLogFlags_EventFont | ImGuiDebugLogFlags_EventInputRouting | ImGuiDebugLogFlags_EventDocking | ImGuiDebugLogFlags_EventViewport, | |
| 2307 | + ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventTable | ImGuiDebugLogFlags_EventIO | ImGuiDebugLogFlags_EventFont | ImGuiDebugLogFlags_EventInputRouting | ImGuiDebugLogFlags_EventDocking | ImGuiDebugLogFlags_EventViewport, | |
| 2104 | 2308 | ImGuiDebugLogFlags_OutputToTTY = 1 << 20, // Also send output to TTY |
| 2105 | 2309 | ImGuiDebugLogFlags_OutputToDebugger = 1 << 21, // Also send output to Debugger Console [Windows only] |
| 2106 | 2310 | ImGuiDebugLogFlags_OutputToTestEngine = 1 << 22, // Also send output to Dear ImGui Test Engine |
| @@ -2134,6 +2338,7 @@ | ||
| 2134 | 2338 | bool ShowDrawCmdBoundingBoxes = true; |
| 2135 | 2339 | bool ShowTextEncodingViewer = false; |
| 2136 | 2340 | bool ShowTextureUsedRect = false; |
| 2341 | + bool ShowDockingNodes = false; | |
| 2137 | 2342 | int ShowWindowsRectsType = -1; |
| 2138 | 2343 | int ShowTablesRectsType = -1; |
| 2139 | 2344 | int HighlightMonitorIdx = -1; |
| @@ -2208,12 +2413,15 @@ | ||
| 2208 | 2413 | bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log() |
| 2209 | 2414 | int FrameCount; |
| 2210 | 2415 | int FrameCountEnded; |
| 2416 | + int FrameCountPlatformEnded; | |
| 2211 | 2417 | int FrameCountRendered; |
| 2212 | 2418 | double Time; |
| 2213 | 2419 | char ContextName[16]; // Storage for a context name (to facilitate debugging multi-context setups) |
| 2214 | 2420 | ImGuiIO IO; |
| 2215 | 2421 | ImGuiPlatformIO PlatformIO; |
| 2216 | 2422 | ImGuiStyle Style; |
| 2423 | + ImGuiConfigFlags ConfigFlagsCurrFrame; // = g.IO.ConfigFlags at the time of NewFrame() | |
| 2424 | + ImGuiConfigFlags ConfigFlagsLastFrame; | |
| 2217 | 2425 | ImVector<ImFontAtlas*> FontAtlases; // List of font atlases used by the context (generally only contains g.IO.Fonts aka the main font atlas) |
| 2218 | 2426 | ImFont* Font; // Currently bound font. (== FontStack.back().Font) |
| 2219 | 2427 | ImFontBaked* FontBaked; // Currently bound font at currently bound size. (== Font->GetFontBaked(FontSize)) |
| @@ -2246,7 +2454,7 @@ | ||
| 2246 | 2454 | ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs. |
| 2247 | 2455 | ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set. |
| 2248 | 2456 | ImGuiWindow* HoveredWindowBeforeClear; // Window the mouse is hovering. Filled even with _NoMouse. This is currently useful for multi-context compositors. |
| 2249 | - ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow. | |
| 2457 | + ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindowDockTree. | |
| 2250 | 2458 | ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window. |
| 2251 | 2459 | ImVec2 WheelingWindowRefMousePos; |
| 2252 | 2460 | int WheelingWindowStartFrame; // This may be set one frame before WheelingWindow is != NULL |
| @@ -2325,7 +2533,16 @@ | ||
| 2325 | 2533 | ImVector<ImGuiTreeNodeStackData>TreeNodeStack; // Stack for TreeNode() |
| 2326 | 2534 | |
| 2327 | 2535 | // Viewports |
| 2328 | - ImVector<ImGuiViewportP*> Viewports; // Active viewports (Size==1 in 'master' branch). Each viewports hold their copy of ImDrawData. | |
| 2536 | + ImVector<ImGuiViewportP*> Viewports; // Active viewports (always 1+, and generally 1 unless multi-viewports are enabled). Each viewports hold their copy of ImDrawData. | |
| 2537 | + ImGuiViewportP* CurrentViewport; // We track changes of viewport (happening in Begin) so we can call Platform_OnChangedViewport() | |
| 2538 | + ImGuiViewportP* MouseViewport; | |
| 2539 | + ImGuiViewportP* MouseLastHoveredViewport; // Last known viewport that was hovered by mouse (even if we are not hovering any viewport any more) + honoring the _NoInputs flag. | |
| 2540 | + ImGuiID PlatformLastFocusedViewportId; | |
| 2541 | + ImGuiPlatformMonitor FallbackMonitor; // Virtual monitor used as fallback if backend doesn't provide monitor information. | |
| 2542 | + ImRect PlatformMonitorsFullWorkRect; // Bounding box of all platform monitors | |
| 2543 | + int ViewportCreatedCount; // Unique sequential creation counter (mostly for testing/debugging) | |
| 2544 | + int PlatformWindowsCreatedCount; // Unique sequential creation counter (mostly for testing/debugging) | |
| 2545 | + int ViewportFocusedStampCount; // Every time the front-most window changes, we stamp its viewport with an incrementing counter | |
| 2329 | 2546 | |
| 2330 | 2547 | // Keyboard/Gamepad Navigation |
| 2331 | 2548 | bool NavCursorVisible; // Nav focus cursor/rectangle is visible? We hide it after a mouse click. We show it after a nav move. |
| @@ -2515,6 +2732,8 @@ | ||
| 2515 | 2732 | // Extensions |
| 2516 | 2733 | // FIXME: We could provide an API to register one slot in an array held in ImGuiContext? |
| 2517 | 2734 | ImVector<ImTextureData*> UserTextures; // List of textures created/managed by user or third-party extension. Automatically appended into platform_io.Textures[]. |
| 2735 | + ImGuiDockContext DockContext; | |
| 2736 | + void (*DockNodeWindowMenuHandler)(ImGuiContext* ctx, ImGuiDockNode* node, ImGuiTabBar* tab_bar); | |
| 2518 | 2737 | |
| 2519 | 2738 | // Settings |
| 2520 | 2739 | bool SettingsLoaded; |
| @@ -2577,6 +2796,7 @@ | ||
| 2577 | 2796 | ImGuiDebugItemPathQuery DebugItemPathQuery; |
| 2578 | 2797 | ImGuiIDStackTool DebugIDStackTool; |
| 2579 | 2798 | ImGuiDebugAllocInfo DebugAllocInfo; |
| 2799 | + ImGuiDockNode* DebugHoveredDockNode; // Hovered dock node. | |
| 2580 | 2800 | #if defined(IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS) && !defined(IMGUI_DISABLE_DEBUG_TOOLS) |
| 2581 | 2801 | ImGuiStorage DebugDrawIdConflictsAliveCount; |
| 2582 | 2802 | ImGuiStorage DebugDrawIdConflictsHighlightSet; |
| @@ -2647,8 +2867,12 @@ | ||
| 2647 | 2867 | ImGuiLayoutType LayoutType; |
| 2648 | 2868 | ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin() |
| 2649 | 2869 | ImU32 ModalDimBgColor; |
| 2870 | + | |
| 2871 | + // Status flags | |
| 2650 | 2872 | ImGuiItemStatusFlags WindowItemStatusFlags; |
| 2651 | 2873 | ImGuiItemStatusFlags ChildItemStatusFlags; |
| 2874 | + ImGuiItemStatusFlags DockTabItemStatusFlags; | |
| 2875 | + ImRect DockTabItemRect; | |
| 2652 | 2876 | |
| 2653 | 2877 | // Local parameters stacks |
| 2654 | 2878 | // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. |
| @@ -2665,9 +2889,13 @@ | ||
| 2665 | 2889 | ImGuiContext* Ctx; // Parent UI context (needs to be set explicitly by parent). |
| 2666 | 2890 | char* Name; // Window name, owned by the window. |
| 2667 | 2891 | ImGuiID ID; // == ImHashStr(Name) |
| 2668 | - ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_ | |
| 2892 | + ImGuiWindowFlags Flags, FlagsPreviousFrame; // See enum ImGuiWindowFlags_ | |
| 2669 | 2893 | ImGuiChildFlags ChildFlags; // Set when window is a child window. See enum ImGuiChildFlags_ |
| 2894 | + ImGuiWindowClass WindowClass; // Advanced users only. Set with SetNextWindowClass() | |
| 2670 | 2895 | ImGuiViewportP* Viewport; // Always set in Begin(). Inactive windows may have a NULL value here if their viewport was discarded. |
| 2896 | + ImGuiID ViewportId; // We backup the viewport id (since the viewport may disappear or never be created if the window is inactive) | |
| 2897 | + ImVec2 ViewportPos; // We backup the viewport position (since the viewport may disappear or never be created if the window is inactive) | |
| 2898 | + int ViewportAllowPlatformMonitorExtend; // Reset to -1 every frame (index is guaranteed to be valid between NewFrame..EndFrame), only used in the Appearing frame of a tooltip/popup to enforce clamping to a given monitor | |
| 2671 | 2899 | ImVec2 Pos; // Position (always rounded-up to nearest pixel) |
| 2672 | 2900 | ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) |
| 2673 | 2901 | ImVec2 SizeFull; // Size when non collapsed |
| @@ -2683,6 +2911,7 @@ | ||
| 2683 | 2911 | float DecoInnerSizeX1, DecoInnerSizeY1; // Applied AFTER/OVER InnerRect. Specialized for Tables as they use specialized form of clipping and frozen rows/columns are inside InnerRect (and not part of regular decoration sizes). |
| 2684 | 2912 | int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)! |
| 2685 | 2913 | ImGuiID MoveId; // == window->GetID("#MOVE") |
| 2914 | + ImGuiID TabId; // == window->GetID("#TAB") | |
| 2686 | 2915 | ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window) |
| 2687 | 2916 | ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling) |
| 2688 | 2917 | ImVec2 Scroll; |
| @@ -2694,6 +2923,7 @@ | ||
| 2694 | 2923 | bool ScrollbarX, ScrollbarY; // Are scrollbars visible? |
| 2695 | 2924 | bool ScrollbarXStabilizeEnabled; // Was ScrollbarX previously auto-stabilized? |
| 2696 | 2925 | ImU8 ScrollbarXStabilizeToggledHistory; // Used to stabilize scrollbar visibility in case of feedback loops |
| 2926 | + bool ViewportOwned; | |
| 2697 | 2927 | bool Active; // Set to true on Begin(), unless Collapsed |
| 2698 | 2928 | bool WasActive; |
| 2699 | 2929 | bool WriteAccessed; // Set to true when any widget access the current window |
| @@ -2724,6 +2954,7 @@ | ||
| 2724 | 2954 | ImGuiCond SetWindowPosAllowFlags : 8; // store acceptable condition flags for SetNextWindowPos() use. |
| 2725 | 2955 | ImGuiCond SetWindowSizeAllowFlags : 8; // store acceptable condition flags for SetNextWindowSize() use. |
| 2726 | 2956 | ImGuiCond SetWindowCollapsedAllowFlags : 8; // store acceptable condition flags for SetNextWindowCollapsed() use. |
| 2957 | + ImGuiCond SetWindowDockAllowFlags : 8; // store acceptable condition flags for SetNextWindowDock() use. | |
| 2727 | 2958 | ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size) |
| 2728 | 2959 | ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0, 0) when positioning from top-left corner; ImVec2(0.5f, 0.5f) for centering; ImVec2(1, 1) for bottom right. |
| 2729 | 2960 | |
| @@ -2743,6 +2974,7 @@ | ||
| 2743 | 2974 | ImVec2ih HitTestHoleOffset; |
| 2744 | 2975 | |
| 2745 | 2976 | int LastFrameActive; // Last frame number the window was Active. |
| 2977 | + int LastFrameJustFocused; // Last frame number the window was made Focused. | |
| 2746 | 2978 | float LastTimeActive; // Last timestamp the window was Active (using float as we don't need high precision there) |
| 2747 | 2979 | ImGuiStorage StateStorage; |
| 2748 | 2980 | ImVector<ImGuiOldColumns> ColumnsStorage; |
| @@ -2757,6 +2989,7 @@ | ||
| 2757 | 2989 | ImGuiWindow* ParentWindowInBeginStack; |
| 2758 | 2990 | ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window. Doesn't cross through popups/dock nodes. |
| 2759 | 2991 | ImGuiWindow* RootWindowPopupTree; // Point to ourself or first ancestor that is not a child window. Cross through popups parent<>child. |
| 2992 | + ImGuiWindow* RootWindowDockTree; // Point to ourself or first ancestor that is not a child window. Cross through dock nodes. | |
| 2760 | 2993 | ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active. |
| 2761 | 2994 | ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag. |
| 2762 | 2995 | ImGuiWindow* ParentWindowForFocusRoute; // Set to manual link a window to its logical parent so that Shortcut() chain are honored (e.g. Tool linked to Document) |
| @@ -2771,6 +3004,17 @@ | ||
| 2771 | 3004 | int MemoryDrawListVtxCapacity; |
| 2772 | 3005 | bool MemoryCompacted; // Set when window extraneous data have been garbage collected |
| 2773 | 3006 | |
| 3007 | + // Docking | |
| 3008 | + bool DockIsActive :1; // When docking artifacts are actually visible. When this is set, DockNode is guaranteed to be != NULL. ~~ (DockNode != NULL) && (DockNode->Windows.Size > 1). | |
| 3009 | + bool DockNodeIsVisible :1; | |
| 3010 | + bool DockTabIsVisible :1; // Is our window visible this frame? ~~ is the corresponding tab selected? | |
| 3011 | + bool DockTabWantClose :1; | |
| 3012 | + short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible. | |
| 3013 | + ImGuiWindowDockStyle DockStyle; | |
| 3014 | + ImGuiDockNode* DockNode; // Which node are we docked into. Important: Prefer testing DockIsActive in many cases as this will still be set when the dock node is hidden. | |
| 3015 | + ImGuiDockNode* DockNodeAsHost; // Which node are we owning (for parent windows) | |
| 3016 | + ImGuiID DockId; // Backup of last valid DockNode->ID, so single window remember their dock node id even when they are not bound any more | |
| 3017 | + | |
| 2774 | 3018 | public: |
| 2775 | 3019 | ImGuiWindow(ImGuiContext* context, const char* name); |
| 2776 | 3020 | ~ImGuiWindow(); |
| @@ -2787,7 +3031,7 @@ | ||
| 2787 | 3031 | ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight; return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight); } |
| 2788 | 3032 | |
| 2789 | 3033 | // [OBSOLETE] ImGuiWindow::CalcFontSize() was removed in 1.92.0 because error-prone/misleading. You can use window->FontRefSize for a copy of g.FontSize at the time of the last Begin() call for this window. |
| 2790 | - //float CalcFontSize() const { ImGuiContext& g = *Ctx; return g.FontSizeBase * FontWindowScale * FontWindowScaleParents; | |
| 3034 | + //float CalcFontSize() const { ImGuiContext& g = *Ctx; return g.FontSizeBase * FontWindowScale * FontDpiScale * FontWindowScaleParents; | |
| 2791 | 3035 | }; |
| 2792 | 3036 | |
| 2793 | 3037 | //----------------------------------------------------------------------------- |
| @@ -2809,14 +3053,15 @@ | ||
| 2809 | 3053 | ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout) |
| 2810 | 3054 | ImGuiTabItemFlags_Button = 1 << 21, // Used by TabItemButton, change the tab item behavior to mimic a button |
| 2811 | 3055 | ImGuiTabItemFlags_Invisible = 1 << 22, // To reserve space e.g. with ImGuiTabItemFlags_Leading |
| 2812 | - //ImGuiTabItemFlags_Unsorted = 1 << 23, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. | |
| 3056 | + ImGuiTabItemFlags_Unsorted = 1 << 23, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. | |
| 2813 | 3057 | }; |
| 2814 | 3058 | |
| 2815 | -// Storage for one active tab item (sizeof() 40 bytes) | |
| 3059 | +// Storage for one active tab item (sizeof() 48 bytes) | |
| 2816 | 3060 | struct ImGuiTabItem |
| 2817 | 3061 | { |
| 2818 | 3062 | ImGuiID ID; |
| 2819 | 3063 | ImGuiTabItemFlags Flags; |
| 3064 | + ImGuiWindow* Window; // When TabItem is part of a DockNode's TabBar, we hold on to a window. | |
| 2820 | 3065 | int LastFrameVisible; |
| 2821 | 3066 | int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance |
| 2822 | 3067 | float Offset; // Position relative to beginning of tab bar |
| @@ -2876,13 +3121,13 @@ | ||
| 2876 | 3121 | }; |
| 2877 | 3122 | |
| 2878 | 3123 | //----------------------------------------------------------------------------- |
| 2879 | -// [SECTION] Table support | |
| 3124 | +// [SECTION] Table support + internal API | |
| 2880 | 3125 | //----------------------------------------------------------------------------- |
| 2881 | 3126 | |
| 2882 | 3127 | #define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color. |
| 2883 | 3128 | #define IMGUI_TABLE_MAX_COLUMNS 512 // Arbitrary "safety" maximum, may be lifted in the future if needed. Must fit in ImGuiTableColumnIdx/ImGuiTableDrawChannelIdx. |
| 2884 | 3129 | |
| 2885 | -// [Internal] sizeof() ~ 112 | |
| 3130 | +// [Internal] sizeof() ~ 120 | |
| 2886 | 3131 | // We use the terminology "Enabled" to refer to a column that is not Hidden by user/api. |
| 2887 | 3132 | // We use the terminology "Clipped" to refer to a column that is out of sight because of scrolling/clipping. |
| 2888 | 3133 | // This is in contrast with some user-facing api such as IsItemVisible() / IsRectVisible() which use "Visible" to mean "not clipped". |
| @@ -2898,7 +3143,8 @@ | ||
| 2898 | 3143 | float StretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially. |
| 2899 | 3144 | float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_). |
| 2900 | 3145 | ImRect ClipRect; // Clipping rectangle for the column |
| 2901 | - ImGuiID UserID; // Optional, value passed to TableSetupColumn() | |
| 3146 | + ImGuiID ID; // Hash of column name (ignoring top of ID stack), used for .ini persistence when available. | |
| 3147 | + ImGuiID UserData; // (Optional) User data value passed to TableSetupColumn() | |
| 2902 | 3148 | float WorkMinX; // Contents region min ~(MinX + CellPaddingX + CellSpacingX1) == cursor start position when entering column |
| 2903 | 3149 | float WorkMaxX; // Contents region max ~(MaxX - CellPaddingX - CellSpacingX2) |
| 2904 | 3150 | float ItemWidth; // Current item width for the column, preserved across rows |
| @@ -2922,10 +3168,14 @@ | ||
| 2922 | 3168 | bool IsVisibleY; |
| 2923 | 3169 | bool IsRequestOutput; // Return value for TableSetColumnIndex() / TableNextColumn(): whether we request user to output contents or not. |
| 2924 | 3170 | bool IsSkipItems; // Do we want item submissions to this column to be completely ignored (no layout will happen). |
| 2925 | - bool IsPreserveWidthAuto; | |
| 3171 | + bool IsPreserveWidthAuto : 1; | |
| 3172 | + bool IsJustCreated : 1; | |
| 3173 | + bool IsLoadedSettings : 1; | |
| 3174 | + bool IsNeedReconcileSrc : 1; | |
| 3175 | + bool IsNeedReconcileDst : 1; | |
| 2926 | 3176 | ImS8 NavLayerCurrent; // ImGuiNavLayer in 1 byte |
| 2927 | - ImU8 AutoFitQueue; // Queue of 8 values for the next 8 frames to request auto-fit | |
| 2928 | - ImU8 CannotSkipItemsQueue; // Queue of 8 values for the next 8 frames to disable Clipped/SkipItem | |
| 3177 | + ImU8 AutoFitQueue : 4; // Queue of 4 values for the next 4 frames to request auto-fit | |
| 3178 | + ImU8 CannotSkipItemsQueue : 4; // Queue of 4 values for the next 4 frames to disable Clipped/SkipItem | |
| 2929 | 3179 | ImU8 SortDirection : 2; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending |
| 2930 | 3180 | ImU8 SortDirectionsAvailCount : 2; // Number of available sort directions (0 to 3) |
| 2931 | 3181 | ImU8 SortDirectionsAvailMask : 4; // Mask of available sort directions (1-bit each) |
| @@ -2940,10 +3190,28 @@ | ||
| 2940 | 3190 | PrevEnabledColumn = NextEnabledColumn = -1; |
| 2941 | 3191 | SortOrder = -1; |
| 2942 | 3192 | SortDirection = ImGuiSortDirection_None; |
| 3193 | + IsJustCreated = true; | |
| 2943 | 3194 | DrawChannelCurrent = DrawChannelFrozen = DrawChannelUnfrozen = (ImU8)-1; |
| 2944 | 3195 | } |
| 2945 | 3196 | }; |
| 2946 | 3197 | |
| 3198 | +// Passed to TableSetupColumn() | |
| 3199 | +// sizeof() ~ 24+120 bytes | |
| 3200 | +struct ImGuiTableReconcileColumnData | |
| 3201 | +{ | |
| 3202 | + // Setup data | |
| 3203 | + ImGuiID ID; | |
| 3204 | + ImS16 NameOffset; | |
| 3205 | + ImGuiTableColumnFlags Flags; | |
| 3206 | + float InitWidthOrWeight; | |
| 3207 | + ImGuiID UserData; | |
| 3208 | + | |
| 3209 | + // Reconcile data | |
| 3210 | + ImGuiTableColumnIdx ColumnNewIdx; // Index in the current table. | |
| 3211 | + ImGuiTableColumnIdx ColumnOldIdx; // Index in the previous frame table. | |
| 3212 | + ImGuiTableColumn ColumnOldData; // Full backup of the column. Could be avoided by storing 1 of them and applying reconcile in the right order. Not worth bothering. | |
| 3213 | +}; | |
| 3214 | + | |
| 2947 | 3215 | // Transient cell data stored per row. |
| 2948 | 3216 | // sizeof() ~ 6 bytes |
| 2949 | 3217 | struct ImGuiTableCellData |
| @@ -3077,6 +3345,7 @@ | ||
| 3077 | 3345 | bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row. |
| 3078 | 3346 | bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow(). |
| 3079 | 3347 | bool IsInitializing; |
| 3348 | + bool IsReconcileMode; | |
| 3080 | 3349 | bool IsSortSpecsDirty; |
| 3081 | 3350 | bool IsUsingHeaders; // Set when the first row had the ImGuiTableRowFlags_Headers flag. |
| 3082 | 3351 | bool IsContextPopupOpen; // Set when default context menu is open (also see: ContextPopupColumn, InstanceInteracted). |
| @@ -3084,8 +3353,10 @@ | ||
| 3084 | 3353 | bool IsSettingsRequestLoad; |
| 3085 | 3354 | bool IsSettingsDirty; // Set when table settings have changed and needs to be reported into ImGuiTableSettings data. |
| 3086 | 3355 | bool IsDefaultDisplayOrder; // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1) |
| 3087 | - bool IsResetAllRequest; | |
| 3356 | + bool IsDefaultVisibility; // Set when enabled/visibility is unchanged from default | |
| 3357 | + bool IsResetAllRequest; // Set to queue a call to TableResetSettings() in BeginTable() | |
| 3088 | 3358 | bool IsResetDisplayOrderRequest; |
| 3359 | + bool IsResetVisibilityRequest; | |
| 3089 | 3360 | bool IsUnfrozenRows; // Set when we got past the frozen row. |
| 3090 | 3361 | bool IsDefaultSizingPolicy; // Set if user didn't explicitly set a sizing policy in BeginTable() |
| 3091 | 3362 | bool IsActiveIdAliveBeforeTable; |
| @@ -3103,15 +3374,20 @@ | ||
| 3103 | 3374 | // - Accessing those requires chasing an extra pointer so for very frequently used data we leave them in the main table structure. |
| 3104 | 3375 | // - We also leave out of this structure data that tend to be particularly useful for debugging/metrics. |
| 3105 | 3376 | // FIXME-TABLE: more transient data could be stored in a stacked ImGuiTableTempData: e.g. SortSpecs. |
| 3106 | -// sizeof() ~ 136 bytes. | |
| 3377 | +// sizeof() ~ 176 bytes. | |
| 3107 | 3378 | struct IMGUI_API ImGuiTableTempData |
| 3108 | 3379 | { |
| 3109 | 3380 | ImGuiID WindowID; // Shortcut to g.Tables[TableIndex]->OuterWindow->ID. |
| 3110 | 3381 | int TableIndex; // Index in g.Tables.Buf[] pool |
| 3111 | 3382 | float LastTimeActive; // Last timestamp this structure was used |
| 3112 | 3383 | float AngledHeadersExtraWidth; // Used in EndTable() |
| 3113 | - ImVector<ImGuiTableHeaderData> AngledHeadersRequests; // Used in TableAngledHeadersRow() | |
| 3384 | + ImVector<ImGuiTableHeaderData> AngledHeadersRequests; // Used in TableAngledHeadersRow() // FIXME: Single instance is enough? | |
| 3114 | 3385 | |
| 3386 | + // Topology change | |
| 3387 | + ImVector<ImGuiTableReconcileColumnData> ReconcileColumnsRequests; // Used in TableSetupColumn(), TableUpdateLayout(). Cleared every frame. | |
| 3388 | + void* OldColumnsRawData; // Used in BeginTable() -> TableUpdateLayout() when resizing. | |
| 3389 | + ImSpan<ImGuiTableColumn> OldColumnsData; | |
| 3390 | + | |
| 3115 | 3391 | ImVec2 UserOuterSize; // outer_size.x passed to BeginTable() |
| 3116 | 3392 | ImDrawListSplitter DrawSplitter; |
| 3117 | 3393 | |
| @@ -3131,23 +3407,25 @@ | ||
| 3131 | 3407 | struct ImGuiTableColumnSettings |
| 3132 | 3408 | { |
| 3133 | 3409 | float WidthOrWeight; |
| 3134 | - ImGuiID UserID; | |
| 3410 | + ImGuiID ID; | |
| 3135 | 3411 | ImGuiTableColumnIdx Index; |
| 3136 | 3412 | ImGuiTableColumnIdx DisplayOrder; |
| 3137 | 3413 | ImGuiTableColumnIdx SortOrder; |
| 3138 | 3414 | ImU8 SortDirection : 2; |
| 3139 | - ImS8 IsEnabled : 2; // "Visible" in ini file | |
| 3415 | + ImS8 IsEnabled : 2; // "Visible" in .ini file | |
| 3140 | 3416 | ImU8 IsStretch : 1; |
| 3417 | + bool IsLoaded : 1; // Using during loading to mark finding a matching column. | |
| 3141 | 3418 | |
| 3142 | 3419 | ImGuiTableColumnSettings() |
| 3143 | 3420 | { |
| 3144 | 3421 | WidthOrWeight = 0.0f; |
| 3145 | - UserID = 0; | |
| 3422 | + ID = 0; | |
| 3146 | 3423 | Index = -1; |
| 3147 | 3424 | DisplayOrder = SortOrder = -1; |
| 3148 | 3425 | SortDirection = ImGuiSortDirection_None; |
| 3149 | 3426 | IsEnabled = -1; |
| 3150 | 3427 | IsStretch = 0; |
| 3428 | + IsLoaded = false; | |
| 3151 | 3429 | } |
| 3152 | 3430 | }; |
| 3153 | 3431 | |
| @@ -3165,6 +3443,87 @@ | ||
| 3165 | 3443 | ImGuiTableColumnSettings* GetColumnSettings() { return (ImGuiTableColumnSettings*)(this + 1); } |
| 3166 | 3444 | }; |
| 3167 | 3445 | |
| 3446 | +namespace ImGui | |
| 3447 | +{ | |
| 3448 | + // Tables: Candidates for public API | |
| 3449 | + IMGUI_API void TableOpenContextMenu(int column_n = -1); | |
| 3450 | + IMGUI_API void TableSetColumnWidth(int column_n, float width); | |
| 3451 | + IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs); | |
| 3452 | + IMGUI_API int TableGetHoveredRow(); // Retrieve *PREVIOUS FRAME* hovered row. This difference with TableGetHoveredColumn() is the reason why this is not public yet. | |
| 3453 | + IMGUI_API float TableGetHeaderRowHeight(); | |
| 3454 | + IMGUI_API float TableGetHeaderAngledMaxLabelWidth(); | |
| 3455 | + IMGUI_API void TablePushBackgroundChannel(); | |
| 3456 | + IMGUI_API void TablePopBackgroundChannel(); | |
| 3457 | + IMGUI_API void TablePushColumnChannel(int column_n); | |
| 3458 | + IMGUI_API void TablePopColumnChannel(); | |
| 3459 | + IMGUI_API void TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label_width, const ImGuiTableHeaderData* data, int data_count); | |
| 3460 | + | |
| 3461 | + // Tables: Internals | |
| 3462 | + inline ImGuiTable* GetCurrentTable() { ImGuiContext& g = *GImGui; return g.CurrentTable; } | |
| 3463 | + IMGUI_API ImGuiTable* TableFindByID(ImGuiID id); | |
| 3464 | + IMGUI_API bool BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f); | |
| 3465 | + IMGUI_API void TableBeginInitMemory(ImGuiTable* table, int columns_count); | |
| 3466 | + IMGUI_API void TableApplyQueuedRequests(ImGuiTable* table); | |
| 3467 | + IMGUI_API void TableSetupDrawChannels(ImGuiTable* table); | |
| 3468 | + IMGUI_API void TableReconcileColumns(ImGuiTable* table); | |
| 3469 | + IMGUI_API void TableUpdateLayout(ImGuiTable* table); | |
| 3470 | + IMGUI_API void TableUpdateBorders(ImGuiTable* table); | |
| 3471 | + IMGUI_API void TableUpdateColumnsWeightFromWidth(ImGuiTable* table); | |
| 3472 | + IMGUI_API void TableApplyExternalUnclipRect(ImGuiTable* table, ImRect& rect); | |
| 3473 | + IMGUI_API void TableDrawBorders(ImGuiTable* table); | |
| 3474 | + IMGUI_API void TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags_for_section_to_display); | |
| 3475 | + IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table); | |
| 3476 | + IMGUI_API void TableMergeDrawChannels(ImGuiTable* table); | |
| 3477 | + inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; } | |
| 3478 | + inline ImGuiID TableGetInstanceID(ImGuiTable* table, int instance_no) { return TableGetInstanceData(table, instance_no)->TableInstanceID; } | |
| 3479 | + IMGUI_API void TableFixDisplayOrder(ImGuiTable* table); | |
| 3480 | + IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); | |
| 3481 | + IMGUI_API void TableSortSpecsBuild(ImGuiTable* table); | |
| 3482 | + IMGUI_API void TableInitColumnDefaults(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags init_mask); | |
| 3483 | + IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column); | |
| 3484 | + IMGUI_API void TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column); | |
| 3485 | + IMGUI_API float TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column); | |
| 3486 | + IMGUI_API void TableBeginRow(ImGuiTable* table); | |
| 3487 | + IMGUI_API void TableEndRow(ImGuiTable* table); | |
| 3488 | + IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n); | |
| 3489 | + IMGUI_API void TableEndCell(ImGuiTable* table); | |
| 3490 | + IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n); | |
| 3491 | + IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n); | |
| 3492 | + IMGUI_API ImGuiID TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no = 0); | |
| 3493 | + IMGUI_API float TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n); | |
| 3494 | + IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); | |
| 3495 | + IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); | |
| 3496 | + IMGUI_API void TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order); | |
| 3497 | + IMGUI_API void TableQueueSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order); | |
| 3498 | + IMGUI_API void TableRemove(ImGuiTable* table); | |
| 3499 | + IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table); | |
| 3500 | + IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table); | |
| 3501 | + IMGUI_API void TableGcCompactSettings(); | |
| 3502 | + | |
| 3503 | + // Tables: Settings | |
| 3504 | + IMGUI_API void TableLoadSettings(ImGuiTable* table); | |
| 3505 | + IMGUI_API void TableLoadSettingsForColumns(ImGuiTable* table); | |
| 3506 | + IMGUI_API void TableLoadSettingsForColumn(ImGuiTableColumn* column, ImGuiTableColumnSettings* column_settings, ImGuiTableFlags load_flags); | |
| 3507 | + IMGUI_API void TableSaveSettings(ImGuiTable* table); | |
| 3508 | + IMGUI_API void TableResetSettings(ImGuiTable* table); | |
| 3509 | + IMGUI_API ImGuiTableSettings* TableGetBoundSettings(ImGuiTable* table); | |
| 3510 | + IMGUI_API void TableSettingsAddSettingsHandler(); | |
| 3511 | + IMGUI_API ImGuiTableSettings* TableSettingsCreate(ImGuiID id, int columns_count); | |
| 3512 | + IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id); | |
| 3513 | + | |
| 3514 | + // Legacy Columns API (this is not exposed because we will encourage transitioning to the Tables API) | |
| 3515 | + IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect); | |
| 3516 | + IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiOldColumnFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). | |
| 3517 | + IMGUI_API void EndColumns(); // close columns | |
| 3518 | + IMGUI_API void PushColumnClipRect(int column_index); | |
| 3519 | + IMGUI_API void PushColumnsBackground(); | |
| 3520 | + IMGUI_API void PopColumnsBackground(); | |
| 3521 | + IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count); | |
| 3522 | + IMGUI_API ImGuiOldColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id); | |
| 3523 | + IMGUI_API float GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm); | |
| 3524 | + IMGUI_API float GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset); | |
| 3525 | +} | |
| 3526 | + | |
| 3168 | 3527 | //----------------------------------------------------------------------------- |
| 3169 | 3528 | // [SECTION] ImGui internal API |
| 3170 | 3529 | // No guarantee of forward compatibility here! |
| @@ -3187,7 +3546,7 @@ | ||
| 3187 | 3546 | IMGUI_API void UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window); |
| 3188 | 3547 | IMGUI_API void UpdateWindowSkipRefresh(ImGuiWindow* window); |
| 3189 | 3548 | IMGUI_API ImVec2 CalcWindowNextAutoFitSize(ImGuiWindow* window); |
| 3190 | - IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy); | |
| 3549 | + IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy, bool dock_hierarchy); | |
| 3191 | 3550 | IMGUI_API bool IsWindowInBeginStack(ImGuiWindow* window); |
| 3192 | 3551 | IMGUI_API bool IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent); |
| 3193 | 3552 | IMGUI_API bool IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below); |
| @@ -3197,7 +3556,7 @@ | ||
| 3197 | 3556 | IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0); |
| 3198 | 3557 | IMGUI_API void SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size); |
| 3199 | 3558 | IMGUI_API void SetWindowHiddenAndSkipItemsForCurrentFrame(ImGuiWindow* window); |
| 3200 | - inline void SetWindowParentWindowForFocusRoute(ImGuiWindow* window, ImGuiWindow* parent_window) { window->ParentWindowForFocusRoute = parent_window; } | |
| 3559 | + inline void SetWindowParentWindowForFocusRoute(ImGuiWindow* window, ImGuiWindow* parent_window) { window->ParentWindowForFocusRoute = parent_window; } // You may also use SetNextWindowClass()'s FocusRouteParentWindowId field. | |
| 3201 | 3560 | inline ImRect WindowRectAbsToRel(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x - off.x, r.Min.y - off.y, r.Max.x - off.x, r.Max.y - off.y); } |
| 3202 | 3561 | inline ImRect WindowRectRelToAbs(ImGuiWindow* window, const ImRect& r) { ImVec2 off = window->DC.CursorStartPos; return ImRect(r.Min.x + off.x, r.Min.y + off.y, r.Max.x + off.x, r.Max.y + off.y); } |
| 3203 | 3562 | inline ImVec2 WindowPosAbsToRel(ImGuiWindow* window, const ImVec2& p) { ImVec2 off = window->DC.CursorStartPos; return ImVec2(p.x - off.x, p.y - off.y); } |
| @@ -3229,9 +3588,7 @@ | ||
| 3229 | 3588 | IMGUI_API ImFont* GetDefaultFont(); |
| 3230 | 3589 | IMGUI_API void PushPasswordFont(); |
| 3231 | 3590 | IMGUI_API void PopPasswordFont(); |
| 3232 | - inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. | |
| 3233 | - IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport); // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. | |
| 3234 | - IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport); // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. | |
| 3591 | + inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { return GetForegroundDrawList(window->Viewport); } | |
| 3235 | 3592 | IMGUI_API void AddDrawListToDrawDataEx(ImDrawData* draw_data, ImVector<ImDrawList*>* out_list, ImDrawList* draw_list); |
| 3236 | 3593 | |
| 3237 | 3594 | // Init |
| @@ -3249,14 +3606,19 @@ | ||
| 3249 | 3606 | IMGUI_API void UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos); |
| 3250 | 3607 | IMGUI_API void FindHoveredWindowEx(const ImVec2& pos, bool find_first_and_in_any_viewport, ImGuiWindow** out_hovered_window, ImGuiWindow** out_hovered_window_under_moving_window); |
| 3251 | 3608 | IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); |
| 3609 | + IMGUI_API void StartMouseMovingWindowOrNode(ImGuiWindow* window, ImGuiDockNode* node, bool undock); | |
| 3252 | 3610 | IMGUI_API void StopMouseMovingWindow(); |
| 3253 | 3611 | IMGUI_API void UpdateMouseMovingWindowNewFrame(); |
| 3254 | 3612 | IMGUI_API void UpdateMouseMovingWindowEndFrame(); |
| 3255 | 3613 | |
| 3256 | 3614 | // Viewports |
| 3257 | - inline ImGuiViewport* GetWindowViewport() { return GetMainViewport(); } // For code consistency. This is public API in docking branch. | |
| 3615 | + IMGUI_API void TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos, const ImVec2& old_size, const ImVec2& new_size); | |
| 3258 | 3616 | IMGUI_API void ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale); |
| 3617 | + IMGUI_API void DestroyPlatformWindow(ImGuiViewportP* viewport); | |
| 3259 | 3618 | IMGUI_API void SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport); |
| 3619 | + IMGUI_API void SetCurrentViewport(ImGuiWindow* window, ImGuiViewportP* viewport); | |
| 3620 | + IMGUI_API const ImGuiPlatformMonitor* GetViewportPlatformMonitor(ImGuiViewport* viewport); | |
| 3621 | + IMGUI_API ImGuiViewportP* FindHoveredViewportFromPlatformWindowStack(const ImVec2& mouse_platform_pos); | |
| 3260 | 3622 | |
| 3261 | 3623 | // Settings |
| 3262 | 3624 | IMGUI_API void MarkIniSettingsDirty(); |
| @@ -3476,6 +3838,61 @@ | ||
| 3476 | 3838 | IMGUI_API bool TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id); |
| 3477 | 3839 | IMGUI_API ImGuiKeyRoutingData* GetShortcutRoutingData(ImGuiKeyChord key_chord); |
| 3478 | 3840 | |
| 3841 | + // Docking | |
| 3842 | + // (some functions are only declared in imgui.cpp, see Docking section) | |
| 3843 | + IMGUI_API void DockContextInitialize(ImGuiContext* ctx); | |
| 3844 | + IMGUI_API void DockContextShutdown(ImGuiContext* ctx); | |
| 3845 | + IMGUI_API void DockContextClearNodes(ImGuiContext* ctx, ImGuiID root_id, bool clear_settings_refs); // Use root_id==0 to clear all | |
| 3846 | + IMGUI_API void DockContextRebuildNodes(ImGuiContext* ctx); | |
| 3847 | + IMGUI_API void DockContextNewFrameUpdateUndocking(ImGuiContext* ctx); | |
| 3848 | + IMGUI_API void DockContextNewFrameUpdateDocking(ImGuiContext* ctx); | |
| 3849 | + IMGUI_API void DockContextEndFrame(ImGuiContext* ctx); | |
| 3850 | + IMGUI_API ImGuiID DockContextGenNodeID(ImGuiContext* ctx); | |
| 3851 | + IMGUI_API void DockContextQueueDock(ImGuiContext* ctx, ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload, ImGuiDir split_dir, float split_ratio, bool split_outer); | |
| 3852 | + IMGUI_API void DockContextQueueUndockWindow(ImGuiContext* ctx, ImGuiWindow* window); | |
| 3853 | + IMGUI_API void DockContextQueueUndockNode(ImGuiContext* ctx, ImGuiDockNode* node); | |
| 3854 | + IMGUI_API void DockContextProcessUndockWindow(ImGuiContext* ctx, ImGuiWindow* window, bool clear_persistent_docking_ref = true); | |
| 3855 | + IMGUI_API void DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node); | |
| 3856 | + IMGUI_API bool DockContextCalcDropPosForDocking(ImGuiWindow* target, ImGuiDockNode* target_node, ImGuiWindow* payload_window, ImGuiDockNode* payload_node, ImGuiDir split_dir, bool split_outer, ImVec2* out_pos); | |
| 3857 | + IMGUI_API ImGuiDockNode*DockContextFindNodeByID(ImGuiContext* ctx, ImGuiID id); | |
| 3858 | + IMGUI_API void DockNodeWindowMenuHandler_Default(ImGuiContext* ctx, ImGuiDockNode* node, ImGuiTabBar* tab_bar); | |
| 3859 | + IMGUI_API bool DockNodeBeginAmendTabBar(ImGuiDockNode* node); | |
| 3860 | + IMGUI_API void DockNodeEndAmendTabBar(); | |
| 3861 | + inline ImGuiDockNode* DockNodeGetRootNode(ImGuiDockNode* node) { while (node->ParentNode) node = node->ParentNode; return node; } | |
| 3862 | + inline bool DockNodeIsInHierarchyOf(ImGuiDockNode* node, ImGuiDockNode* parent) { while (node) { if (node == parent) return true; node = node->ParentNode; } return false; } | |
| 3863 | + inline int DockNodeGetDepth(const ImGuiDockNode* node) { int depth = 0; while (node->ParentNode) { node = node->ParentNode; depth++; } return depth; } | |
| 3864 | + inline ImGuiID DockNodeGetWindowMenuButtonId(const ImGuiDockNode* node) { return ImHashStr("#COLLAPSE", 0, node->ID); } | |
| 3865 | + inline ImGuiDockNode* GetWindowDockNode() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DockNode; } | |
| 3866 | + IMGUI_API bool GetWindowAlwaysWantOwnTabBar(ImGuiWindow* window); | |
| 3867 | + IMGUI_API void BeginDocked(ImGuiWindow* window, bool* p_open); | |
| 3868 | + IMGUI_API void BeginDockableDragDropSource(ImGuiWindow* window); | |
| 3869 | + IMGUI_API void BeginDockableDragDropTarget(ImGuiWindow* window); | |
| 3870 | + IMGUI_API void SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond); | |
| 3871 | + | |
| 3872 | + // Docking - Builder function needs to be generally called before the node is used/submitted. | |
| 3873 | + // - The DockBuilderXXX functions are designed to _eventually_ become a public API, but it is too early to expose it and guarantee stability. | |
| 3874 | + // - Do not hold on ImGuiDockNode* pointers! They may be invalidated by any split/merge/remove operation and every frame. | |
| 3875 | + // - To create a DockSpace() node, make sure to set the ImGuiDockNodeFlags_DockSpace flag when calling DockBuilderAddNode(). | |
| 3876 | + // You can create dockspace nodes (attached to a window) _or_ floating nodes (carry its own window) with this API. | |
| 3877 | + // - DockBuilderSplitNode() create 2 child nodes within 1 node. The initial node becomes a parent node. | |
| 3878 | + // - If you intend to split the node immediately after creation using DockBuilderSplitNode(), make sure | |
| 3879 | + // to call DockBuilderSetNodeSize() beforehand. If you don't, the resulting split sizes may not be reliable. | |
| 3880 | + // - Call DockBuilderFinish() after you are done. | |
| 3881 | + IMGUI_API void DockBuilderDockWindow(const char* window_name, ImGuiID node_id); | |
| 3882 | + IMGUI_API ImGuiDockNode*DockBuilderGetNode(ImGuiID node_id); | |
| 3883 | + inline ImGuiDockNode* DockBuilderGetCentralNode(ImGuiID node_id) { ImGuiDockNode* node = DockBuilderGetNode(node_id); if (!node) return NULL; return DockNodeGetRootNode(node)->CentralNode; } | |
| 3884 | + IMGUI_API ImGuiID DockBuilderAddNode(ImGuiID node_id = 0, ImGuiDockNodeFlags flags = 0); | |
| 3885 | + IMGUI_API void DockBuilderRemoveNode(ImGuiID node_id); // Remove node and all its child, undock all windows | |
| 3886 | + IMGUI_API void DockBuilderRemoveNodeDockedWindows(ImGuiID node_id, bool clear_settings_refs = true); | |
| 3887 | + IMGUI_API void DockBuilderRemoveNodeChildNodes(ImGuiID node_id); // Remove all split/hierarchy. All remaining docked windows will be re-docked to the remaining root node (node_id). | |
| 3888 | + IMGUI_API void DockBuilderSetNodePos(ImGuiID node_id, ImVec2 pos); | |
| 3889 | + IMGUI_API void DockBuilderSetNodeSize(ImGuiID node_id, ImVec2 size); | |
| 3890 | + IMGUI_API ImGuiID DockBuilderSplitNode(ImGuiID node_id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_at_dir, ImGuiID* out_id_at_opposite_dir); // Create 2 child nodes in this parent node. | |
| 3891 | + IMGUI_API void DockBuilderCopyDockSpace(ImGuiID src_dockspace_id, ImGuiID dst_dockspace_id, ImVector<const char*>* in_window_remap_pairs); | |
| 3892 | + IMGUI_API void DockBuilderCopyNode(ImGuiID src_node_id, ImGuiID dst_node_id, ImVector<ImGuiID>* out_node_remap_pairs); | |
| 3893 | + IMGUI_API void DockBuilderCopyWindowSettings(const char* src_name, const char* dst_name); | |
| 3894 | + IMGUI_API void DockBuilderFinish(ImGuiID node_id); | |
| 3895 | + | |
| 3479 | 3896 | // [EXPERIMENTAL] Focus Scope |
| 3480 | 3897 | // This is generally used to identify a unique input location (for e.g. a selection set) |
| 3481 | 3898 | // There is one per window (automatically set in Begin), but: |
| @@ -3512,86 +3929,12 @@ | ||
| 3512 | 3929 | |
| 3513 | 3930 | // Multi-Select API |
| 3514 | 3931 | IMGUI_API void MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags* p_button_flags); |
| 3515 | - IMGUI_API void MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed); | |
| 3932 | + IMGUI_API void MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed, ImGuiMultiSelectFlags extra_flags = 0); | |
| 3516 | 3933 | IMGUI_API void MultiSelectAddSetAll(ImGuiMultiSelectTempData* ms, bool selected); |
| 3517 | 3934 | IMGUI_API void MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, int range_dir, ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item); |
| 3518 | 3935 | inline ImGuiBoxSelectState* GetBoxSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.BoxSelectState.ID == id && g.BoxSelectState.IsActive) ? &g.BoxSelectState : NULL; } |
| 3519 | 3936 | inline ImGuiMultiSelectState* GetMultiSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return g.MultiSelectStorage.GetByKey(id); } |
| 3520 | 3937 | |
| 3521 | - // Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API) | |
| 3522 | - IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect); | |
| 3523 | - IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiOldColumnFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). | |
| 3524 | - IMGUI_API void EndColumns(); // close columns | |
| 3525 | - IMGUI_API void PushColumnClipRect(int column_index); | |
| 3526 | - IMGUI_API void PushColumnsBackground(); | |
| 3527 | - IMGUI_API void PopColumnsBackground(); | |
| 3528 | - IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count); | |
| 3529 | - IMGUI_API ImGuiOldColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id); | |
| 3530 | - IMGUI_API float GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm); | |
| 3531 | - IMGUI_API float GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset); | |
| 3532 | - | |
| 3533 | - // Tables: Candidates for public API | |
| 3534 | - IMGUI_API void TableOpenContextMenu(int column_n = -1); | |
| 3535 | - IMGUI_API void TableSetColumnWidth(int column_n, float width); | |
| 3536 | - IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs); | |
| 3537 | - IMGUI_API int TableGetHoveredRow(); // Retrieve *PREVIOUS FRAME* hovered row. This difference with TableGetHoveredColumn() is the reason why this is not public yet. | |
| 3538 | - IMGUI_API float TableGetHeaderRowHeight(); | |
| 3539 | - IMGUI_API float TableGetHeaderAngledMaxLabelWidth(); | |
| 3540 | - IMGUI_API void TablePushBackgroundChannel(); | |
| 3541 | - IMGUI_API void TablePopBackgroundChannel(); | |
| 3542 | - IMGUI_API void TablePushColumnChannel(int column_n); | |
| 3543 | - IMGUI_API void TablePopColumnChannel(); | |
| 3544 | - IMGUI_API void TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label_width, const ImGuiTableHeaderData* data, int data_count); | |
| 3545 | - | |
| 3546 | - // Tables: Internals | |
| 3547 | - inline ImGuiTable* GetCurrentTable() { ImGuiContext& g = *GImGui; return g.CurrentTable; } | |
| 3548 | - IMGUI_API ImGuiTable* TableFindByID(ImGuiID id); | |
| 3549 | - IMGUI_API bool BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f); | |
| 3550 | - IMGUI_API void TableBeginInitMemory(ImGuiTable* table, int columns_count); | |
| 3551 | - IMGUI_API void TableBeginApplyRequests(ImGuiTable* table); | |
| 3552 | - IMGUI_API void TableSetupDrawChannels(ImGuiTable* table); | |
| 3553 | - IMGUI_API void TableUpdateLayout(ImGuiTable* table); | |
| 3554 | - IMGUI_API void TableUpdateBorders(ImGuiTable* table); | |
| 3555 | - IMGUI_API void TableUpdateColumnsWeightFromWidth(ImGuiTable* table); | |
| 3556 | - IMGUI_API void TableApplyExternalUnclipRect(ImGuiTable* table, ImRect& rect); | |
| 3557 | - IMGUI_API void TableDrawBorders(ImGuiTable* table); | |
| 3558 | - IMGUI_API void TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags_for_section_to_display); | |
| 3559 | - IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table); | |
| 3560 | - IMGUI_API void TableMergeDrawChannels(ImGuiTable* table); | |
| 3561 | - inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; } | |
| 3562 | - inline ImGuiID TableGetInstanceID(ImGuiTable* table, int instance_no) { return TableGetInstanceData(table, instance_no)->TableInstanceID; } | |
| 3563 | - IMGUI_API void TableFixDisplayOrder(ImGuiTable* table); | |
| 3564 | - IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); | |
| 3565 | - IMGUI_API void TableSortSpecsBuild(ImGuiTable* table); | |
| 3566 | - IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column); | |
| 3567 | - IMGUI_API void TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column); | |
| 3568 | - IMGUI_API float TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column); | |
| 3569 | - IMGUI_API void TableBeginRow(ImGuiTable* table); | |
| 3570 | - IMGUI_API void TableEndRow(ImGuiTable* table); | |
| 3571 | - IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n); | |
| 3572 | - IMGUI_API void TableEndCell(ImGuiTable* table); | |
| 3573 | - IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n); | |
| 3574 | - IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n); | |
| 3575 | - IMGUI_API ImGuiID TableGetColumnResizeID(ImGuiTable* table, int column_n, int instance_no = 0); | |
| 3576 | - IMGUI_API float TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n); | |
| 3577 | - IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); | |
| 3578 | - IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); | |
| 3579 | - IMGUI_API void TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order); | |
| 3580 | - IMGUI_API void TableQueueSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order); | |
| 3581 | - IMGUI_API void TableRemove(ImGuiTable* table); | |
| 3582 | - IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table); | |
| 3583 | - IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table); | |
| 3584 | - IMGUI_API void TableGcCompactSettings(); | |
| 3585 | - | |
| 3586 | - // Tables: Settings | |
| 3587 | - IMGUI_API void TableLoadSettings(ImGuiTable* table); | |
| 3588 | - IMGUI_API void TableSaveSettings(ImGuiTable* table); | |
| 3589 | - IMGUI_API void TableResetSettings(ImGuiTable* table); | |
| 3590 | - IMGUI_API ImGuiTableSettings* TableGetBoundSettings(ImGuiTable* table); | |
| 3591 | - IMGUI_API void TableSettingsAddSettingsHandler(); | |
| 3592 | - IMGUI_API ImGuiTableSettings* TableSettingsCreate(ImGuiID id, int columns_count); | |
| 3593 | - IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id); | |
| 3594 | - | |
| 3595 | 3938 | // Tab Bars |
| 3596 | 3939 | inline ImGuiTabBar* GetCurrentTabBar() { ImGuiContext& g = *GImGui; return g.CurrentTabBar; } |
| 3597 | 3940 | IMGUI_API ImGuiTabBar* TabBarFindByID(ImGuiID id); |
| @@ -3599,9 +3942,11 @@ | ||
| 3599 | 3942 | IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags); |
| 3600 | 3943 | IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id); |
| 3601 | 3944 | IMGUI_API ImGuiTabItem* TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order); |
| 3945 | + IMGUI_API ImGuiTabItem* TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar); | |
| 3602 | 3946 | IMGUI_API ImGuiTabItem* TabBarGetCurrentTab(ImGuiTabBar* tab_bar); |
| 3603 | 3947 | inline int TabBarGetTabOrder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) { return tab_bar->Tabs.index_from_ptr(tab); } |
| 3604 | 3948 | IMGUI_API const char* TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); |
| 3949 | + IMGUI_API void TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window); | |
| 3605 | 3950 | IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id); |
| 3606 | 3951 | IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); |
| 3607 | 3952 | IMGUI_API void TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab); |
| @@ -3628,7 +3973,7 @@ | ||
| 3628 | 3973 | IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); |
| 3629 | 3974 | IMGUI_API void RenderColorComponentMarker(const ImRect& bb, ImU32 col, float rounding); |
| 3630 | 3975 | IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0); |
| 3631 | - IMGUI_API void RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None); // Navigation highlight | |
| 3976 | + IMGUI_API void RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None, float rounding = -1.0f); // Navigation highlight | |
| 3632 | 3977 | #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS |
| 3633 | 3978 | inline void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None) { RenderNavCursor(bb, id, flags); } // Renamed in 1.91.4 |
| 3634 | 3979 | #endif |
| @@ -3640,6 +3985,7 @@ | ||
| 3640 | 3985 | IMGUI_API void RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col); |
| 3641 | 3986 | IMGUI_API void RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz); |
| 3642 | 3987 | IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col); |
| 3988 | + IMGUI_API void RenderArrowDockMenu(ImDrawList* draw_list, ImVec2 p_min, float sz, ImU32 col); | |
| 3643 | 3989 | IMGUI_API void RenderRectFilledInRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float fill_x0, float fill_x1, float rounding); |
| 3644 | 3990 | IMGUI_API void RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding); |
| 3645 | 3991 | IMGUI_API ImDrawFlags CalcRoundingFlagsForRectInRect(const ImRect& r_in, const ImRect& r_outer, float threshold); |
| @@ -3660,7 +4006,7 @@ | ||
| 3660 | 4006 | |
| 3661 | 4007 | // Widgets: Window Decorations |
| 3662 | 4008 | IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos); |
| 3663 | - IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); | |
| 4009 | + IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_node); | |
| 3664 | 4010 | IMGUI_API void Scrollbar(ImGuiAxis axis); |
| 3665 | 4011 | IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 avail_v, ImS64 contents_v, ImDrawFlags draw_rounding_flags = 0); |
| 3666 | 4012 | IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis); |
| @@ -3760,6 +4106,7 @@ | ||
| 3760 | 4106 | IMGUI_API ImU64 DebugTextureIDToU64(ImTextureID tex_id); |
| 3761 | 4107 | IMGUI_API void DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end); |
| 3762 | 4108 | IMGUI_API void DebugNodeColumns(ImGuiOldColumns* columns); |
| 4109 | + IMGUI_API void DebugNodeDockNode(ImGuiDockNode* node, const char* label); | |
| 3763 | 4110 | IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label); |
| 3764 | 4111 | IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); |
| 3765 | 4112 | IMGUI_API void DebugNodeFont(ImFont* font); |
| @@ -3769,7 +4116,7 @@ | ||
| 3769 | 4116 | IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label); |
| 3770 | 4117 | IMGUI_API void DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label); |
| 3771 | 4118 | IMGUI_API void DebugNodeTable(ImGuiTable* table); |
| 3772 | - IMGUI_API void DebugNodeTableSettings(ImGuiTableSettings* settings); | |
| 4119 | + IMGUI_API void DebugNodeTableSettings(ImGuiTableSettings* settings, ImGuiTable* table); | |
| 3773 | 4120 | IMGUI_API void DebugNodeInputTextState(ImGuiInputTextState* state); |
| 3774 | 4121 | IMGUI_API void DebugNodeTypingSelectState(ImGuiTypingSelectState* state); |
| 3775 | 4122 | IMGUI_API void DebugNodeMultiSelectState(ImGuiMultiSelectState* state); |
| @@ -3778,6 +4125,7 @@ | ||
| 3778 | 4125 | IMGUI_API void DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* label); |
| 3779 | 4126 | IMGUI_API void DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack); |
| 3780 | 4127 | IMGUI_API void DebugNodeViewport(ImGuiViewportP* viewport); |
| 4128 | + IMGUI_API void DebugNodePlatformMonitor(ImGuiPlatformMonitor* monitor, const char* label, int idx); | |
| 3781 | 4129 | IMGUI_API void DebugRenderKeyboardPreview(ImDrawList* draw_list); |
| 3782 | 4130 | IMGUI_API void DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb); |
| 3783 | 4131 | |
| @@ -3979,6 +4327,7 @@ | ||
| 3979 | 4327 | IMGUI_API void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h); |
| 3980 | 4328 | IMGUI_API void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h); |
| 3981 | 4329 | |
| 4330 | +IMGUI_API bool ImTextureDataUpdateNewFrame(ImTextureData* tex); | |
| 3982 | 4331 | IMGUI_API void ImTextureDataQueueUpload(ImTextureData* tex, int x, int y, int w, int h); |
| 3983 | 4332 | IMGUI_API int ImTextureDataGetFormatBytesPerPixel(ImTextureFormat format); |
| 3984 | 4333 | IMGUI_API const char* ImTextureDataGetStatusName(ImTextureStatus status); |
| @@ -1,4 +1,4 @@ | ||
| 1 | -// dear imgui, v1.92.8 | |
| 1 | +// dear imgui, v1.92.9 WIP | |
| 2 | 2 | // (tables and columns code) |
| 3 | 3 | |
| 4 | 4 | /* |
| @@ -40,13 +40,15 @@ | ||
| 40 | 40 | // | TableBeginInitMemory() - first time table is used |
| 41 | 41 | // | TableResetSettings() - on settings reset |
| 42 | 42 | // | TableLoadSettings() - on settings load |
| 43 | -// | TableBeginApplyRequests() - apply queued resizing/reordering/hiding requests | |
| 44 | -// | - TableSetColumnWidth() - apply resizing width (for mouse resize, often requested by previous frame) | |
| 45 | -// | - TableUpdateColumnsWeightFromWidth()- recompute columns weights (of stretch columns) from their respective width | |
| 43 | +//----------------------------------------------------------------------------- | |
| 46 | 44 | // - TableSetupColumn() user submit columns details (optional) |
| 47 | 45 | // - TableSetupScrollFreeze() user submit scroll freeze information (optional) |
| 48 | 46 | //----------------------------------------------------------------------------- |
| 49 | 47 | // - TableUpdateLayout() [Internal] followup to BeginTable(): setup everything: widths, columns positions, clipping rectangles. Automatically called by the FIRST call to TableNextRow() or TableHeadersRow(). |
| 48 | +// | TableApplyQueuedRequests() - apply queued resizing/reordering/hiding requests | |
| 49 | +// | - TableSetColumnWidth() - apply resizing width (for mouse resize, often requested by previous frame) | |
| 50 | +// | - TableUpdateColumnsWeightFromWidth()- recompute columns weights (of stretch columns) from their respective width | |
| 51 | +// | - TableSetColumnDisplayOrder() - apply reordering a column | |
| 50 | 52 | // | TableSetupDrawChannels() - setup ImDrawList channels |
| 51 | 53 | // | TableUpdateBorders() - detect hovering columns for resize, ahead of contents submission |
| 52 | 54 | // | TableBeginContextMenuPopup() |
| @@ -252,7 +254,7 @@ | ||
| 252 | 254 | // - BeginTable() |
| 253 | 255 | // - BeginTableEx() [Internal] |
| 254 | 256 | // - TableBeginInitMemory() [Internal] |
| 255 | -// - TableBeginApplyRequests() [Internal] | |
| 257 | +// - TableApplyQueuedRequests() [Internal] | |
| 256 | 258 | // - TableSetupColumnFlags() [Internal] |
| 257 | 259 | // - TableUpdateLayout() [Internal] |
| 258 | 260 | // - TableUpdateBorders() [Internal] |
| @@ -361,6 +363,7 @@ | ||
| 361 | 363 | g.TablesTempData.resize(g.TablesTempDataStacked, ImGuiTableTempData()); |
| 362 | 364 | ImGuiTableTempData* temp_data = table->TempData = &g.TablesTempData[g.TablesTempDataStacked - 1]; |
| 363 | 365 | temp_data->TableIndex = table_idx; |
| 366 | + temp_data->ReconcileColumnsRequests.resize(0); // FIXME: Use shrink(0) everywhere? | |
| 364 | 367 | table->DrawSplitter = &table->TempData->DrawSplitter; |
| 365 | 368 | table->DrawSplitter->Clear(); |
| 366 | 369 | |
| @@ -372,6 +375,7 @@ | ||
| 372 | 375 | const int previous_frame_active = table->LastFrameActive; |
| 373 | 376 | const int instance_no = (previous_frame_active != g.FrameCount) ? 0 : table->InstanceCurrent + 1; |
| 374 | 377 | const ImGuiTableFlags previous_flags = table->Flags; |
| 378 | + const bool is_new_table = (previous_frame_active == -1); | |
| 375 | 379 | table->ID = id; |
| 376 | 380 | table->Flags = flags; |
| 377 | 381 | table->LastFrameActive = g.FrameCount; |
| @@ -561,29 +565,36 @@ | ||
| 561 | 565 | table->MemoryCompacted = false; |
| 562 | 566 | |
| 563 | 567 | // Setup memory buffer (clear data if columns count changed) |
| 564 | - ImGuiTableColumn* old_columns_to_preserve = NULL; | |
| 565 | - void* old_columns_raw_data = NULL; | |
| 566 | 568 | const int old_columns_count = table->Columns.size(); |
| 567 | 569 | if (old_columns_count != 0 && old_columns_count != columns_count) |
| 568 | 570 | { |
| 569 | - // Attempt to preserve width and other settings on column count/specs change (#4046) | |
| 570 | - old_columns_to_preserve = table->Columns.Data; | |
| 571 | - old_columns_raw_data = table->RawData; // Free at end of function | |
| 571 | + // Attempt to preserve width and other settings on column count/specs change (#4046, #9108) | |
| 572 | + IMGUI_DEBUG_LOG_TABLE("[table] Table 0x%08X column count %d -> %d, recreating storage.\n", table->ID, old_columns_count, columns_count); | |
| 573 | + IM_ASSERT(temp_data->OldColumnsRawData == NULL); | |
| 574 | + temp_data->OldColumnsRawData = table->RawData; // Freed during layout | |
| 575 | + temp_data->OldColumnsData = table->Columns; | |
| 576 | + for (ImGuiTableColumn& src_column : table->TempData->OldColumnsData) | |
| 577 | + src_column.IsNeedReconcileSrc = true; | |
| 572 | 578 | table->RawData = NULL; |
| 573 | 579 | } |
| 574 | 580 | if (table->RawData == NULL) |
| 575 | 581 | { |
| 576 | 582 | TableBeginInitMemory(table, columns_count); |
| 577 | - table->IsInitializing = table->IsSettingsRequestLoad = true; | |
| 583 | + table->IsInitializing = true; | |
| 578 | 584 | } |
| 579 | 585 | if (table->IsResetAllRequest) |
| 580 | 586 | TableResetSettings(table); |
| 581 | 587 | if (table->IsInitializing) |
| 582 | 588 | { |
| 583 | 589 | // Initialize |
| 584 | - table->SettingsOffset = -1; | |
| 590 | + if (is_new_table) | |
| 591 | + { | |
| 592 | + table->SettingsOffset = -1; | |
| 593 | + table->IsSettingsRequestLoad = true; | |
| 594 | + } | |
| 585 | 595 | table->IsSortSpecsDirty = true; |
| 586 | 596 | table->IsSettingsDirty = true; // Records itself into .ini file even when in default state (#7934) |
| 597 | + table->IsReconcileMode = false; | |
| 587 | 598 | table->InstanceInteracted = -1; |
| 588 | 599 | table->ContextPopupColumn = -1; |
| 589 | 600 | table->ReorderColumn = table->ReorderColumnDstOrder = table->ResizedColumn = table->LastResizedColumn = -1; |
| @@ -592,9 +603,9 @@ | ||
| 592 | 603 | for (int n = 0; n < columns_count; n++) |
| 593 | 604 | { |
| 594 | 605 | ImGuiTableColumn* column = &table->Columns[n]; |
| 595 | - if (old_columns_to_preserve && n < old_columns_count) | |
| 606 | + if (temp_data->OldColumnsData.Data && n < temp_data->OldColumnsData.size()) | |
| 596 | 607 | { |
| 597 | - *column = old_columns_to_preserve[n]; | |
| 608 | + *column = temp_data->OldColumnsData[n]; | |
| 598 | 609 | } |
| 599 | 610 | else |
| 600 | 611 | { |
| @@ -608,28 +619,11 @@ | ||
| 608 | 619 | table->DisplayOrderToIndex[n] = column->DisplayOrder; |
| 609 | 620 | } |
| 610 | 621 | } |
| 611 | - if (old_columns_raw_data) | |
| 612 | - IM_FREE(old_columns_raw_data); | |
| 613 | 622 | |
| 614 | 623 | // Load settings |
| 615 | 624 | if (table->IsSettingsRequestLoad) |
| 616 | 625 | TableLoadSettings(table); |
| 617 | 626 | |
| 618 | - // Handle DPI/font resize | |
| 619 | - // This is designed to facilitate DPI changes with the assumption that e.g. style.CellPadding has been scaled as well. | |
| 620 | - // It will also react to changing fonts with mixed results. It doesn't need to be perfect but merely provide a decent transition. | |
| 621 | - // FIXME-DPI: Provide consistent standards for reference size. Perhaps using g.CurrentDpiScale would be more self explanatory. | |
| 622 | - // This is will lead us to non-rounded WidthRequest in columns, which should work but is a poorly tested path. | |
| 623 | - const float new_ref_scale_unit = g.FontSize; // g.Font->GetCharAdvance('A') ? | |
| 624 | - if (table->RefScale != 0.0f && table->RefScale != new_ref_scale_unit) | |
| 625 | - { | |
| 626 | - const float scale_factor = new_ref_scale_unit / table->RefScale; | |
| 627 | - //IMGUI_DEBUG_PRINT("[table] %08X RefScaleUnit %.3f -> %.3f, scaling width by %.3f\n", table->ID, table->RefScaleUnit, new_ref_scale_unit, scale_factor); | |
| 628 | - for (int n = 0; n < columns_count; n++) | |
| 629 | - table->Columns[n].WidthRequest = table->Columns[n].WidthRequest * scale_factor; | |
| 630 | - } | |
| 631 | - table->RefScale = new_ref_scale_unit; | |
| 632 | - | |
| 633 | 627 | // Disable output until user calls TableNextRow() or TableNextColumn() leading to the TableUpdateLayout() call.. |
| 634 | 628 | // This is not strictly necessary but will reduce cases were "out of table" output will be misleading to the user. |
| 635 | 629 | // Because we cannot safely assert in EndTable() when no rows have been created, this seems like our best option. |
| @@ -639,10 +633,7 @@ | ||
| 639 | 633 | // At this point the ->NameOffset field of each column will be invalid until TableUpdateLayout() or the first call to TableSetupColumn() |
| 640 | 634 | if (table->ColumnsNames.Buf.Size > 0) |
| 641 | 635 | table->ColumnsNames.Buf.resize(0); |
| 642 | - | |
| 643 | - // Apply queued resizing/reordering/hiding requests | |
| 644 | - TableBeginApplyRequests(table); | |
| 645 | - | |
| 636 | + | |
| 646 | 637 | return true; |
| 647 | 638 | } |
| 648 | 639 | |
| @@ -677,7 +668,7 @@ | ||
| 677 | 668 | } |
| 678 | 669 | |
| 679 | 670 | // Apply queued resizing/reordering/hiding requests |
| 680 | -void ImGui::TableBeginApplyRequests(ImGuiTable* table) | |
| 671 | +void ImGui::TableApplyQueuedRequests(ImGuiTable* table) | |
| 681 | 672 | { |
| 682 | 673 | // Handle resizing request |
| 683 | 674 | // (We process this in the TableBegin() of the first instance of each table) |
| @@ -719,7 +710,7 @@ | ||
| 719 | 710 | // table->ReorderColumn = -1; |
| 720 | 711 | } |
| 721 | 712 | |
| 722 | - // Handle display order reset request | |
| 713 | + // Handle display order / visibility reset requests | |
| 723 | 714 | if (table->IsResetDisplayOrderRequest) |
| 724 | 715 | { |
| 725 | 716 | for (int n = 0; n < table->ColumnsCount; n++) |
| @@ -727,6 +718,13 @@ | ||
| 727 | 718 | table->IsResetDisplayOrderRequest = false; |
| 728 | 719 | table->IsSettingsDirty = true; |
| 729 | 720 | } |
| 721 | + if (table->IsResetVisibilityRequest) | |
| 722 | + { | |
| 723 | + for (ImGuiTableColumn& column : table->Columns) | |
| 724 | + column.IsUserEnabled = column.IsUserEnabledNextFrame = (column.Flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1; | |
| 725 | + table->IsResetVisibilityRequest = false; | |
| 726 | + table->IsSettingsDirty = true; | |
| 727 | + } | |
| 730 | 728 | } |
| 731 | 729 | |
| 732 | 730 | // Apply immediately. See TableQueueSetColumnDisplayOrder() for additional checks/constraints. |
| @@ -782,8 +780,9 @@ | ||
| 782 | 780 | table->ReorderColumn = (ImGuiTableColumnIdx)column_n; |
| 783 | 781 | table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)-1; |
| 784 | 782 | dst_order = TableGetMaxDisplayOrderAllowed(table, src_order, dst_order); |
| 785 | - if (dst_order != src_order) | |
| 786 | - table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)dst_order; | |
| 783 | + if (table->IsLayoutLocked && dst_order == src_order) // We allow calling the function before layout w/ reconcile so don't early out. | |
| 784 | + return; | |
| 785 | + table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)dst_order; | |
| 787 | 786 | } |
| 788 | 787 | |
| 789 | 788 | // Adjust flags: default width mode + stretch columns are not allowed when auto extending |
| @@ -849,13 +848,61 @@ | ||
| 849 | 848 | void ImGui::TableUpdateLayout(ImGuiTable* table) |
| 850 | 849 | { |
| 851 | 850 | ImGuiContext& g = *GImGui; |
| 851 | + ImGuiTableTempData* temp_data = table->TempData; | |
| 852 | 852 | IM_ASSERT(table->IsLayoutLocked == false); |
| 853 | + const int columns_count = table->ColumnsCount; | |
| 853 | 854 | |
| 855 | + // Reconcile moved columns | |
| 856 | + if (temp_data->ReconcileColumnsRequests.Size > 0) | |
| 857 | + TableReconcileColumns(table); | |
| 858 | + if (temp_data->OldColumnsRawData) | |
| 859 | + { | |
| 860 | + IM_FREE(temp_data->OldColumnsRawData); | |
| 861 | + temp_data->OldColumnsRawData = NULL; | |
| 862 | + temp_data->OldColumnsData.clear(); | |
| 863 | + } | |
| 864 | + | |
| 865 | + // Apply columns settings | |
| 866 | + if (table->IsSettingsRequestLoad) | |
| 867 | + TableLoadSettingsForColumns(table); | |
| 868 | + if (table->IsInitializing || table->IsSettingsRequestLoad) | |
| 869 | + { | |
| 870 | + for (ImGuiTableColumn& column : table->Columns) | |
| 871 | + { | |
| 872 | + ImGuiTableFlags init_flags; | |
| 873 | + if (table->IsSettingsRequestLoad) | |
| 874 | + init_flags = column.IsLoadedSettings ? ~table->SettingsLoadedFlags : ~0; | |
| 875 | + else | |
| 876 | + init_flags = column.IsJustCreated ? ~0 : 0; | |
| 877 | + TableInitColumnDefaults(table, &column, init_flags); | |
| 878 | + } | |
| 879 | + TableFixDisplayOrder(table); // Call even for non _Reorderable table as we loaded .ini data. | |
| 880 | + table->IsSettingsRequestLoad = false; | |
| 881 | + } | |
| 882 | + | |
| 883 | + // Apply queued resizing/reordering/hiding requests | |
| 884 | + TableApplyQueuedRequests(table); | |
| 885 | + | |
| 886 | + // Handle DPI/font resize | |
| 887 | + // This is designed to facilitate DPI changes with the assumption that e.g. style.CellPadding has been scaled as well. | |
| 888 | + // It will also react to changing fonts with mixed results. It doesn't need to be perfect but merely provide a decent transition. | |
| 889 | + // FIXME-DPI: Provide consistent standards for reference size. Perhaps using g.CurrentDpiScale would be more self explanatory. | |
| 890 | + // This is will lead us to non-rounded WidthRequest in columns, which should work but is a poorly tested path. | |
| 891 | + const float new_ref_scale_unit = g.FontSize; // g.Font->GetCharAdvance('A') ? | |
| 892 | + if (table->RefScale != 0.0f && table->RefScale != new_ref_scale_unit) | |
| 893 | + { | |
| 894 | + const float scale_factor = new_ref_scale_unit / table->RefScale; | |
| 895 | + IMGUI_DEBUG_LOG_TABLE("[table] 0x%08X RefScale %.3f -> %.3f, scaling width by %.3f\n", table->ID, table->RefScale, new_ref_scale_unit, scale_factor); | |
| 896 | + for (int n = 0; n < columns_count; n++) | |
| 897 | + table->Columns[n].WidthRequest = table->Columns[n].WidthRequest * scale_factor; | |
| 898 | + } | |
| 899 | + table->RefScale = new_ref_scale_unit; | |
| 900 | + | |
| 854 | 901 | const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_); |
| 855 | - table->IsDefaultDisplayOrder = true; | |
| 902 | + table->IsDefaultDisplayOrder = table->IsDefaultVisibility = true; | |
| 856 | 903 | table->ColumnsEnabledCount = 0; |
| 857 | - ImBitArrayClearAllBits(table->EnabledMaskByIndex, table->ColumnsCount); | |
| 858 | - ImBitArrayClearAllBits(table->EnabledMaskByDisplayOrder, table->ColumnsCount); | |
| 904 | + ImBitArrayClearAllBits(table->EnabledMaskByIndex, columns_count); | |
| 905 | + ImBitArrayClearAllBits(table->EnabledMaskByDisplayOrder, columns_count); | |
| 859 | 906 | table->LeftMostEnabledColumn = -1; |
| 860 | 907 | table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE |
| 861 | 908 | |
| @@ -868,11 +915,9 @@ | ||
| 868 | 915 | bool has_resizable = false; |
| 869 | 916 | float stretch_sum_width_auto = 0.0f; |
| 870 | 917 | float fixed_max_width_auto = 0.0f; |
| 871 | - for (int order_n = 0; order_n < table->ColumnsCount; order_n++) | |
| 918 | + for (int order_n = 0; order_n < columns_count; order_n++) | |
| 872 | 919 | { |
| 873 | 920 | const int column_n = table->DisplayOrderToIndex[order_n]; |
| 874 | - if (column_n != order_n) | |
| 875 | - table->IsDefaultDisplayOrder = false; | |
| 876 | 921 | ImGuiTableColumn* column = &table->Columns[column_n]; |
| 877 | 922 | |
| 878 | 923 | // Clear column setup if not submitted by user. Currently we make it mandatory to call TableSetupColumn() every frame. |
| @@ -882,7 +927,7 @@ | ||
| 882 | 927 | { |
| 883 | 928 | TableSetupColumnFlags(table, column, ImGuiTableColumnFlags_None); |
| 884 | 929 | column->NameOffset = -1; |
| 885 | - column->UserID = 0; | |
| 930 | + column->ID = column->UserData = 0; | |
| 886 | 931 | column->InitStretchWeightOrWidth = -1.0f; |
| 887 | 932 | } |
| 888 | 933 | |
| @@ -895,7 +940,13 @@ | ||
| 895 | 940 | table->IsSettingsDirty = true; |
| 896 | 941 | } |
| 897 | 942 | column->IsEnabled = column->IsUserEnabled && (column->Flags & ImGuiTableColumnFlags_Disabled) == 0; |
| 943 | + column->IsJustCreated = false; | |
| 898 | 944 | |
| 945 | + if (column->IsEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1)) | |
| 946 | + table->IsDefaultVisibility = false; | |
| 947 | + if (column_n != order_n) | |
| 948 | + table->IsDefaultDisplayOrder = false; | |
| 949 | + | |
| 899 | 950 | if (column->SortOrder != -1 && !column->IsEnabled) |
| 900 | 951 | table->IsSortSpecsDirty = true; |
| 901 | 952 | if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti)) |
| @@ -967,7 +1018,7 @@ | ||
| 967 | 1018 | float sum_width_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns but including spacing/padding. |
| 968 | 1019 | float stretch_sum_weights = 0.0f; // Sum of all weights for stretch columns. |
| 969 | 1020 | table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1; |
| 970 | - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) | |
| 1021 | + for (int column_n = 0; column_n < columns_count; column_n++) | |
| 971 | 1022 | { |
| 972 | 1023 | if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) |
| 973 | 1024 | continue; |
| @@ -1031,7 +1082,7 @@ | ||
| 1031 | 1082 | const float width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests; |
| 1032 | 1083 | float width_remaining_for_stretched_columns = width_avail_for_stretched_columns; |
| 1033 | 1084 | table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount; |
| 1034 | - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) | |
| 1085 | + for (int column_n = 0; column_n < columns_count; column_n++) | |
| 1035 | 1086 | { |
| 1036 | 1087 | if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) |
| 1037 | 1088 | continue; |
| @@ -1058,7 +1109,7 @@ | ||
| 1058 | 1109 | // [Part 5] Redistribute stretch remainder width due to rounding (remainder width is < 1.0f * number of Stretch column). |
| 1059 | 1110 | // Using right-to-left distribution (more likely to match resizing cursor). |
| 1060 | 1111 | if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths)) |
| 1061 | - for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) | |
| 1112 | + for (int order_n = columns_count - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) | |
| 1062 | 1113 | { |
| 1063 | 1114 | if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) |
| 1064 | 1115 | continue; |
| @@ -1098,8 +1149,8 @@ | ||
| 1098 | 1149 | float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1; |
| 1099 | 1150 | ImRect host_clip_rect = table->InnerClipRect; |
| 1100 | 1151 | //host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2; |
| 1101 | - ImBitArrayClearAllBits(table->VisibleMaskByIndex, table->ColumnsCount); | |
| 1102 | - for (int order_n = 0; order_n < table->ColumnsCount; order_n++) | |
| 1152 | + ImBitArrayClearAllBits(table->VisibleMaskByIndex, columns_count); | |
| 1153 | + for (int order_n = 0; order_n < columns_count; order_n++) | |
| 1103 | 1154 | { |
| 1104 | 1155 | const int column_n = table->DisplayOrderToIndex[order_n]; |
| 1105 | 1156 | ImGuiTableColumn* column = &table->Columns[column_n]; |
| @@ -1247,7 +1298,7 @@ | ||
| 1247 | 1298 | const float unused_x1 = ImMax(table->WorkRect.Min.x, table->Columns[table->RightMostEnabledColumn].ClipRect.Max.x); |
| 1248 | 1299 | if (is_hovering_table && table->HoveredColumnBody == -1) |
| 1249 | 1300 | if (mouse_skewed_x >= unused_x1) |
| 1250 | - table->HoveredColumnBody = (ImGuiTableColumnIdx)table->ColumnsCount; | |
| 1301 | + table->HoveredColumnBody = (ImGuiTableColumnIdx)columns_count; | |
| 1251 | 1302 | if (has_resizable == false && (table->Flags & ImGuiTableFlags_Resizable)) |
| 1252 | 1303 | table->Flags &= ~ImGuiTableFlags_Resizable; |
| 1253 | 1304 | |
| @@ -1289,7 +1340,7 @@ | ||
| 1289 | 1340 | table->HighlightColumnHeader = -1; |
| 1290 | 1341 | if (table->IsContextPopupOpen && table->ContextPopupColumn != -1 && table->InstanceInteracted == table->InstanceCurrent) |
| 1291 | 1342 | table->HighlightColumnHeader = table->ContextPopupColumn; |
| 1292 | - else if ((table->Flags & ImGuiTableFlags_HighlightHoveredColumn) && table->HoveredColumnBody != -1 && table->HoveredColumnBody != table->ColumnsCount && table->HoveredColumnBorder == -1) | |
| 1343 | + else if ((table->Flags & ImGuiTableFlags_HighlightHoveredColumn) && table->HoveredColumnBody != -1 && table->HoveredColumnBody != columns_count && table->HoveredColumnBorder == -1) | |
| 1293 | 1344 | if (g.ActiveId == 0 || (table->IsActiveIdInTable || g.DragDropActive)) |
| 1294 | 1345 | table->HighlightColumnHeader = table->HoveredColumnBody; |
| 1295 | 1346 | |
| @@ -1629,9 +1680,9 @@ | ||
| 1629 | 1680 | NavUpdateCurrentWindowIsScrollPushableX(); |
| 1630 | 1681 | } |
| 1631 | 1682 | |
| 1632 | -// Called in TableSetupColumn() when initializing and in TableLoadSettings() for defaults before applying stored settings. | |
| 1683 | +// Called in TableUpdateLayout() when initializing/after loading settings. | |
| 1633 | 1684 | // 'init_mask' specify which fields to initialize. |
| 1634 | -static void TableInitColumnDefaults(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags init_mask) | |
| 1685 | +void ImGui::TableInitColumnDefaults(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags init_mask) | |
| 1635 | 1686 | { |
| 1636 | 1687 | ImGuiTableColumnFlags flags = column->Flags; |
| 1637 | 1688 | if (init_mask & ImGuiTableFlags_Resizable) |
| @@ -1643,7 +1694,7 @@ | ||
| 1643 | 1694 | column->AutoFitQueue = 0x00; |
| 1644 | 1695 | } |
| 1645 | 1696 | if (init_mask & ImGuiTableFlags_Reorderable) |
| 1646 | - column->DisplayOrder = (ImGuiTableColumnIdx)table->Columns.index_from_ptr(column); | |
| 1697 | + column->DisplayOrder = (ImGuiTableColumnIdx)((table->Flags & ImGuiTableFlags_Reorderable) ? -1 : table->Columns.index_from_ptr(column)); | |
| 1647 | 1698 | if (init_mask & ImGuiTableFlags_Hideable) |
| 1648 | 1699 | column->IsUserEnabled = column->IsUserEnabledNextFrame = (flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1; |
| 1649 | 1700 | if (init_mask & ImGuiTableFlags_Sortable) |
| @@ -1656,18 +1707,10 @@ | ||
| 1656 | 1707 | |
| 1657 | 1708 | // See "COLUMNS SIZING POLICIES" comments at the top of this file |
| 1658 | 1709 | // If (init_width_or_weight <= 0.0f) it is ignored |
| 1659 | -void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id) | |
| 1710 | +static void TableSetupColumnApply(ImGuiTable* table, int idx, ImGuiID id, ImS16 name_offset, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_data) | |
| 1660 | 1711 | { |
| 1661 | - ImGuiContext& g = *GImGui; | |
| 1662 | - ImGuiTable* table = g.CurrentTable; | |
| 1663 | - IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!"); | |
| 1664 | - IM_ASSERT_USER_ERROR_RET(table->DeclColumnsCount < table->ColumnsCount, "TableSetupColumn(): called too many times!"); | |
| 1665 | - IM_ASSERT_USER_ERROR_RET(table->IsLayoutLocked == false, "TableSetupColumn(): need to call before first row!"); // Table layout is locked when submitting a row or when calling BeginMultiSelect() with box-select. | |
| 1666 | - IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()"); | |
| 1712 | + ImGuiTableColumn* column = &table->Columns[idx]; | |
| 1667 | 1713 | |
| 1668 | - ImGuiTableColumn* column = &table->Columns[table->DeclColumnsCount]; | |
| 1669 | - table->DeclColumnsCount++; | |
| 1670 | - | |
| 1671 | 1714 | // Assert when passing a width or weight if policy is entirely left to default, to avoid storing width into weight and vice-versa. |
| 1672 | 1715 | // Give a grace to users of ImGuiTableFlags_ScrollX. |
| 1673 | 1716 | if (table->IsDefaultSizingPolicy && (flags & ImGuiTableColumnFlags_WidthMask_) == 0 && (flags & ImGuiTableFlags_ScrollX) == 0) |
| @@ -1685,29 +1728,129 @@ | ||
| 1685 | 1728 | } |
| 1686 | 1729 | |
| 1687 | 1730 | TableSetupColumnFlags(table, column, flags); |
| 1688 | - column->UserID = user_id; | |
| 1689 | - flags = column->Flags; | |
| 1690 | - | |
| 1691 | - // Initialize defaults | |
| 1731 | + column->ID = id; | |
| 1732 | + column->UserData = user_data; | |
| 1733 | + column->NameOffset = name_offset; | |
| 1692 | 1734 | column->InitStretchWeightOrWidth = init_width_or_weight; |
| 1693 | - if (table->IsInitializing) | |
| 1694 | - { | |
| 1695 | - ImGuiTableFlags init_flags = ~table->SettingsLoadedFlags; | |
| 1696 | - if (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f) | |
| 1697 | - init_flags |= ImGuiTableFlags_Resizable; | |
| 1698 | - TableInitColumnDefaults(table, column, init_flags); | |
| 1699 | - } | |
| 1735 | +} | |
| 1700 | 1736 | |
| 1737 | +void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_data) | |
| 1738 | +{ | |
| 1739 | + ImGuiContext& g = *GImGui; | |
| 1740 | + ImGuiTable* table = g.CurrentTable; | |
| 1741 | + IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!"); | |
| 1742 | + IM_ASSERT_USER_ERROR_RET(table->DeclColumnsCount < table->ColumnsCount, "TableSetupColumn(): called too many times!"); | |
| 1743 | + IM_ASSERT_USER_ERROR_RET(table->IsLayoutLocked == false, "TableSetupColumn(): need to call before first row!"); // Table layout is locked when submitting a row or when calling BeginMultiSelect() with box-select. | |
| 1744 | + IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()"); | |
| 1745 | + | |
| 1701 | 1746 | // Store name (append with zero-terminator in contiguous buffer) |
| 1702 | 1747 | // FIXME: If we recorded the number of \n in names we could compute header row height |
| 1703 | - column->NameOffset = -1; | |
| 1748 | + ImS16 name_offset = -1; | |
| 1704 | 1749 | if (label != NULL && label[0] != 0) |
| 1705 | 1750 | { |
| 1706 | - column->NameOffset = (ImS16)table->ColumnsNames.size(); | |
| 1751 | + name_offset = (ImS16)table->ColumnsNames.size(); | |
| 1707 | 1752 | table->ColumnsNames.append(label, label + ImStrlen(label) + 1); |
| 1708 | 1753 | } |
| 1754 | + const ImGuiID column_id = (label != NULL && label[0] != 0) ? ImHashStr(label) : 0; | |
| 1755 | + | |
| 1756 | + // When ID changed or a column moved: defer the request until layout where we will process full reconcile. | |
| 1757 | + const int column_idx = table->DeclColumnsCount++; | |
| 1758 | + ImGuiTableColumn* column = &table->Columns[column_idx]; | |
| 1759 | + | |
| 1760 | + // If topology change goes into reconcile mode | |
| 1761 | + if (table->IsReconcileMode == false && column->ID != column_id) | |
| 1762 | + { | |
| 1763 | + table->IsReconcileMode = true; | |
| 1764 | + table->TempData->ReconcileColumnsRequests.reserve(table->ColumnsCount - column_idx); | |
| 1765 | + } | |
| 1766 | + | |
| 1767 | + // Fast/common path | |
| 1768 | + if (table->IsReconcileMode == false) | |
| 1769 | + { | |
| 1770 | + TableSetupColumnApply(table, column_idx, column_id, name_offset, flags, init_width_or_weight, user_data); | |
| 1771 | + column->IsNeedReconcileSrc = column->IsNeedReconcileDst = false; | |
| 1772 | + if (column_idx < table->TempData->OldColumnsData.size()) | |
| 1773 | + table->TempData->OldColumnsData[column_idx].IsNeedReconcileSrc = false; | |
| 1774 | + return; | |
| 1775 | + } | |
| 1776 | + | |
| 1777 | + // Reconcile path: defer applying data to TableUpdateLayout() -> TableReconcileMovedColumns() -> TableSetupColumnApply(). | |
| 1778 | + // On column count change: search the previous columns: | |
| 1779 | + // - the live Columns[] array is truncated on shrink, so a moved column may only exist in old data. | |
| 1780 | + // - the live Columns[] array may already be partially reset. | |
| 1781 | + table->TempData->ReconcileColumnsRequests.push_back(ImGuiTableReconcileColumnData()); | |
| 1782 | + ImGuiTableReconcileColumnData& reconcile_data = table->TempData->ReconcileColumnsRequests.back(); | |
| 1783 | + reconcile_data.ID = column_id; | |
| 1784 | + reconcile_data.NameOffset = name_offset; | |
| 1785 | + reconcile_data.Flags = flags; | |
| 1786 | + reconcile_data.InitWidthOrWeight = init_width_or_weight; | |
| 1787 | + reconcile_data.UserData = user_data; | |
| 1788 | + reconcile_data.ColumnNewIdx = (ImGuiTableColumnIdx)column_idx; | |
| 1789 | + reconcile_data.ColumnOldIdx = (ImGuiTableColumnIdx)-1; | |
| 1790 | + column->NameOffset = name_offset; // Allow TableGetColumnName() to work before layout | |
| 1791 | + column->IsNeedReconcileSrc = column->IsNeedReconcileDst = true; | |
| 1709 | 1792 | } |
| 1710 | 1793 | |
| 1794 | +// NB: This was written to be similar to the logic in TableLoadSettingsForColumns(). | |
| 1795 | +void ImGui::TableReconcileColumns(ImGuiTable* table) | |
| 1796 | +{ | |
| 1797 | + ImGuiContext& g = *GImGui; | |
| 1798 | + ImGuiTableTempData* temp_data = table->TempData; | |
| 1799 | + IM_UNUSED(g); | |
| 1800 | + IMGUI_DEBUG_LOG_TABLE("[table] Reconcile columns for table 0x%08X\n", table->ID); | |
| 1801 | + | |
| 1802 | + ImSpan<ImGuiTableColumn>& dst_columns = table->Columns; | |
| 1803 | + ImSpan<ImGuiTableColumn>& src_columns = table->TempData->OldColumnsData.empty() ? table->Columns : table->TempData->OldColumnsData; | |
| 1804 | + | |
| 1805 | + // Find matches for named columns. | |
| 1806 | + int matches = 0; | |
| 1807 | + ImVector<ImGuiTableReconcileColumnData>& reconcile_requests = temp_data->ReconcileColumnsRequests; | |
| 1808 | + for (ImGuiTableReconcileColumnData& reconcile_data : reconcile_requests) | |
| 1809 | + if (reconcile_data.ID != 0) | |
| 1810 | + for (ImGuiTableColumn& src_column : src_columns) | |
| 1811 | + if (src_column.ID == reconcile_data.ID && src_column.IsNeedReconcileSrc) | |
| 1812 | + { | |
| 1813 | + ImGuiTableColumn& dst_column = dst_columns[reconcile_data.ColumnNewIdx]; | |
| 1814 | + IM_ASSERT(src_column.IsNeedReconcileSrc && dst_column.IsNeedReconcileDst); | |
| 1815 | + src_column.IsNeedReconcileSrc = dst_column.IsNeedReconcileDst = false; | |
| 1816 | + reconcile_data.ColumnOldIdx = (ImGuiTableColumnIdx)src_columns.index_from_ptr(&src_column); | |
| 1817 | + reconcile_data.ColumnOldData = src_column; | |
| 1818 | + matches++; | |
| 1819 | + break; | |
| 1820 | + } | |
| 1821 | + | |
| 1822 | + // Remaining entries are matched sequentially. | |
| 1823 | + int dst_idx = 0; // index in reconcile array | |
| 1824 | + if (matches != reconcile_requests.Size) | |
| 1825 | + for (ImGuiTableColumn& src_column : src_columns) | |
| 1826 | + { | |
| 1827 | + if (!src_column.IsNeedReconcileSrc) | |
| 1828 | + continue; | |
| 1829 | + while (dst_idx < reconcile_requests.Size && reconcile_requests[dst_idx].ColumnOldIdx != (ImGuiTableColumnIdx)-1) | |
| 1830 | + dst_idx++; | |
| 1831 | + if (dst_idx == reconcile_requests.Size) | |
| 1832 | + break; | |
| 1833 | + ImGuiTableReconcileColumnData& reconcile_data = reconcile_requests[dst_idx]; | |
| 1834 | + ImGuiTableColumn& dst_column = dst_columns[reconcile_data.ColumnNewIdx]; | |
| 1835 | + IM_ASSERT(src_column.IsNeedReconcileSrc && dst_column.IsNeedReconcileDst); | |
| 1836 | + src_column.IsNeedReconcileSrc = dst_column.IsNeedReconcileDst = false; | |
| 1837 | + reconcile_data.ColumnOldIdx = (ImGuiTableColumnIdx)src_columns.index_from_ptr(&src_column); | |
| 1838 | + reconcile_data.ColumnOldData = src_column; | |
| 1839 | + } | |
| 1840 | + | |
| 1841 | + // Apply in the final pass. Because it is possible that src_columns == table->Columns we went through a temporary copy. | |
| 1842 | + for (ImGuiTableReconcileColumnData& reconcile_data : reconcile_requests) | |
| 1843 | + { | |
| 1844 | + table->Columns[reconcile_data.ColumnNewIdx] = reconcile_data.ColumnOldData; // When old column was not found clear anyway with default-constructed data (which will set IsJustCreated=true) | |
| 1845 | + TableSetupColumnApply(table, reconcile_data.ColumnNewIdx, reconcile_data.ID, reconcile_data.NameOffset, reconcile_data.Flags, reconcile_data.InitWidthOrWeight, reconcile_data.UserData); | |
| 1846 | + IMGUI_DEBUG_LOG_TABLE("[table] - old %d -> new %d \"%s\"\n", reconcile_data.ColumnOldIdx, reconcile_data.ColumnNewIdx, TableGetColumnName(table, reconcile_data.ColumnNewIdx)); // Log at the end so NameOffset was copied. | |
| 1847 | + } | |
| 1848 | + TableFixDisplayOrder(table); | |
| 1849 | + table->IsSettingsDirty = true; // FIXME-RECONCILE: Necessary? | |
| 1850 | + table->IsReconcileMode = false; | |
| 1851 | + reconcile_requests.resize(0); // GC-ed once in NewFrame() | |
| 1852 | +} | |
| 1853 | + | |
| 1711 | 1854 | // [Public] |
| 1712 | 1855 | void ImGui::TableSetupScrollFreeze(int columns, int rows) |
| 1713 | 1856 | { |
| @@ -3081,7 +3224,7 @@ | ||
| 3081 | 3224 | continue; |
| 3082 | 3225 | IM_ASSERT(column->SortOrder < table->SortSpecsCount); |
| 3083 | 3226 | ImGuiTableColumnSortSpecs* sort_spec = &sort_specs[column->SortOrder]; |
| 3084 | - sort_spec->ColumnUserID = column->UserID; | |
| 3227 | + sort_spec->ColumnUserID = column->UserData; | |
| 3085 | 3228 | sort_spec->ColumnIndex = (ImGuiTableColumnIdx)column_n; |
| 3086 | 3229 | sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder; |
| 3087 | 3230 | sort_spec->SortDirection = (ImGuiSortDirection)column->SortDirection; |
| @@ -3252,7 +3395,7 @@ | ||
| 3252 | 3395 | if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0) |
| 3253 | 3396 | TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn); |
| 3254 | 3397 | } |
| 3255 | - RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding); | |
| 3398 | + RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact, 0.0f); | |
| 3256 | 3399 | if (held) |
| 3257 | 3400 | table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n; |
| 3258 | 3401 | window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f; |
| @@ -3277,7 +3420,9 @@ | ||
| 3277 | 3420 | } |
| 3278 | 3421 | |
| 3279 | 3422 | // Sort order arrow |
| 3280 | - const float ellipsis_max = ImMax(cell_r.Max.x - w_arrow - w_sort_text, label_pos.x); | |
| 3423 | + // - Only clip label for a visible arrow. Auto-fit still accounts for a possible arrow, but when | |
| 3424 | + // manually sized smaller we don't clip the label for the sake of an arrow that isn't displayed. | |
| 3425 | + const float ellipsis_max = ImMax(cell_r.Max.x - (sort_arrow ? w_arrow + w_sort_text : 0.0f), label_pos.x); | |
| 3281 | 3426 | if ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort)) |
| 3282 | 3427 | { |
| 3283 | 3428 | if (column->SortOrder != -1) |
| @@ -3597,18 +3742,21 @@ | ||
| 3597 | 3742 | want_separator = true; |
| 3598 | 3743 | } |
| 3599 | 3744 | |
| 3600 | - // Ordering | |
| 3601 | - if (flags_for_section_to_display & ImGuiTableFlags_Reorderable) | |
| 3602 | - { | |
| 3603 | - if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetOrder), NULL, false, !table->IsDefaultDisplayOrder)) | |
| 3604 | - table->IsResetDisplayOrderRequest = true; | |
| 3605 | - want_separator = true; | |
| 3606 | - } | |
| 3745 | + // Reset Order/Visibility etc. | |
| 3746 | + if (flags_for_section_to_display & (ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) | |
| 3747 | + if (BeginMenu(LocalizeGetMsg(ImGuiLocKey_TableReset))) | |
| 3748 | + { | |
| 3749 | + //if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetAll))) // FIXME: Hiding because altering Sort Order + requesting auto-fit simultaneously has a tendency to exhibit a sizing glitch. | |
| 3750 | + // table->IsResetAllRequest = true; | |
| 3751 | + if (flags_for_section_to_display & ImGuiTableFlags_Reorderable) | |
| 3752 | + if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetOrder), NULL, false, !table->IsDefaultDisplayOrder)) // PS: cannot be hidden because it would mess with drag reordering. | |
| 3753 | + table->IsResetDisplayOrderRequest = true; | |
| 3754 | + if (flags_for_section_to_display & ImGuiTableFlags_Hideable) | |
| 3755 | + if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetVisibility), NULL, false, !table->IsDefaultVisibility)) | |
| 3756 | + table->IsResetVisibilityRequest = true; | |
| 3757 | + EndMenu(); | |
| 3758 | + } | |
| 3607 | 3759 | |
| 3608 | - // Reset all (should work but seems unnecessary/noisy to expose?) | |
| 3609 | - //if (MenuItem("Reset all")) | |
| 3610 | - // table->IsResetAllRequest = true; | |
| 3611 | - | |
| 3612 | 3760 | // Sorting |
| 3613 | 3761 | // (modify TableOpenContextMenu() to add _Sortable flag if enabling this) |
| 3614 | 3762 | #if 0 |
| @@ -3692,6 +3840,7 @@ | ||
| 3692 | 3840 | // - TableResetSettings() |
| 3693 | 3841 | // - TableSaveSettings() [Internal] |
| 3694 | 3842 | // - TableLoadSettings() [Internal] |
| 3843 | +// - TableLoadSettingsForColumns() [Internal] | |
| 3695 | 3844 | // - TableSettingsHandler_ClearAll() [Internal] |
| 3696 | 3845 | // - TableSettingsHandler_ApplyAll() [Internal] |
| 3697 | 3846 | // - TableSettingsHandler_ReadOpen() [Internal] |
| @@ -3726,6 +3875,8 @@ | ||
| 3726 | 3875 | ImGuiTableSettings* ImGui::TableSettingsCreate(ImGuiID id, int columns_count) |
| 3727 | 3876 | { |
| 3728 | 3877 | ImGuiContext& g = *GImGui; |
| 3878 | + //ImGuiTableSettings* old_settings = TableSettingsFindByID(id); // Comment out sanity check to avoid unnecessary lookups. | |
| 3879 | + //IM_ASSERT(old_settings == NULL || old_settings->ColumnsCountMax < columns_count); | |
| 3729 | 3880 | ImGuiTableSettings* settings = g.SettingsTables.alloc_chunk(TableSettingsCalcChunkSize(columns_count)); |
| 3730 | 3881 | TableSettingsInit(settings, id, columns_count, columns_count); |
| 3731 | 3882 | return settings; |
| @@ -3745,16 +3896,12 @@ | ||
| 3745 | 3896 | // Get settings for a given table, NULL if none |
| 3746 | 3897 | ImGuiTableSettings* ImGui::TableGetBoundSettings(ImGuiTable* table) |
| 3747 | 3898 | { |
| 3748 | - if (table->SettingsOffset != -1) | |
| 3749 | - { | |
| 3750 | - ImGuiContext& g = *GImGui; | |
| 3751 | - ImGuiTableSettings* settings = g.SettingsTables.ptr_from_offset(table->SettingsOffset); | |
| 3752 | - IM_ASSERT(settings->ID == table->ID); | |
| 3753 | - if (settings->ColumnsCountMax >= table->ColumnsCount) | |
| 3754 | - return settings; // OK | |
| 3755 | - settings->ID = 0; // Invalidate storage, we won't fit because of a count change | |
| 3756 | - } | |
| 3757 | - return NULL; | |
| 3899 | + if (table->SettingsOffset == -1) | |
| 3900 | + return NULL; | |
| 3901 | + ImGuiContext& g = *GImGui; | |
| 3902 | + ImGuiTableSettings* settings = g.SettingsTables.ptr_from_offset(table->SettingsOffset); | |
| 3903 | + IM_ASSERT(settings->ID == table->ID); | |
| 3904 | + return settings; | |
| 3758 | 3905 | } |
| 3759 | 3906 | |
| 3760 | 3907 | // Restore initial state of table (with or without saved settings) |
| @@ -3775,6 +3922,11 @@ | ||
| 3775 | 3922 | // Bind or create settings data |
| 3776 | 3923 | ImGuiContext& g = *GImGui; |
| 3777 | 3924 | ImGuiTableSettings* settings = TableGetBoundSettings(table); |
| 3925 | + if (settings != NULL && table->ColumnsCount > settings->ColumnsCountMax) | |
| 3926 | + { | |
| 3927 | + settings->ID = 0; // Invalidate storage, we won't fit because of a count change | |
| 3928 | + settings = NULL; | |
| 3929 | + } | |
| 3778 | 3930 | if (settings == NULL) |
| 3779 | 3931 | { |
| 3780 | 3932 | settings = TableSettingsCreate(table->ID, table->ColumnsCount); |
| @@ -3793,6 +3945,7 @@ | ||
| 3793 | 3945 | for (int n = 0; n < table->ColumnsCount; n++, column++, column_settings++) |
| 3794 | 3946 | { |
| 3795 | 3947 | const float width_or_weight = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? column->StretchWeight : column->WidthRequest; |
| 3948 | + column_settings->ID = column->ID; | |
| 3796 | 3949 | column_settings->WidthOrWeight = width_or_weight; |
| 3797 | 3950 | column_settings->Index = (ImGuiTableColumnIdx)n; |
| 3798 | 3951 | column_settings->DisplayOrder = column->DisplayOrder; |
| @@ -3824,9 +3977,11 @@ | ||
| 3824 | 3977 | void ImGui::TableLoadSettings(ImGuiTable* table) |
| 3825 | 3978 | { |
| 3826 | 3979 | ImGuiContext& g = *GImGui; |
| 3827 | - table->IsSettingsRequestLoad = false; | |
| 3828 | 3980 | if (table->Flags & ImGuiTableFlags_NoSavedSettings) |
| 3981 | + { | |
| 3982 | + table->IsSettingsRequestLoad = false; // Done | |
| 3829 | 3983 | return; |
| 3984 | + } | |
| 3830 | 3985 | |
| 3831 | 3986 | // Bind settings |
| 3832 | 3987 | ImGuiTableSettings* settings; |
| @@ -3846,44 +4001,83 @@ | ||
| 3846 | 4001 | |
| 3847 | 4002 | table->SettingsLoadedFlags = settings->SaveFlags; |
| 3848 | 4003 | table->RefScale = settings->RefScale; |
| 4004 | + // TableUpdateLayout() will then call TableLoadSettingsForColumns() to apply the data. | |
| 4005 | +} | |
| 3849 | 4006 | |
| 3850 | - // Initialize default columns settings | |
| 3851 | - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) | |
| 3852 | - { | |
| 3853 | - ImGuiTableColumn* column = &table->Columns[column_n]; | |
| 3854 | - TableInitColumnDefaults(table, column, ~0); | |
| 3855 | - column->AutoFitQueue = 0x00; | |
| 3856 | - } | |
| 4007 | +// NB: This was written to be similar to the logic in TableReconcileColumns(). | |
| 4008 | +void ImGui::TableLoadSettingsForColumns(ImGuiTable* table) | |
| 4009 | +{ | |
| 4010 | + for (ImGuiTableColumn& column : table->Columns) | |
| 4011 | + column.IsLoadedSettings = false; | |
| 4012 | + ImGuiTableSettings* settings = TableGetBoundSettings(table); | |
| 4013 | + if (settings == NULL) | |
| 4014 | + return; | |
| 3857 | 4015 | |
| 4016 | + table->SettingsLoadedFlags |= ImGuiTableFlags_Reorderable; // We handle above in code above. | |
| 4017 | + | |
| 3858 | 4018 | // Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn |
| 3859 | 4019 | ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings(); |
| 3860 | - for (int data_n = 0; data_n < settings->ColumnsCount; data_n++, column_settings++) | |
| 4020 | + | |
| 4021 | + // Fast path | |
| 4022 | + int matches = 0; | |
| 4023 | + for (int n = 0; n < table->ColumnsCount; n++) | |
| 3861 | 4024 | { |
| 3862 | - int column_n = column_settings->Index; | |
| 3863 | - if (column_n < 0 || column_n >= table->ColumnsCount) | |
| 3864 | - continue; | |
| 4025 | + if (n >= settings->ColumnsCount || column_settings[n].ID != table->Columns[n].ID) | |
| 4026 | + break; | |
| 4027 | + TableLoadSettingsForColumn(&table->Columns[n], &column_settings[n], settings->SaveFlags); | |
| 4028 | + matches++; | |
| 4029 | + } | |
| 4030 | + if (matches == settings->ColumnsCount) | |
| 4031 | + return; | |
| 4032 | + const int settings_start_n = matches; // Small optimization | |
| 4033 | + for (int n = settings_start_n; n < settings->ColumnsCount; n++) | |
| 4034 | + column_settings[n].IsLoaded = false; | |
| 3865 | 4035 | |
| 3866 | - ImGuiTableColumn* column = &table->Columns[column_n]; | |
| 3867 | - if (settings->SaveFlags & ImGuiTableFlags_Resizable) | |
| 4036 | + // Find matches for named columns | |
| 4037 | + for (ImGuiTableColumn& column : table->Columns) | |
| 4038 | + if (column.ID != 0 && !column.IsLoadedSettings) | |
| 4039 | + for (int n = settings_start_n; n < settings->ColumnsCount; n++) | |
| 4040 | + if (column_settings[n].ID == column.ID && !column_settings[n].IsLoaded) | |
| 4041 | + { | |
| 4042 | + TableLoadSettingsForColumn(&column, &column_settings[n], settings->SaveFlags); | |
| 4043 | + matches++; | |
| 4044 | + break; | |
| 4045 | + } | |
| 4046 | + | |
| 4047 | + // Remaining entries are matched sequentially | |
| 4048 | + int dst_idx = 0; | |
| 4049 | + for (int n = settings_start_n; n < settings->ColumnsCount; n++) | |
| 4050 | + if (!column_settings[n].IsLoaded) | |
| 3868 | 4051 | { |
| 3869 | - if (column_settings->IsStretch) | |
| 3870 | - column->StretchWeight = column_settings->WidthOrWeight; | |
| 3871 | - else | |
| 3872 | - column->WidthRequest = column_settings->WidthOrWeight; | |
| 4052 | + while (dst_idx < table->ColumnsCount && table->Columns[dst_idx].IsLoadedSettings) | |
| 4053 | + dst_idx++; | |
| 4054 | + if (dst_idx >= table->ColumnsCount) | |
| 4055 | + break; | |
| 4056 | + TableLoadSettingsForColumn(&table->Columns[dst_idx], &column_settings[n], settings->SaveFlags); | |
| 4057 | + dst_idx++; | |
| 3873 | 4058 | } |
| 3874 | - if (settings->SaveFlags & ImGuiTableFlags_Reorderable) | |
| 3875 | - column->DisplayOrder = column_settings->DisplayOrder; | |
| 3876 | - if ((settings->SaveFlags & ImGuiTableFlags_Hideable) && column_settings->IsEnabled != -1) | |
| 3877 | - column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled == 1; | |
| 3878 | - column->SortOrder = column_settings->SortOrder; | |
| 3879 | - column->SortDirection = column_settings->SortDirection; | |
| 3880 | - } | |
| 4059 | +} | |
| 3881 | 4060 | |
| 3882 | - // Fix display order and build index | |
| 3883 | - if (settings->SaveFlags & ImGuiTableFlags_Reorderable) | |
| 3884 | - TableFixDisplayOrder(table); | |
| 3885 | - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) | |
| 3886 | - table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n; | |
| 4061 | +void ImGui::TableLoadSettingsForColumn(ImGuiTableColumn* column, ImGuiTableColumnSettings* column_settings, ImGuiTableFlags load_flags) | |
| 4062 | +{ | |
| 4063 | + column->IsLoadedSettings = true; | |
| 4064 | + column_settings->IsLoaded = true; | |
| 4065 | + if (load_flags & ImGuiTableFlags_Resizable) | |
| 4066 | + { | |
| 4067 | + if (column_settings->IsStretch) | |
| 4068 | + column->StretchWeight = column_settings->WidthOrWeight; | |
| 4069 | + else | |
| 4070 | + column->WidthRequest = column_settings->WidthOrWeight; | |
| 4071 | + column->AutoFitQueue = 0x00; | |
| 4072 | + } | |
| 4073 | + if (load_flags & ImGuiTableFlags_Reorderable) | |
| 4074 | + column->DisplayOrder = column_settings->DisplayOrder; | |
| 4075 | + else | |
| 4076 | + column->DisplayOrder = column_settings->Index; // Because default depends on previous Index, we need to set that up and cannot rely on TableInitColumnDefaults() | |
| 4077 | + if ((load_flags & ImGuiTableFlags_Hideable) && column_settings->IsEnabled != -1) | |
| 4078 | + column->IsUserEnabled = column->IsUserEnabledNextFrame = (column_settings->IsEnabled == 1); | |
| 4079 | + column->SortOrder = column_settings->SortOrder; | |
| 4080 | + column->SortDirection = column_settings->SortDirection; | |
| 3887 | 4081 | } |
| 3888 | 4082 | |
| 3889 | 4083 | struct ImGuiTableFixDisplayOrderColumnData |
| @@ -3898,7 +4092,8 @@ | ||
| 3898 | 4092 | const ImGuiTable* table = ((const ImGuiTableFixDisplayOrderColumnData*)lhs)->Table; |
| 3899 | 4093 | const ImGuiTableColumnIdx lhs_idx = ((const ImGuiTableFixDisplayOrderColumnData*)lhs)->Idx; |
| 3900 | 4094 | const ImGuiTableColumnIdx rhs_idx = ((const ImGuiTableFixDisplayOrderColumnData*)rhs)->Idx; |
| 3901 | - const int order_delta = (table->Columns[lhs_idx].DisplayOrder - table->Columns[rhs_idx].DisplayOrder); | |
| 4095 | + // Assume ImGuiTableColumnIdx == signed short, to turn -1 into a large value so that it always sort after. | |
| 4096 | + const int order_delta = ((unsigned short)table->Columns[lhs_idx].DisplayOrder - (unsigned short)table->Columns[rhs_idx].DisplayOrder); | |
| 3902 | 4097 | return (order_delta > 0) ? +1 : (order_delta < 0) ? -1 : (lhs_idx > rhs_idx) ? +1 : -1; |
| 3903 | 4098 | } |
| 3904 | 4099 | |
| @@ -3916,6 +4111,8 @@ | ||
| 3916 | 4111 | ImQsort(fdo_columns, (size_t)table->ColumnsCount, sizeof(ImGuiTableFixDisplayOrderColumnData), TableFixDisplayOrderComparer); |
| 3917 | 4112 | for (int n = 0; n < table->ColumnsCount; n++) |
| 3918 | 4113 | table->Columns[fdo_columns[n].Idx].DisplayOrder = (ImGuiTableColumnIdx)n; |
| 4114 | + for (int n = 0; n < table->ColumnsCount; n++) | |
| 4115 | + table->DisplayOrderToIndex[table->Columns[n].DisplayOrder] = (ImGuiTableColumnIdx)n; | |
| 3919 | 4116 | } |
| 3920 | 4117 | |
| 3921 | 4118 | static void TableSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) |
| @@ -3975,12 +4172,13 @@ | ||
| 3975 | 4172 | char c = 0; |
| 3976 | 4173 | ImGuiTableColumnSettings* column = settings->GetColumnSettings() + column_n; |
| 3977 | 4174 | column->Index = (ImGuiTableColumnIdx)column_n; |
| 3978 | - if (sscanf(line, "UserID=0x%08X%n", (ImU32*)&n, &r)==1) { line = ImStrSkipBlank(line + r); column->UserID = (ImGuiID)n; } | |
| 4175 | + if (sscanf(line, "UserID=0x%08X%n", (ImU32*)&n, &r)==1) { line = ImStrSkipBlank(line + r); } // FIXME-LEGACY: Removed 2025/11/12, was never properly set. | |
| 3979 | 4176 | if (sscanf(line, "Width=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = (float)n; column->IsStretch = 0; settings->SaveFlags |= ImGuiTableFlags_Resizable; } |
| 3980 | 4177 | if (sscanf(line, "Weight=%f%n", &f, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = f; column->IsStretch = 1; settings->SaveFlags |= ImGuiTableFlags_Resizable; } |
| 3981 | 4178 | if (sscanf(line, "Visible=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->IsEnabled = (ImU8)n; settings->SaveFlags |= ImGuiTableFlags_Hideable; } |
| 3982 | 4179 | if (sscanf(line, "Order=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->DisplayOrder = (ImGuiTableColumnIdx)n; settings->SaveFlags |= ImGuiTableFlags_Reorderable; } |
| 3983 | 4180 | if (sscanf(line, "Sort=%d%c%n", &n, &c, &r) == 2) { line = ImStrSkipBlank(line + r); column->SortOrder = (ImGuiTableColumnIdx)n; column->SortDirection = (c == '^') ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending; settings->SaveFlags |= ImGuiTableFlags_Sortable; } |
| 4181 | + if (sscanf(line, "ID=0x%08X%n", (ImU32*)&n, &r) == 1) { line = ImStrSkipBlank(line + r); column->ID = (ImGuiID)n; } | |
| 3984 | 4182 | } |
| 3985 | 4183 | } |
| 3986 | 4184 | |
| @@ -4008,16 +4206,16 @@ | ||
| 4008 | 4206 | for (int column_n = 0; column_n < settings->ColumnsCount; column_n++, column++) |
| 4009 | 4207 | { |
| 4010 | 4208 | // "Column 0 UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v" |
| 4011 | - bool save_column = column->UserID != 0 || save_size || save_visible || save_order || (save_sort && column->SortOrder != -1); | |
| 4209 | + bool save_column = save_size || save_visible || save_order || (save_sort && column->SortOrder != -1); | |
| 4012 | 4210 | if (!save_column) |
| 4013 | 4211 | continue; |
| 4014 | 4212 | buf->appendf("Column %-2d", column_n); |
| 4015 | - if (column->UserID != 0) { buf->appendf(" UserID=%08X", column->UserID); } | |
| 4016 | 4213 | if (save_size && column->IsStretch) { buf->appendf(" Weight=%.4f", column->WidthOrWeight); } |
| 4017 | 4214 | if (save_size && !column->IsStretch) { buf->appendf(" Width=%d", (int)column->WidthOrWeight); } |
| 4018 | 4215 | if (save_visible) { buf->appendf(" Visible=%d", column->IsEnabled); } |
| 4019 | 4216 | if (save_order) { buf->appendf(" Order=%d", column->DisplayOrder); } |
| 4020 | 4217 | if (save_sort && column->SortOrder != -1) { buf->appendf(" Sort=%d%c", column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? 'v' : '^'); } |
| 4218 | + if (column->ID != 0) { buf->appendf(" ID=0x%08X", column->ID); } | |
| 4021 | 4219 | buf->append("\n"); |
| 4022 | 4220 | } |
| 4023 | 4221 | buf->append("\n"); |
| @@ -4075,11 +4273,12 @@ | ||
| 4075 | 4273 | |
| 4076 | 4274 | void ImGui::TableGcCompactTransientBuffers(ImGuiTableTempData* temp_data) |
| 4077 | 4275 | { |
| 4276 | + temp_data->AngledHeadersRequests.clear(); | |
| 4078 | 4277 | temp_data->DrawSplitter.ClearFreeMemory(); |
| 4079 | 4278 | temp_data->LastTimeActive = -1.0f; |
| 4080 | 4279 | } |
| 4081 | 4280 | |
| 4082 | -// Compact and remove unused settings data (currently only used by TestEngine) | |
| 4281 | +// Compact and remove unused or resize settings data (only TestEngine mark unused, but resizing table down can lead to compaction) | |
| 4083 | 4282 | void ImGui::TableGcCompactSettings() |
| 4084 | 4283 | { |
| 4085 | 4284 | ImGuiContext& g = *GImGui; |
| @@ -4095,6 +4294,9 @@ | ||
| 4095 | 4294 | if (settings->ID != 0) |
| 4096 | 4295 | memcpy(new_chunk_stream.alloc_chunk(TableSettingsCalcChunkSize(settings->ColumnsCount)), settings, TableSettingsCalcChunkSize(settings->ColumnsCount)); |
| 4097 | 4296 | g.SettingsTables.swap(new_chunk_stream); |
| 4297 | + for (int table_n = 0; table_n < g.Tables.GetMapSize(); table_n++) | |
| 4298 | + if (ImGuiTable* table = g.Tables.TryGetMapData(table_n)) | |
| 4299 | + table->SettingsOffset = -1; | |
| 4098 | 4300 | } |
| 4099 | 4301 | |
| 4100 | 4302 | |
| @@ -4102,6 +4304,7 @@ | ||
| 4102 | 4304 | // [SECTION] Tables: Debugging |
| 4103 | 4305 | //------------------------------------------------------------------------- |
| 4104 | 4306 | // - DebugNodeTable() [Internal] |
| 4307 | +// - DebugNodeTableSettings() [Internal] | |
| 4105 | 4308 | //------------------------------------------------------------------------- |
| 4106 | 4309 | |
| 4107 | 4310 | #ifndef IMGUI_DISABLE_DEBUG_TOOLS |
| @@ -4165,13 +4368,13 @@ | ||
| 4165 | 4368 | "WidthGiven: %.1f, Request/Auto: %.1f/%.1f, StretchWeight: %.3f (%.1f%%)\n" |
| 4166 | 4369 | "MinX: %.1f, MaxX: %.1f (%+.1f), ClipRect: %.1f to %.1f (+%.1f)\n" |
| 4167 | 4370 | "ContentWidth: %.1f,%.1f, HeadersUsed/Ideal %.1f/%.1f\n" |
| 4168 | - "Sort: %d%s, UserID: 0x%08X, Flags: 0x%04X: %s%s%s..", | |
| 4371 | + "Sort: %d%s, UserData: 0x%08X, Flags: 0x%04X: %s%s%s..", | |
| 4169 | 4372 | n, column->DisplayOrder, name, column->MinX - table->WorkRect.Min.x, column->MaxX - table->WorkRect.Min.x, (n < table->FreezeColumnsRequest) ? " (Frozen)" : "", |
| 4170 | 4373 | column->IsEnabled, column->IsVisibleX, column->IsVisibleY, column->IsRequestOutput, column->IsSkipItems, column->DrawChannelFrozen, column->DrawChannelUnfrozen, |
| 4171 | 4374 | column->WidthGiven, column->WidthRequest, column->WidthAuto, column->StretchWeight, column->StretchWeight > 0.0f ? (column->StretchWeight / sum_weights) * 100.0f : 0.0f, |
| 4172 | 4375 | column->MinX, column->MaxX, column->MaxX - column->MinX, column->ClipRect.Min.x, column->ClipRect.Max.x, column->ClipRect.Max.x - column->ClipRect.Min.x, |
| 4173 | 4376 | column->ContentMaxXFrozen - column->WorkMinX, column->ContentMaxXUnfrozen - column->WorkMinX, column->ContentMaxXHeadersUsed - column->WorkMinX, column->ContentMaxXHeadersIdeal - column->WorkMinX, |
| 4174 | - column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? " (Asc)" : (column->SortDirection == ImGuiSortDirection_Descending) ? " (Des)" : "", column->UserID, column->Flags, | |
| 4377 | + column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? " (Asc)" : (column->SortDirection == ImGuiSortDirection_Descending) ? " (Des)" : "", column->UserData, column->Flags, | |
| 4175 | 4378 | (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? "WidthStretch " : "", |
| 4176 | 4379 | (column->Flags & ImGuiTableColumnFlags_WidthFixed) ? "WidthFixed " : "", |
| 4177 | 4380 | (column->Flags & ImGuiTableColumnFlags_NoResize) ? "NoResize " : ""); |
| @@ -4184,34 +4387,45 @@ | ||
| 4184 | 4387 | } |
| 4185 | 4388 | } |
| 4186 | 4389 | if (ImGuiTableSettings* settings = TableGetBoundSettings(table)) |
| 4187 | - DebugNodeTableSettings(settings); | |
| 4390 | + DebugNodeTableSettings(settings, table); | |
| 4188 | 4391 | if (clear_settings) |
| 4189 | - table->IsResetAllRequest = true; | |
| 4392 | + table->IsResetAllRequest = true; // Queue a call to TableResetSettings() | |
| 4190 | 4393 | TreePop(); |
| 4191 | 4394 | } |
| 4192 | 4395 | |
| 4193 | -void ImGui::DebugNodeTableSettings(ImGuiTableSettings* settings) | |
| 4396 | +void ImGui::DebugNodeTableSettings(ImGuiTableSettings* settings, ImGuiTable* table) | |
| 4194 | 4397 | { |
| 4195 | - if (!TreeNode((void*)(intptr_t)settings->ID, "Settings 0x%08X (%d columns)", settings->ID, settings->ColumnsCount)) | |
| 4196 | - return; | |
| 4197 | - BulletText("SaveFlags: 0x%08X", settings->SaveFlags); | |
| 4198 | - BulletText("ColumnsCount: %d (max %d)", settings->ColumnsCount, settings->ColumnsCountMax); | |
| 4199 | - for (int n = 0; n < settings->ColumnsCount; n++) | |
| 4398 | + if (settings->ID == 0) | |
| 4399 | + PushID(settings); | |
| 4400 | + const bool open = TreeNode((void*)(intptr_t)settings->ID, "Settings 0x%08X (%d columns)", settings->ID, settings->ColumnsCount); | |
| 4401 | + const bool hovered = IsItemHovered(); | |
| 4402 | + if (hovered && table == NULL && settings->ID != 0) | |
| 4403 | + table = TableFindByID(settings->ID); | |
| 4404 | + if (hovered && table != NULL) | |
| 4405 | + GetForegroundDrawList(table->OuterWindow)->AddRect(table->OuterRect.Min, table->OuterRect.Max, IM_COL32(255, 255, 0, 255)); | |
| 4406 | + if (open) | |
| 4200 | 4407 | { |
| 4201 | - ImGuiTableColumnSettings* column_settings = &settings->GetColumnSettings()[n]; | |
| 4202 | - ImGuiSortDirection sort_dir = (column_settings->SortOrder != -1) ? (ImGuiSortDirection)column_settings->SortDirection : ImGuiSortDirection_None; | |
| 4203 | - BulletText("Column %d Order %d SortOrder %d %s Vis %d %s %7.3f UserID 0x%08X", | |
| 4204 | - n, column_settings->DisplayOrder, column_settings->SortOrder, | |
| 4205 | - (sort_dir == ImGuiSortDirection_Ascending) ? "Asc" : (sort_dir == ImGuiSortDirection_Descending) ? "Des" : "---", | |
| 4206 | - column_settings->IsEnabled, column_settings->IsStretch ? "Weight" : "Width ", column_settings->WidthOrWeight, column_settings->UserID); | |
| 4408 | + BulletText("SaveFlags: 0x%08X", settings->SaveFlags); | |
| 4409 | + BulletText("ColumnsCount: %d (max %d)", settings->ColumnsCount, settings->ColumnsCountMax); | |
| 4410 | + for (int n = 0; n < settings->ColumnsCount; n++) | |
| 4411 | + { | |
| 4412 | + ImGuiTableColumnSettings* column_settings = &settings->GetColumnSettings()[n]; | |
| 4413 | + ImGuiSortDirection sort_dir = (column_settings->SortOrder != -1) ? (ImGuiSortDirection)column_settings->SortDirection : ImGuiSortDirection_None; | |
| 4414 | + BulletText("Column %d Order %d SortOrder %2d %s Vis %d %s %7.3f ID 0x%08X", | |
| 4415 | + n, column_settings->DisplayOrder, column_settings->SortOrder, | |
| 4416 | + (sort_dir == ImGuiSortDirection_Ascending) ? "Asc" : (sort_dir == ImGuiSortDirection_Descending) ? "Des" : "---", | |
| 4417 | + column_settings->IsEnabled, column_settings->IsStretch ? "Weight" : "Width ", column_settings->WidthOrWeight, column_settings->ID); | |
| 4418 | + } | |
| 4419 | + TreePop(); | |
| 4207 | 4420 | } |
| 4208 | - TreePop(); | |
| 4421 | + if (settings->ID == 0) | |
| 4422 | + PopID(); | |
| 4209 | 4423 | } |
| 4210 | 4424 | |
| 4211 | 4425 | #else // #ifndef IMGUI_DISABLE_DEBUG_TOOLS |
| 4212 | 4426 | |
| 4213 | 4427 | void ImGui::DebugNodeTable(ImGuiTable*) {} |
| 4214 | -void ImGui::DebugNodeTableSettings(ImGuiTableSettings*) {} | |
| 4428 | +void ImGui::DebugNodeTableSettings(ImGuiTableSettings*, ImGuiTable*) {} | |
| 4215 | 4429 | |
| 4216 | 4430 | #endif |
| 4217 | 4431 |
| @@ -1,4 +1,4 @@ | ||
| 1 | -// dear imgui, v1.92.8 | |
| 1 | +// dear imgui, v1.92.9 WIP | |
| 2 | 2 | // (widgets code) |
| 3 | 3 | |
| 4 | 4 | /* |
| @@ -266,6 +266,8 @@ | ||
| 266 | 266 | } |
| 267 | 267 | } |
| 268 | 268 | |
| 269 | +// Note that all functions taking format strings in the API may be passed ("%s", text) or ("%.*s", text_len, text), | |
| 270 | +// which will automatically bypass the formatter. | |
| 269 | 271 | void ImGui::TextUnformatted(const char* text, const char* text_end) |
| 270 | 272 | { |
| 271 | 273 | TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText); |
| @@ -562,7 +564,7 @@ | ||
| 562 | 564 | flags |= (item_flags & ImGuiItemFlags_ButtonRepeat) ? ImGuiButtonFlags_PressedOnClick : ImGuiButtonFlags_PressedOnDefault_; |
| 563 | 565 | |
| 564 | 566 | ImGuiWindow* backup_hovered_window = g.HoveredWindow; |
| 565 | - const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window->RootWindow; | |
| 567 | + const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindowDockTree == window->RootWindowDockTree; | |
| 566 | 568 | if (flatten_hovered_children) |
| 567 | 569 | g.HoveredWindow = window; |
| 568 | 570 | |
| @@ -937,7 +939,8 @@ | ||
| 937 | 939 | return pressed; |
| 938 | 940 | } |
| 939 | 941 | |
| 940 | -bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos) | |
| 942 | +// The Collapse button also functions as a Dock Menu button. | |
| 943 | +bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_node) | |
| 941 | 944 | { |
| 942 | 945 | ImGuiContext& g = *GImGui; |
| 943 | 946 | ImGuiWindow* window = g.CurrentWindow; |
| @@ -950,16 +953,21 @@ | ||
| 950 | 953 | return pressed; |
| 951 | 954 | |
| 952 | 955 | // Render |
| 956 | + //bool is_dock_menu = (window->DockNodeAsHost && !window->Collapsed); | |
| 953 | 957 | ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); |
| 954 | 958 | ImU32 text_col = GetColorU32(ImGuiCol_Text); |
| 955 | 959 | if (hovered || held) |
| 956 | 960 | window->DrawList->AddRectFilled(bb.Min, bb.Max, bg_col); |
| 957 | 961 | RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact); |
| 958 | - RenderArrow(window->DrawList, bb.Min, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); | |
| 959 | 962 | |
| 963 | + if (dock_node) | |
| 964 | + RenderArrowDockMenu(window->DrawList, bb.Min, g.FontSize, text_col); | |
| 965 | + else | |
| 966 | + RenderArrow(window->DrawList, bb.Min, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); | |
| 967 | + | |
| 960 | 968 | // Switch to moving the window after mouse is moved beyond the initial drag threshold |
| 961 | 969 | if (IsItemActive() && IsMouseDragging(0)) |
| 962 | - StartMouseMovingWindow(window); | |
| 970 | + StartMouseMovingWindowOrNode(window, dock_node, true); // Undock from window/collapse menu button | |
| 963 | 971 | |
| 964 | 972 | return pressed; |
| 965 | 973 | } |
| @@ -1003,7 +1011,8 @@ | ||
| 1003 | 1011 | |
| 1004 | 1012 | // Calculate scrollbar bounding box |
| 1005 | 1013 | ImRect bb = GetWindowScrollbarRect(window, axis); |
| 1006 | - ImDrawFlags rounding_corners = CalcRoundingFlagsForRectInRect(bb, window->Rect(), g.Style.WindowBorderSize); | |
| 1014 | + ImRect host_rect = (window->DockIsActive ? window->DockNode->HostWindow : window)->Rect(); | |
| 1015 | + ImDrawFlags rounding_corners = CalcRoundingFlagsForRectInRect(bb, host_rect, g.Style.WindowBorderSize); | |
| 1007 | 1016 | float size_visible = window->InnerRect.Max[axis] - window->InnerRect.Min[axis]; |
| 1008 | 1017 | float size_contents = window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f; |
| 1009 | 1018 | ImS64 scroll = (ImS64)window->Scroll[axis]; |
| @@ -1272,7 +1281,7 @@ | ||
| 1272 | 1281 | |
| 1273 | 1282 | // Range-Selection/Multi-selection support (footer) |
| 1274 | 1283 | if (is_multi_select) |
| 1275 | - MultiSelectItemFooter(id, &checked, &pressed); | |
| 1284 | + MultiSelectItemFooter(id, &checked, &pressed, ImGuiMultiSelectFlags_CheckboxMode_); | |
| 1276 | 1285 | else if (pressed) |
| 1277 | 1286 | checked = !checked; |
| 1278 | 1287 | |
| @@ -1575,7 +1584,7 @@ | ||
| 1575 | 1584 | bool pressed = TextLink(label); |
| 1576 | 1585 | if (pressed && g.PlatformIO.Platform_OpenInShellFn != NULL) |
| 1577 | 1586 | g.PlatformIO.Platform_OpenInShellFn(&g, url); |
| 1578 | - SetItemTooltip(LocalizeGetMsg(ImGuiLocKey_OpenLink_s), url); // It is more reassuring for user to _always_ display URL when we same as label | |
| 1587 | + SetItemTooltip(LocalizeGetMsg(ImGuiLocKey_OpenLink_s), url); // It is more reassuring for user to _always_ display URL when it is the same as the label. | |
| 1579 | 1588 | if (BeginPopupContextItem()) |
| 1580 | 1589 | { |
| 1581 | 1590 | if (MenuItem(LocalizeGetMsg(ImGuiLocKey_CopyLink))) |
| @@ -1746,14 +1755,14 @@ | ||
| 1746 | 1755 | const float separator_thickness = style.SeparatorTextBorderSize; |
| 1747 | 1756 | const ImVec2 min_size(label_size.x + extra_w + padding.x * 2.0f, ImMax(label_size.y + padding.y * 2.0f, separator_thickness)); |
| 1748 | 1757 | const ImRect bb(pos, ImVec2(window->WorkRect.Max.x, pos.y + min_size.y)); |
| 1749 | - const float text_baseline_y = ImTrunc((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.99999f); //ImMax(padding.y, ImTrunc((style.SeparatorTextSize - label_size.y) * 0.5f)); | |
| 1758 | + const float text_baseline_y = ImTrunc((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.999f); //ImMax(padding.y, ImTrunc((style.SeparatorTextSize - label_size.y) * 0.5f)); | |
| 1750 | 1759 | ItemSize(min_size, text_baseline_y); |
| 1751 | 1760 | if (!ItemAdd(bb, id)) |
| 1752 | 1761 | return; |
| 1753 | 1762 | |
| 1754 | 1763 | const float sep1_x1 = pos.x; |
| 1755 | 1764 | const float sep2_x2 = bb.Max.x; |
| 1756 | - const float seps_y = ImTrunc((bb.Min.y + bb.Max.y) * 0.5f + 0.99999f); | |
| 1765 | + const float seps_y = ImTrunc((bb.Min.y + bb.Max.y) * 0.5f + 0.999f); | |
| 1757 | 1766 | |
| 1758 | 1767 | const float label_avail_w = ImMax(0.0f, sep2_x2 - sep1_x1 - padding.x * 2.0f); |
| 1759 | 1768 | const ImVec2 label_pos(pos.x + padding.x + ImMax(0.0f, (label_avail_w - label_size.x - extra_w) * style.SeparatorTextAlign.x), pos.y + text_baseline_y); // FIXME-ALIGN |
| @@ -5641,7 +5650,7 @@ | ||
| 5641 | 5650 | ImVec2 cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll); |
| 5642 | 5651 | 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); |
| 5643 | 5652 | if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) |
| 5644 | - draw_window->DrawList->AddLineV(cursor_screen_rect.Min.x, cursor_screen_rect.Min.y, cursor_screen_rect.Max.y, GetColorU32(ImGuiCol_InputTextCursor), 1.0f * (float)(int)style._MainScale); // FIXME-DPI: Cursor thickness (#7031) | |
| 5653 | + draw_window->DrawList->AddLineV(cursor_screen_rect.Min.x, cursor_screen_rect.Min.y, cursor_screen_rect.Max.y, GetColorU32(ImGuiCol_InputTextCursor), style.InputTextCursorSize); | |
| 5645 | 5654 | |
| 5646 | 5655 | // 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.) |
| 5647 | 5656 | // This is required for some backends (SDL3) to start emitting character/text inputs. |
| @@ -7114,9 +7123,9 @@ | ||
| 7114 | 7123 | if (hovered || selected) |
| 7115 | 7124 | { |
| 7116 | 7125 | const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); |
| 7117 | - RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false); | |
| 7126 | + RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false, 0.0f); | |
| 7118 | 7127 | } |
| 7119 | - RenderNavCursor(frame_bb, id, nav_render_cursor_flags); | |
| 7128 | + RenderNavCursor(frame_bb, id, nav_render_cursor_flags, 0.0f); | |
| 7120 | 7129 | if (span_all_columns && !span_all_columns_label) |
| 7121 | 7130 | TablePopBackgroundChannel(); |
| 7122 | 7131 | if (flags & ImGuiTreeNodeFlags_Bullet) |
| @@ -7496,14 +7505,14 @@ | ||
| 7496 | 7505 | { |
| 7497 | 7506 | // Between 1.91.0 and 1.91.4 we made selected Selectable use an arbitrary lerp between _Header and _HeaderHovered. Removed that now. (#8106) |
| 7498 | 7507 | ImU32 col = GetColorU32((held && highlighted) ? ImGuiCol_HeaderActive : highlighted ? ImGuiCol_HeaderHovered : ImGuiCol_Header); |
| 7499 | - RenderFrame(bb.Min, bb.Max, col, false, 0.0f); | |
| 7508 | + RenderFrame(bb.Min, bb.Max, col, false, style.SelectableRounding); | |
| 7500 | 7509 | } |
| 7501 | 7510 | if (g.NavId == id) |
| 7502 | 7511 | { |
| 7503 | - ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding; | |
| 7512 | + ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact; | |
| 7504 | 7513 | if (is_multi_select) |
| 7505 | 7514 | nav_render_cursor_flags |= ImGuiNavRenderCursorFlags_AlwaysDraw; // Always show the nav rectangle |
| 7506 | - RenderNavCursor(bb, id, nav_render_cursor_flags); | |
| 7515 | + RenderNavCursor(bb, id, nav_render_cursor_flags, style.SelectableRounding); | |
| 7507 | 7516 | } |
| 7508 | 7517 | } |
| 7509 | 7518 | |
| @@ -8305,7 +8314,7 @@ | ||
| 8305 | 8314 | // - Altering selection based on Ctrl/Shift modifiers, both for keyboard and mouse. |
| 8306 | 8315 | // - Record current selection state for RangeSrc |
| 8307 | 8316 | // This is all rather complex, best to run and refer to "widgets_multiselect_xxx" tests in imgui_test_suite. |
| 8308 | -void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed) | |
| 8317 | +void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed, ImGuiMultiSelectFlags extra_flags) | |
| 8309 | 8318 | { |
| 8310 | 8319 | ImGuiContext& g = *GImGui; |
| 8311 | 8320 | ImGuiWindow* window = g.CurrentWindow; |
| @@ -8325,7 +8334,7 @@ | ||
| 8325 | 8334 | |
| 8326 | 8335 | ImGuiSelectionUserData item_data = g.NextItemData.SelectionUserData; |
| 8327 | 8336 | |
| 8328 | - ImGuiMultiSelectFlags flags = ms->Flags; | |
| 8337 | + ImGuiMultiSelectFlags flags = ms->Flags | extra_flags; | |
| 8329 | 8338 | const bool is_singleselect = (flags & ImGuiMultiSelectFlags_SingleSelect) != 0; |
| 8330 | 8339 | bool is_ctrl = (ms->KeyMods & ImGuiMod_Ctrl) != 0; |
| 8331 | 8340 | bool is_shift = (ms->KeyMods & ImGuiMod_Shift) != 0; |
| @@ -8479,7 +8488,7 @@ | ||
| 8479 | 8488 | //IM_ASSERT(storage->HasRangeSrc && storage->HasRangeValue); |
| 8480 | 8489 | if (storage->RangeSrcItem == ImGuiSelectionUserData_Invalid) |
| 8481 | 8490 | storage->RangeSrcItem = item_data; |
| 8482 | - if ((flags & ImGuiMultiSelectFlags_NoAutoSelect) == 0) | |
| 8491 | + if ((flags & ImGuiMultiSelectFlags_CheckboxMode_) == 0) | |
| 8483 | 8492 | { |
| 8484 | 8493 | // Shift+Arrow always select |
| 8485 | 8494 | // Ctrl+Shift+Arrow copy source selection state (already stored by BeginMultiSelect() in storage->RangeSelected) |
| @@ -8499,7 +8508,7 @@ | ||
| 8499 | 8508 | else |
| 8500 | 8509 | { |
| 8501 | 8510 | // Ctrl inverts selection, otherwise always select |
| 8502 | - if ((flags & ImGuiMultiSelectFlags_NoAutoSelect) == 0) | |
| 8511 | + if ((flags & ImGuiMultiSelectFlags_CheckboxMode_) == 0) | |
| 8503 | 8512 | selected = is_ctrl ? !selected : true; |
| 8504 | 8513 | else |
| 8505 | 8514 | selected = !selected; |
| @@ -8950,7 +8959,7 @@ | ||
| 8950 | 8959 | // Tooltip on hover |
| 8951 | 8960 | if (hovered && inner_bb.Contains(g.IO.MousePos)) |
| 8952 | 8961 | { |
| 8953 | - const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f); | |
| 8962 | + const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.999f); | |
| 8954 | 8963 | const int v_idx = (int)(t * item_count); |
| 8955 | 8964 | IM_ASSERT(v_idx >= 0 && v_idx < values_count); |
| 8956 | 8965 | |
| @@ -9163,9 +9172,10 @@ | ||
| 9163 | 9172 | |
| 9164 | 9173 | // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. |
| 9165 | 9174 | // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. |
| 9166 | - const float border_top = ImMax(window->WindowBorderSize * 0.5f - window->TitleBarHeight, 0.0f); | |
| 9175 | + const float border_top = ImMax(IM_ROUND(window->WindowBorderSize * 0.5f - window->TitleBarHeight), 0.0f); | |
| 9176 | + const float border_half = IM_ROUND(window->WindowBorderSize * 0.5f); | |
| 9167 | 9177 | ImRect bar_rect = window->MenuBarRect(); |
| 9168 | - ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize * 0.5f), IM_ROUND(bar_rect.Min.y + border_top), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize * 0.5f))), IM_ROUND(bar_rect.Max.y)); | |
| 9178 | + ImRect clip_rect(ImFloor(bar_rect.Min.x + border_half), ImFloor(bar_rect.Min.y + border_top), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, border_half))), ImFloor(bar_rect.Max.y)); | |
| 9169 | 9179 | clip_rect.ClipWith(window->OuterRectClipped); |
| 9170 | 9180 | PushClipRect(clip_rect.Min, clip_rect.Max, false); |
| 9171 | 9181 | |
| @@ -9246,10 +9256,10 @@ | ||
| 9246 | 9256 | IM_ASSERT(dir != ImGuiDir_None); |
| 9247 | 9257 | |
| 9248 | 9258 | ImGuiWindow* bar_window = FindWindowByName(name); |
| 9259 | + ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)(viewport_p ? viewport_p : GetMainViewport()); | |
| 9249 | 9260 | if (bar_window == NULL || bar_window->BeginCount == 0) |
| 9250 | 9261 | { |
| 9251 | 9262 | // Calculate and set window size/position |
| 9252 | - ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)(viewport_p ? viewport_p : GetMainViewport()); | |
| 9253 | 9263 | ImRect avail_rect = viewport->GetBuildWorkRect(); |
| 9254 | 9264 | ImGuiAxis axis = (dir == ImGuiDir_Up || dir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X; |
| 9255 | 9265 | ImVec2 pos = avail_rect.Min; |
| @@ -9267,7 +9277,8 @@ | ||
| 9267 | 9277 | viewport->BuildWorkInsetMax[axis] += axis_size; |
| 9268 | 9278 | } |
| 9269 | 9279 | |
| 9270 | - window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; | |
| 9280 | + window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDocking; | |
| 9281 | + SetNextWindowViewport(viewport->ID); // Enforce viewport so we don't create our own viewport when ImGuiConfigFlags_ViewportsNoMerge is set. | |
| 9271 | 9282 | PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); |
| 9272 | 9283 | PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0)); // Lift normal size constraint |
| 9273 | 9284 | bool is_open = Begin(name, NULL, window_flags); |
| @@ -9281,6 +9292,9 @@ | ||
| 9281 | 9292 | ImGuiContext& g = *GImGui; |
| 9282 | 9293 | ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport(); |
| 9283 | 9294 | |
| 9295 | + // Notify of viewport change so GetFrameHeight() can be accurate in case of DPI change | |
| 9296 | + SetCurrentViewport(NULL, viewport); | |
| 9297 | + | |
| 9284 | 9298 | // For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set. |
| 9285 | 9299 | // FIXME: This could be generalized as an opt-in way to clamp window->DC.CursorStartPos to avoid SafeArea? |
| 9286 | 9300 | // FIXME: Consider removing support for safe area down the line... it's messy. Nowadays consoles have support for TV calibration in OS settings. |
| @@ -9338,7 +9352,7 @@ | ||
| 9338 | 9352 | const ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size]; |
| 9339 | 9353 | if (window->DC.NavLayerCurrent != upper_popup->ParentNavLayer) |
| 9340 | 9354 | return false; |
| 9341 | - return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window, true); | |
| 9355 | + return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window, true, false); | |
| 9342 | 9356 | } |
| 9343 | 9357 | |
| 9344 | 9358 | bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) |
| @@ -9348,7 +9362,7 @@ | ||
| 9348 | 9362 | return false; |
| 9349 | 9363 | |
| 9350 | 9364 | ImGuiContext& g = *GImGui; |
| 9351 | - const ImGuiStyle& style = g.Style; | |
| 9365 | + ImGuiStyle& style = g.Style; | |
| 9352 | 9366 | const ImGuiID id = window->GetID(label); |
| 9353 | 9367 | bool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None); |
| 9354 | 9368 | |
| @@ -9393,6 +9407,8 @@ | ||
| 9393 | 9407 | |
| 9394 | 9408 | bool pressed; |
| 9395 | 9409 | |
| 9410 | + const float backup_rounding = style.SelectableRounding; | |
| 9411 | + style.SelectableRounding = style.MenuItemRounding; | |
| 9396 | 9412 | const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoAutoClosePopups | (ImGuiSelectableFlags)ImGuiSelectableFlags_SelectOnClick; |
| 9397 | 9413 | ImGuiMenuColumns* offsets = &window->DC.MenuColumns; |
| 9398 | 9414 | if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) |
| @@ -9428,6 +9444,7 @@ | ||
| 9428 | 9444 | RenderArrow(window->DrawList, ImVec2(text_pos.x + offsets->OffsetMark + extra_w + g.FontSize * 0.30f, text_pos.y), GetColorU32(ImGuiCol_Text), ImGuiDir_Right); |
| 9429 | 9445 | popup_pos = ImVec2(pos.x, text_pos.y - style.WindowPadding.y); |
| 9430 | 9446 | } |
| 9447 | + style.SelectableRounding = backup_rounding; | |
| 9431 | 9448 | if (!enabled) |
| 9432 | 9449 | EndDisabled(); |
| 9433 | 9450 | |
| @@ -9614,6 +9631,8 @@ | ||
| 9614 | 9631 | BeginDisabled(); |
| 9615 | 9632 | |
| 9616 | 9633 | // We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another. |
| 9634 | + const float backup_rounding = style.SelectableRounding; | |
| 9635 | + style.SelectableRounding = style.MenuItemRounding; | |
| 9617 | 9636 | const ImGuiSelectableFlags selectable_flags = (ImGuiSelectableFlags)ImGuiSelectableFlags_SelectOnRelease | (ImGuiSelectableFlags)ImGuiSelectableFlags_SetNavIdOnHover; |
| 9618 | 9637 | ImGuiMenuColumns* offsets = &window->DC.MenuColumns; |
| 9619 | 9638 | if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) |
| @@ -9636,7 +9655,7 @@ | ||
| 9636 | 9655 | // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.) |
| 9637 | 9656 | float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; |
| 9638 | 9657 | float shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, NULL).x : 0.0f; |
| 9639 | - float checkmark_w = IM_TRUNC(g.FontSize * 1.20f); | |
| 9658 | + float checkmark_w = IM_TRUNC(g.FontSize * 1.20f); // FIXME: Always accounted for, even in a menu with none, because 'selected' has no neutral setting. | |
| 9640 | 9659 | float min_w = offsets->DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame |
| 9641 | 9660 | float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); |
| 9642 | 9661 | ImVec2 text_pos(pos.x, pos.y + window->DC.CurrLineTextBaseOffset); |
| @@ -9657,6 +9676,7 @@ | ||
| 9657 | 9676 | RenderCheckMark(window->DrawList, text_pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f); |
| 9658 | 9677 | } |
| 9659 | 9678 | } |
| 9679 | + style.SelectableRounding = backup_rounding; | |
| 9660 | 9680 | |
| 9661 | 9681 | // Once dragged, release ActiveId + key ownership. This is to allow the idiom of mouse down a menu, dragging elsewhere, up on some other MenuItem(). (#8233, #9394) |
| 9662 | 9682 | // Could move logic into lower-level ImGuiButtonFlags_AutoReleaseActiveId + ImGuiButtonFlags_AutoReleaseKeyOwner? Easier once we get rid of the Selectable() middle-man here. |
| @@ -9705,8 +9725,10 @@ | ||
| 9705 | 9725 | // - TabBarCalcMaxTabWidth() [Internal] |
| 9706 | 9726 | // - TabBarFindTabById() [Internal] |
| 9707 | 9727 | // - TabBarFindTabByOrder() [Internal] |
| 9728 | +// - TabBarFindMostRecentlySelectedTabForActiveWindow() [Internal] | |
| 9708 | 9729 | // - TabBarGetCurrentTab() [Internal] |
| 9709 | 9730 | // - TabBarGetTabName() [Internal] |
| 9731 | +// - TabBarAddTab() [Internal] | |
| 9710 | 9732 | // - TabBarRemoveTab() [Internal] |
| 9711 | 9733 | // - TabBarCloseTab() [Internal] |
| 9712 | 9734 | // - TabBarScrollClamp() [Internal] |
| @@ -9823,7 +9845,7 @@ | ||
| 9823 | 9845 | return false; |
| 9824 | 9846 | |
| 9825 | 9847 | IM_ASSERT(tab_bar->ID != 0); |
| 9826 | - if ((flags & ImGuiTabBarFlags_DockNode) == 0) | |
| 9848 | + if ((flags & ImGuiTabBarFlags_DockNode) == 0) // Already done | |
| 9827 | 9849 | PushOverrideID(tab_bar->ID); |
| 9828 | 9850 | |
| 9829 | 9851 | // Add to stack |
| @@ -9842,7 +9864,8 @@ | ||
| 9842 | 9864 | |
| 9843 | 9865 | // Ensure correct ordering when toggling ImGuiTabBarFlags_Reorderable flag, or when a new tab was added while being not reorderable |
| 9844 | 9866 | if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable))) |
| 9845 | - ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder); | |
| 9867 | + if ((flags & ImGuiTabBarFlags_DockNode) == 0) // FIXME: TabBar with DockNode can now be hybrid | |
| 9868 | + ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByBeginOrder); | |
| 9846 | 9869 | tab_bar->TabsAddedNew = false; |
| 9847 | 9870 | |
| 9848 | 9871 | // Flags |
| @@ -9905,7 +9928,7 @@ | ||
| 9905 | 9928 | window->DC.CursorPos = tab_bar->BackupCursorPos; |
| 9906 | 9929 | |
| 9907 | 9930 | tab_bar->LastTabItemIdx = -1; |
| 9908 | - if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) | |
| 9931 | + if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) // Already done | |
| 9909 | 9932 | PopID(); |
| 9910 | 9933 | |
| 9911 | 9934 | g.CurrentTabBarStack.pop_back(); |
| @@ -10147,6 +10170,10 @@ | ||
| 10147 | 10170 | tab_bar->VisibleTabId = tab_bar->SelectedTabId; |
| 10148 | 10171 | tab_bar->VisibleTabWasSubmitted = false; |
| 10149 | 10172 | |
| 10173 | + // CTRL+TAB can override visible tab temporarily | |
| 10174 | + if (g.NavWindowingTarget != NULL && g.NavWindowingTarget->DockNode && g.NavWindowingTarget->DockNode->TabBar == tab_bar) | |
| 10175 | + tab_bar->VisibleTabId = scroll_to_tab_id = g.NavWindowingTarget->TabId; | |
| 10176 | + | |
| 10150 | 10177 | // Apply request requests |
| 10151 | 10178 | if (scroll_to_tab_id != 0) |
| 10152 | 10179 | TabBarScrollToTab(tab_bar, scroll_to_tab_id, sections); |
| @@ -10192,11 +10219,11 @@ | ||
| 10192 | 10219 | // Dockable windows uses Name/ID in the global namespace. Non-dockable items use the ID stack. |
| 10193 | 10220 | static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label, ImGuiWindow* docked_window) |
| 10194 | 10221 | { |
| 10195 | - IM_ASSERT(docked_window == NULL); // master branch only | |
| 10196 | - IM_UNUSED(docked_window); | |
| 10197 | - if (tab_bar->Flags & ImGuiTabBarFlags_DockNode) | |
| 10222 | + if (docked_window != NULL) | |
| 10198 | 10223 | { |
| 10199 | - ImGuiID id = ImHashStr(label); | |
| 10224 | + IM_UNUSED(tab_bar); | |
| 10225 | + IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_DockNode); | |
| 10226 | + ImGuiID id = docked_window->TabId; | |
| 10200 | 10227 | KeepAliveID(id); |
| 10201 | 10228 | return id; |
| 10202 | 10229 | } |
| @@ -10230,6 +10257,20 @@ | ||
| 10230 | 10257 | return &tab_bar->Tabs[order]; |
| 10231 | 10258 | } |
| 10232 | 10259 | |
| 10260 | +// FIXME: See references to #2304 in TODO.txt | |
| 10261 | +ImGuiTabItem* ImGui::TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar) | |
| 10262 | +{ | |
| 10263 | + ImGuiTabItem* most_recently_selected_tab = NULL; | |
| 10264 | + for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) | |
| 10265 | + { | |
| 10266 | + ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; | |
| 10267 | + if (most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) | |
| 10268 | + if (tab->Window && tab->Window->WasActive) | |
| 10269 | + most_recently_selected_tab = tab; | |
| 10270 | + } | |
| 10271 | + return most_recently_selected_tab; | |
| 10272 | +} | |
| 10273 | + | |
| 10233 | 10274 | ImGuiTabItem* ImGui::TabBarGetCurrentTab(ImGuiTabBar* tab_bar) |
| 10234 | 10275 | { |
| 10235 | 10276 | if (tab_bar->LastTabItemIdx < 0 || tab_bar->LastTabItemIdx >= tab_bar->Tabs.Size) |
| @@ -10239,12 +10280,35 @@ | ||
| 10239 | 10280 | |
| 10240 | 10281 | const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) |
| 10241 | 10282 | { |
| 10283 | + if (tab->Window) | |
| 10284 | + return tab->Window->Name; | |
| 10242 | 10285 | if (tab->NameOffset == -1) |
| 10243 | 10286 | return "N/A"; |
| 10244 | 10287 | IM_ASSERT(tab->NameOffset < tab_bar->TabsNames.Buf.Size); |
| 10245 | 10288 | return tab_bar->TabsNames.Buf.Data + tab->NameOffset; |
| 10246 | 10289 | } |
| 10247 | 10290 | |
| 10291 | +// The purpose of this call is to register tab in advance so we can control their order at the time they appear. | |
| 10292 | +// Otherwise calling this is unnecessary as tabs are appending as needed by the BeginTabItem() function. | |
| 10293 | +void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window) | |
| 10294 | +{ | |
| 10295 | + ImGuiContext& g = *GImGui; | |
| 10296 | + IM_ASSERT(TabBarFindTabByID(tab_bar, window->TabId) == NULL); | |
| 10297 | + IM_ASSERT(g.CurrentTabBar != tab_bar); // Can't work while the tab bar is active as our tab doesn't have an X offset yet, in theory we could/should test something like (tab_bar->CurrFrameVisible < g.FrameCount) but we'd need to solve why triggers the commented early-out assert in BeginTabBarEx() (probably dock node going from implicit to explicit in same frame) | |
| 10298 | + | |
| 10299 | + if (!window->HasCloseButton) | |
| 10300 | + tab_flags |= ImGuiTabItemFlags_NoCloseButton; // Set _NoCloseButton immediately because it will be used for first-frame width calculation. | |
| 10301 | + | |
| 10302 | + ImGuiTabItem new_tab; | |
| 10303 | + new_tab.ID = window->TabId; | |
| 10304 | + new_tab.Flags = tab_flags; | |
| 10305 | + new_tab.LastFrameVisible = tab_bar->CurrFrameVisible; // Required so BeginTabBar() doesn't ditch the tab | |
| 10306 | + if (new_tab.LastFrameVisible == -1) | |
| 10307 | + new_tab.LastFrameVisible = g.FrameCount - 1; | |
| 10308 | + new_tab.Window = window; // Required so tab bar layout can compute the tab width before tab submission | |
| 10309 | + tab_bar->Tabs.push_back(new_tab); | |
| 10310 | +} | |
| 10311 | + | |
| 10248 | 10312 | // The *TabId fields are already set by the docking system _before_ the actual TabItem was created, so we clear them regardless. |
| 10249 | 10313 | void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id) |
| 10250 | 10314 | { |
| @@ -10646,11 +10710,14 @@ | ||
| 10646 | 10710 | const bool is_tab_button = (flags & ImGuiTabItemFlags_Button) != 0; |
| 10647 | 10711 | tab->LastFrameVisible = g.FrameCount; |
| 10648 | 10712 | tab->Flags = flags; |
| 10713 | + tab->Window = docked_window; | |
| 10649 | 10714 | |
| 10650 | 10715 | // Append name _WITH_ the zero-terminator |
| 10716 | + // (regular tabs are permitted in a DockNode tab bar, but window tabs not permitted in a non-DockNode tab bar) | |
| 10651 | 10717 | if (docked_window != NULL) |
| 10652 | 10718 | { |
| 10653 | - IM_ASSERT(docked_window == NULL); // master branch only | |
| 10719 | + IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_DockNode); | |
| 10720 | + tab->NameOffset = -1; | |
| 10654 | 10721 | } |
| 10655 | 10722 | else |
| 10656 | 10723 | { |
| @@ -10675,7 +10742,7 @@ | ||
| 10675 | 10742 | tab_bar->VisibleTabWasSubmitted = true; |
| 10676 | 10743 | |
| 10677 | 10744 | // On the very first frame of a tab bar we let first tab contents be visible to minimize appearing glitches |
| 10678 | - if (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing) | |
| 10745 | + if (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing && docked_window == NULL) | |
| 10679 | 10746 | if (tab_bar->Tabs.Size == 1 && !(tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs)) |
| 10680 | 10747 | tab_contents_visible = true; |
| 10681 | 10748 | |
| @@ -10723,9 +10790,8 @@ | ||
| 10723 | 10790 | } |
| 10724 | 10791 | |
| 10725 | 10792 | // Click to Select a tab |
| 10726 | - // Allow the close button to overlap | |
| 10727 | 10793 | ImGuiButtonFlags button_flags = ((ImGuiButtonFlags)(is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap); |
| 10728 | - if (g.DragDropActive) | |
| 10794 | + if (g.DragDropActive && !g.DragDropPayload.IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW)) // FIXME: May be an opt-in property of the payload to disable this | |
| 10729 | 10795 | button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; |
| 10730 | 10796 | bool hovered, held, pressed; |
| 10731 | 10797 | if (flags & ImGuiTabItemFlags_Invisible) |
| @@ -10735,21 +10801,74 @@ | ||
| 10735 | 10801 | if (pressed && !is_tab_button) |
| 10736 | 10802 | TabBarQueueFocus(tab_bar, tab); |
| 10737 | 10803 | |
| 10738 | - // Drag and drop: re-order tabs | |
| 10739 | - if (held && !tab_appearing && IsMouseDragging(0)) | |
| 10804 | + // Transfer active id window so the active id is not owned by the dock host (as StartMouseMovingWindow() | |
| 10805 | + // will only do it on the drag). This allows FocusWindow() to be more conservative in how it clears active id. | |
| 10806 | + if (held && docked_window && g.ActiveId == id && g.ActiveIdIsJustActivated) | |
| 10807 | + g.ActiveIdWindow = docked_window; | |
| 10808 | + | |
| 10809 | + // Drag and drop a single floating window node moves it | |
| 10810 | + ImGuiDockNode* node = docked_window ? docked_window->DockNode : NULL; | |
| 10811 | + const bool single_floating_window_node = node && node->IsFloatingNode() && (node->Windows.Size == 1); | |
| 10812 | + if (held && single_floating_window_node && IsMouseDragging(0, 0.0f)) | |
| 10740 | 10813 | { |
| 10741 | - if (!g.DragDropActive && (tab_bar->Flags & ImGuiTabBarFlags_Reorderable)) | |
| 10814 | + // Move | |
| 10815 | + StartMouseMovingWindow(docked_window); | |
| 10816 | + } | |
| 10817 | + else if (held && !tab_appearing && IsMouseDragging(0)) | |
| 10818 | + { | |
| 10819 | + // Drag and drop: re-order tabs | |
| 10820 | + int drag_dir = 0; | |
| 10821 | + float drag_distance_from_edge_x = 0.0f; | |
| 10822 | + if (!g.DragDropActive && ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (docked_window != NULL))) | |
| 10742 | 10823 | { |
| 10743 | 10824 | // While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x |
| 10744 | 10825 | if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x) |
| 10745 | 10826 | { |
| 10827 | + drag_dir = -1; | |
| 10828 | + drag_distance_from_edge_x = bb.Min.x - g.IO.MousePos.x; | |
| 10746 | 10829 | TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos); |
| 10747 | 10830 | } |
| 10748 | 10831 | else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x) |
| 10749 | 10832 | { |
| 10833 | + drag_dir = +1; | |
| 10834 | + drag_distance_from_edge_x = g.IO.MousePos.x - bb.Max.x; | |
| 10750 | 10835 | TabBarQueueReorderFromMousePos(tab_bar, tab, g.IO.MousePos); |
| 10751 | 10836 | } |
| 10752 | 10837 | } |
| 10838 | + | |
| 10839 | + // Extract a Dockable window out of it's tab bar | |
| 10840 | + const bool can_undock = docked_window != NULL && !(docked_window->Flags & ImGuiWindowFlags_NoMove) && !(node->MergedFlags & ImGuiDockNodeFlags_NoUndocking); | |
| 10841 | + if (can_undock) | |
| 10842 | + { | |
| 10843 | + // We use a variable threshold to distinguish dragging tabs within a tab bar and extracting them out of the tab bar | |
| 10844 | + bool undocking_tab = (g.DragDropActive && g.DragDropPayload.SourceId == id); | |
| 10845 | + if (!undocking_tab) //&& (!g.IO.ConfigDockingWithShift || g.IO.KeyShift) | |
| 10846 | + { | |
| 10847 | + float threshold_base = g.FontSize; | |
| 10848 | + float threshold_x = (threshold_base * 2.2f); | |
| 10849 | + float threshold_y = (threshold_base * 1.5f) + ImClamp((ImFabs(g.IO.MouseDragMaxDistanceAbs[0].x) - threshold_base * 2.0f) * 0.20f, 0.0f, threshold_base * 4.0f); | |
| 10850 | + //GetForegroundDrawList()->AddRect(ImVec2(bb.Min.x - threshold_x, bb.Min.y - threshold_y), ImVec2(bb.Max.x + threshold_x, bb.Max.y + threshold_y), IM_COL32_WHITE); // [DEBUG] | |
| 10851 | + | |
| 10852 | + float distance_from_edge_y = ImMax(bb.Min.y - g.IO.MousePos.y, g.IO.MousePos.y - bb.Max.y); | |
| 10853 | + if (distance_from_edge_y >= threshold_y) | |
| 10854 | + undocking_tab = true; | |
| 10855 | + if (drag_distance_from_edge_x > threshold_x) | |
| 10856 | + if ((drag_dir < 0 && TabBarGetTabOrder(tab_bar, tab) == 0) || (drag_dir > 0 && TabBarGetTabOrder(tab_bar, tab) == tab_bar->Tabs.Size - 1)) | |
| 10857 | + undocking_tab = true; | |
| 10858 | + } | |
| 10859 | + | |
| 10860 | + if (undocking_tab) | |
| 10861 | + { | |
| 10862 | + // Undock | |
| 10863 | + // FIXME: refactor to share more code with e.g. StartMouseMovingWindow | |
| 10864 | + DockContextQueueUndockWindow(&g, docked_window); | |
| 10865 | + g.MovingWindow = docked_window; | |
| 10866 | + SetActiveID(g.MovingWindow->MoveId, g.MovingWindow); | |
| 10867 | + g.ActiveIdClickOffset -= g.MovingWindow->Pos - bb.Min; | |
| 10868 | + g.ActiveIdNoClearOnFocusLoss = true; | |
| 10869 | + SetActiveIdUsingAllKeyboardKeys(); | |
| 10870 | + } | |
| 10871 | + } | |
| 10753 | 10872 | } |
| 10754 | 10873 | |
| 10755 | 10874 | #if 0 |
| @@ -10798,7 +10917,7 @@ | ||
| 10798 | 10917 | flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; |
| 10799 | 10918 | |
| 10800 | 10919 | // Render tab label, process close button |
| 10801 | - const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, id) : 0; | |
| 10920 | + const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, docked_window ? docked_window->ID : id) : 0; | |
| 10802 | 10921 | bool just_closed; |
| 10803 | 10922 | bool text_clipped; |
| 10804 | 10923 | TabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped); |
| @@ -10808,6 +10927,11 @@ | ||
| 10808 | 10927 | TabBarCloseTab(tab_bar, tab); |
| 10809 | 10928 | } |
| 10810 | 10929 | |
| 10930 | + // Forward Hovered state so IsItemHovered() after Begin() can work (even though we are technically hovering our parent) | |
| 10931 | + // That state is copied to window->DockTabItemStatusFlags by our caller. | |
| 10932 | + if (docked_window && (hovered || g.HoveredId == close_button_id)) | |
| 10933 | + g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; | |
| 10934 | + | |
| 10811 | 10935 | // Tooltip |
| 10812 | 10936 | // (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok) |
| 10813 | 10937 | // (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores) |
| @@ -10843,6 +10967,16 @@ | ||
| 10843 | 10967 | if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id)) |
| 10844 | 10968 | tab->WantClose = true; // Will be processed by next call to TabBarLayout() |
| 10845 | 10969 | } |
| 10970 | + else if (ImGuiWindow* window = FindWindowByName(label)) | |
| 10971 | + { | |
| 10972 | + if (window->DockIsActive) | |
| 10973 | + if (ImGuiDockNode* node = window->DockNode) | |
| 10974 | + { | |
| 10975 | + ImGuiID tab_id = TabBarCalcTabID(node->TabBar, label, window); | |
| 10976 | + TabBarRemoveTab(node->TabBar, tab_id); | |
| 10977 | + window->DockTabWantClose = true; | |
| 10978 | + } | |
| 10979 | + } | |
| 10846 | 10980 | } |
| 10847 | 10981 | |
| 10848 | 10982 | ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker) |
| @@ -10857,10 +10991,9 @@ | ||
| 10857 | 10991 | return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y); |
| 10858 | 10992 | } |
| 10859 | 10993 | |
| 10860 | -ImVec2 ImGui::TabItemCalcSize(ImGuiWindow*) | |
| 10994 | +ImVec2 ImGui::TabItemCalcSize(ImGuiWindow* window) | |
| 10861 | 10995 | { |
| 10862 | - IM_ASSERT(0); // This function exists to facilitate merge with 'docking' branch. | |
| 10863 | - return ImVec2(0.0f, 0.0f); | |
| 10996 | + return TabItemCalcSize(window->Name, window->HasCloseButton || (window->Flags & ImGuiWindowFlags_UnsavedDocument)); | |
| 10864 | 10997 | } |
| 10865 | 10998 | |
| 10866 | 10999 | void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col) |
| @@ -10871,13 +11004,9 @@ | ||
| 10871 | 11004 | IM_UNUSED(flags); |
| 10872 | 11005 | IM_ASSERT(width > 0.0f); |
| 10873 | 11006 | const float rounding = ImMax(0.0f, ImMin((flags & ImGuiTabItemFlags_Button) ? g.Style.FrameRounding : g.Style.TabRounding, width * 0.5f - 1.0f)); |
| 10874 | - const float y1 = bb.Min.y + 1.0f; | |
| 11007 | + const float y1 = bb.Min.y + 1.0f; // Leave a bit of room in title bars. | |
| 10875 | 11008 | const float y2 = bb.Max.y - g.Style.TabBarBorderSize; |
| 10876 | - draw_list->PathLineTo(ImVec2(bb.Min.x, y2)); | |
| 10877 | - draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9); | |
| 10878 | - draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12); | |
| 10879 | - draw_list->PathLineTo(ImVec2(bb.Max.x, y2)); | |
| 10880 | - draw_list->PathFillConvex(col); | |
| 11009 | + draw_list->AddRectFilled(bb.Min, ImVec2(bb.Max.x, y2), col, rounding, ImDrawFlags_RoundCornersTop); | |
| 10881 | 11010 | if (g.Style.TabBorderSize > 0.0f) |
| 10882 | 11011 | { |
| 10883 | 11012 | draw_list->PathLineTo(ImVec2(bb.Min.x + 0.5f, y2)); |
| @@ -55,4 +55,8 @@ | ||
| 55 | 55 | <DisplayString>{{Name {Name,s} Active {(Active||WasActive)?1:0,d} Child {(Flags & 0x01000000)?1:0,d} Popup {(Flags & 0x04000000)?1:0,d} Hidden {(Hidden)?1:0,d}}</DisplayString> |
| 56 | 56 | </Type> |
| 57 | 57 | |
| 58 | +<Type Name="ImGuiDockNode"> | |
| 59 | + <DisplayString>{{ID {ID,x} Pos=({Pos.x,g} {Pos.y,g}) Size=({Size.x,g} {Size.y,g}) Parent {(ParentNode==0)?0:ParentNode->ID,x} Childs {(ChildNodes[0] != 0)+(ChildNodes[1] != 0)} Windows {Windows.Size} }</DisplayString> | |
| 60 | +</Type> | |
| 61 | + | |
| 58 | 62 | </AutoVisualizer> |