Supporting+different+DPI+values

//by Richard Russell, July 2006//

Windows assumes, for certain operations (particularly displaying text), a specific **dots per inch** (or **pixels per inch**) value for the current display. The most common value used is 96 dots per inch (dpi), but other values, for example 120 dpi, will be encountered. A user can choose the higher value in **Display Properties... Settings** (in some versions of Windows by selecting **Large Fonts** and in others by selecting the DPI value directly).

The table below shows the screen sizes (in inches, diagonal) which correspond to some common display resolutions at 96 dpi, 120 dpi and 144 dpi:


 * Display resolution || Diagonal at 96 dpi || Diagonal at 120 dpi || Diagonal at 144 dpi ||
 * 800 x 600 || 10.4" || 8.3" || 6.9" ||
 * 1024 x 768 || 13.3" || 10.7" || 8.9" ||
 * 1152 x 864 || 15.0" || 12.0" || 10.0" ||
 * 1280 x 1024 || 17.1" || 13.7" || 11.4" ||
 * 1400 x 1050 || 18.2" || 14.6" || 12.2" ||
 * 1600 x 1200 || 20.8" || 16.7" || 13.9" ||

So for example if you have a 15" diagonal screen, Windows would display text at approximately the intended size either by selecting 1152 x 864 at 96 dpi or 1400 x 1050 at 120 dpi. Of course if you have a flat panel screen there is likely to be only one display resolution at which it will give good results, giving you little choice over the DPI value.  This is one reason why the 120 dpi setting is becoming more common.

Since Windows displays text approximately 25% larger (in pixels) at 120dpi than at 96dpi you may well have to take the variation in text size into account when writing your programs. Listed below are some of the possible consequences for your programs of supporting different DPI values:

Use of *FONT
The good news is that if your program doesn't use ***FONT** you probably won't need to worry about the direct effect of DPI on text displayed by your program. This is because the fonts selected by the BBC BASIC **MODE** statement (or **VDU 23,22**) are set to be a particular size in //pixels// not //inches//. The different DPI value may well alter the style or appearance of the text, but it should remain the same size in relationship to the rest of your output.

However if you do use ***FONT** then you will need to take into account the effect of different DPI values. The options available to you are as follows:


 * 1) Choose a size for your text that will look OK, and fit in the space available, at both 96dpi and 120dpi.  This is the simplest solution, but will probably involve the text appearing slightly smaller than you would prefer at 96 dpi and slightly larger at 120 dpi.
 * 2) Adjust the size of the text according to the DPI value so that it always displays at approximately the same size in pixels.
 * 3) Use the approach described in Selecting a font by pixel height.
 * 4) Adjust the size of your window and any graphics you draw (e.g. boxes containing text) to take account of the different text size.  This is the most complicated solution, but is arguably the best one because it results in your program's output remaining approximately the same size in inches.

You can discover the current DPI value, from which you can deduce the text size, as follows:

code format="bb4w" SYS "GetDeviceCaps", @memhdc%, 88 TO dpi% code In all cases it is most important that any calculations involving text dimensions (for example calculations to ensure text is correctly centered) discover the actual height and width of the characters rather than assuming constant values. For a fixed-pitch font you can use the system variables **@vdu%!216** and **@vdu%!220** to find the width and height of a character in pixels; for a proportional-spaced font you will need to use **** as described [|here]

Window components
Those components of the normal window 'furniture' which can contain text may also change their size depending on the DPI value; these are principally the **title bar**, the **menu bar** and the **status bar**. This has two significant consequences for your programs:


 * Since the text (in the title bar, menu bar or status bar) is displayed larger at 120 dpi than at 96 dpi, fewer characters may fit in the available width. Therefore you should check that any menu names, messages displayed in the status bar etc. are still entirely visible at 120 dpi.


 * Since the height of the title bar, menu bar and/or status bar may change, you should never assume constant values for them in calculating the window size, graphics origin etc.(in any case they may also change between different Windows 'styles', e.g. **Classic** versus **XP**).

The code below will resize your window to give a particular //client// size in pixels (i.e. the area in which your program's output will appear), taking into account different DPI values and the presence of a menu bar, toolbar and status bar:

code format="bb4w" GWL_STYLE = -16 DIM rc{l%,t%,r%,b%} SYS "GetWindowRect", hs%, rc{} status_bar_height% = rc.b%-rc.t%     SYS "GetWindowRect", ht%, rc{} toolbar_height% = rc.b%-rc.t%     rc.l% = 0 rc.r% = dx% rc.t% = 0 rc.b% = dy% + status_bar_height% + toolbar_height% SYS "GetWindowLong", @hwnd%, GWL_STYLE TO style% SYS "AdjustWindowRect", rc{}, style%, menu% SYS "SetWindowPos", @hwnd%, 0, 0, 0, rc.r%-rc.l%, rc.b%-rc.t%, 6 SYS "SetWindowPos", hs%, 0, 0, 0, 0, 0, 32 VDU 26 ORIGIN 0,2*status_bar_height% code Here **hs%** is the value returned from ****, **ht%** is the value returned from ****, **dx%** is the required //client// width in pixels, **dy%** is the required //client// height in pixels and **menu%** is 1 if there is a menu bar and 0 otherwise.

Dialogue boxes
In Windows, the dimensions of dialogue boxes and the controls they contain are specified in //dialogue box units// rather than pixels. These are related to the size of the font used in the dialogue box, and hence also to the DPI setting. The result is that the dialogue box itself, all the controls it contains and the text displayed within those controls will all be approximately 25% larger at 120dpi than at 96dpi.

Often this won't matter too much, because the text and the box(s) containing it are both scaled. However you should never assume the text will occupy a precise amount of space, or be formatted in a particular way, because of slight differences in the way the scaling is carried out.

Where it will matter is if you use, for example, a **static box** to display a bitmap image. An image that is the correct size to fit neatly within the box at 96dpi will be too small at 120 dpi. The simplest solution is not to worry, because the effect is generally only cosmetic, but if it matters you will need to scale your bitmap image to the required size (or provide different images for the different DPI settings).

You can convert the dimensions of a dialogue box (or a control contained therein) from dialogue box units to pixels as follows:

code format="bb4w" DIM rc{l%,t%,r%,b%} rc.l% = 0 rc.r% = dlgx% rc.t% = 0 rc.b% = dlgy% SYS "MapDialogRect", !dlg%, rc{} pixx% = rc.r%-rc.l%     pixy% = rc.b%-rc.t% code Here **dlgx%** and **dlgy%** are the width and height in dialogue box units, **pixx%** and **pixy%** are the calculated width and height in pixels, and **dlg%** is the value returned from ****. You must execute this code **//after//** the call to ****.

For more information on supporting different DPI values see this [|Microsoft article].