# Recommended Approaches for Global UI Scaling in FiveWin
Based on the FiveWin codebase, here are the cleanest and most production-ready approaches to implement global 125% UI scaling without modifying individual dialogs:
1. Foundation: Enable DPI Awareness (Required First Step)
Add a manifest file to your application to declare DPI awareness. This is essential for Windows 10/11 to respect your application-level scaling: 0-cite-0
This tells Windows your application will handle DPI scaling itself, preventing Windows from applying bitmap scaling to your UI.
2. Recommended Approach: TLayoutManager Class (Newest & Cleanest)
FiveWin recently added the TLayoutManager class specifically for this purpose. It provides automatic scaling of sizes, positions, and fonts based on screen resolution: 0-cite-1
Key features:
- CalcSize() - Scales control sizes proportionally
- CalcPos() - Scales positions
- CalcFontSize() - Scales font sizes automatically
- Uses minimum factor to maintain aspect ratio 0-cite-2
This class was added in 2025 as a modern solution for high-resolution displays.
3. Global Font Scaling Approach (Production Pattern)
For a 125% scale factor, use the DPI detection function and apply scaled fonts globally:
Step A: Detect Current DPI
0-cite-3
This function returns the scaling factor (e.g., 1.25 for 125%, 1.5 for 150%).
Step B: Create Scaled Fonts
0-cite-4
Step C: Apply Font Globally Using TWindow Inheritance
The TWindow:GetFont() method implements recursive parent font inheritance. When you set a font on a parent window, child controls automatically inherit it: 0-cite-5
Production pattern (as shown in testfon3.prg): 0-cite-6
This pattern sets the font on the main window, then iterates through all controls to apply it globally.
4. System Default Font Override
You can override the system default font that FiveWin uses. When no font is specified, FiveWin creates one using: 0-cite-7
You can define a global scaled font at application startup and assign it to all windows/dialogs using the inheritance pattern above.
5. Alternative to MSGINFO() with Scaling Support
For message boxes, use the Alert() function instead of MSGINFO(). It creates a custom TDialog-based dialog that respects your application's font settings: 0-cite-8
Notice that Alert() uses GetSysFont() and creates a TDialog, which will inherit your global font settings, unlike the Windows MessageBox API used by MSGINFO().
6. Complete Working Example (DPI-Aware Dialog)
The scrolldlg.prg sample demonstrates a production-ready DPI-aware implementation: 0-cite-9
This shows how to:
- Get current DPI using GetDeviceCaps(hDC, LOGPIXELSX)
- Calculate scaling factor: nDpi * baseSize / 96
- Apply dynamically at runtime
7. Modern UI Components with Built-in DPI Scaling
The TMyTitle class (added October 2025) includes automatic DPI awareness: 0-cite-10
This demonstrates the framework's direction toward built-in DPI support in modern controls.
---
Recommended Production Strategy
For a clean 125% global scaling without modifying individual dialogs:
Add the DPI-aware manifest to your executable
At application startup, detect DPI and create scaled fonts:
Code: Select all | Expand
nDpi := GetDpiForSystem() // or use DispFontPerSize() * 96
nScaleFactor := 1.25 // Your desired 125%
DEFINE FONT oAppFont NAME GetSysFont() SIZE 0, ScaleFontSize(-12, nDpi * nScaleFactor)
Apply font to main window (which propagates to all child controls via inheritance)
Use Alert() instead of MSGINFO() for scalable message boxes
For new development, consider using TLayoutManager for automatic scaling
For graphics, the GDI+ layer already supports DPI scaling through the dx variable
---
Notes
MSGINFO() limitation: It uses the Windows MessageBox API directly, which doesn't respect application fonts - only system DPI settings. This is why Alert() is recommended as an alternative.
Font inheritance: FiveWin's architecture automatically propagates fonts from parent windows to child controls, making global font scaling very effective.
RDP sessions: The manifest-based approach works well with RDP, as the DPI awareness is declared at the application level.
TLayoutManager is the most modern approach but requires refactoring to use its methods. The font scaling approach is simpler and works with existing code.
For truly comprehensive scaling (including control sizes, positions, spacing), you'll need to either use TLayoutManager or implement your own scaling calculations similar to the scrolldlg.prg example.
Citations
File: samples/ui/box/manifest.xml (L6-7)
Code: Select all | Expand
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
File: source/classes/Tlayman.prg (L4-18)
Code: Select all | Expand
CLASS TLayoutManager
DATA nScreenWidth, nScreenHeight // Current screen resolution
DATA nBaseWidth, nBaseHeight // Reference resolution (es. 1280x800)
DATA nSpacing // Spacing between controls
DATA nMarginTop, nMarginLeft // Upper and lower margins
DATA nMarginRight, nMarginBottom // Right and lower margins
METHOD New(nScreenWidth, nScreenHeight, nBaseWidth, nBaseHeight, nSpacing, nMarginTop, nMarginLeft, nMarginRight, nMarginBottom) CONSTRUCTOR
METHOD CalcSize(nBaseSize) // Calculate scaled size
METHOD CalcPos(nBasePos) // Calculate climbed position
METHOD CalcGridPos(nIndex, nItemsPerRow, nBaseWidth, nBaseHeight, nBaseTop, nBaseLeft) // Grid position
METHOD CalcFontSize(nBaseFontSize) // Calculate scaled font size
METHOD GetUsableWidth() //Usable width (excluding margins)
METHOD GetUsableHeight() // Usable height (excluding margins)
ENDCLASS
File: source/classes/Tlayman.prg (L49-51)
Code: Select all | Expand
METHOD CalcFontSize(nBaseFontSize) CLASS TLayoutManager
// Calculate scaled font size
RETURN Int(nBaseFontSize * Min(::nScreenWidth / ::nBaseWidth, ::nScreenHeight / ::nBaseHeight))
File: source/function/getsysin.prg (L103-112)
Code: Select all | Expand
function DispFontPerSize()
local hDC, nPixelX
hDC = CreateDC( "DISPLAY", "", "" )
nPixelX = GetDeviceCaps( hDC, LOGPIXELSX )
DeleteDC( hDC )
return ( nPixelX / 96 )
File: samples/ui/title/mytitle.prg (L91-92)
Code: Select all | Expand
FUNCTION ScaleFontSize( nBaseSize, nDpi )
RETURN Int( nBaseSize * nDpi / 96 )
File: source/classes/window.prg (L3182-3204)
Code: Select all | Expand
METHOD GetFont() CLASS TWindow
local hFont, aInfo, oFont
/*
if ::oFont == nil .and. ::oWnd != nil .and. ::oWnd:oFont != nil
::oFont = ::oWnd:oFont
::SendMsg( WM_SETFONT, ::oFont:hFont )
DEFAULT ::oFont:nCount := 0
::oFont:nCount++
return ::oFont
endif
*/
if ::oFont == nil
if ::oWnd != nil
::oFont = ::oWnd:GetFont()
if ::oFont != nil
::oFont:nCount++
::SendMsg( WM_SETFONT, ::oFont:hFont )
endif
endif
endif
File: source/classes/window.prg (L3226-3226)
Code: Select all | Expand
DEFINE FONT ::oFont NAME GetSysFont() SIZE 0, -12 // BOLD
File: samples/test/testfon3.prg (L95-106)
Code: Select all | Expand
STATIC FUNCTION REFRESHWND( oWnd, oFont )
LOCAL i
oWnd:SetFont( oFont )
FOR i = 1 TO LEN( oWnd:aControls )
oWnd:aControls[ i ]:SetFont( oFont )
oWnd:aControls[ i ]:Refresh()
NEXT
RETURN NIL
File: source/function/alert.prg (L34-60)
Code: Select all | Expand
function Alert( cMsg, aOptions, cTitle, nDefault, xIcon )
#endif
Local oDlg, oFont
DEFAULT cMsg := "Alert dialog box" ,;
aOptions := {"&OK"} ,;
cTitle := "Attention" ,;
nDefault := 1
if CenterMsgs( "?" )
SetAsMsgBox()
endif
DEFINE FONT oFont NAME GetSysFont() SIZE NIL, -14
DEFINE DIALOG oDlg TITLE cTitle FONT oFont
oDlg:Cargo := 0
oDlg:lHelpIcon := .f.
ACTIVATE DIALOG oDlg ;
ON INIT ( Self, DlgInit(oDlg, oFont, cMsg, aOptions, cTitle, nDefault, xIcon) )
oFont:End()
RETURN oDlg:Cargo
File: samples/ui/dialogs/scrolldlg.prg (L51-74)
Code: Select all | Expand
PROCEDURE Set_D_Height()
LOCAL nDpi := GetCurrentDpi()
d_height := (nDpi * 13 / 96)
RETURN
//============================================================================
// FUNCTION : GetCurrentDpi()
// Purpose : To Get the Windows Current DPI Setting
//============================================================================
FUNCTION GetCurrentDpi()
local hDc := GetDc(0)
local nDpi := GetDeviceCaps( hDC, LOGPIXELSX )
nDpi := GetDeviceCaps( hDC, LOGPIXELSX )
MsgInfo( LTRIM(STR(nDpi))+" DPI" )
ReleaseDC( 0, hDC )
RETURN nDpi
File: whatsnew.txt (L128-141)
Code: Select all | Expand
* New: Class TMyTitle developed by Carlos Vargas. Please review samples\ui\mytitle.prg
A very nice class to create modern title bars.
**TMyTitle Class Functionality Summary:**
- **Gradient Backgrounds**: Supports horizontal and vertical gradient fills with customizable begin/end colors
- **Glass Effect**: Optional glass-like visual effect for modern UI appearance
- **Bitmap Integration**: Displays bitmaps with alpha channel support (ABPaint) and automatic DPI scaling
- **Typography**: Custom font support with precise text positioning and centering
- **Borders**: Optional borders with customizable colors
- **DPI Awareness**: Automatic font and bitmap scaling for high-resolution displays
- **Flexible Positioning**: Configurable offsets for bitmap and text placement
- **Resource Support**: Can load bitmaps from resources or external files
- **Color Customization**: Full control over gradient colors, text color, and border color
- **Cross-Platform**: Works with both 32-bit and 64-bit compilation