SFML / imgui-sfml

Dear ImGui backend for use with SFML
MIT License
1.15k stars 172 forks source link

DPI-awareness on Windows #284

Closed nefarius closed 5 months ago

nefarius commented 5 months ago

Ahoy there, long time user and lurker of this amazing project 😀

It appears that neither SFML nor ImGui ship with or document a "best practice" on how to deal with DPI-awareness on Windows, like reacting to users who are on like 150% or 200% but the ImGui app stays "tiny" in comparison instead of adjusting width, height, fonts etc.

Anybody knows how to achieve this most elegantly?

Thanks & cheers

Alia5 commented 5 months ago

I'm not sure that this is the most elegant way, however,
you could...

// stolen from: https://building.enlyze.com/posts/writing-win32-apps-like-its-2020-part-3/
typedef HRESULT(WINAPI* PGetDpiForMonitor)(HMONITOR hmonitor, int dpiType, UINT* dpiX, UINT* dpiY);
WORD GetWindowDPI(HWND hWnd)
{
    // Try to get the DPI setting for the monitor where the given window is located.
    // This API is Windows 8.1+.
    HMODULE hShcore = LoadLibraryW(L"shcore");
    if (hShcore) {
        PGetDpiForMonitor pGetDpiForMonitor =
            reinterpret_cast<PGetDpiForMonitor>(GetProcAddress(hShcore, "GetDpiForMonitor"));
        if (pGetDpiForMonitor) {
            HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY);
            UINT uiDpiX;
            UINT uiDpiY;
            HRESULT hr = pGetDpiForMonitor(hMonitor, 0, &uiDpiX, &uiDpiY);
            if (SUCCEEDED(hr)) {
                return static_cast<WORD>(uiDpiX);
            }
        }
    }

    // We couldn't get the window's DPI above, so get the DPI of the primary monitor
    // using an API that is available in all Windows versions.
    HDC hScreenDC = GetDC(0);
    int iDpiX = GetDeviceCaps(hScreenDC, LOGPIXELSX);
    ReleaseDC(0, hScreenDC);

    return static_cast<WORD>(iDpiX);
}

Then adjust ImGUIs fontScale

    HWND hwnd = window_.getSystemHandle();
    auto dpi = GetWindowDPI(hwnd);
    ImGuiIO& io = ImGui::GetIO();
    io.FontGlobalScale = dpi / 96.f;
    ImGui::SFML::UpdateFontTexture();
nefarius commented 5 months ago

I pretty much have solved this challenge, for those interested in the implementation details check out this PR.

Cheers