Viewport, DPI: Some early work on per-viewport DPI support. At the moment the easiest way is to replace fonts during the ChangedViewport callback, but down the line we should aim at handling some of it at ImFont level. (#1542, #1676)

This commit is contained in:
omar 2018-03-09 19:08:47 +01:00
parent a2fbcc9ad4
commit 5e63711084
5 changed files with 69 additions and 23 deletions

View File

@ -67,6 +67,10 @@ void CleanupDeviceD3D()
if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = NULL; }
}
#ifndef WM_DPICHANGED
#define WM_DPICHANGED 0x02E0 // From Windows SDK 8.1+ headers
#endif
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
@ -92,6 +96,15 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_DPICHANGED:
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_EnableDpiScaleViewports)
{
//const int dpi = HIWORD(wParam);
//printf("WM_DPICHANGED to %d (%.0f%%)\n", dpi, (float)dpi / 96.0f * 100.0f);
const RECT* suggested_rect = (RECT*)lParam;
::SetWindowPos(hWnd, NULL, suggested_rect->left, suggested_rect->top, suggested_rect->right - suggested_rect->left, suggested_rect->bottom - suggested_rect->top, SWP_NOZORDER | SWP_NOACTIVATE);
}
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
@ -121,6 +134,8 @@ int main(int, char**)
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_EnableViewports;
io.ConfigFlags |= ImGuiConfigFlags_EnableDpiScaleFonts;
io.ConfigFlags |= ImGuiConfigFlags_EnableDpiScaleViewports;
io.ConfigFlags |= ImGuiConfigFlags_PlatformNoTaskBar;
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls

View File

@ -470,6 +470,18 @@ static void ImGui_ImplWin32_SetWindowTitle(ImGuiViewport* viewport, const char*
::SetWindowTextA(data->Hwnd, title);
}
static float ImGui_ImplWin32_GetWindowDpiScale(ImGuiViewport* viewport)
{
ImGuiPlatformDataWin32* data = (ImGuiPlatformDataWin32*)viewport->PlatformUserData;
if (data && data->Hwnd)
return ImGui_ImplWin32_GetDpiScaleForHwnd(data->Hwnd);
// The first frame a viewport is created we don't have a window yet
return ImGui_ImplWin32_GetDpiScaleForRect(
(int)(viewport->PlatformOsDesktopPos.x), (int)(viewport->PlatformOsDesktopPos.y),
(int)(viewport->PlatformOsDesktopPos.x + viewport->Size.x), (int)(viewport->PlatformOsDesktopPos.y + viewport->Size.y));
}
static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
@ -531,6 +543,7 @@ static void ImGui_ImplWin32_InitPlatformInterface()
io.PlatformInterface.SetWindowSize = ImGui_ImplWin32_SetWindowSize;
io.PlatformInterface.GetWindowSize = ImGui_ImplWin32_GetWindowSize;
io.PlatformInterface.SetWindowTitle = ImGui_ImplWin32_SetWindowTitle;
io.PlatformInterface.GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale;
// Register main window handle
ImGuiViewport* main_viewport = ImGui::GetMainViewport();

View File

@ -1944,7 +1944,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
LastFrameActive = -1;
ItemWidthDefault = 0.0f;
FontWindowScale = 1.0f;
FontWindowScale = FontDpiScale = 1.0f;
DrawList = IM_NEW(ImDrawList)(&context->DrawListSharedData);
DrawList->_OwnerName = Name;
@ -3388,13 +3388,20 @@ static void ImGui::UpdateViewports()
if (g.IO.PlatformInterface.GetWindowDpiScale)
new_dpi_scale = g.IO.PlatformInterface.GetWindowDpiScale(viewport);
else
new_dpi_scale = (viewport->PlatformDpiScale != 0.0f) ? viewport->PlatformDpiScale : 1.0f;
if (viewport->PlatformDpiScale != 0.0f && new_dpi_scale != viewport->PlatformDpiScale)
new_dpi_scale = (viewport->DpiScale != 0.0f) ? viewport->DpiScale : 1.0f;
if (viewport->DpiScale != 0.0f && new_dpi_scale != viewport->DpiScale)
{
float scale_factor = new_dpi_scale / viewport->PlatformDpiScale;
ScaleWindowsInViewport(viewport, scale_factor);
float scale_factor = new_dpi_scale / viewport->DpiScale;
if (g.IO.ConfigFlags & ImGuiConfigFlags_EnableDpiScaleViewports)
ScaleWindowsInViewport(viewport, scale_factor);
//if (viewport == GetMainViewport())
// g.IO.PlatformInterface.SetWindowSize(viewport, viewport->Size * scale_factor);
// FIXME-DPI: We need to preserve our pivots
//if (g.MovingWindow)
// g.ActiveIdClickOffset = g.ActiveIdClickOffset * scale_factor;
}
viewport->PlatformDpiScale = new_dpi_scale;
viewport->DpiScale = new_dpi_scale;
}
// Update main viewport with current size (and OS window position, if known)
@ -4527,11 +4534,9 @@ void ImGui::SetCurrentViewport(ImGuiViewport* viewport)
viewport->LastFrameActive = g.FrameCount;
if (g.CurrentViewport == viewport)
return;
if (g.CurrentViewport && g.IO.PlatformInterface.EndViewport)
g.IO.PlatformInterface.EndViewport(g.CurrentViewport);
g.CurrentViewport = viewport;
if (g.CurrentViewport && g.IO.PlatformInterface.BeginViewport)
g.IO.PlatformInterface.BeginViewport(g.CurrentViewport);
if (g.CurrentViewport && g.IO.PlatformInterface.ChangedViewport)
g.IO.PlatformInterface.ChangedViewport(g.CurrentViewport);
}
ImGuiViewport* ImGui::Viewport(ImGuiWindow* window, ImGuiID id, ImGuiViewportFlags flags, const ImVec2& os_desktop_pos, const ImVec2& size)
@ -4558,6 +4563,10 @@ ImGuiViewport* ImGui::Viewport(ImGuiWindow* window, ImGuiID id, ImGuiViewportFla
viewport->Flags = flags;
viewport->PlatformOsDesktopPos = os_desktop_pos;
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);
return viewport;
}
@ -6322,6 +6331,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
UpdateWindowViewport(window, window_pos_set_by_api);
SetCurrentViewport(window->Viewport);
window->FontDpiScale = (g.IO.ConfigFlags & ImGuiConfigFlags_EnableDpiScaleFonts) ? window->Viewport->DpiScale : 1.0f;
SetCurrentWindow(window);
flags = window->Flags;
@ -13805,6 +13815,11 @@ static void ScaleWindow(ImGuiWindow* window, float scale)
void ImGui::ScaleWindowsInViewport(ImGuiViewport* viewport, float scale)
{
ImGuiContext& g = *GImGui;
if (g.IO.MousePosViewport == viewport->ID)
{
//g.IO.MousePos = g.IO.MousePosPrev = ImFloor((g.IO.MousePos - viewport->Pos) * scale) + viewport->Pos;
//g.IO.MouseDelta = ImVec2(0,0);
}
if (viewport->Window)
{
ScaleWindow(viewport->Window, scale);
@ -13992,7 +14007,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
{
ImGui::BulletText("Pos: (%.0f,%.0f)", viewport->Pos.x, viewport->Pos.y);
ImGui::BulletText("Flags: 0x%04X", viewport->Flags);
ImGui::BulletText("PlatformOsDesktopPos: (%.0f,%.0f); DpiScale: %.0f%%", viewport->PlatformOsDesktopPos.x, viewport->PlatformOsDesktopPos.y, viewport->PlatformDpiScale * 100.0f);
ImGui::BulletText("PlatformOsDesktopPos: (%.0f,%.0f); DpiScale: %.0f%%", viewport->PlatformOsDesktopPos.x, viewport->PlatformOsDesktopPos.y, viewport->DpiScale * 100.0f);
for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[0].Size; draw_list_i++)
Funcs::NodeDrawList(NULL, viewport->DrawDataBuilder.Layers[0][draw_list_i], "DrawList");
ImGui::TreePop();

18
imgui.h
View File

@ -779,12 +779,15 @@ enum ImGuiConfigFlags_
// [BETA] Viewports
ImGuiConfigFlags_EnableViewports = 1 << 4, // Viewport enable flags (require both ImGuiConfigFlags_PlatformHasViewports + ImGuiConfigFlags_RendererHasViewports set by the respective back-ends)
ImGuiConfigFlags_PlatformNoTaskBar = 1 << 5,
ImGuiConfigFlags_PlatformHasViewports = 1 << 6, // Back-end Platform supports multiple viewports
ImGuiConfigFlags_PlatformHasMouseHoveredViewport = 1 << 7, // Back-end Platform supports setting io.MouseHoveredViewport to the viewport directly under the mouse _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag and _REGARDLESS_ of whether another viewport is focused and may be capturing the mouse. This information is _NOT EASY_ to provide correctly with most high-level engines. Don't see this without studying how the examples/ back-end handle it.
ImGuiConfigFlags_PlatformHasWantMoveMouseSupport = 1 << 8, // Back-end Platform supports io.WantMoveMouse request by updating the OS mouse cursor position (currently only used by ImGuiConfigFlags_NavMoveMouse feature, will be useful for widgets teleporting/wrapping the cursor)
ImGuiConfigFlags_PlatformHasWindowAlpha = 1 << 9, // Back-end Platform supports transparent windows
ImGuiConfigFlags_RendererHasViewports = 1 << 10, // Back-end Renderer supports multiple viewports
ImGuiConfigFlags_EnableDpiScaleViewports = 1 << 5,
ImGuiConfigFlags_EnableDpiScaleFonts = 1 << 6,
ImGuiConfigFlags_PlatformNoTaskBar = 1 << 10,
ImGuiConfigFlags_PlatformHasViewports = 1 << 11, // Back-end Platform supports multiple viewports
ImGuiConfigFlags_PlatformHasMouseHoveredViewport = 1 << 12, // Back-end Platform supports setting io.MouseHoveredViewport to the viewport directly under the mouse _IGNORING_ viewports with the ImGuiViewportFlags_NoInputs flag and _REGARDLESS_ of whether another viewport is focused and may be capturing the mouse. This information is _NOT EASY_ to provide correctly with most high-level engines. Don't see this without studying how the examples/ back-end handle it.
ImGuiConfigFlags_PlatformHasWantMoveMouseSupport = 1 << 13, // Back-end Platform supports io.WantMoveMouse request by updating the OS mouse cursor position (currently only used by ImGuiConfigFlags_NavMoveMouse feature, will be useful for widgets teleporting/wrapping the cursor)
ImGuiConfigFlags_PlatformHasWindowAlpha = 1 << 14, // Back-end Platform supports transparent windows
ImGuiConfigFlags_RendererHasViewports = 1 << 15, // Back-end Renderer supports multiple viewports
// Platform Info (free of use, for user/application convenience)
ImGuiConfigFlags_IsSRGB = 1 << 20, // Back-end is SRGB-aware (Storage flag to allow your back-end to communicate to shared widgets. Not used by core ImGui)
@ -965,8 +968,7 @@ struct ImGuiPlatformInterface
// FIXME-DPI
float (*GetWindowDpiScale)(ImGuiViewport* viewport); // (Optional)
void (*BeginViewport)(ImGuiViewport* viewport); // (Optional) Called during Begin() every time the viewport we are outputting into changes (viewport = next viewport)
void (*EndViewport)(ImGuiViewport* viewport); // (Optional) Called during Begin() every time the viewport we are outputting into changes (viewport = previous viewport)
void (*ChangedViewport)(ImGuiViewport* viewport); // (Optional) Called during Begin() every time the viewport we are outputting into changes (viewport = next viewport)
};
// (Optional) Setup required only if (io.ConfigFlags & ImGuiConfigFlags_EnableMultiViewport) is enabled

View File

@ -534,19 +534,19 @@ struct ImGuiViewport
ImGuiWindow* Window;
ImVec2 Pos; // Position in imgui virtual space (Pos.y == 0.0)
ImVec2 Size;
float DpiScale;
ImDrawData DrawData;
ImDrawDataBuilder DrawDataBuilder;
// [Optional] OS/Platform Layer data. This is to allow the creation/manipulate of multiple OS/Platform windows. Not all back-ends will allow this.
ImVec2 PlatformOsDesktopPos; // Position in OS desktop/native space
float PlatformDpiScale; // FIXME-DPI: Unused
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
void* RendererUserData; // void* to hold custom data structure for the renderer (e.g. framebuffer)
ImGuiViewport(ImGuiID id, int idx) { ID = id; Idx = idx; Flags = 0; LastFrameActive = LastFrameAsRefViewport = -1; LastNameHash = 0; Window = NULL; PlatformDpiScale = 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 = PlatformRequestResize = false; 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); }
float GetNextX() const { const float SPACING = 4.0f; return Pos.x + Size.x + SPACING; }
@ -1010,7 +1010,8 @@ struct IMGUI_API ImGuiWindow
ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items
ImGuiStorage StateStorage;
ImVector<ImGuiColumnsSet> ColumnsStorage;
float FontWindowScale; // Scale multiplier per-window
float FontWindowScale; // User scale multiplier per-window
float FontDpiScale;
ImDrawList* DrawList;
ImGuiWindow* ParentWindow; // If we are a child _or_ popup window, this is pointing to our parent. Otherwise NULL.
ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window.
@ -1042,7 +1043,7 @@ public:
// We don't use g.FontSize because the window may be != g.CurrentWidow.
ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); }
float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; }
float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale * FontDpiScale; }
float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; }
ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); }
float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; }