Viewport, Platform: Refactored platform interface. Removed need to use imgui_internal.h in backends. Split viewport into public facing ImGuiViewport and internal structure. Exposing enough data to provide custom tweaked renderers. Renamed handlers, fixed lots of inconsistencies. (#1542, #1042)

This commit is contained in:
omar
2018-03-18 18:44:57 +01:00
parent bcf4ed28a9
commit 46b61427e1
19 changed files with 460 additions and 412 deletions

333
imgui.cpp
View File

@ -739,12 +739,13 @@ static void FocusFrontMostActiveWindow(ImGuiWindow* ignore_window);
// Viewport
const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111; // Using a constant instead of e.g. ImHash("ViewportDefault", 0); so it's easier to spot in the debugger. The exact value doesn't matter.
static inline ImRect GetViewportRect(ImGuiWindow* window) { return window->Viewport->GetRect(); }
static inline ImVec2 ConvertViewportPosToPlatformPos(const ImVec2& imgui_pos, ImGuiViewport* viewport) { return imgui_pos - viewport->Pos + viewport->PlatformPos; }
static inline ImVec2 ConvertViewportPosToPlatformPos(const ImVec2& imgui_pos, ImGuiViewport* viewport) { return imgui_pos - viewport->Pos + viewport->PlatformPos; }
static inline ImVec2 ConvertPlatformPosToViewportPos(const ImVec2& platform_pos, ImGuiViewport* viewport) { return platform_pos - viewport->PlatformPos + viewport->Pos; }
static ImGuiViewportP* Viewport(ImGuiWindow* window, ImGuiID id, ImGuiViewportFlags flags, const ImVec2& platform_pos, const ImVec2& size);
static void UpdateViewports();
static void UpdateWindowViewport(ImGuiWindow* window, bool window_pos_set_by_api);
static void SetCurrentViewport(ImGuiViewport* viewport);
static void SetWindowViewportTranslateToPreservePlatformPos(ImGuiWindow* window, ImGuiViewport* old_viewport, ImGuiViewport* new_viewport);
static void SetCurrentViewport(ImGuiViewportP* viewport);
static void SetWindowViewportTranslateToPreservePlatformPos(ImGuiWindow* window, ImGuiViewportP* old_viewport, ImGuiViewportP* new_viewport);
static void ResizeViewportTranslateWindows(int viewport_idx_min, int viewport_idx_max, float pos_x_delta, int idx_delta, ImGuiViewport* viewport_to_erase);
}
@ -891,9 +892,6 @@ ImGuiIO::ImGuiIO()
ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl;
ImeWindowHandle = NULL;
memset(&PlatformInterface, 0, sizeof(PlatformInterface));
memset(&RendererInterface, 0, sizeof(RendererInterface));
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
RenderDrawListsFn = NULL;
#endif
@ -2659,6 +2657,12 @@ ImGuiIO& ImGui::GetIO()
return GImGui->IO;
}
ImGuiPlatformIO& ImGui::GetPlatformIO()
{
IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
return GImGui->PlatformIO;
}
ImGuiStyle& ImGui::GetStyle()
{
IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
@ -2669,13 +2673,7 @@ ImGuiStyle& ImGui::GetStyle()
ImDrawData* ImGui::GetDrawData()
{
ImGuiContext& g = *GImGui;
return g.Viewports[0]->DrawData.Valid ? &g.Viewports[0]->DrawData : NULL;
}
ImDrawData* ImGui::GetDrawDataForViewport(ImGuiID viewport_id)
{
ImGuiViewport* viewport = FindViewportByID(viewport_id);
return viewport && viewport->DrawData.Valid ? &viewport->DrawData : NULL;
return g.Viewports[0]->DrawDataP.Valid ? &g.Viewports[0]->DrawDataP : NULL;
}
float ImGui::GetTime()
@ -3255,10 +3253,10 @@ static void ImGui::UpdateMovingWindowDropViewport(ImGuiWindow* window)
ImRect mouse_viewport_rect = g.MouseViewport->GetRect();
ImVec2 window_pos_in_mouse_viewport = ConvertPlatformPosToViewportPos(ConvertViewportPosToPlatformPos(window->Pos, window->Viewport), g.MouseViewport);
ImRect window_rect_in_mouse_viewport = ImRect(window_pos_in_mouse_viewport, window_pos_in_mouse_viewport + window->Size);
if ((g.MouseViewport->Flags & ImGuiViewportFlags_HostOtherWindows) && mouse_viewport_rect.Contains(window_rect_in_mouse_viewport))
if ((g.MouseViewport->Flags & ImGuiViewportFlags_CanHostOtherWindows) && mouse_viewport_rect.Contains(window_rect_in_mouse_viewport))
{
// Drop on an existing viewport
ImGuiViewport* old_viewport = window->Viewport;
ImGuiViewportP* old_viewport = window->Viewport;
SetWindowViewportTranslateToPreservePlatformPos(window, window->Viewport, g.MouseViewport);
// Our current scheme allow any window to land on a viewport, so when that viewport merges, move other windows as well
@ -3272,7 +3270,7 @@ static void ImGui::UpdateMovingWindowDropViewport(ImGuiWindow* window)
{
// Create new viewport
ImVec2 platform_pos = ConvertViewportPosToPlatformPos(window->Pos, window->Viewport);
ImGuiViewport* viewport = Viewport(window, window->ID, 0, platform_pos, window->Size);
ImGuiViewportP* viewport = Viewport(window, window->ID, 0, platform_pos, window->Size);
SetWindowViewportTranslateToPreservePlatformPos(window, window->Viewport, viewport);
}
}
@ -3326,13 +3324,13 @@ static void ImGui::UpdateMovingWindow()
// If the back-end doesn't set MouseLastHoveredViewport or doesn't honor ImGuiViewportFlags_NoInputs, we do a search ourselves.
// This search won't take account of the possibility that non-imgui windows may be in-between our dragged window and our target window.
static ImGuiViewport* FindViewportHoveredFromPlatformWindowStack(const ImVec2 mouse_platform_pos)
static ImGuiViewportP* FindViewportHoveredFromPlatformWindowStack(const ImVec2 mouse_platform_pos)
{
ImGuiContext& g = *GImGui;
ImGuiViewport* best_candidate = NULL;
ImGuiViewportP* best_candidate = NULL;
for (int n = 0; n < g.Viewports.Size; n++)
{
ImGuiViewport* viewport = g.Viewports[n];
ImGuiViewportP* viewport = g.Viewports[n];
ImRect platform_rect = ImRect(viewport->PlatformPos, viewport->PlatformPos + viewport->Size);
if (!(viewport->Flags & ImGuiViewportFlags_NoInputs) && platform_rect.Contains(mouse_platform_pos))
if (best_candidate == NULL || best_candidate->LastFrameAsRefViewport < viewport->LastFrameAsRefViewport)
@ -3344,33 +3342,31 @@ static ImGuiViewport* FindViewportHoveredFromPlatformWindowStack(const ImVec2 mo
static void ImGui::UpdateViewports()
{
ImGuiContext& g = *GImGui;
IM_ASSERT(g.PlatformData.Viewports.Size <= g.Viewports.Size);
// Mouse handling: latch the expected mouse OS position (if any) before processing viewport erasure
ImGuiViewport* viewport_ref = g.IO.MousePosViewport ? FindViewportByID(g.IO.MousePosViewport) : g.Viewports[0];
ImGuiViewportP* viewport_ref = g.IO.MousePosViewport ? FindViewportByID(g.IO.MousePosViewport) : g.Viewports[0];
const ImVec2 mouse_platform_pos = ConvertViewportPosToPlatformPos(g.IO.MousePos, viewport_ref);
g.CurrentViewport = NULL;
for (int n = 0; n < g.Viewports.Size; n++)
{
// Erase unused viewports
ImGuiViewport* viewport = g.Viewports[n];
ImGuiViewportP* viewport = g.Viewports[n];
IM_ASSERT(viewport->Idx == n);
if (n > 0 && viewport->LastFrameActive < g.FrameCount - 2)
{
// Translate windows like if we were resizing the viewport to be zero-width
ResizeViewportTranslateWindows(n + 1, g.Viewports.Size, viewport->Pos.x - viewport->GetNextX(), -1, viewport);
if (g.IO.RendererInterface.DestroyViewport)
g.IO.RendererInterface.DestroyViewport(viewport);
if (g.IO.PlatformInterface.DestroyViewport)
g.IO.PlatformInterface.DestroyViewport(viewport);
viewport->PlatformUserData = viewport->PlatformHandle = viewport->RendererUserData = NULL;
g.Viewports.erase(g.Viewports.Data + n);
// Destroy
if (viewport == viewport_ref) viewport_ref = NULL;
if (viewport == g.MouseViewport) g.MouseViewport = NULL;
if (viewport == g.MouseLastHoveredViewport) g.MouseLastHoveredViewport = NULL;
IM_ASSERT(viewport->RendererUserData == NULL && viewport->PlatformUserData == NULL && viewport->PlatformHandle == NULL);
IM_ASSERT(g.PlatformData.Viewports.contains(viewport) == false);
IM_DELETE(viewport);
n--;
continue;
@ -3384,16 +3380,18 @@ 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.
// Apply Position and Size (from Platform Window to ImGui) if requested
// We do it here early in the frame 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.
if (viewport->PlatformRequestMove)
viewport->PlatformPos = g.PlatformIO.Platform_GetWindowPos(viewport);
if (viewport->PlatformRequestResize)
viewport->Size = g.IO.PlatformInterface.GetWindowSize(viewport);
viewport->Size = g.PlatformIO.Platform_GetWindowSize(viewport);
// Update DPI Scale
float new_dpi_scale;
if (g.IO.PlatformInterface.GetWindowDpiScale)
new_dpi_scale = g.IO.PlatformInterface.GetWindowDpiScale(viewport);
if (g.PlatformIO.Platform_GetWindowDpiScale)
new_dpi_scale = g.PlatformIO.Platform_GetWindowDpiScale(viewport);
else
new_dpi_scale = (viewport->DpiScale != 0.0f) ? viewport->DpiScale : 1.0f;
if (viewport->DpiScale != 0.0f && new_dpi_scale != viewport->DpiScale)
@ -3402,7 +3400,7 @@ static void ImGui::UpdateViewports()
if (g.IO.ConfigFlags & ImGuiConfigFlags_EnableDpiScaleViewports)
ScaleWindowsInViewport(viewport, scale_factor);
//if (viewport == GetMainViewport())
// g.IO.PlatformInterface.SetWindowSize(viewport, viewport->Size * scale_factor);
// g.PlatformInterface.SetWindowSize(viewport, viewport->Size * scale_factor);
// FIXME-DPI: We need to preserve our pivots
//if (g.MovingWindow)
@ -3412,12 +3410,12 @@ static void ImGui::UpdateViewports()
}
// Update main viewport with current size (and OS window position, if known)
ImGuiViewport* main_viewport = g.Viewports[0];
ImGuiViewportP* main_viewport = g.Viewports[0];
IM_ASSERT(main_viewport->ID == IMGUI_VIEWPORT_DEFAULT_ID);
ImVec2 main_viewport_platform_pos = ImVec2(0.0f, 0.0f);
if ((g.IO.ConfigFlags & ImGuiConfigFlags_EnableViewports))
main_viewport_platform_pos = g.IO.PlatformInterface.GetWindowPos(main_viewport);
Viewport(NULL, IMGUI_VIEWPORT_DEFAULT_ID, ImGuiViewportFlags_MainViewport | ImGuiViewportFlags_HostOtherWindows, main_viewport_platform_pos, g.IO.DisplaySize);
main_viewport_platform_pos = g.PlatformIO.Platform_GetWindowPos(main_viewport);
Viewport(NULL, IMGUI_VIEWPORT_DEFAULT_ID, ImGuiViewportFlags_CanHostOtherWindows, main_viewport_platform_pos, g.IO.DisplaySize);
if (!(g.IO.ConfigFlags & ImGuiConfigFlags_EnableViewports))
{
@ -3426,7 +3424,7 @@ static void ImGui::UpdateViewports()
}
// Mouse handling: decide on the actual mouse viewport for this frame between the active/focused viewport and the hovered viewport.
ImGuiViewport* viewport_hovered = NULL;
ImGuiViewportP* viewport_hovered = NULL;
if (g.IO.ConfigFlags & ImGuiConfigFlags_PlatformHasMouseHoveredViewport)
{
viewport_hovered = g.IO.MouseHoveredViewport ? FindViewportByID(g.IO.MouseHoveredViewport) : NULL;
@ -3474,52 +3472,75 @@ static void ImGui::UpdateViewports()
IM_ASSERT(g.MouseViewport != NULL);
}
static void UpdatePlatformWindows()
ImGuiPlatformData* ImGui::GetPlatformData()
{
return &GImGui->PlatformData;
}
void ImGui::UpdatePlatformWindows()
{
// Create/resize windows
ImGuiContext& g = *GImGui;
for (int i = 0; i < g.Viewports.Size; i++)
IM_ASSERT(g.FrameCountEnded == g.FrameCount && "Forgot to call Render() or EndFrame() before UpdatePlatformWindows()?");
IM_ASSERT(g.FrameCountPlatformEnded < g.FrameCount);
g.FrameCountPlatformEnded = g.FrameCount;
g.PlatformData.MainViewport = g.Viewports[0];
g.PlatformData.Viewports.resize(0);
g.PlatformData.Viewports.push_back(g.Viewports[0]);
if (!(g.IO.ConfigFlags & ImGuiConfigFlags_EnableViewports))
return;
// Create/resize/destroy platform windows and update the list that the user can process
for (int i = 1; i < g.Viewports.Size; i++)
{
ImGuiViewport* viewport = g.Viewports[i];
if ((viewport->Flags & ImGuiViewportFlags_MainViewport) || (viewport->LastFrameActive < g.FrameCount))
ImGuiViewportP* viewport = g.Viewports[i];
if (viewport->LastFrameActive < g.FrameCount)
{
if (viewport->LastFrameActive < g.FrameCount - 1)
{
if (g.PlatformIO.Renderer_DestroyWindow)
g.PlatformIO.Renderer_DestroyWindow(viewport);
if (g.PlatformIO.Platform_DestroyWindow)
g.PlatformIO.Platform_DestroyWindow(viewport);
IM_ASSERT(viewport->RendererUserData == NULL);
IM_ASSERT(viewport->PlatformUserData == NULL && viewport->PlatformHandle == NULL);
}
continue;
}
g.PlatformData.Viewports.push_back(viewport);
IM_ASSERT(viewport->Window != NULL);
if (viewport->PlatformRequestMove)
viewport->PlatformPos = 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)
g.PlatformIO.Platform_CreateWindow(viewport);
if (is_new_window && viewport->RendererUserData == NULL && g.PlatformIO.Renderer_CreateWindow != NULL)
{
g.IO.PlatformInterface.CreateViewport(viewport);
}
if (is_new_window && viewport->RendererUserData == NULL && g.IO.RendererInterface.CreateViewport != NULL)
{
g.IO.RendererInterface.CreateViewport(viewport);
g.PlatformIO.Renderer_CreateWindow(viewport);
viewport->RendererLastSize = viewport->Size;
}
// Update Pos/Size for Platform
// Apply Position and Size (from ImGui to Platform Window)
if (!viewport->PlatformRequestMove)
g.IO.PlatformInterface.SetWindowPos(viewport, viewport->PlatformPos);
g.PlatformIO.Platform_SetWindowPos(viewport, viewport->PlatformPos);
if (!viewport->PlatformRequestResize)
g.IO.PlatformInterface.SetWindowSize(viewport, viewport->Size);
g.PlatformIO.Platform_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);
if (g.PlatformIO.Renderer_SetWindowSize && (viewport->RendererLastSize.x != viewport->Size.x || viewport->RendererLastSize.y != viewport->Size.y))
g.PlatformIO.Renderer_SetWindowSize(viewport, viewport->Size);
viewport->RendererLastSize = viewport->Size;
// Update title bar
const char* title_begin = viewport->Window->Name;
const char* title_end = ImGui::FindRenderedTextEnd(title_begin);
const ImGuiID title_hash = ImHash(title_begin, (int)(title_end - title_begin));
if (viewport->LastNameHash != title_hash )
if (viewport->LastNameHash != title_hash)
{
viewport->LastNameHash = title_hash;
char* title_displayed = ImStrdup(viewport->Window->Name);
title_displayed[title_end - title_begin] = 0;
g.IO.PlatformInterface.SetWindowTitle(viewport, title_displayed);
g.PlatformIO.Platform_SetWindowTitle(viewport, title_displayed);
ImGui::MemFree(title_displayed);
}
@ -3528,43 +3549,47 @@ static void UpdatePlatformWindows()
{
if (g.FrameCount < 2)
viewport->Flags |= ImGuiViewportFlags_NoFocusOnAppearing;
g.IO.PlatformInterface.ShowWindow(viewport);
g.PlatformIO.Platform_ShowWindow(viewport);
}
// Clear request flags
viewport->PlatformRequestClose = false;
viewport->PlatformRequestMove = false;
viewport->PlatformRequestResize = false;
viewport->PlatformRequestClose = viewport->PlatformRequestMove = viewport->PlatformRequestResize = false;
}
}
void ImGui::RenderAdditionalViewports()
// This is a default/basic function for performing the rendering/swap of multiple platform windows.
// Custom renderers may prefer to not call this function at all, and instead iterate the platform data and handle rendering/sync themselves.
// The Render/Swap functions stored in ImGuiPlatformInterface are merely here to allow for this helper to exist, but you can do it yourself:
//
// ImGuiPlatformData* data = ImGui::GetPlatformData();
// for (int i = 1; i < data->Viewports.Size; i++)
// MyRenderFunction(data->Viewports[i], my_args);
// for (int i = 1; i < data->Viewports.Size; i++)
// MySwapBufferFunction(data->Viewports[i], my_args);
//
// Note how we intentionally skip the main viewport (index 0) which is generally rendered as part of our main application.
void ImGui::RenderPlatformWindows()
{
ImGuiContext& g = *GImGui;
if (!(g.IO.ConfigFlags & ImGuiConfigFlags_EnableViewports))
if (!(ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_EnableViewports))
return;
for (int i = 0; i < g.Viewports.Size; i++)
{
ImGuiViewport* viewport = g.Viewports[i];
if ((viewport->Flags & ImGuiViewportFlags_MainViewport) || (viewport->LastFrameActive < g.FrameCount))
continue;
if (g.IO.PlatformInterface.RenderViewport)
g.IO.PlatformInterface.RenderViewport(viewport);
if (g.IO.RendererInterface.RenderViewport)
g.IO.RendererInterface.RenderViewport(viewport);
}
// Swap
for (int i = 0; i < g.Viewports.Size; i++)
ImGuiPlatformData* data = ImGui::GetPlatformData();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
for (int i = 1; i < data->Viewports.Size; i++)
{
ImGuiViewport* viewport = g.Viewports[i];
if ((viewport->Flags & ImGuiViewportFlags_MainViewport) || (viewport->LastFrameActive < g.FrameCount))
continue;
if (g.IO.PlatformInterface.SwapBuffers)
g.IO.PlatformInterface.SwapBuffers(viewport);
if (g.IO.RendererInterface.SwapBuffers)
g.IO.RendererInterface.SwapBuffers(viewport);
ImGuiViewport* viewport = data->Viewports[i];
if (platform_io.Platform_RenderWindow)
platform_io.Platform_RenderWindow(viewport);
if (platform_io.Renderer_RenderWindow)
platform_io.Renderer_RenderWindow(viewport);
}
for (int i = 1; i < data->Viewports.Size; i++)
{
ImGuiViewport* viewport = data->Viewports[i];
if (platform_io.Platform_SwapBuffers)
platform_io.Platform_SwapBuffers(viewport);
if (platform_io.Renderer_SwapBuffers)
platform_io.Renderer_SwapBuffers(viewport);
}
}
@ -3574,7 +3599,7 @@ void ImGui::NewFrame()
ImGuiContext& g = *GImGui;
// Check user data
// (We pass an error message in the assert expression as a trick to get it visible to programmers who are not using a debugger, as most assert handlers display their argument)
// (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument)
IM_ASSERT(g.Initialized);
IM_ASSERT(g.IO.DeltaTime >= 0.0f && "Need a positive DeltaTime (zero is tolerated but will cause some timing issues)");
IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value");
@ -3586,21 +3611,22 @@ void ImGui::NewFrame()
for (int n = 0; n < ImGuiKey_COUNT; n++)
IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)");
// Do a simple check for required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was super recently added in 1.60 WIP)
// Perform simple check for required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only recently added in 1.60 WIP)
if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)
IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
// Perform simple checks for multi-viewport and platform windows support
if (g.IO.ConfigFlags & ImGuiConfigFlags_EnableViewports)
{
if ((g.IO.ConfigFlags & ImGuiConfigFlags_PlatformHasViewports) && (g.IO.ConfigFlags & ImGuiConfigFlags_RendererHasViewports))
{
IM_ASSERT(g.FrameCount == 0 || g.FrameCountPlatformEnded == g.FrameCount && "Forgot to call UpdatePlatformWindows() at the end of the previous frame?");
IM_ASSERT(g.PlatformIO.Platform_CreateWindow != NULL && "Platform init didn't install handlers?");
IM_ASSERT(g.PlatformIO.Platform_DestroyWindow != NULL && "Platform init didn't install handlers?");
IM_ASSERT(g.Viewports[0]->PlatformUserData != NULL && "Platform init didn't setup main viewport.");
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
IM_ASSERT(g.IO.RenderDrawListsFn == NULL); // Call ImGui::Render() then pass ImGui::GetDrawData() yourself to your render function!
#endif
IM_ASSERT(g.IO.PlatformInterface.CreateViewport != NULL);
IM_ASSERT(g.IO.PlatformInterface.DestroyViewport != NULL);
//IM_ASSERT(g.IO.PlatformInterface.RenderViewport != NULL || g.IO.RendererInterface.RenderViewport != NULL); // Missing rendering function
IM_ASSERT(g.Viewports[0]->PlatformUserData != NULL); // Platform init function didn't setup main viewport
}
else
{
@ -3641,7 +3667,10 @@ void ImGui::NewFrame()
// Mark rendering data as invalid to prevent user who may have a handle on it to use it
for (int n = 0; n < g.Viewports.Size; n++)
g.Viewports[n]->DrawData.Clear();
{
g.Viewports[n]->DrawData = NULL;
g.Viewports[n]->DrawDataP.Clear();
}
// Clear reference to active widget if the widget isn't alive anymore
if (!g.HoveredIdPreviousFrame)
@ -3955,24 +3984,23 @@ void ImGui::Initialize(ImGuiContext* context)
g.SettingsHandlers.push_front(ini_handler);
// Create default viewport
ImGuiViewport* viewport = IM_NEW(ImGuiViewport)(IMGUI_VIEWPORT_DEFAULT_ID, 0);
ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)();
viewport->ID = IMGUI_VIEWPORT_DEFAULT_ID;
viewport->Idx = 0;
g.Viewports.push_back(viewport);
g.Initialized = true;
}
void ImGui::DestroyViewportsPlaformData(ImGuiContext* context)
void ImGui::DestroyPlatformWindows()
{
if (context->IO.PlatformInterface.DestroyViewport)
for (int i = 0; i < context->Viewports.Size; i++)
context->IO.PlatformInterface.DestroyViewport(context->Viewports[i]);
}
void ImGui::DestroyViewportsRendererData(ImGuiContext* context)
{
if (context->IO.RendererInterface.DestroyViewport)
for (int i = 0; i < context->Viewports.Size; i++)
context->IO.RendererInterface.DestroyViewport(context->Viewports[i]);
ImGuiContext& g = *GImGui;
if (g.PlatformIO.Renderer_DestroyWindow)
for (int i = 0; i < g.Viewports.Size; i++)
g.PlatformIO.Renderer_DestroyWindow(g.Viewports[i]);
if (g.PlatformIO.Platform_DestroyWindow)
for (int i = 0; i < g.Viewports.Size; i++)
g.PlatformIO.Platform_DestroyWindow(g.Viewports[i]);
}
// This function is merely here to free heap allocations.
@ -3990,6 +4018,12 @@ void ImGui::Shutdown(ImGuiContext* context)
SaveIniSettingsToDisk(g.IO.IniFilename);
// Destroy platform windows
ImGuiContext* backup_context = ImGui::GetCurrentContext();
SetCurrentContext(context);
DestroyPlatformWindows();
SetCurrentContext(backup_context);
// Clear everything else
for (int i = 0; i < g.Windows.Size; i++)
IM_DELETE(g.Windows[i]);
@ -4011,14 +4045,8 @@ void ImGui::Shutdown(ImGuiContext* context)
g.OpenPopupStack.clear();
g.CurrentPopupStack.clear();
g.CurrentViewport = g.MouseViewport = g.MouseLastViewport = g.MouseLastHoveredViewport = NULL;
DestroyViewportsPlaformData(context);
DestroyViewportsRendererData(context);
for (int i = 0; i < g.Viewports.Size; i++)
{
ImGuiViewport* viewport = g.Viewports[i];
viewport->PlatformUserData = viewport->PlatformHandle = viewport->RendererUserData = NULL;
IM_DELETE(viewport);
}
IM_DELETE(g.Viewports[i]);
g.Viewports.clear();
g.OverlayDrawList.ClearFreeMemory();
g.PrivateClipboard.clear();
@ -4291,18 +4319,20 @@ void ImDrawDataBuilder::FlattenIntoSingleLayer()
}
}
static void SetupViewportDrawData(ImGuiViewport* viewport, ImVector<ImDrawList*>* draw_lists)
static void SetupViewportDrawData(ImGuiViewportP* viewport, ImVector<ImDrawList*>* draw_lists)
{
viewport->DrawData.Valid = true;
viewport->DrawData.CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL;
viewport->DrawData.CmdListsCount = draw_lists->Size;
viewport->DrawData.TotalVtxCount = viewport->DrawData.TotalIdxCount = 0;
viewport->DrawData.DisplayPos = viewport->Pos;
viewport->DrawData.DisplaySize = viewport->Size;
ImDrawData* draw_data = &viewport->DrawDataP;
viewport->DrawData = draw_data; // Make publicly accessible
draw_data->Valid = true;
draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL;
draw_data->CmdListsCount = draw_lists->Size;
draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0;
draw_data->DisplayPos = viewport->Pos;
draw_data->DisplaySize = viewport->Size;
for (int n = 0; n < draw_lists->Size; n++)
{
viewport->DrawData.TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size;
viewport->DrawData.TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size;
draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size;
draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size;
}
}
@ -4412,9 +4442,6 @@ void ImGui::EndFrame()
memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
g.FrameCountEnded = g.FrameCount;
if (g.IO.ConfigFlags & ImGuiConfigFlags_EnableViewports)
UpdatePlatformWindows();
}
void ImGui::Render()
@ -4461,22 +4488,28 @@ void ImGui::Render()
g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0;
for (int n = 0; n < g.Viewports.Size; n++)
{
ImGuiViewport* viewport = g.Viewports[n];
ImGuiViewportP* viewport = g.Viewports[n];
viewport->DrawDataBuilder.FlattenIntoSingleLayer();
AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], &g.OverlayDrawList);
SetupViewportDrawData(viewport, &viewport->DrawDataBuilder.Layers[0]);
g.IO.MetricsRenderVertices += viewport->DrawData.TotalVtxCount;
g.IO.MetricsRenderIndices += viewport->DrawData.TotalIdxCount;
g.IO.MetricsRenderVertices += viewport->DrawData->TotalVtxCount;
g.IO.MetricsRenderIndices += viewport->DrawData->TotalIdxCount;
}
// Render. If user hasn't set a callback then they may retrieve the draw data via GetDrawData()
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
if (g.Viewports[0]->DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL)
g.IO.RenderDrawListsFn(&g.Viewports[0]->DrawData);
if (g.Viewports[0]->DrawData->CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL)
g.IO.RenderDrawListsFn(g.Viewports[0]->DrawData);
#endif
}
ImGuiViewport* ImGui::FindViewportByID(ImGuiID id)
ImGuiViewport* ImGui::GetMainViewport()
{
ImGuiContext& g = *GImGui;
return g.Viewports[0];
}
ImGuiViewportP* ImGui::FindViewportByID(ImGuiID id)
{
ImGuiContext& g = *GImGui;
for (int n = 0; n < g.Viewports.Size; n++)
@ -4531,9 +4564,9 @@ static void ImGui::ResizeViewportTranslateWindows(int viewport_idx_min, int view
}
}
void ImGui::SetCurrentViewport(ImGuiViewport* viewport)
void ImGui::SetCurrentViewport(ImGuiViewportP* viewport)
{
// Notify platform interface of viewport changes
// Notify platform layer of viewport changes
// FIXME-DPI: This is only currently used for experimenting with handling of multiple DPI
ImGuiContext& g = *GImGui;
if (viewport)
@ -4541,16 +4574,16 @@ void ImGui::SetCurrentViewport(ImGuiViewport* viewport)
if (g.CurrentViewport == viewport)
return;
g.CurrentViewport = viewport;
if (g.CurrentViewport && g.IO.PlatformInterface.ChangedViewport)
g.IO.PlatformInterface.ChangedViewport(g.CurrentViewport);
if (g.CurrentViewport && g.PlatformIO.Platform_OnChangedViewport)
g.PlatformIO.Platform_OnChangedViewport(g.CurrentViewport);
}
ImGuiViewport* ImGui::Viewport(ImGuiWindow* window, ImGuiID id, ImGuiViewportFlags flags, const ImVec2& platform_pos, const ImVec2& size)
ImGuiViewportP* ImGui::Viewport(ImGuiWindow* window, ImGuiID id, ImGuiViewportFlags flags, const ImVec2& platform_pos, const ImVec2& size)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(id != 0);
ImGuiViewport* viewport = FindViewportByID(id);
ImGuiViewportP* viewport = (ImGuiViewportP*)FindViewportByID(id);
if (viewport)
{
// We defer translating windows to the beginning of the frame.
@ -4560,7 +4593,9 @@ ImGuiViewport* ImGui::Viewport(ImGuiWindow* window, ImGuiID id, ImGuiViewportFla
else
{
// New viewport
viewport = IM_NEW(ImGuiViewport)(id, g.Viewports.Size);
viewport = IM_NEW(ImGuiViewportP)();
viewport->ID = id;
viewport->Idx = g.Viewports.Size;
viewport->Pos = ImVec2(g.Viewports.back()->GetNextX(), 0.0f);
viewport->Size = size;
g.Viewports.push_back(viewport);
@ -4573,8 +4608,8 @@ ImGuiViewport* ImGui::Viewport(ImGuiWindow* window, ImGuiID id, ImGuiViewportFla
viewport->LastFrameActive = g.FrameCount;
// Request an initial DpiScale before the OS platform window creation
if (g.IO.PlatformInterface.GetWindowDpiScale)
viewport->DpiScale = g.IO.PlatformInterface.GetWindowDpiScale(viewport);
if (g.PlatformIO.Platform_GetWindowDpiScale)
viewport->DpiScale = g.PlatformIO.Platform_GetWindowDpiScale(viewport);
return viewport;
}
@ -5922,7 +5957,7 @@ static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& co
*out_size = size_constrained;
}
static void ImGui::SetWindowViewportTranslateToPreservePlatformPos(ImGuiWindow* window, ImGuiViewport* prev_viewport, ImGuiViewport* curr_viewport)
static void ImGui::SetWindowViewportTranslateToPreservePlatformPos(ImGuiWindow* window, ImGuiViewportP* prev_viewport, ImGuiViewportP* curr_viewport)
{
if (prev_viewport == curr_viewport)
return;
@ -5948,8 +5983,8 @@ static void ImGui::UpdateWindowViewport(ImGuiWindow* window, bool window_pos_set
ImGuiWindowFlags flags = window->Flags;
(void)window_pos_set_by_api;
// Restore main viewport if multi viewports are not supported by the back-end
ImGuiViewport* main_viewport = g.Viewports[0];
// Restore main viewport if multi-viewport is not supported by the back-end
ImGuiViewportP* main_viewport = g.Viewports[0];
if (!(g.IO.ConfigFlags & ImGuiConfigFlags_EnableViewports))
{
window->Viewport = main_viewport;
@ -5976,13 +6011,13 @@ static void ImGui::UpdateWindowViewport(ImGuiWindow* window, bool window_pos_set
else if (window_follow_mouse_viewport && IsMousePosValid())
{
// Calculate mouse position in OS/platform coordinates
ImGuiViewport* current_viewport = window->Viewport;
ImGuiViewportP* current_viewport = window->Viewport;
if (!window_is_mouse_tooltip && !current_viewport->GetRect().Contains(window->Rect()))
{
// Create an undecorated, temporary OS/platform window
ImVec2 platform_pos = ConvertViewportPosToPlatformPos(g.IO.MousePos - g.ActiveIdClickOffset, g.MouseViewport);
ImGuiViewportFlags viewport_flags = ImGuiViewportFlags_NoDecoration | ImGuiViewportFlags_NoFocusOnAppearing | ImGuiViewportFlags_NoInputs;
ImGuiViewport* viewport = Viewport(window, window->ID, viewport_flags, platform_pos, window->Size);
ImGuiViewportP* viewport = Viewport(window, window->ID, viewport_flags, platform_pos, window->Size);
window->Flags |= ImGuiWindowFlags_FullViewport;
window->Viewport = viewport;
created_viewport = true;
@ -6021,7 +6056,7 @@ static void ImGui::UpdateWindowViewport(ImGuiWindow* window, bool window_pos_set
{
if (window->ViewportPlatformPos.x != FLT_MAX && window->ViewportPlatformPos.y != FLT_MAX)
{
ImGuiViewport* viewport = Viewport(window, window->ID, ImGuiViewportFlags_NoDecoration, window->ViewportPlatformPos, window->Size);
ImGuiViewportP* viewport = Viewport(window, window->ID, ImGuiViewportFlags_NoDecoration, window->ViewportPlatformPos, window->Size);
window->Flags |= ImGuiWindowFlags_FullViewport;
window->Viewport = viewport;
created_viewport = true;
@ -6352,7 +6387,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
SetCurrentWindow(window);
flags = window->Flags;
if (p_open != NULL && window->Viewport->PlatformRequestClose && !(window->Viewport->Flags & ImGuiViewportFlags_MainViewport))
if (p_open != NULL && window->Viewport->PlatformRequestClose && window->Viewport != GetMainViewport())
{
window->Viewport->PlatformRequestClose = false;
*p_open = false;
@ -6360,7 +6395,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Lock window rounding, border size and padding for the frame (so that altering them doesn't cause inconsistencies)
window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
if (window->Viewport != GetMainViewport())
if (window->Flags & ImGuiWindowFlags_FullViewport)
window->WindowRounding = 0.0f;
window->WindowBorderSize = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildBorderSize : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize;
window->WindowPadding = style.WindowPadding;
@ -13827,7 +13862,7 @@ static void ScaleWindow(ImGuiWindow* window, float scale)
}
// Scale all windows (position, size). Use when e.g. changing DPI. (This is a lossy operation!)
void ImGui::ScaleWindowsInViewport(ImGuiViewport* viewport, float scale)
void ImGui::ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale)
{
ImGuiContext& g = *GImGui;
if (g.IO.MousePosViewport == viewport->ID)
@ -13857,7 +13892,7 @@ void ImGui::ShowViewportThumbnails()
ImVec2 p = window->DC.CursorPos;
for (int n = 0; n < g.Viewports.Size; n++)
{
ImGuiViewport* viewport = g.Viewports[n];
ImGuiViewportP* viewport = g.Viewports[n];
if (n > 0)
ImGui::SameLine();
ImRect bb(p + (viewport->Pos) * SCALE, p + (viewport->Pos + viewport->Size) * SCALE);
@ -14015,7 +14050,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
for (int i = 0; i < g.Viewports.Size; i++)
{
ImGuiViewport* viewport = g.Viewports[i];
ImGuiViewportP* viewport = g.Viewports[i];
ImGui::SetNextTreeNodeOpen(true, ImGuiCond_Once);
if (ImGui::TreeNode((void*)(intptr_t)viewport->ID, "Viewport #%d, ID: 0x%08X, DrawLists: %d, Size: (%.0f,%.0f)", i, viewport->ID, viewport->DrawDataBuilder.GetDrawListCount(), viewport->Size.x, viewport->Size.y))
{