With the PICKFONT program, shown in Figure 14-5, you can create a logical font and see the characteristics of the real font after the logical font is selected into the screen device context.
PICKFONT.MAK
#------------------------
# PICKFONT.MAK make file
#------------------------
pickfont.exe : pickfont.obj pickfont.def pickfont.res
link pickfont, /align:16, NUL, /nod slibcew libw, pickfont
rc pickfont.res
pickfont.obj : pickfont.c pickfont.h
cl -c -Gsw -Ow -W2 -Zp pickfont.c
pickfont.res : pickfont.rc pickfont.h
rc -r pickfont.rc
PICKFONT.C
/*-----------------------------------------
PICKFONT.C -- Font Picker Program
(c) Charles Petzold, 1990
-----------------------------------------*/
#include <windows.h>
#include "pickfont.h"
long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;
BOOL FAR PASCAL DlgProc (HWND, WORD, WORD, LONG) ;
char szAppName [] = "PickFont" ;
DWORD dwAspectMatch = 0L ;
HWND hDlg ;
LOGFONT lf ;
short nMapMode = IDD_TEXT ;
int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
if (!hPrevInstance)
{
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
RegisterClass (&wndclass) ;
}
hwnd = CreateWindow (szAppName, "Font Picker",
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, nCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
if (hDlg == 0 || !IsDialogMessage (hDlg, &msg))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
}
return msg.wParam ;
}
void MySetMapMode (HDC hdc)
{
if (nMapMode == IDD_LTWPS)
{
SetMapMode (hdc, MM_ANISOTROPIC) ;
SetWindowExt (hdc, 1440, 1440) ;
SetViewportExt (hdc, GetDeviceCaps (hdc, LOGPIXELSX),
GetDeviceCaps (hdc, LOGPIXELSY)) ;
}
else
SetMapMode (hdc, MM_TEXT + nMapMode - IDD_TEXT) ;
}
void ShowMetrics (HWND hDlg)
{
static TEXTMETRIC tm ;
static struct
{
short nDlgID ;
short *pData ;
}
shorts [] =
{
TM_HEIGHT, &tm.tmHeight,
TM_ASCENT, &tm.tmAscent,
TM_DESCENT, &tm.tmDescent,
TM_INTLEAD, &tm.tmInternalLeading,
TM_EXTLEAD, &tm.tmExternalLeading,
TM_AVEWIDTH, &tm.tmAveCharWidth,
TM_MAXWIDTH, &tm.tmMaxCharWidth,
TM_WEIGHT, &tm.tmWeight,
TM_OVER, &tm.tmOverhang,
TM_DIGX, &tm.tmDigitizedAspectX,
TM_DIGY, &tm.tmDigitizedAspectY
} ;
static char *szFamily [] = { "Don't Care", "Roman", "Swiss",
"Modern", "Script", "Decorative" } ;
BOOL bTrans ;
char szFaceName [LF_FACESIZE] ;
HDC hdc ;
HFONT hFont ;
short i ;
lf.lfHeight = GetDlgItemInt (hDlg, IDD_HEIGHT, &bTrans, TRUE) ;
lf.lfWidth = GetDlgItemInt (hDlg, IDD_WIDTH, &bTrans, FALSE) ;
lf.lfWeight = GetDlgItemInt (hDlg, IDD_WEIGHT, &bTrans, FALSE) ;
lf.lfItalic = (BYTE) (IsDlgButtonChecked (hDlg, IDD_ITALIC) ? 1 : 0) ;
lf.lfUnderline = (BYTE) (IsDlgButtonChecked (hDlg, IDD_UNDER) ? 1 : 0) ;
lf.lfStrikeOut = (BYTE) (IsDlgButtonChecked (hDlg, IDD_STRIKE) ? 1 : 0) ;
GetDlgItemText (hDlg, IDD_FACE, lf.lfFaceName, LF_FACESIZE) ;
dwAspectMatch = IsDlgButtonChecked (hDlg, IDD_ASPECT) ? 1L : 0L ;
hdc = GetDC (hDlg) ;
MySetMapMode (hdc) ;
SetMapperFlags (hdc, dwAspectMatch) ;
hFont = SelectObject (hdc, CreateFontIndirect (&lf)) ;
GetTextMetrics (hdc, &tm) ;
GetTextFace (hdc, sizeof szFaceName, szFaceName) ;
DeleteObject (SelectObject (hdc, hFont)) ;
ReleaseDC (hDlg, hdc) ;
for (i = 0 ; i < sizeof shorts / sizeof shorts [0] ; i++)
SetDlgItemInt (hDlg, shorts[i].nDlgID, *shorts[i].pData, TRUE) ;
SetDlgItemText (hDlg, TM_PITCH, tm.tmPitchAndFamily & 1 ?
"VARIABLE":"FIXED") ;
SetDlgItemText (hDlg, TM_FAMILY, szFamily [tm.tmPitchAndFamily >> 4]) ;
SetDlgItemText (hDlg, TM_CHARSET, tm.tmCharSet ? "OEM" : "ANSI") ;
SetDlgItemText (hDlg, TF_NAME, szFaceName) ;
}
BOOL FAR PASCAL DlgProc (HWND hDlg, WORD message, WORD wParam, LONG lParam)
{
switch (message)
{
case WM_INITDIALOG :
CheckRadioButton (hDlg, IDD_TEXT, IDD_LTWPS, IDD_TEXT) ;
CheckRadioButton (hDlg, IDD_ANSI, IDD_OEM, IDD_ANSI) ;
CheckRadioButton (hDlg, IDD_QDRAFT, IDD_QPROOF, IDD_QDRAFT) ;
CheckRadioButton (hDlg, IDD_PDEF, IDD_PVAR, IDD_PDEF) ;
CheckRadioButton (hDlg, IDD_DONT, IDD_DEC, IDD_DONT) ;
lf.lfEscapement = 0 ;
lf.lfOrientation = 0 ;
lf.lfOutPrecision = OUT_DEFAULT_PRECIS ;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS ;
ShowMetrics (hDlg) ;
/* fall through */
case WM_SETFOCUS :
SetFocus (GetDlgItem (hDlg, IDD_HEIGHT)) ;
return FALSE ;
case WM_COMMAND :
switch (wParam)
{
case IDD_TEXT :
case IDD_LOMET :
case IDD_HIMET :
case IDD_LOENG :
case IDD_HIENG :
case IDD_TWIPS :
case IDD_LTWPS :
CheckRadioButton (hDlg, IDD_TEXT, IDD_LTWPS, wParam) ;
nMapMode = wParam ;
break ;
case IDD_ASPECT :
case IDD_ITALIC :
case IDD_UNDER :
case IDD_STRIKE :
CheckDlgButton (hDlg, wParam,
IsDlgButtonChecked (hDlg, wParam) ? 0 : 1) ;
break ;
case IDD_ANSI :
case IDD_OEM :
CheckRadioButton (hDlg, IDD_ANSI, IDD_OEM, wParam) ;
lf.lfCharSet = (BYTE) (wParam == IDD_ANSI ? 0 : 255) ;
break ;
case IDD_QDRAFT :
case IDD_QDEF :
case IDD_QPROOF :
CheckRadioButton (hDlg, IDD_QDRAFT, IDD_QPROOF,
wParam) ;
lf.lfQuality = (BYTE) (wParam - IDD_QDRAFT) ;
break ;
case IDD_PDEF :
case IDD_PFIXED :
case IDD_PVAR :
CheckRadioButton (hDlg, IDD_PDEF, IDD_PVAR, wParam) ;
lf.lfPitchAndFamily &= 0xF0 ;
lf.lfPitchAndFamily |= (BYTE) (wParam - IDD_PDEF) ;
break ;
case IDD_DONT :
case IDD_ROMAN :
case IDD_SWISS :
case IDD_MODERN :
case IDD_SCRIPT :
case IDD_DEC :
CheckRadioButton (hDlg, IDD_DONT, IDD_DEC, wParam) ;
lf.lfPitchAndFamily &= 0x0F ;
lf.lfPitchAndFamily |= (BYTE) (wParam-IDD_DONT << 4) ;
break ;
case IDD_OK :
ShowMetrics (hDlg) ;
InvalidateRect (GetParent (hDlg), NULL, TRUE) ;
break ;
}
break ;
default :
return FALSE ;
}
return TRUE ;
}
long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
static char szText [] =
"AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPqQqRrSsTtUuVvWwXxYyZz" ;
static short cxClient, cyClient ;
HANDLE hInstance ;
HDC hdc ;
HFONT hFont ;
FARPROC lpfnDlgProc ;
PAINTSTRUCT ps ;
RECT rect ;
switch (message)
{
case WM_CREATE :
hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;
lpfnDlgProc = MakeProcInstance (DlgProc, hInstance) ;
hDlg = CreateDialog (hInstance, szAppName, hwnd, lpfnDlgProc) ;
return 0 ;
case WM_SETFOCUS :
SetFocus (hDlg) ;
return 0 ;
case WM_PAINT :
hdc = BeginPaint (hwnd, &ps) ;
MySetMapMode (hdc) ;
SetMapperFlags (hdc, dwAspectMatch) ;
GetClientRect (hDlg, &rect) ;
rect.bottom += 1 ;
DPtoLP (hdc, (LPPOINT) &rect, 2) ;
hFont = SelectObject (hdc, CreateFontIndirect (&lf)) ;
TextOut (hdc, rect.left, rect.bottom, szText, 52) ;
DeleteObject (SelectObject (hdc, hFont)) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
PICKFONT.RC
/*-----------------------------
PICKFONT.RC resource script
-----------------------------*/
#include <windows.h>
#include "pickfont.h"
#define GT (WS_GROUP | WS_TABSTOP)
#define GR (WS_GROUP)
#define TA (WS_TABSTOP)
PickFont DIALOG 0, 0, 320, 170
STYLE WS_CHILD | WS_BORDER | WS_VISIBLE | DS_ABSALIGN
{
LTEXT "&Height" -1, 6, 8, 30, 8
EDITTEXT IDD_HEIGHT, 36, 6, 30, 12
LTEXT "&Width" -1, 6, 24, 30, 8
EDITTEXT IDD_WIDTH, 36, 22, 30, 12
LTEXT "Weigh&t" -1, 6, 40, 30, 8
EDITTEXT IDD_WEIGHT, 36, 38, 30, 12
GROUPBOX "&Mapping Mode" -1, 70, 2, 116, 60
RADIOBUTTON "Text" IDD_TEXT, 74, 12, 50, 12, GT
RADIOBUTTON "Lo Metric" IDD_LOMET, 74, 24, 50, 12
RADIOBUTTON "Hi Metric" IDD_HIMET, 74, 36, 50, 12
RADIOBUTTON "Lo English" IDD_LOENG, 130, 12, 54, 12
RADIOBUTTON "Hi English" IDD_HIENG, 130, 24, 52, 12
RADIOBUTTON "Twips" IDD_TWIPS, 130, 36, 52, 12
RADIOBUTTON "'Logical Twips'", IDD_LTWPS, 74, 48, 80, 12
CHECKBOX "Match &Aspect" IDD_ASPECT, 6, 52, 60, 12, GT
CHECKBOX "&Italic" IDD_ITALIC, 6, 64, 60, 12, GT
CHECKBOX "&Underline" IDD_UNDER, 6, 76, 60, 12, GT
CHECKBOX "&Strike-Out" IDD_STRIKE, 6, 88, 60, 12, GT
GROUPBOX "&Char Set" -1, 70, 66, 52, 36, GR
RADIOBUTTON "ANSI" IDD_ANSI, 74, 76, 28, 12, GT
RADIOBUTTON "OEM" IDD_OEM, 74, 88, 28, 12
GROUPBOX "&Quality" -1, 4, 102, 62, 48, GR
RADIOBUTTON "Draft" IDD_QDRAFT, 8, 112, 42, 12, GT
RADIOBUTTON "Default" IDD_QDEF, 8, 124, 40, 12
RADIOBUTTON "Proof" IDD_QPROOF, 8, 136, 42, 12
GROUPBOX "&Pitch" -1, 70, 102, 52, 48, GR
RADIOBUTTON "Default" IDD_PDEF, 74, 112, 46, 12, GT
RADIOBUTTON "Fixed" IDD_PFIXED, 74, 124, 46, 12
RADIOBUTTON "Variable" IDD_PVAR, 74, 136, 46, 12
GROUPBOX "&Family" -1, 126, 66, 60, 84, GR
RADIOBUTTON "Don't Care" IDD_DONT, 130, 76, 54, 12, GT
RADIOBUTTON "Roman" IDD_ROMAN, 130, 88, 54, 12
RADIOBUTTON "Swiss" IDD_SWISS, 130, 100, 54, 12
RADIOBUTTON "Modern" IDD_MODERN, 130, 112, 54, 12
RADIOBUTTON "Script" IDD_SCRIPT, 130, 124, 54, 12
RADIOBUTTON "Decorative" IDD_DEC, 130, 136, 52, 12
LTEXT "Face &Name" -1, 4, 154, 42, 8
EDITTEXT IDD_FACE, 48, 152, 74, 14
DEFPUSHBUTTON "&Ok" IDD_OK, 126, 152, 60, 14, GT
GROUPBOX "Text Metrics" -1, 192, 2, 110, 164, GR
LTEXT "Height:" -1, 200, 14, 44, 8
LTEXT "Ascent:" -1, 200, 24, 44, 8
LTEXT "Descent:" -1, 200, 34, 46, 8
LTEXT "Int Lead:" -1, 200, 44, 44, 8
LTEXT "Ext Lead:" -1, 200, 54, 44, 8
LTEXT "Ave Width:" -1, 200, 64, 44, 8
LTEXT "Max Width:" -1, 200, 74, 44, 8
LTEXT "Weight:" -1, 200, 84, 44, 8
LTEXT "Pitch:" -1, 200, 94, 44, 8
LTEXT "Family:" -1, 200, 104, 42, 8
LTEXT "Char Set:" -1, 200, 114, 44, 8
LTEXT "Overhang:" -1, 200, 124, 44, 8
LTEXT "X Aspect:" -1, 200, 134, 44, 8
LTEXT "Y Aspect:" -1, 200, 144, 44, 8
LTEXT "Face Name:" -1, 200, 154, 44, 8
RTEXT "0" TM_HEIGHT, 250, 14, 44, 8
RTEXT "0" TM_ASCENT, 250, 24, 44, 8
RTEXT "0" TM_DESCENT, 250, 34, 44, 8
RTEXT "0" TM_EXTLEAD, 250, 54, 44, 8
RTEXT "0" TM_INTLEAD, 250, 44, 44, 8
RTEXT "0" TM_AVEWIDTH, 250, 64, 44, 8
RTEXT "0" TM_MAXWIDTH, 250, 74, 44, 8
RTEXT "0" TM_WEIGHT, 250, 84, 44, 8
RTEXT "" TM_PITCH, 250, 94, 44, 8
RTEXT "" TM_FAMILY, 250, 104, 44, 8
RTEXT "" TM_CHARSET, 250, 114, 44, 8
RTEXT "0" TM_OVER, 250, 124, 44, 8
RTEXT "0" TM_DIGX, 250, 134, 44, 8
RTEXT "0" TM_DIGY, 250, 144, 44, 8
RTEXT "" TF_NAME, 250, 154, 44, 8
}
PICKFONT.H
/*------------------------
PICKFONT.H header file
------------------------*/
#define IDD_OK 1
#define IDD_HEIGHT 10
#define IDD_WIDTH 11
#define IDD_WEIGHT 12
#define IDD_ITALIC 13
#define IDD_UNDER 14
#define IDD_STRIKE 15
#define IDD_ASPECT 16
#define IDD_TEXT 17
#define IDD_LOMET 18
#define IDD_HIMET 19
#define IDD_LOENG 20
#define IDD_HIENG 21
#define IDD_TWIPS 22
#define IDD_LTWPS 23
#define IDD_ANSI 24
#define IDD_OEM 25
#define IDD_QDRAFT 26
#define IDD_QDEF 27
#define IDD_QPROOF 28
#define IDD_PDEF 29
#define IDD_PFIXED 30
#define IDD_PVAR 31
#define IDD_DONT 32
#define IDD_ROMAN 33
#define IDD_SWISS 34
#define IDD_MODERN 35
#define IDD_SCRIPT 36
#define IDD_DEC 37
#define IDD_FACE 38
#define TM_HEIGHT 39
#define TM_ASCENT 40
#define TM_DESCENT 41
#define TM_INTLEAD 42
#define TM_EXTLEAD 43
#define TM_AVEWIDTH 44
#define TM_MAXWIDTH 45
#define TM_WEIGHT 46
#define TM_PITCH 47
#define TM_FAMILY 48
#define TM_CHARSET 49
#define TM_OVER 50
#define TM_DIGX 51
#define TM_DIGY 52
#define TF_NAME 53
PICKFONT.DEF
;-------------------------------------
; PICKFONT.DEF module definition file
;-------------------------------------
NAME PICKFONT
DESCRIPTION 'Font Picker Program (c) Charles Petzold, 1990'
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 1024
STACKSIZE 8192
EXPORTS WndProc
DlgProc
Figure 14-6 shows a typical PICKFONT screen. The left side of the PICKFONT display is a modeless dialog box that allows you to select most of the fields of the logical font structure. The right side shows the results of GetTextMetrics after the font is selected into the device context. A sample line of text using this font appears at the bottom of the screen.
The modeless dialog box also contains some options that are not part of the logical font structure. These are the mapping mode (including my ”Logical Twips“ mapping mode) and the ”Match Aspect“ option, which changes the way Windows matches a logical font to a real font.
Much of the PICKFONT program contains the logic necessary to maintain the dialog box, so I won't go into detail on the workings of the program. Instead, I'll explain what you're doing when you create and select a logical font.