Browse Source

Viewport, Platform, Examples: Changes to resizing flow + restored support for Platform events affecting the ImGui windows (so Decorated windows are functional). (#1542, #1042) ..
SDL: Added platform move/resize/close support.
GLFW: Added platform move/resize support. Moved Close to use callback for consistency.
Win32:
Vulkan: Fixed resize support.
Naming is WIP "PlatforrmRequestXXX" is too ambiguous. Basically we either have a ImGui->Platform flow or a Platform->ImGui flow. Working a bigger refactor now.

omar 7 years ago
parent
commit
6e58a95a01

+ 21 - 3
examples/imgui_impl_glfw.cpp

@@ -310,6 +310,24 @@ struct ImGuiPlatformDataGlfw
     ~ImGuiPlatformDataGlfw() { IM_ASSERT(Window == NULL); }
 };
 
+static void ImGui_ImplGlfw_WindowCloseCallback(GLFWwindow* window)
+{
+    if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
+        viewport->PlatformRequestClose = true;
+}
+
+static void ImGui_ImplGlfw_WindowPosCallback(GLFWwindow* window, int, int)
+{
+    if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
+        viewport->PlatformRequestMove = true;
+}
+
+static void ImGui_ImplGlfw_WindowSizeCallback(GLFWwindow* window, int, int)
+{
+    if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
+        viewport->PlatformRequestResize = true;
+}
+
 static void ImGui_ImplGlfw_CreateViewport(ImGuiViewport* viewport)
 {
     ImGuiPlatformDataGlfw* data = IM_NEW(ImGuiPlatformDataGlfw)();
@@ -324,6 +342,9 @@ static void ImGui_ImplGlfw_CreateViewport(ImGuiViewport* viewport)
     data->WindowOwned = true;
     viewport->PlatformHandle = (void*)data->Window;
     ImGui_ImplGlfw_InstallCallbacks(data->Window);
+    glfwSetWindowCloseCallback(data->Window, ImGui_ImplGlfw_WindowCloseCallback);
+    glfwSetWindowPosCallback(data->Window, ImGui_ImplGlfw_WindowPosCallback);
+    glfwSetWindowSizeCallback(data->Window, ImGui_ImplGlfw_WindowSizeCallback);
 }
 
 static void ImGui_ImplGlfw_DestroyViewport(ImGuiViewport* viewport)
@@ -431,9 +452,6 @@ static void ImGui_ImplGlfw_RenderViewport(ImGuiViewport* viewport)
     ImGuiPlatformDataGlfw* data = (ImGuiPlatformDataGlfw*)viewport->PlatformUserData;
     if (g_ClientApi == GlfwClientApi_OpenGL)
         glfwMakeContextCurrent(data->Window);
-
-    if (glfwWindowShouldClose(data->Window))
-        viewport->PlatformRequestClose = true;
 }
 
 static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport)

+ 19 - 3
examples/imgui_impl_sdl2.cpp

@@ -100,6 +100,21 @@ bool ImGui_ImplSDL2_ProcessEvent(SDL_Event* event)
             io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
             return true;
         }
+    // Multi-viewport support
+    case SDL_WINDOWEVENT:
+        Uint8 window_event = event->window.event;
+        if (window_event == SDL_WINDOWEVENT_CLOSE || window_event == SDL_WINDOWEVENT_MOVED || window_event == SDL_WINDOWEVENT_RESIZED)
+            if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(event->window.windowID)))
+            {
+                if (window_event == SDL_WINDOWEVENT_CLOSE)
+                    viewport->PlatformRequestClose = true;
+                if (window_event == SDL_WINDOWEVENT_MOVED)
+                    viewport->PlatformRequestMove = true;
+                if (window_event == SDL_WINDOWEVENT_RESIZED)
+                    viewport->PlatformRequestResize = true;
+                return true;
+            }
+        break;
     }
     return false;
 }
@@ -288,7 +303,8 @@ static void ImGui_ImplSDL2_CreateViewport(ImGuiViewport* viewport)
     sdl_flags |= SDL_WINDOW_HIDDEN;
     sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0;
     sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE;
-    data->Window = SDL_CreateWindow("No Title Yet", 0, 0, (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags);
+    data->Window = SDL_CreateWindow("No Title Yet", 
+        (int)viewport->PlatformOsDesktopPos.x, (int)viewport->PlatformOsDesktopPos.y, (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags);
     if (main_viewport_data->GLContext)
         data->GLContext = SDL_GL_CreateContext(data->Window);
     viewport->PlatformHandle = (void*)data->Window;
@@ -328,7 +344,7 @@ static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport)
             ex_style &= ~WS_EX_APPWINDOW;
             ex_style |= WS_EX_TOOLWINDOW;
             ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
-    }
+        }
 
         // SDL hack: SDL always activate/focus windows :/
         if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
@@ -336,7 +352,7 @@ static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport)
             ::ShowWindow(hwnd, SW_SHOWNA);
             return;
         }
-}
+    }
 #endif
 
     SDL_ShowWindow(data->Window);

+ 3 - 2
examples/imgui_impl_vulkan.cpp

@@ -1108,8 +1108,9 @@ static void ImGui_ImplVulkan_DestroyViewport(ImGuiViewport* viewport)
 static void ImGui_ImplVulkan_ResizeViewport(ImGuiViewport* viewport, ImVec2 size)
 {
     ImGuiPlatformDataVulkan* data = (ImGuiPlatformDataVulkan*)viewport->RendererUserData;
-    ImGui_ImplVulkan_WindowData* wd = &data->WindowData;
-    ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, wd, g_Allocator, (int)size.x, (int)size.y);
+    if (data == NULL) // This is NULL for the main viewport (which is left to the user/app to handle)
+        return;
+    ImGui_ImplVulkanH_CreateWindowDataSwapChainAndFramebuffer(g_PhysicalDevice, g_Device, &data->WindowData, g_Allocator, (int)size.x, (int)size.y);
 }
 
 static void ImGui_ImplVulkan_RenderViewport(ImGuiViewport* viewport)

+ 6 - 17
examples/imgui_impl_win32.cpp

@@ -356,11 +356,10 @@ float ImGui_ImplWin32_GetDpiScaleForRect(int x1, int y1, int x2, int y2)
 struct ImGuiPlatformDataWin32
 {
     HWND    Hwnd;
-    bool    ExternalResize;
     DWORD   DwStyle;
     DWORD   DwExStyle;
 
-    ImGuiPlatformDataWin32() { Hwnd = NULL; ExternalResize = false; DwStyle = DwExStyle = 0; }
+    ImGuiPlatformDataWin32() { Hwnd = NULL; DwStyle = DwExStyle = 0; }
     ~ImGuiPlatformDataWin32() { IM_ASSERT(Hwnd == NULL); }
 };
 
@@ -386,12 +385,11 @@ static void ImGui_ImplWin32_CreateViewport(ImGuiViewport* viewport)
     // Create window
     RECT rect = { (LONG)viewport->PlatformOsDesktopPos.x, (LONG)viewport->PlatformOsDesktopPos.y, (LONG)(viewport->PlatformOsDesktopPos.x + viewport->Size.x), (LONG)(viewport->PlatformOsDesktopPos.y + viewport->Size.y) };
     ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle);
-    data->ExternalResize = true;
     data->Hwnd = ::CreateWindowExA(
         data->DwExStyle, "ImGui Platform", "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->ExternalResize = false;
+    viewport->PlatformRequestResize = false;
     viewport->PlatformHandle = data->Hwnd;
 }
 
@@ -417,12 +415,10 @@ static void ImGui_ImplWin32_ShowWindow(ImGuiViewport* viewport)
 {
     ImGuiPlatformDataWin32* data = (ImGuiPlatformDataWin32*)viewport->PlatformUserData;
     IM_ASSERT(data->Hwnd != 0);
-    data->ExternalResize = true;
     if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
         ::ShowWindow(data->Hwnd, SW_SHOWNA);
     else
         ::ShowWindow(data->Hwnd, SW_SHOW);
-    data->ExternalResize = false;
 }
 
 static ImVec2 ImGui_ImplWin32_GetWindowPos(ImGuiViewport* viewport)
@@ -456,11 +452,9 @@ static void ImGui_ImplWin32_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
 {
     ImGuiPlatformDataWin32* data = (ImGuiPlatformDataWin32*)viewport->PlatformUserData;
     IM_ASSERT(data->Hwnd != 0);
-    data->ExternalResize = true;
     RECT rect = { 0, 0, (LONG)size.x, (LONG)size.y };
     ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle); // Client to Screen
     ::SetWindowPos(data->Hwnd, NULL, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
-    data->ExternalResize = false;
 }
 
 static void ImGui_ImplWin32_SetWindowTitle(ImGuiViewport* viewport, const char* title)
@@ -489,27 +483,22 @@ static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd,
 
     if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hWnd))
     {
-        ImGuiIO& io = ImGui::GetIO();
-        ImGuiPlatformDataWin32* data = (ImGuiPlatformDataWin32*)viewport->PlatformUserData;
         switch (msg)
         {
         case WM_CLOSE:
             viewport->PlatformRequestClose = true;
             return 0;
         case WM_MOVE:
-            viewport->PlatformOsDesktopPos = ImVec2((float)(short)LOWORD(lParam), (float)(short)HIWORD(lParam));
+            viewport->PlatformRequestMove = true;
+            break;
+        case WM_SIZE:
+            viewport->PlatformRequestResize = true;
             break;
         case WM_NCHITTEST:
             // Let mouse pass-through the window, this is used while e.g. dragging a window, we creates a temporary overlay but want the cursor to aim behind our overlay.
             if (viewport->Flags & ImGuiViewportFlags_NoInputs)
                 return HTTRANSPARENT;
             break;
-        case WM_SIZE:
-            if (!data->ExternalResize)
-                viewport->PlatformRequestResize = true;
-            if (io.RendererInterface.ResizeViewport)
-                io.RendererInterface.ResizeViewport(viewport, ImVec2((float)LOWORD(lParam), (float)HIWORD(lParam)));
-            break;
         }
     }
 

+ 37 - 7
imgui.cpp

@@ -3384,6 +3384,12 @@ static void ImGui::UpdateViewports()
                 ResizeViewportTranslateWindows(viewport->Idx + 1, g.Viewports.Size, dx, 0, NULL);
         }
 
+        // Apply Platform Size to ImGui Size if requested
+        // We do it here instead of UpdatePlatformWindows() to allow the platform back-end to set PlatformRequestResize early 
+        // (e.g. in their own message handler before NewFrame) and not have a frame of lag with it.
+        if (viewport->PlatformRequestResize)
+            viewport->Size = g.IO.PlatformInterface.GetWindowSize(viewport);
+
         // Update DPI Scale
         float new_dpi_scale;
         if (g.IO.PlatformInterface.GetWindowDpiScale)
@@ -3478,17 +3484,31 @@ static void UpdatePlatformWindows()
         if ((viewport->Flags & ImGuiViewportFlags_MainViewport) || (viewport->LastFrameActive < g.FrameCount))
             continue;
         IM_ASSERT(viewport->Window != NULL);
-        viewport->PlatformRequestClose = false;
 
-        // FIXME-PLATFORM
+        if (viewport->PlatformRequestMove)
+            viewport->PlatformOsDesktopPos = g.IO.PlatformInterface.GetWindowPos(viewport);
+
         bool is_new_window = viewport->PlatformHandle == NULL && viewport->PlatformUserData == NULL && viewport->RendererUserData == NULL;
         if (is_new_window && viewport->PlatformHandle == NULL && viewport->PlatformUserData == NULL)
+        {
             g.IO.PlatformInterface.CreateViewport(viewport);
+        }
         if (is_new_window && viewport->RendererUserData == NULL && g.IO.RendererInterface.CreateViewport != NULL)
+        {
             g.IO.RendererInterface.CreateViewport(viewport);
+            viewport->RendererLastSize = viewport->Size;
+        }
+
+        // Update Pos/Size for Platform
+        if (!viewport->PlatformRequestMove)
+            g.IO.PlatformInterface.SetWindowPos(viewport, viewport->PlatformOsDesktopPos);
+        if (!viewport->PlatformRequestResize)
+            g.IO.PlatformInterface.SetWindowSize(viewport, viewport->Size);
 
-        g.IO.PlatformInterface.SetWindowPos(viewport, viewport->PlatformOsDesktopPos);
-        g.IO.PlatformInterface.SetWindowSize(viewport, viewport->Size);
+        // Update Size for Renderer
+        if (g.IO.RendererInterface.ResizeViewport && (viewport->RendererLastSize.x != viewport->Size.x || viewport->RendererLastSize.y != viewport->Size.y))
+            g.IO.RendererInterface.ResizeViewport(viewport, viewport->Size);
+        viewport->RendererLastSize = viewport->Size;
 
         // Update title bar
         const char* title_begin = viewport->Window->Name;
@@ -3503,13 +3523,18 @@ static void UpdatePlatformWindows()
             ImGui::MemFree(title_displayed);
         }
 
+        // Show window. On startup ensure platform window don't get focus.
         if (is_new_window)
         {
-            // On startup ensure platform window don't get focus.
             if (g.FrameCount < 2)
                 viewport->Flags |= ImGuiViewportFlags_NoFocusOnAppearing;
             g.IO.PlatformInterface.ShowWindow(viewport);
         }
+
+        // Clear request flags
+        viewport->PlatformRequestClose = false;
+        viewport->PlatformRequestMove = false;
+        viewport->PlatformRequestResize = false;
     }
 }
 
@@ -6013,10 +6038,11 @@ static void ImGui::UpdateWindowViewport(ImGuiWindow* window, bool window_pos_set
         window->Viewport = main_viewport;
 
     // When we own the viewport update its size
-    if (window->ID == window->Viewport->ID && !created_viewport)
+    if (window == window->Viewport->Window && !created_viewport)
     {
         window->Viewport->Flags |= ImGuiViewportFlags_NoDecoration;
-        window->Viewport->Size = window->Size;
+        if (!window->Viewport->PlatformRequestResize)
+            window->Viewport->Size = window->Size;
         window->Viewport->PlatformOsDesktopPos = ConvertViewportPosToOsDesktopPos(window->Pos, window->Viewport);
         window->Flags |= ImGuiWindowFlags_FullViewport;
     }
@@ -6026,7 +6052,11 @@ static void ImGui::UpdateWindowViewport(ImGuiWindow* window, bool window_pos_set
         window->Flags |= ImGuiWindowFlags_NoTitleBar;
 
     if (window->Flags & ImGuiWindowFlags_FullViewport)
+    {
         SetWindowPos(window, window->Viewport->Pos, ImGuiCond_Always);
+        if (window->Viewport->PlatformRequestResize)
+            SetWindowSize(window, window->Viewport->Size, ImGuiCond_Always);
+    }
 
     window->ViewportId = window->Viewport->ID;
 }

+ 4 - 2
imgui_internal.h

@@ -535,10 +535,12 @@ struct ImGuiViewport
     void*               PlatformUserData;       // void* to hold custom data structure for the platform (e.g. windowing info, render context)
     void*               PlatformHandle;         // void* for FindViewportByPlatformHandle(). (e.g. HWND, GlfwWindow*)
     bool                PlatformRequestClose;   // Platform window requested closure
-    bool                PlatformRequestResize;  // Platform window requested resize
+    bool                PlatformRequestMove;    // Platform window requested move (e.g. window was moved using OS windowing facility)
+    bool                PlatformRequestResize;  // Platform window requested resize (e.g. window was resize using OS windowing facility)
     void*               RendererUserData;       // void* to hold custom data structure for the renderer (e.g. framebuffer)
+    ImVec2              RendererLastSize;
 
-    ImGuiViewport(ImGuiID id, int idx)  { ID = id; Idx = idx; Flags = 0; LastFrameActive = LastFrameAsRefViewport = -1; LastNameHash = 0; Window = NULL; DpiScale = 0.0f; PlatformUserData = PlatformHandle = NULL; PlatformRequestClose = PlatformRequestResize = false; RendererUserData = NULL; }
+    ImGuiViewport(ImGuiID id, int idx)  { ID = id; Idx = idx; Flags = 0; LastFrameActive = LastFrameAsRefViewport = -1; LastNameHash = 0; Window = NULL; DpiScale = 0.0f; PlatformUserData = PlatformHandle = NULL; PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; RendererUserData = NULL; RendererLastSize = ImVec2(-1.0f,-1.0f); }
     ~ImGuiViewport()                    { IM_ASSERT(PlatformUserData == NULL && RendererUserData == NULL); }
     ImRect  GetRect() const             { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
     float   GetNextX() const            { const float SPACING = 4.0f; return Pos.x + Size.x + SPACING; }