From 4a6f95acc881f09de2835a93273cf725801790e1 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 Jan 2019 16:06:58 +0100 Subject: [PATCH] Viewport: Added Platform_UpdateWindow hook for general purpose: Rework Win32 code to reflect viewport flags changes into Win32 while the window is active. --- examples/imgui_impl_win32.cpp | 65 ++++++++++++++++++++++++++--------- imgui.cpp | 4 +++ imgui.h | 1 + 3 files changed, 53 insertions(+), 17 deletions(-) diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index ef22fa47..fed43afd 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -431,33 +431,38 @@ struct ImGuiViewportDataWin32 ~ImGuiViewportDataWin32() { IM_ASSERT(Hwnd == NULL); } }; +static void ImGui_ImplWin32_GetWin32StyleFromViewportFlags(ImGuiViewportFlags flags, DWORD* out_style, DWORD* out_ex_style) +{ + if (flags & ImGuiViewportFlags_NoDecoration) + *out_style = WS_POPUP; + else + *out_style = WS_OVERLAPPEDWINDOW; + + if (flags & ImGuiViewportFlags_NoTaskBarIcon) + *out_ex_style = WS_EX_TOOLWINDOW; + else + *out_ex_style = WS_EX_APPWINDOW; + + if (flags & ImGuiViewportFlags_TopMost) + *out_ex_style |= WS_EX_TOPMOST; +} + static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport) { ImGuiViewportDataWin32* data = IM_NEW(ImGuiViewportDataWin32)(); viewport->PlatformUserData = data; - bool no_decoration = (viewport->Flags & ImGuiViewportFlags_NoDecoration) != 0; - bool no_task_bar_icon = (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) != 0; - if (no_decoration) - { - data->DwStyle = WS_POPUP; - data->DwExStyle = no_task_bar_icon ? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW; - } - else - { - data->DwStyle = WS_OVERLAPPEDWINDOW; - data->DwExStyle = no_task_bar_icon ? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW; - } - if (viewport->Flags & ImGuiViewportFlags_TopMost) - data->DwExStyle |= WS_EX_TOPMOST; + // Select style and parent window + HWND parent_window = g_hWnd; + ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &data->DwStyle, &data->DwExStyle); // Create window RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) }; ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle); data->Hwnd = ::CreateWindowEx( - data->DwExStyle, _T("ImGui Platform"), _T("No Title Yet"), data->DwStyle, // Style, class name, window name - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area - g_hWnd, NULL, ::GetModuleHandle(NULL), NULL); // Parent window, Menu, Instance, Param + data->DwExStyle, _T("ImGui Platform"), _T("Untitled"), data->DwStyle, // Style, class name, window name + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area + parent_window, NULL, ::GetModuleHandle(NULL), NULL); // Parent window, Menu, Instance, Param data->HwndOwned = true; viewport->PlatformRequestResize = false; viewport->PlatformHandle = data->Hwnd; @@ -491,6 +496,31 @@ static void ImGui_ImplWin32_ShowWindow(ImGuiViewport* viewport) ::ShowWindow(data->Hwnd, SW_SHOW); } +static void ImGui_ImplWin32_UpdateWindow(ImGuiViewport* viewport) +{ + // (Optional) Update Win32 style if it changed _after_ creation. + // Generally they won't change unless configuration flags are changed, but advanced uses (such as manually rewriting viewport flags) make this useful. + ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData; + IM_ASSERT(data->Hwnd != 0); + DWORD new_style; + DWORD new_ex_style; + ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &new_style, &new_ex_style); + + // Only reapply the flags that have been changed from our point of view (as other flags are being modified by Windows) + if (data->DwStyle != new_style || data->DwExStyle != new_ex_style) + { + data->DwStyle = new_style; + data->DwExStyle = new_ex_style; + ::SetWindowLong(data->Hwnd, GWL_STYLE, data->DwStyle); + ::SetWindowLong(data->Hwnd, GWL_EXSTYLE, data->DwExStyle); + RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) }; + ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle); // Client to Screen + ::SetWindowPos(data->Hwnd, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + ::ShowWindow(data->Hwnd, SW_SHOWNA); // This is necessary when we alter the style + viewport->PlatformRequestMove = viewport->PlatformRequestResize = true; + } +} + static ImVec2 ImGui_ImplWin32_GetWindowPos(ImGuiViewport* viewport) { ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData; @@ -695,6 +725,7 @@ static void ImGui_ImplWin32_InitPlatformInterface() platform_io.Platform_GetWindowMinimized = ImGui_ImplWin32_GetWindowMinimized; platform_io.Platform_SetWindowTitle = ImGui_ImplWin32_SetWindowTitle; platform_io.Platform_SetWindowAlpha = ImGui_ImplWin32_SetWindowAlpha; + platform_io.Platform_UpdateWindow = ImGui_ImplWin32_UpdateWindow; platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale; // FIXME-DPI platform_io.Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport; // FIXME-DPI #if HAS_WIN32_IME diff --git a/imgui.cpp b/imgui.cpp index f18c61aa..681d8210 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7794,6 +7794,10 @@ void ImGui::UpdatePlatformWindows() g.PlatformIO.Platform_SetWindowAlpha(viewport, viewport->Alpha); viewport->LastAlpha = viewport->Alpha; + // Optional, general purpose call to allow the back-end to perform general book-keeping even if things haven't changed. + if (g.PlatformIO.Platform_UpdateWindow) + g.PlatformIO.Platform_UpdateWindow(viewport); + if (is_new_platform_window) { // On startup ensure new platform window don't steal focus (give it a few frames, as nested contents may lead to viewport being created a few frames late) diff --git a/imgui.h b/imgui.h index b0f1dccc..6d7f8dd2 100644 --- a/imgui.h +++ b/imgui.h @@ -2186,6 +2186,7 @@ struct ImGuiPlatformIO bool (*Platform_GetWindowMinimized)(ImGuiViewport* vp); void (*Platform_SetWindowTitle)(ImGuiViewport* vp, const char* title); void (*Platform_SetWindowAlpha)(ImGuiViewport* vp, float alpha); // (Optional) Setup window transparency + void (*Platform_UpdateWindow)(ImGuiViewport* vp); // (Optional) Called in UpdatePlatforms(). Optional hook to allow the platform back-end from doing general book-keeping every frame. void (*Platform_RenderWindow)(ImGuiViewport* vp, void* render_arg); // (Optional) Setup for render void (*Platform_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // (Optional) Call Present/SwapBuffers (platform side) float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // (Optional) [BETA] (FIXME-DPI) DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI.