DPI Awareness

Sorry I haven’t said much recently, but the last couple of months have been busy. While tracking down a strange report from a customer about a small application we had built, I discovered that SIMPOL had been bitten by the small fonts/large fonts issue that I remembered from way back in the old days with Superbase. Resolving this issue took a few weeks and a lot of refactoring of existing code, including example programs, but it was worth it. In a later post, I will describe some of the other things we have been working on, but for now read on about the large fonts issue.

What Does “Small Fonts” and “Large Fonts” Mean?

For those who are unfamiliar with the issues: Windows normally runs in what is commonly called “small fonts” mode. What this means in practice is that the resolution of the screen is 96 DPI (dots per inch). When the user changes their system to run in large fonts (which is becoming more common as high resolution displays become more affordable), the screen runs in 120 DPI. The effect for the user is that fonts are drawn large and smoother on the screen.

How Does Changing to Large Fonts Affect Things?

Windows draws the fonts are drawn 25% larger than in small fonts mode, so the container needs to be scaled up or otherwise the text will be cut off, reducing the effective screen resolution by 25%. For example, a screen (and graphic card) that has a resolution of 1024 x 768 pixels, will have an effective resolution of 800 x 600.

So Why is That a Problem for Me?

As mentioned earlier, the container needs to be scaled up, assuming that the DPI during design was 96. SIMPOL can’t just automatically scale up all containers, because if the developer was running in large fonts when they created their forms, then they would actually need to scale down the containers when running in small fonts. So the problem is that you need to know the original DPI at design time, plus the current DPI at run time in order to even have a hope of adjusting things correctly.

And the Solution Is?

Actually, in SIMPOL there was a multifaceted solution. That is because we have both the wxform and dataform1 families of user interface types. It turned out the solution to the problem for dataform1 was quite simple. A designdpi property was added to the dataform1 type, and that is stored in the form file. In formlib, when the form is opened the designdpi value is compared to the current DPI of the running system, and an adjustment factor is calculated that is then applied to most (but not all) objects. Currently it will not scale the size of bitmap buttons, though it will reposition them. Images on the forms themselves should be set to “preserve aspect” to ensure adequate scaling.
A second solution needed to be found for the wxform family of types, since we don’t have a storage format for them other than in source code. The decision was made to change how the source code is generated, to include the designdpi value and all the code necessary to calculate the factor and apply it.
Obviously this also required changes to the form storage format, and all older forms are assumed to be in 96 DPI. The Form Designer also required changes under the hood, though not too many.
Final cleanup included modifying examples and various utilities. All very time consuming, but worth it. One of the issues that arose, however, was that many of the wxforms in use pre-dated being able to create and save them in the Form Designer. To make refactoring those types of forms easier, a new function was added to formlib, that converts a wxform into a dataform1, which can then be saved as a form file. Very neat that bit!