Page 1 of 1

Per-Monitor DPI Aware guidelins (C++ SDK)

Posted: 23 May 2017, 08:36
by nikobarli
Hi,

I am trying to make my sample application to be Per-Monitor DPI Aware.

Basically I call SetLayoutTransform(new ScaleTransform(scaleX, scaleY)) of the root XAML element during initial setup and when WM_DPICHANGED is sent to the application, and it seems that Noesis correctly scale the UI and render it crisply. So far seems very good.
        // m_xamlRenderer is a wrapper around Noesis GUI
        m_xamlRenderer = CXamlRenderer::Create(m_hWnd);
        auto monitor = ::MonitorFromWindow(m_hWnd, MONITOR_DEFAULTTONEAREST);
        auto dpiX = unsigned{};
        auto dpiY = unsigned{};
        GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
        m_xamlRenderer->SetDpi(dpiX, dpiY); // see below snippet
    afx_msg LRESULT OnDpiChanged(WPARAM wParam, LPARAM lParam) {
        auto dpiX = HIWORD(wParam);
        auto dpiY = LOWORD(wParam);
        m_xamlRenderer->SetDpi(dpiX, dpiY); // see below snippet
        auto rect = *reinterpret_cast<RECT *>(lParam);
        SetWindowPos(nullptr, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOACTIVATE | SWP_NOZORDER);
        return 0;
    }
    void  CXamlRenderer::SetDpi(int dpiX, int dpiY) {
        auto root = m_xaml->GetContent(); // Get root XAML element
        auto scaleX = dpiX / 96.0f;
        auto scaleY = dpiY / 96.0f;
        root->SetLayoutTransform(new ScaleTransform(scaleX, scaleY));
    }

Is there anything else I need to be aware of ?
Or maybe there is some guidelines to follow when adapting DPI changes ?

Thanks.

Re: Per-Monitor DPI Aware guidelins (C++ SDK)

Posted: 25 May 2017, 22:03
by jsantos
Your code is correct if both dpiX and dpiY are the same. If not the same, you will get aspect ratio distortions. You can use a ViewBox also for this. It is a more complete solution.

By the way, there is a leak in your code (you are not deleting the memory created by new)
root->SetLayoutTransform(new ScaleTransform(scaleX, scaleY));
You can use a smart pointer to do it for you.
Ptr<ScaleTransform> t = *new ScaleTransform(scaleX, scaleY);
root->SetLayoutTransform(t.GetPtr());

Re: Per-Monitor DPI Aware guidelins (C++ SDK)

Posted: 26 May 2017, 04:49
by nikobarli
Your code is correct if both dpiX and dpiY are the same. If not the same, you will get aspect ratio distortions. You can use a ViewBox also for this. It is a more complete solution.
Hhmmh, but when the dpi scaling is not changed, I don't want to stretch my contents when I resize the window. Only when the dpi scaling is changed (for example from 100% to 200%), the window size is scaled (by 200%, done by calling SetWindowPos), and the contents are also scaled (by 200%). Thus resulting exactly the same proportion of the view.

BTW, here is my reference from where I learned the approach: https://msdn.microsoft.com/en-us/librar ... s.85).aspx
By the way, there is a leak in your code (you are not deleting the memory created by new)
root->SetLayoutTransform(new ScaleTransform(scaleX, scaleY));
You can use a smart pointer to do it for you.
Ptr<ScaleTransform> t = *new ScaleTransform(scaleX, scaleY);
root->SetLayoutTransform(t.GetPtr());
Ah, yes. Thank you.

Re: Per-Monitor DPI Aware guidelins (C++ SDK)

Posted: 31 May 2017, 20:11
by sfernandez
Given your requirements I think the tutorial from Microsoft you mentioned would fit better than using the Viewbox approach. But as @jsantos noticed, you have to make sure that aspect ratio doesn't change when scaling or your UI will get distorted.

Viewboxes work fine when you deal with different aspect ratios and need to scale several regions of your interface separately (something like this: viewtopic.php?f=12&t=834).

Re: Per-Monitor DPI Aware guidelins (C++ SDK)

Posted: 01 Jun 2017, 06:35
by nikobarli
Ok, thanks for the clarification.