|
|
Home » U++ Library support » Draw, Display, Images, Bitmaps, Icons » Native DPI
Native DPI [message #44682] |
Thu, 21 May 2015 11:45  |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
Hi,
Is there any specific reason for having a fixed Size(96,96) returned for screen DPI in the following Windows SystemDraw function?:
Size SystemDraw::GetNativeDpi() const
{
return Dots() ? nativeDpi : Size(96, 96);
}
I just got a new 32" 4K display on my desktop with native 144 DPI and metric size of objects is now wrong because of this default DPI.
May I suggest GetNativeDpi() reporting whatever Windows reports directly, like this?
Size SystemDraw::GetNativeDpi() const
{
return nativeDpi;
}
Best regards,
Tom
|
|
|
|
Re: Native DPI [message #44684 is a reply to message #44683] |
Sun, 24 May 2015 10:29   |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
Hi,
In fact I'm already using GetStdFontSize for scaling GUI in general, but my map display is supposed to work with real scales, like 1:10000 etc. This can not be compensated for using GetStdFontSize. So, could you consider the GetNativeDpi change anyway? If my client purchases displays with drivers reporting bad DPI values, then it's no longer my problem. Of course one way to go is to add user calibration of display DPI, but this may get difficult in multi display environments with different screens.
And yes: GUIs are damaged, especially toolbars with icons... For example, TheIDE toolbar on the same line with menu gets partly clipped and icons are really tiny. I think it would be useful if the system scales toolbars and selects properly sized icon variants based on the StdFontSize.
I started to render my (simple) toolbar icon bitmaps run-time from vector data using Painter, so that the icons scale perfectly to the toolbar button rect derived from StdFontSize. A bit of work but I only had a few icons in this case.
If you do something about those icons in TheIDE, I can report the results here. Just let me know if there are any changes to this.
Best regards,
Tom
|
|
|
|
|
|
Re: Native DPI [message #44689 is a reply to message #44688] |
Mon, 25 May 2015 23:13   |
 |
mirek
Messages: 14257 Registered: November 2005
|
Ultimate Member |
|
|
Tom1 wrote on Mon, 25 May 2015 16:54Hi,
It seems Hi-DPI aware applications now have new requirements for per monitor DPI awareness. This is new in Windows 8.1. I think we need support for this inside upp:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd4 64659%28v=vs.85%29.aspx
Best regards,
Tom
Well, great, GetDPIForMonitor is Win8.1 specific only...
Anyway, I agree we need to handle all this and soon. Based on screenshots, I would say that in reality, we are in fact quite close, theide needs fixing but these are not problems of library. Except that we need have a new Chameleon variable that would rescale images 2x here and there...
As for rescaling algorithm, that one is tricky. Maybe generic Lancosz3 or bilinear would be OK, but we might consider somehing like these:
http://en.wikipedia.org/wiki/Image_scaling
Mirek
|
|
|
|
Re: Native DPI [message #44693 is a reply to message #44689] |
Tue, 26 May 2015 10:22   |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
Hi,
Not having GetDPIForMonitor() does not seem to be a catastropy. I tried a few things on Windows 8.1 with two displays (UHD as primary and FullHD as secondary):
It seems we can always query "Windows main display's" DPI using GetDeviceCaps(handle,LOGPIXELSX) and GetDeviceCaps(handle,LOGPIXELSY).
If the window is moved to another display, a WM_DPICHANGED message is received with wParam LOWORD and HIWORD reporting the new DPI values of the monitor, the window was moved to.
If the initial display DPI is read at window creation time with GetDeviceCaps() and always updated when a WM_DPICHANGED message is received, I think we have it all covered.
Best regards,
Tom
|
|
|
|
Re: Native DPI [message #44696 is a reply to message #44693] |
Wed, 27 May 2015 10:14   |
 |
mirek
Messages: 14257 Registered: November 2005
|
Ultimate Member |
|
|
Tom1 wrote on Tue, 26 May 2015 10:22Hi,
Not having GetDPIForMonitor() does not seem to be a catastropy. I tried a few things on Windows 8.1 with two displays (UHD as primary and FullHD as secondary):
It seems we can always query "Windows main display's" DPI using GetDeviceCaps(handle,LOGPIXELSX) and GetDeviceCaps(handle,LOGPIXELSY).
Is default font size being changed as well?
(I sort of doubt it, this is our current code for reading font height
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
name = FromSystemCharset(ncm.lfMenuFont.lfFaceName);
height = abs((int)ncm.lfMenuFont.lfHeight);
- there does not seem anything that would link it with any monitor)
Quote:
If the window is moved to another display, a WM_DPICHANGED message is received with wParam LOWORD and HIWORD reporting the new DPI values of the monitor, the window was moved to.
If the initial display DPI is read at window creation time with GetDeviceCaps() and always updated when a WM_DPICHANGED message is received, I think we have it all covered.
Well, as long as we maintain single DPI for the whole application...
Mirek
|
|
|
Re: Native DPI [message #44697 is a reply to message #44696] |
Wed, 27 May 2015 13:32   |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
Hi,
Thanks! Your icon scalings and other changes work well across the displays. (Of course, icons are not as sharp on UHD as one might wish, but this is a minor issue.) Drop lists and some other items still have rather small arrow heads compared to the button size. Also, the check marks in front of menu items are perhaps slightly small. On secondary display there is an overall fuzzyness issue, but more on that can be found below.
--
Multi display:
The current code for reading font height returns the same exact value regardless the monitor the window is dragged to. (Declaring the process PM aware or not, does not have any effect to the result.)
Unless the process is declared per-monitor hi-dpi aware, the entire window contents look fuzzy on the smaller FullHD (secondary) display because of Windows scaling for non-per-monitor-hi-dpi-compliant applications. Declaring per-monitor hi-dpi support for the application removes the fuzzyness, but everything grows in size because the fonts and everything else around retains the same size in pixels now. So, the application should be able to handle the DPI change now.
IMO: Proper per-monitor hidpi support in upp would:
- Work on per-TopWindow basis
- First detect the primary display DPI using GetDeviceCaps(handle,LOGPIXELSX) and read the system default font size using the current code.
- Then the actual StdFontSize would be calculated based on the above and the TopWindow hosting display reported DPI from received WM_DPICHANGED messages
--
I'm now aware of the stupid way Windows reports DPI values. It is simply a user setting of type: 'How large items would you like to have on your screen?'. So there is nothing there to work on towards scaling e.g. a map content on screen to a real scale. In order to implement true map scaling in my software, I would need two things: The pixel resolution of the display the window is currently hosted on and the diagonal size of the monitor involved. I'm afraid the diagonal size needs to be manually input by the user, but the pixel resolution can be read from Windows using code similar to this when WM_DPICHANGED message arrives:
MONITORINFO mi;
Zero(mi);
mi.cbSize=sizeof(MONITORINFO);
if(GetMonitorInfo(MonitorFromWindow(hWnd,MONITOR_DEFAULTTONEAREST),&mi)){
Rect monitor_resolution(mi.rcMonitor);
Hopefully this code can be embedded in TopWindow's message loop and the resulting pixel resolution of current monitor exposed through some TopWindow function.
Best regards,
Tom
|
|
|
Re: Native DPI [message #44698 is a reply to message #44697] |
Wed, 27 May 2015 14:13   |
 |
mirek
Messages: 14257 Registered: November 2005
|
Ultimate Member |
|
|
Tom1 wrote on Wed, 27 May 2015 13:32Hi,
Thanks! Your icon scalings and other changes work well across the displays. (Of course, icons are not as sharp on UHD as one might wish, but this is a minor issue.) Drop lists and some other items still have rather small arrow heads compared to the button size. Also, the check marks in front of menu items are perhaps slightly small. On secondary display there is an overall fuzzyness issue, but more on that can be found below.
Well, hopefully I will find a better scaling algorithm...
Quote:
- Then the actual StdFontSize would be calculated based on the above and the TopWindow hosting display reported DPI from received WM_DPICHANGED messages
I still miss how this is possible. The function we are using does not have any binding to monitor (there is no HDC or HWND or HMONITOR passed as parameter).
Obviously, as long as UHD is your primary display and application sets "Vista style" DPI awarness, you are getting "BIG" font size...
Mirek
|
|
|
Re: Native DPI [message #44699 is a reply to message #44698] |
Thu, 28 May 2015 09:47   |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
Hi,
This is what I tried.
Added file manifest.xml to the ide package to enable per-monitor DPI awareness:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>True/PM</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
This also needs a Custom build step to be added for WIN32 - post-link to be effective:
mt.exe -manifest manifest.xml -outputresource:$(EXEPATH);1
Then added two Size variables to TopWindow class in TopWindow.h:
Size currentdpi;
Size primarydpi;
Finally added two new cases to TopWindow::WindowProc in TopWin32.cpp:
case WM_CREATE:{
HDC hdc=GetDC(hwnd);
primarydpi=Size(GetDeviceCaps(hdc,LOGPIXELSX),GetDeviceCaps(hdc,LOGPIXELSY)); // Returns primary display DPI
ReleaseDC(hwnd,hdc);
// RLOG(Format("WM_CREATE: primary DPI(%d,%d)",primarydpi.cx,primarydpi.cy));
break;
}
case 0x02E0: // WM_DPICHANGED -- e.g. moved window to another monitor with different DPI
// WndSetPos(Rect(*(RECT*)lParam)); // LPARAM: RECT* of suggested new window pos -- non-optimal
currentdpi=Size(LOWORD(wParam),HIWORD(wParam)); // Get DPI setting for current display monitor
// RLOG(Format("WM_DPICHANGED: current DPI(%d,%d)",currentdpi.cx,currentdpi.cy));
if(primarydpi.cy&¤tdpi.cy){
String face;
int height;
GetStdFontSys(face,height);
SetStdFont(GetStdFont().Height(height*currentdpi.cy/primarydpi.cy));
GUI_HiDPI_Write(currentdpi.cx>150?1:0); // This does not work optimally here.
}
break;
Possible DPI values returned by Windows depending on scaling set in Control Panel / Display:
96 DPI = 100% scaling
120 DPI = 125% scaling
144 DPI = 150% scaling
192 DPI = 200% scaling
... but there may be even more available. I think I saw 250% somewhere already.(?)
---
The result is that Font size scales properly when moving the window between the two monitors with different DPI -- 192 and 96 in my case.
There are problems though:
- Line spacing in lists does not adjust according to the StdFontSize while the actual fonts in the lists do.
- Check boxes, radio buttons, scroll bars and spin control arrows in dialogs remain in the HI-DPI mode regardless the change in the mode.
- Manually set font sizes in TheIDE do not scale according to the changes in StdFontSize. In fact, it would be very useful to just declare a scaling percentage e.g. 25... 400 in comparison to the StdFontSize for these fonts instead of their actual sizes. This would keep them proportionally sized even in single monitor scenarios where display scaling is changed in Windows Control Panel.
Further on I think all controls should be scaled and drawn based directly on a per TopWindow defined StdFontSize. This becomes evident when opening a new dialog on a different monitor or moving it onto another monitor. Then scaling really gets out of control.
Best regards,
Tom
|
|
|
Re: Native DPI [message #44702 is a reply to message #44699] |
Fri, 29 May 2015 10:16   |
 |
mirek
Messages: 14257 Registered: November 2005
|
Ultimate Member |
|
|
Tom1 wrote on Thu, 28 May 2015 09:47Hi,
This is what I tried.
Added file manifest.xml to the ide package to enable per-monitor DPI awareness:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>True/PM</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>
This also needs a Custom build step to be added for WIN32 - post-link to be effective:
mt.exe -manifest manifest.xml -outputresource:$(EXEPATH);1
Then added two Size variables to TopWindow class in TopWindow.h:
Size currentdpi;
Size primarydpi;
Finally added two new cases to TopWindow::WindowProc in TopWin32.cpp:
case WM_CREATE:{
HDC hdc=GetDC(hwnd);
primarydpi=Size(GetDeviceCaps(hdc,LOGPIXELSX),GetDeviceCaps(hdc,LOGPIXELSY)); // Returns primary display DPI
ReleaseDC(hwnd,hdc);
// RLOG(Format("WM_CREATE: primary DPI(%d,%d)",primarydpi.cx,primarydpi.cy));
break;
}
case 0x02E0: // WM_DPICHANGED -- e.g. moved window to another monitor with different DPI
// WndSetPos(Rect(*(RECT*)lParam)); // LPARAM: RECT* of suggested new window pos -- non-optimal
currentdpi=Size(LOWORD(wParam),HIWORD(wParam)); // Get DPI setting for current display monitor
// RLOG(Format("WM_DPICHANGED: current DPI(%d,%d)",currentdpi.cx,currentdpi.cy));
if(primarydpi.cy&¤tdpi.cy){
String face;
int height;
GetStdFontSys(face,height);
SetStdFont(GetStdFont().Height(height*currentdpi.cy/primarydpi.cy));
GUI_HiDPI_Write(currentdpi.cx>150?1:0); // This does not work optimally here.
}
break;
Possible DPI values returned by Windows depending on scaling set in Control Panel / Display:
96 DPI = 100% scaling
120 DPI = 125% scaling
144 DPI = 150% scaling
192 DPI = 200% scaling
... but there may be even more available. I think I saw 250% somewhere already.(?)
---
The result is that Font size scales properly when moving the window between the two monitors with different DPI -- 192 and 96 in my case.
There are problems though:
- Line spacing in lists does not adjust according to the StdFontSize while the actual fonts in the lists do.
- Check boxes, radio buttons, scroll bars and spin control arrows in dialogs remain in the HI-DPI mode regardless the change in the mode.
- Manually set font sizes in TheIDE do not scale according to the changes in StdFontSize. In fact, it would be very useful to just declare a scaling percentage e.g. 25... 400 in comparison to the StdFontSize for these fonts instead of their actual sizes. This would keep them proportionally sized even in single monitor scenarios where display scaling is changed in Windows Control Panel.
Further on I think all controls should be scaled and drawn based directly on a per TopWindow defined StdFontSize. This becomes evident when opening a new dialog on a different monitor or moving it onto another monitor. Then scaling really gets out of control.
Best regards,
Tom
I am afraid that per-window scaling is a massive change. We will do it eventually, but for the next release, I would concentrate on 'Vista style' DPI awareness (means primary UHD display scaled by us, secondary non-UHD display scaled down by windows).
(Note that HiDPI is not the primary focus of next release; new Assist++ parser, better support for C++11 are main topics).
Mirek
|
|
|
|
Re: Native DPI [message #44705 is a reply to message #44703] |
Fri, 29 May 2015 17:23   |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
Hi,
In my opinion method 4 without any sharpening gives the best overall result. The details appear relatively sharp while jagging on 45 degree angles is negligible.
(The circle is not good in any case. Either everything becomes too fuzzy or the circle remains jagged on the edge -- or both at the same time. I think the circle is not going to be nice no matter what.)
I can see your point with the sharper 7 + 50/2 or 20/3. However, they seem to leave some artifact behind -- like faint shadows around the objects -- but from a distance, those are barely visible.
So, just follow your own preference on this one.
Best regards,
Tom
|
|
|
|
Re: Native DPI [message #44731 is a reply to message #44728] |
Mon, 08 June 2015 10:31   |
Tom1
Messages: 1303 Registered: March 2007
|
Ultimate Contributor |
|
|
Hi,
I'm afraid I can't imagine all the implications of this approach.
Are you saying that coordinates in Draw would no longer be mapped 1:1 to pixels on screen, unless BeginNative was called? If so, I'm afraid many programs with Draw based graphics would break, or at least the quality of the graphic content would suffer. (Then graphics based on Draw in many applications should be changed to use BeginNative to restore rendering quality.)
Did I get this right?
Generally, I think that the coordinate space should be native in pixels and only drawing of controls should be scaled to match the desired physical size on screen -- which for standard controls should probably be determined from the Std font size.
Best regards,
Tom
|
|
|
Re: Native DPI [message #44747 is a reply to message #44731] |
Sat, 13 June 2015 17:04   |
 |
mirek
Messages: 14257 Registered: November 2005
|
Ultimate Member |
|
|
Well, I am afraid we have run here into the same problem that made M$ create that HiDPI-aware flag in the first place..
In theory, all U++ apps should use LayoutZoom logic everywhere, then (with a bit of icon rescaling or replacing) everything would work just fine.
In practice, even in CtrlLib there is a lot of "fixed number of pixels" issues. Fixing them all will take time - and that would not solve all U++ user applications out there having the same issues.
Well, I am now not thinking about "BeginNative" anymore, but rather about per Ctrl HiDPI-aware flag. If not set (which unfortunately has to be default), Draw would scale up all things automatically.
Unlike Win32, which scales resulting bitmap graphics, Draw would scale before rendering, which would result in crisp texts - I would say, this is still quite and advantage.
So the only disadvantage would be less precise "placement" (IMO hardly detectable) and images. The issue of images is in fact the same for HiDPI aware mode...
Mirek
|
|
|
Goto Forum:
Current Time: Fri May 09 13:33:35 CEST 2025
Total time taken to generate the page: 0.00471 seconds
|
|
|