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.
This commit is contained in:
omar 2018-03-15 10:54:27 +01:00
parent 207ad45983
commit 6e58a95a01
6 changed files with 90 additions and 34 deletions

View File

@ -310,6 +310,24 @@ struct ImGuiPlatformDataGlfw
~ImGuiPlatformDataGlfw() { IM_ASSERT(Window == NULL); } ~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) static void ImGui_ImplGlfw_CreateViewport(ImGuiViewport* viewport)
{ {
ImGuiPlatformDataGlfw* data = IM_NEW(ImGuiPlatformDataGlfw)(); ImGuiPlatformDataGlfw* data = IM_NEW(ImGuiPlatformDataGlfw)();
@ -324,6 +342,9 @@ static void ImGui_ImplGlfw_CreateViewport(ImGuiViewport* viewport)
data->WindowOwned = true; data->WindowOwned = true;
viewport->PlatformHandle = (void*)data->Window; viewport->PlatformHandle = (void*)data->Window;
ImGui_ImplGlfw_InstallCallbacks(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) static void ImGui_ImplGlfw_DestroyViewport(ImGuiViewport* viewport)
@ -431,9 +452,6 @@ static void ImGui_ImplGlfw_RenderViewport(ImGuiViewport* viewport)
ImGuiPlatformDataGlfw* data = (ImGuiPlatformDataGlfw*)viewport->PlatformUserData; ImGuiPlatformDataGlfw* data = (ImGuiPlatformDataGlfw*)viewport->PlatformUserData;
if (g_ClientApi == GlfwClientApi_OpenGL) if (g_ClientApi == GlfwClientApi_OpenGL)
glfwMakeContextCurrent(data->Window); glfwMakeContextCurrent(data->Window);
if (glfwWindowShouldClose(data->Window))
viewport->PlatformRequestClose = true;
} }
static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport) static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport)

View File

@ -100,6 +100,21 @@ bool ImGui_ImplSDL2_ProcessEvent(SDL_Event* event)
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0); io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
return true; 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; return false;
} }
@ -288,7 +303,8 @@ static void ImGui_ImplSDL2_CreateViewport(ImGuiViewport* viewport)
sdl_flags |= SDL_WINDOW_HIDDEN; sdl_flags |= SDL_WINDOW_HIDDEN;
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0; sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0;
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE; 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) if (main_viewport_data->GLContext)
data->GLContext = SDL_GL_CreateContext(data->Window); data->GLContext = SDL_GL_CreateContext(data->Window);
viewport->PlatformHandle = (void*)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_APPWINDOW;
ex_style |= WS_EX_TOOLWINDOW; ex_style |= WS_EX_TOOLWINDOW;
::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style); ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
} }
// SDL hack: SDL always activate/focus windows :/ // SDL hack: SDL always activate/focus windows :/
if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
@ -336,7 +352,7 @@ static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport)
::ShowWindow(hwnd, SW_SHOWNA); ::ShowWindow(hwnd, SW_SHOWNA);
return; return;
} }
} }
#endif #endif
SDL_ShowWindow(data->Window); SDL_ShowWindow(data->Window);

View File

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

View File

@ -356,11 +356,10 @@ float ImGui_ImplWin32_GetDpiScaleForRect(int x1, int y1, int x2, int y2)
struct ImGuiPlatformDataWin32 struct ImGuiPlatformDataWin32
{ {
HWND Hwnd; HWND Hwnd;
bool ExternalResize;
DWORD DwStyle; DWORD DwStyle;
DWORD DwExStyle; DWORD DwExStyle;
ImGuiPlatformDataWin32() { Hwnd = NULL; ExternalResize = false; DwStyle = DwExStyle = 0; } ImGuiPlatformDataWin32() { Hwnd = NULL; DwStyle = DwExStyle = 0; }
~ImGuiPlatformDataWin32() { IM_ASSERT(Hwnd == NULL); } ~ImGuiPlatformDataWin32() { IM_ASSERT(Hwnd == NULL); }
}; };
@ -386,12 +385,11 @@ static void ImGui_ImplWin32_CreateViewport(ImGuiViewport* viewport)
// Create window // 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) }; 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); ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle);
data->ExternalResize = true;
data->Hwnd = ::CreateWindowExA( data->Hwnd = ::CreateWindowExA(
data->DwExStyle, "ImGui Platform", "No Title Yet", data->DwStyle, // Style, class name, window name 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 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 g_hWnd, NULL, ::GetModuleHandle(NULL), NULL); // Parent window, Menu, Instance, Param
data->ExternalResize = false; viewport->PlatformRequestResize = false;
viewport->PlatformHandle = data->Hwnd; viewport->PlatformHandle = data->Hwnd;
} }
@ -417,12 +415,10 @@ static void ImGui_ImplWin32_ShowWindow(ImGuiViewport* viewport)
{ {
ImGuiPlatformDataWin32* data = (ImGuiPlatformDataWin32*)viewport->PlatformUserData; ImGuiPlatformDataWin32* data = (ImGuiPlatformDataWin32*)viewport->PlatformUserData;
IM_ASSERT(data->Hwnd != 0); IM_ASSERT(data->Hwnd != 0);
data->ExternalResize = true;
if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
::ShowWindow(data->Hwnd, SW_SHOWNA); ::ShowWindow(data->Hwnd, SW_SHOWNA);
else else
::ShowWindow(data->Hwnd, SW_SHOW); ::ShowWindow(data->Hwnd, SW_SHOW);
data->ExternalResize = false;
} }
static ImVec2 ImGui_ImplWin32_GetWindowPos(ImGuiViewport* viewport) 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; ImGuiPlatformDataWin32* data = (ImGuiPlatformDataWin32*)viewport->PlatformUserData;
IM_ASSERT(data->Hwnd != 0); IM_ASSERT(data->Hwnd != 0);
data->ExternalResize = true;
RECT rect = { 0, 0, (LONG)size.x, (LONG)size.y }; RECT rect = { 0, 0, (LONG)size.x, (LONG)size.y };
::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle); // Client to Screen ::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); ::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) 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)) if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hWnd))
{ {
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformDataWin32* data = (ImGuiPlatformDataWin32*)viewport->PlatformUserData;
switch (msg) switch (msg)
{ {
case WM_CLOSE: case WM_CLOSE:
viewport->PlatformRequestClose = true; viewport->PlatformRequestClose = true;
return 0; return 0;
case WM_MOVE: 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; break;
case WM_NCHITTEST: 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. // 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) if (viewport->Flags & ImGuiViewportFlags_NoInputs)
return HTTRANSPARENT; return HTTRANSPARENT;
break; 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;
} }
} }

View File

@ -3384,6 +3384,12 @@ static void ImGui::UpdateViewports()
ResizeViewportTranslateWindows(viewport->Idx + 1, g.Viewports.Size, dx, 0, NULL); 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 // Update DPI Scale
float new_dpi_scale; float new_dpi_scale;
if (g.IO.PlatformInterface.GetWindowDpiScale) if (g.IO.PlatformInterface.GetWindowDpiScale)
@ -3478,17 +3484,31 @@ static void UpdatePlatformWindows()
if ((viewport->Flags & ImGuiViewportFlags_MainViewport) || (viewport->LastFrameActive < g.FrameCount)) if ((viewport->Flags & ImGuiViewportFlags_MainViewport) || (viewport->LastFrameActive < g.FrameCount))
continue; continue;
IM_ASSERT(viewport->Window != NULL); 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; bool is_new_window = viewport->PlatformHandle == NULL && viewport->PlatformUserData == NULL && viewport->RendererUserData == NULL;
if (is_new_window && viewport->PlatformHandle == NULL && viewport->PlatformUserData == NULL) if (is_new_window && viewport->PlatformHandle == NULL && viewport->PlatformUserData == NULL)
{
g.IO.PlatformInterface.CreateViewport(viewport); g.IO.PlatformInterface.CreateViewport(viewport);
}
if (is_new_window && viewport->RendererUserData == NULL && g.IO.RendererInterface.CreateViewport != NULL) if (is_new_window && viewport->RendererUserData == NULL && g.IO.RendererInterface.CreateViewport != NULL)
{
g.IO.RendererInterface.CreateViewport(viewport); g.IO.RendererInterface.CreateViewport(viewport);
viewport->RendererLastSize = viewport->Size;
}
g.IO.PlatformInterface.SetWindowPos(viewport, viewport->PlatformOsDesktopPos); // Update Pos/Size for Platform
g.IO.PlatformInterface.SetWindowSize(viewport, viewport->Size); if (!viewport->PlatformRequestMove)
g.IO.PlatformInterface.SetWindowPos(viewport, viewport->PlatformOsDesktopPos);
if (!viewport->PlatformRequestResize)
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 // Update title bar
const char* title_begin = viewport->Window->Name; const char* title_begin = viewport->Window->Name;
@ -3503,13 +3523,18 @@ static void UpdatePlatformWindows()
ImGui::MemFree(title_displayed); ImGui::MemFree(title_displayed);
} }
// Show window. On startup ensure platform window don't get focus.
if (is_new_window) if (is_new_window)
{ {
// On startup ensure platform window don't get focus.
if (g.FrameCount < 2) if (g.FrameCount < 2)
viewport->Flags |= ImGuiViewportFlags_NoFocusOnAppearing; viewport->Flags |= ImGuiViewportFlags_NoFocusOnAppearing;
g.IO.PlatformInterface.ShowWindow(viewport); 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; window->Viewport = main_viewport;
// When we own the viewport update its size // 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->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->Viewport->PlatformOsDesktopPos = ConvertViewportPosToOsDesktopPos(window->Pos, window->Viewport);
window->Flags |= ImGuiWindowFlags_FullViewport; window->Flags |= ImGuiWindowFlags_FullViewport;
} }
@ -6026,7 +6052,11 @@ static void ImGui::UpdateWindowViewport(ImGuiWindow* window, bool window_pos_set
window->Flags |= ImGuiWindowFlags_NoTitleBar; window->Flags |= ImGuiWindowFlags_NoTitleBar;
if (window->Flags & ImGuiWindowFlags_FullViewport) if (window->Flags & ImGuiWindowFlags_FullViewport)
{
SetWindowPos(window, window->Viewport->Pos, ImGuiCond_Always); SetWindowPos(window, window->Viewport->Pos, ImGuiCond_Always);
if (window->Viewport->PlatformRequestResize)
SetWindowSize(window, window->Viewport->Size, ImGuiCond_Always);
}
window->ViewportId = window->Viewport->ID; window->ViewportId = window->Viewport->ID;
} }

View File

@ -535,10 +535,12 @@ struct ImGuiViewport
void* PlatformUserData; // void* to hold custom data structure for the platform (e.g. windowing info, render context) 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*) void* PlatformHandle; // void* for FindViewportByPlatformHandle(). (e.g. HWND, GlfwWindow*)
bool PlatformRequestClose; // Platform window requested closure 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) 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); } ~ImGuiViewport() { IM_ASSERT(PlatformUserData == NULL && RendererUserData == NULL); }
ImRect GetRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } 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; } float GetNextX() const { const float SPACING = 4.0f; return Pos.x + Size.x + SPACING; }