xref: /reactos/dll/cpl/console/font.c (revision e5813c46)
1 /*
2  * PROJECT:         ReactOS Console Configuration DLL
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            dll/cpl/console/font.c
5  * PURPOSE:         Font dialog
6  * PROGRAMMERS:     Johannes Anderwald (johannes.anderwald@reactos.org)
7  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8  *                  Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
9  */
10 
11 #include "console.h"
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 
17 /*
18  * Current active font, corresponding to the active console font,
19  * and used for painting the text samples.
20  */
21 FONT_PREVIEW FontPreview = {NULL, 0, 0};
22 
23 
24 /*
25  * Standard font pixel/point heights for TrueType fonts
26  */
27 static const SHORT TrueTypePoints[] =
28 {
29     5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72
30 };
31 
32 typedef struct _FONTSIZE_LIST_CTL
33 {
34     LIST_CTL RasterSizeList;    // ListBox for Raster font sizes; needs to handle bisection.
35     HWND hWndTTSizeList;        // ComboBox for TrueType font sizes.
36     BOOL bIsTTSizeDirty;        // TRUE or FALSE depending on whether we have edited the edit zone.
37     BOOL UseRasterOrTTList;     // TRUE: Use the Raster size list; FALSE: Use the TrueType size list.
38     BOOL TTSizePixelUnit;       // TRUE: Size in pixels (default); FALSE: Size in points.
39     LONG CurrentRasterSize;
40     LONG CurrentTTSize;         // In whatever unit (pixels or points) currently selected.
41 } FONTSIZE_LIST_CTL, *PFONTSIZE_LIST_CTL;
42 
43 /* Used by FontTypeChange() only */
44 static INT   CurrentSelFont  = LB_ERR;
45 static DWORD CurrentFontType = (DWORD)-1;   // Invalid font type
46 
47 
48 VOID
49 RefreshFontPreview(
50     IN FONT_PREVIEW* Preview,
51     IN PCONSOLE_STATE_INFO pConInfo)
52 {
53     if (Preview->hFont) DeleteObject(Preview->hFont);
54     Preview->hFont = CreateConsoleFont(pConInfo);
55     if (Preview->hFont == NULL)
56         DPRINT1("RefreshFontPreview: CreateConsoleFont() failed\n");
57     GetFontCellSize(NULL, Preview->hFont, &Preview->CharHeight, &Preview->CharWidth);
58 }
59 
60 VOID
61 UpdateFontPreview(
62     IN FONT_PREVIEW* Preview,
63     IN HFONT hFont,
64     IN UINT  CharWidth,
65     IN UINT  CharHeight)
66 {
67     if (Preview->hFont) DeleteObject(Preview->hFont);
68     Preview->hFont = hFont;
69     Preview->CharWidth  = CharWidth;
70     Preview->CharHeight = CharHeight;
71 }
72 
73 // PLIST_GETCOUNT
74 static INT
75 RasterSizeList_GetCount(
76     IN PLIST_CTL ListCtl)
77 {
78     return (INT)SendMessageW(ListCtl->hWndList, LB_GETCOUNT, 0, 0);
79 }
80 
81 // PLIST_GETDATA
82 static ULONG_PTR
83 RasterSizeList_GetData(
84     IN PLIST_CTL ListCtl,
85     IN INT Index)
86 {
87     return (ULONG_PTR)SendMessageW(ListCtl->hWndList, LB_GETITEMDATA, (WPARAM)Index, 0);
88 }
89 
90 
91 INT
92 LogicalSizeToPointSize(
93     IN HDC hDC OPTIONAL,
94     IN UINT LogicalSize)
95 {
96     INT PointSize;
97     HDC hOrgDC = hDC;
98 
99     if (!hDC)
100         hDC = GetDC(NULL);
101 
102     // LogicalSize = tm.tmHeight - tm.tmInternalLeading;
103     PointSize = MulDiv(LogicalSize, 72, GetDeviceCaps(hDC, LOGPIXELSY));
104 
105     if (!hOrgDC)
106         ReleaseDC(NULL, hDC);
107 
108     return PointSize;
109 }
110 
111 INT
112 PointSizeToLogicalSize(
113     IN HDC hDC OPTIONAL,
114     IN INT PointSize)
115 {
116     INT LogicalSize;
117     HDC hOrgDC = hDC;
118 
119     if (!hDC)
120         hDC = GetDC(NULL);
121 
122     LogicalSize = MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
123 
124     if (!hOrgDC)
125         ReleaseDC(NULL, hDC);
126 
127     return LogicalSize;
128 }
129 
130 
131 static VOID
132 FontSizeList_SelectFontSize(
133     IN PFONTSIZE_LIST_CTL SizeList,
134     IN ULONG FontSize)
135 {
136     INT nSel;
137     WCHAR szFontSize[100];
138 
139     //
140     // FIXME: Check whether FontSize == 0
141     // (or in the case of raster font maybe, whether HIWORD(FontSize) == Height == 0) ??
142     //
143 
144     /* Find and select the best font size in the list corresponding to the current size */
145     if (SizeList->UseRasterOrTTList)
146     {
147         INT idx;
148 
149         /* Raster font size (in pixels) */
150         SizeList->CurrentRasterSize = FontSize;
151 
152         nSel = BisectListSortedByValue(&SizeList->RasterSizeList, FontSize, NULL, FALSE);
153         idx  = (INT)SendMessageW(SizeList->RasterSizeList.hWndList, LB_GETCOUNT, 0, 0);
154         if (nSel == LB_ERR)
155         {
156             /* Not found, select the first element of the list */
157             nSel = 0;
158         }
159         else if (nSel >= idx)
160         {
161             /*
162              * We got an index beyond the end of the list (as per Bisect* functionality),
163              * so instead, select the last element of the list.
164              */
165             nSel = idx-1;
166         }
167         SendMessageW(SizeList->RasterSizeList.hWndList, LB_SETCURSEL, (WPARAM)nSel, 0);
168     }
169     else
170     {
171         /* TrueType font size (in pixels or points) */
172         SizeList->CurrentTTSize = FontSize;
173 
174         // _ultow(szFontSize, FontSize, 10);
175         StringCchPrintfW(szFontSize, ARRAYSIZE(szFontSize), L"%d", FontSize);
176 
177         /* Find the font size in the list, or add it both in the ComboBox list, sorted by size value (string), and its edit box */
178         nSel = SendMessageW(SizeList->hWndTTSizeList, CB_FINDSTRINGEXACT, 0, (LPARAM)szFontSize);
179         if (nSel == CB_ERR)
180         {
181             nSel = (UINT)SendMessageW(SizeList->hWndTTSizeList, CB_ADDSTRING, -1, (LPARAM)szFontSize);
182             // ComboBox_SetText(...)
183             SetWindowTextW(SizeList->hWndTTSizeList, szFontSize);
184             SizeList->bIsTTSizeDirty = TRUE;
185         }
186         SendMessageW(SizeList->hWndTTSizeList, CB_SETCURSEL, (WPARAM)nSel, 0);
187     }
188 }
189 
190 static LONG
191 FontSizeList_GetSelectedFontSize(
192     IN PFONTSIZE_LIST_CTL SizeList)
193 {
194     INT nSel;
195     LONG FontSize;
196     PWCHAR pszNext = NULL;
197     WCHAR szFontSize[100];
198 
199     if (SizeList->UseRasterOrTTList)
200     {
201         /* Raster font size (in pixels) */
202 
203         nSel = (INT)SendMessageW(SizeList->RasterSizeList.hWndList, LB_GETCURSEL, 0, 0);
204         if (nSel == LB_ERR) return 0;
205 
206         FontSize = (LONG)SizeList->RasterSizeList.GetData(&SizeList->RasterSizeList, nSel);
207         if (FontSize == LB_ERR) return 0;
208 
209         SizeList->CurrentRasterSize = FontSize;
210     }
211     else
212     {
213         /* TrueType font size (in pixels or points) */
214 
215         if (!SizeList->bIsTTSizeDirty)
216         {
217             /*
218              * The user just selected an existing size, read the ComboBox selection.
219              *
220              * See: https://support.microsoft.com/en-us/help/66365/how-to-process-a-cbn-selchange-notification-message
221              * for more details.
222              */
223             nSel = SendMessageW(SizeList->hWndTTSizeList, CB_GETCURSEL, 0, 0);
224             SendMessageW(SizeList->hWndTTSizeList, CB_GETLBTEXT, nSel, (LPARAM)szFontSize);
225 
226             /* Validate the font size */
227             FontSize = wcstoul(szFontSize, &pszNext, 10);
228             if ((FontSize == 0) || (*pszNext))
229                 return 0;
230         }
231         else
232         {
233             /* Read the ComboBox edit string, as the user has entered a custom size */
234             // ComboBox_GetText(...)
235             GetWindowTextW(SizeList->hWndTTSizeList, szFontSize, ARRAYSIZE(szFontSize));
236 
237             /* Validate the font size */
238             FontSize = wcstoul(szFontSize, &pszNext, 10);
239             if ((FontSize == 0) || (*pszNext))
240                 return 0;
241 
242             /* Find if the font size already exists in the list; if not, add it */
243             nSel = SendMessageW(SizeList->hWndTTSizeList, CB_FINDSTRINGEXACT, 0, (LPARAM)szFontSize);
244             if (nSel == CB_ERR)
245             {
246                 nSel = (UINT)SendMessageW(SizeList->hWndTTSizeList, CB_ADDSTRING, -1, (LPARAM)szFontSize);
247                 //// ComboBox_SetText(...)
248                 //SetWindowTextW(SizeList->hWndTTSizeList, szFontSize);
249                 //SizeList->bIsTTSizeDirty = TRUE;
250             }
251             SendMessageW(SizeList->hWndTTSizeList, CB_SETCURSEL, (WPARAM)nSel, 0);
252         }
253 
254         SizeList->bIsTTSizeDirty = FALSE;
255 
256         SizeList->CurrentTTSize = FontSize;
257 
258         /*
259          * If the font size is given in points, instead of pixels,
260          * convert it into logical size.
261          */
262         if (!SizeList->TTSizePixelUnit)
263             FontSize = -PointSizeToLogicalSize(NULL, FontSize);
264     }
265 
266     return FontSize;
267 }
268 
269 
270 static VOID
271 AddFontToList(
272     IN HWND hWndList,
273     IN LPCWSTR pszFaceName,
274     IN DWORD FontType)
275 {
276     INT iItem;
277 
278     /* Make sure the font doesn't already exist in the list */
279     if (SendMessageW(hWndList, LB_FINDSTRINGEXACT, 0, (LPARAM)pszFaceName) != LB_ERR)
280         return;
281 
282     /* Add the font */
283     iItem = (INT)SendMessageW(hWndList, LB_ADDSTRING, 0, (LPARAM)pszFaceName);
284     if (iItem == LB_ERR)
285     {
286         DPRINT1("Failed to add font '%S'\n", pszFaceName);
287         return;
288     }
289 
290     DPRINT1("Add font '%S'\n", pszFaceName);
291 
292     /* Store this information in the list-item's userdata area */
293     // SendMessageW(hWndList, LB_SETITEMDATA, idx, MAKELPARAM(fFixed, fTrueType));
294     SendMessageW(hWndList, LB_SETITEMDATA, iItem, (LPARAM)FontType);
295 }
296 
297 typedef struct _FACE_NAMES_PROC_PARAM
298 {
299     HWND hWndList;
300     UINT CodePage;
301 } FACE_NAMES_PROC_PARAM, *PFACE_NAMES_PROC_PARAM;
302 
303 static BOOL CALLBACK
304 EnumFaceNamesProc(
305     IN PLOGFONTW lplf,
306     IN PNEWTEXTMETRICW lpntm,
307     IN DWORD  FontType,
308     IN LPARAM lParam)
309 {
310     PFACE_NAMES_PROC_PARAM Param = (PFACE_NAMES_PROC_PARAM)lParam;
311 
312     if (IsValidConsoleFont2(lplf, lpntm, FontType, Param->CodePage))
313     {
314         /* Add the font to the list */
315         AddFontToList(Param->hWndList, lplf->lfFaceName, FontType);
316     }
317 
318     /* Continue the font enumeration */
319     return TRUE;
320 }
321 
322 static BOOL CALLBACK
323 EnumFontSizesProc(
324     IN PLOGFONTW lplf,
325     IN PNEWTEXTMETRICW lpntm,
326     IN DWORD  FontType,
327     IN LPARAM lParam)
328 {
329     PFONTSIZE_LIST_CTL SizeList = (PFONTSIZE_LIST_CTL)lParam;
330     UINT iItem, iDupItem;
331     WCHAR szFontSize[100];
332 
333     if (FontType != TRUETYPE_FONTTYPE)
334     {
335         WPARAM FontSize;
336 
337         /*
338          * Format:
339          * Width  = FontSize.X = LOWORD(FontSize);
340          * Height = FontSize.Y = HIWORD(FontSize);
341          */
342 
343         StringCchPrintfW(szFontSize, ARRAYSIZE(szFontSize), L"%d x %d", lplf->lfWidth, lplf->lfHeight);
344         FontSize = MAKEWPARAM(lplf->lfWidth, lplf->lfHeight);
345 
346         /* Add the font size into the list, sorted by size value. Avoid any duplicates. */
347         /* Store this information in the list-item's userdata area */
348         iDupItem = LB_ERR;
349         iItem = BisectListSortedByValue(&SizeList->RasterSizeList, FontSize, &iDupItem, TRUE);
350         if (iItem == LB_ERR)
351             iItem = 0;
352         if (iDupItem == LB_ERR)
353         {
354             iItem = (UINT)SendMessageW(SizeList->RasterSizeList.hWndList, LB_INSERTSTRING, iItem, (LPARAM)szFontSize);
355             if (iItem != LB_ERR && iItem != LB_ERRSPACE)
356                 iItem = SendMessageW(SizeList->RasterSizeList.hWndList, LB_SETITEMDATA, iItem, FontSize);
357         }
358 
359         return TRUE;
360     }
361     else
362     {
363         /* TrueType or vectored font: list all the hardcoded font points */
364         ULONG i;
365         for (i = 0; i < ARRAYSIZE(TrueTypePoints); ++i)
366         {
367             // _ultow(szFontSize, TrueTypePoints[i], 10);
368             StringCchPrintfW(szFontSize, ARRAYSIZE(szFontSize), L"%d", TrueTypePoints[i]);
369 
370             /* Add the font size into the list, sorted by size value (string). Avoid any duplicates. */
371             if (SendMessageW(SizeList->hWndTTSizeList, CB_FINDSTRINGEXACT, 0, (LPARAM)szFontSize) == CB_ERR)
372                 iItem = (UINT)SendMessageW(SizeList->hWndTTSizeList, CB_INSERTSTRING, -1, (LPARAM)szFontSize);
373         }
374 
375         /* Stop the enumeration now */
376         return FALSE;
377     }
378 }
379 
380 static VOID
381 FaceNameList_Initialize(
382     IN HWND hWndList,
383     IN UINT CodePage)
384 {
385     FACE_NAMES_PROC_PARAM Param;
386     HDC hDC;
387     LOGFONTW lf;
388     INT idx;
389 
390     Param.hWndList = hWndList;
391     Param.CodePage = CodePage;
392 
393     ZeroMemory(&lf, sizeof(lf));
394     lf.lfCharSet = DEFAULT_CHARSET; // CodePageToCharSet(CodePage);
395     // lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
396 
397     hDC = GetDC(NULL);
398     EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFaceNamesProc, (LPARAM)&Param, 0);
399     ReleaseDC(NULL, hDC);
400 
401     idx = (INT)SendMessageW(hWndList, LB_GETCOUNT, 0, 0);
402     if (idx != LB_ERR && idx != 0)
403     {
404         /* We have found some fonts and filled the list, we are fine! */
405         return;
406     }
407 
408     /* No fonts were found. Manually add default ones into the list. */
409     DPRINT1("The ideal console fonts were not found; manually add default ones.\n");
410 
411     AddFontToList(hWndList, L"Terminal", RASTER_FONTTYPE);
412     AddFontToList(hWndList, L"Lucida Console", TRUETYPE_FONTTYPE);
413     if (CodePageToCharSet(CodePage) != DEFAULT_CHARSET)
414         AddFontToList(hWndList, L"Droid Sans Fallback", TRUETYPE_FONTTYPE);
415 }
416 
417 static VOID
418 FaceNameList_SelectFont(
419     IN HWND hDlg,
420     IN HWND hWndList,
421     IN PFONTSIZE_LIST_CTL SizeList,
422     IN LPCWSTR FaceName,
423     IN ULONG FontFamily,
424     IN ULONG FontWeight,
425     IN COORD FontSize)
426 {
427     INT iItem;
428 
429     iItem = (INT)SendMessageW(hWndList, LB_FINDSTRINGEXACT, 0, (LPARAM)FaceName);
430     if (iItem == LB_ERR)
431         iItem = (INT)SendMessageW(hWndList, LB_FINDSTRINGEXACT, 0, (LPARAM)L"Terminal");
432     if (iItem == LB_ERR)
433         iItem = 0;
434     SendMessageW(hWndList, LB_SETCURSEL, (WPARAM)iItem, 0);
435 
436     if (FontWeight >= FW_BOLD)
437         CheckDlgButton(hDlg, IDC_CHECK_BOLD_FONTS, BST_CHECKED);
438     else
439         CheckDlgButton(hDlg, IDC_CHECK_BOLD_FONTS, BST_UNCHECKED);
440 
441     /* Select the current font size */
442     /*
443      * Format:
444      * Width  = FontSize.X = LOWORD(FontSize);
445      * Height = FontSize.Y = HIWORD(FontSize);
446      */
447     SizeList->CurrentRasterSize = MAKELONG(FontSize.X, FontSize.Y);
448     SizeList->CurrentTTSize = FontSize.Y;
449     // FontSizeList_SelectFontSize(SizeList, SizeList->CurrentRasterSize);
450 
451     // return iItem;
452 }
453 
454 static VOID
455 UpdateFontSizeList(
456     IN HWND hDlg,
457     IN PFONTSIZE_LIST_CTL SizeList)
458 {
459     HWND hDlgItem;
460 
461     if (SizeList->UseRasterOrTTList)
462     {
463         /*
464          * Raster font: show the Raster size list, and
465          * hide the TrueType size list and the units.
466          */
467 
468         // EnableDlgItem(hDlg, IDC_CHECK_BOLD_FONTS, FALSE);
469 
470         hDlgItem = GetDlgItem(hDlg, IDC_RADIO_PIXEL_UNIT);
471         ShowWindow(hDlgItem, SW_HIDE);
472         EnableWindow(hDlgItem, FALSE);
473 
474         hDlgItem = GetDlgItem(hDlg, IDC_RADIO_POINT_UNIT);
475         ShowWindow(hDlgItem, SW_HIDE);
476         EnableWindow(hDlgItem, FALSE);
477 
478         hDlgItem = SizeList->hWndTTSizeList;
479         ShowWindow(hDlgItem, SW_HIDE);
480         EnableWindow(hDlgItem, FALSE);
481 
482         hDlgItem = SizeList->RasterSizeList.hWndList;
483         EnableWindow(hDlgItem, TRUE);
484         ShowWindow(hDlgItem, SW_SHOW);
485     }
486     else
487     {
488         /*
489          * TrueType font: show the TrueType size list
490          * and the units, and hide the Raster size list.
491          */
492 
493         // EnableDlgItem(hDlg, IDC_CHECK_BOLD_FONTS, TRUE);
494 
495         hDlgItem = SizeList->RasterSizeList.hWndList;
496         ShowWindow(hDlgItem, SW_HIDE);
497         EnableWindow(hDlgItem, FALSE);
498 
499         hDlgItem = SizeList->hWndTTSizeList;
500         EnableWindow(hDlgItem, TRUE);
501         ShowWindow(hDlgItem, SW_SHOW);
502 
503         hDlgItem = GetDlgItem(hDlg, IDC_RADIO_PIXEL_UNIT);
504         EnableWindow(hDlgItem, TRUE);
505         ShowWindow(hDlgItem, SW_SHOW);
506 
507         hDlgItem = GetDlgItem(hDlg, IDC_RADIO_POINT_UNIT);
508         EnableWindow(hDlgItem, TRUE);
509         ShowWindow(hDlgItem, SW_SHOW);
510     }
511 }
512 
513 static BOOL
514 FontSizeChange(
515     IN HWND hDlg,
516     IN PFONTSIZE_LIST_CTL SizeList,
517     IN OUT PCONSOLE_STATE_INFO pConInfo);
518 
519 static BOOL
520 FontTypeChange(
521     IN HWND hDlg,
522     IN PFONTSIZE_LIST_CTL SizeList,
523     IN OUT PCONSOLE_STATE_INFO pConInfo)
524 {
525     HWND hListBox = GetDlgItem(hDlg, IDC_LBOX_FONTTYPE);
526     INT Length, nSel;
527     LPWSTR FaceName;
528     DWORD FontType;
529     LPCWSTR FontGrpBoxLabelTpl = NULL;
530     WCHAR FontGrpBoxLabel[260];
531 
532     nSel = (INT)SendMessageW(hListBox, LB_GETCURSEL, 0, 0);
533     if (nSel == LB_ERR) return FALSE;
534 
535     /*
536      * This is disabled, because there can be external parameters
537      * that may have changed (e.g. ConInfo->FontWeight, code page, ...)
538      * and that we don't control here, and that need a font refresh.
539      */
540 #if 0
541     /* Check whether the selection has changed */
542     if (nSel == CurrentSelFont)
543         return FALSE;
544 #endif
545 
546     Length = (INT)SendMessageW(hListBox, LB_GETTEXTLEN, nSel, 0);
547     if (Length == LB_ERR) return FALSE;
548 
549     FaceName = HeapAlloc(GetProcessHeap(),
550                          HEAP_ZERO_MEMORY,
551                          (Length + 1) * sizeof(WCHAR));
552     if (FaceName == NULL) return FALSE;
553 
554     Length = (INT)SendMessageW(hListBox, LB_GETTEXT, nSel, (LPARAM)FaceName);
555     FaceName[Length] = L'\0';
556 
557     StringCchCopyW(pConInfo->FaceName, ARRAYSIZE(pConInfo->FaceName), FaceName);
558     DPRINT("pConInfo->FaceName = '%S'\n", pConInfo->FaceName);
559 
560     /*
561      * Retrieve the read-only font group box label string template,
562      * and set the group box label to the name of the selected font.
563      */
564     Length = LoadStringW(hApplet, IDS_GROUPBOX_FONT_NAME, (LPWSTR)&FontGrpBoxLabelTpl, 0);
565     if (FontGrpBoxLabelTpl && Length > 0)
566     {
567         StringCchCopyNW(FontGrpBoxLabel, ARRAYSIZE(FontGrpBoxLabel), FontGrpBoxLabelTpl, Length);
568         StringCchCatW(FontGrpBoxLabel, ARRAYSIZE(FontGrpBoxLabel), FaceName);
569         SetDlgItemTextW(hDlg, IDC_GROUPBOX_FONT_NAME, FontGrpBoxLabel);
570     }
571 
572     HeapFree(GetProcessHeap(), 0, FaceName);
573 
574     /*
575      * Reset the font size list, only:
576      * - if we have changed the type of font, or
577      * - if the font type is the same and is RASTER but the font has changed.
578      * Otherwise, if the font type is not RASTER and has not changed,
579      * we always display the TrueType default sizes and we don't need to
580      * recreate the list when we change between different TrueType fonts.
581      */
582     FontType = SendMessageW(hListBox, LB_GETITEMDATA, nSel, 0);
583     if (FontType != LB_ERR)
584     {
585         SizeList->UseRasterOrTTList = (FontType == RASTER_FONTTYPE);
586 
587         /* Display the correct font size list (if needed) */
588         if (CurrentFontType != FontType)
589             UpdateFontSizeList(hDlg, SizeList);
590 
591         /* Enumerate the available sizes for the selected font */
592         if ((CurrentFontType != FontType) ||
593             (FontType == RASTER_FONTTYPE && CurrentSelFont != nSel))
594         {
595             LOGFONTW lf;
596             HDC hDC;
597 
598             if (SizeList->UseRasterOrTTList)
599                 SendMessageW(SizeList->RasterSizeList.hWndList, LB_RESETCONTENT, 0, 0);
600             else
601                 SendMessageW(SizeList->hWndTTSizeList, CB_RESETCONTENT, 0, 0);
602 
603             ZeroMemory(&lf, sizeof(lf));
604             lf.lfCharSet = DEFAULT_CHARSET; // CodePageToCharSet(pConInfo->CodePage);
605             // lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
606             StringCchCopyW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), pConInfo->FaceName);
607 
608             hDC = GetDC(NULL);
609             EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFontSizesProc, (LPARAM)SizeList, 0);
610             ReleaseDC(NULL, hDC);
611 
612             /* Re-select the current font size */
613             if (SizeList->UseRasterOrTTList)
614                 FontSizeList_SelectFontSize(SizeList, SizeList->CurrentRasterSize);
615             else
616                 FontSizeList_SelectFontSize(SizeList, SizeList->CurrentTTSize);
617         }
618     }
619     else
620     {
621         /* We failed, display the raster fonts size list */
622         SizeList->UseRasterOrTTList = TRUE;
623         UpdateFontSizeList(hDlg, SizeList);
624     }
625     CurrentFontType = FontType;
626     CurrentSelFont  = nSel;
627 
628     FontSizeChange(hDlg, SizeList, pConInfo);
629     return TRUE;
630 }
631 
632 static BOOL
633 FontSizeChange(
634     IN HWND hDlg,
635     IN PFONTSIZE_LIST_CTL SizeList,
636     IN OUT PCONSOLE_STATE_INFO pConInfo)
637 {
638     LONG FontSize;
639     UINT CharWidth, CharHeight;
640     HFONT hFont;
641     WCHAR szFontSize[100];
642 
643     /*
644      * Retrieve the current selected font size.
645      * - If SizeList->UseRasterOrTTList is TRUE, or if it is FALSE but
646      *   if SizeList->TTSizePixelUnit is TRUE, then the font size is in pixels;
647      * - If SizeList->TTSizePixelUnit is FALSE, then the font size is in points.
648      */
649     FontSize = FontSizeList_GetSelectedFontSize(SizeList);
650     if (FontSize == 0)
651         return FALSE; // We have got an invalid font size...
652 
653     /*
654      * For TrueType fonts we set the requested width to zero
655      * so as to obtain a default aspect-ratio width.
656      */
657     CharHeight = (UINT)(SizeList->UseRasterOrTTList ? HIWORD(FontSize) : FontSize);
658     CharWidth  = (UINT)(SizeList->UseRasterOrTTList ? LOWORD(FontSize) : 0);
659 
660     hFont = CreateConsoleFont2((LONG)CharHeight, (LONG)CharWidth, pConInfo);
661     if (hFont == NULL)
662         DPRINT1("FontSizeChange: CreateConsoleFont2() failed\n");
663 
664     /* Retrieve the real character size in pixels */
665     GetFontCellSize(NULL, hFont, &CharHeight, &CharWidth);
666 
667     /*
668      * Update the font preview as well, and store the font handle. It will be
669      * freed at later update or when the font preview is refreshed or reset.
670      * For TrueType fonts, the preview will show the actual character width.
671      */
672     UpdateFontPreview(&FontPreview, hFont, CharWidth, CharHeight);
673 
674     /*
675      * Format:
676      * Width  = FontSize.X = LOWORD(FontSize);
677      * Height = FontSize.Y = HIWORD(FontSize);
678      */
679     pConInfo->FontSize.X = (SHORT)(SizeList->UseRasterOrTTList ? CharWidth : 0);
680     pConInfo->FontSize.Y = (SHORT)CharHeight;
681 
682     DPRINT("pConInfo->FontSize = (%d x %d) ; (CharWidth x CharHeight) = (%d x %d)\n",
683            pConInfo->FontSize.X, pConInfo->FontSize.Y, CharWidth, CharHeight);
684 
685     InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_FONT_WINDOW_PREVIEW), NULL, TRUE);
686     InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_SELECT_FONT_PREVIEW), NULL, TRUE);
687 
688     StringCchPrintfW(szFontSize, ARRAYSIZE(szFontSize), L"%d", CharWidth);
689     SetDlgItemText(hDlg, IDC_FONT_SIZE_X, szFontSize);
690     StringCchPrintfW(szFontSize, ARRAYSIZE(szFontSize), L"%d", CharHeight);
691     SetDlgItemText(hDlg, IDC_FONT_SIZE_Y, szFontSize);
692 
693     return TRUE;
694 }
695 
696 
697 INT_PTR
698 CALLBACK
699 FontProc(HWND hDlg,
700          UINT uMsg,
701          WPARAM wParam,
702          LPARAM lParam)
703 {
704     PFONTSIZE_LIST_CTL SizeList;
705 
706     SizeList = (PFONTSIZE_LIST_CTL)GetWindowLongPtrW(hDlg, DWLP_USER);
707 
708     switch (uMsg)
709     {
710         case WM_INITDIALOG:
711         {
712             HWND hFontList = GetDlgItem(hDlg, IDC_LBOX_FONTTYPE);
713 
714             SizeList = (PFONTSIZE_LIST_CTL)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*SizeList));
715             if (!SizeList)
716             {
717                 EndDialog(hDlg, 0);
718                 return (INT_PTR)TRUE;
719             }
720             SizeList->RasterSizeList.hWndList = GetDlgItem(hDlg, IDC_LBOX_FONTSIZE);
721             SizeList->RasterSizeList.GetCount = RasterSizeList_GetCount;
722             SizeList->RasterSizeList.GetData  = RasterSizeList_GetData;
723             SizeList->hWndTTSizeList = GetDlgItem(hDlg, IDC_CBOX_FONTSIZE);
724             SizeList->bIsTTSizeDirty = FALSE;
725             SetWindowLongPtrW(hDlg, DWLP_USER, (LONG_PTR)SizeList);
726 
727             /* By default show the raster font size list */
728             SizeList->UseRasterOrTTList = TRUE;
729 
730             /* By default show the font sizes in pixel units */
731             CheckRadioButton(hDlg, IDC_RADIO_PIXEL_UNIT, IDC_RADIO_POINT_UNIT, IDC_RADIO_PIXEL_UNIT);
732             SizeList->TTSizePixelUnit = TRUE;
733 
734             UpdateFontSizeList(hDlg, SizeList);
735 
736             /* Initialize the font list */
737             FaceNameList_Initialize(hFontList, ConInfo->CodePage);
738 
739             /* Select the current font */
740             DPRINT1("ConInfo->FaceName = '%S'\n", ConInfo->FaceName);
741             FaceNameList_SelectFont(hDlg, hFontList,
742                                     SizeList,
743                                     ConInfo->FaceName,
744                                     ConInfo->FontFamily,
745                                     ConInfo->FontWeight,
746                                     ConInfo->FontSize);
747 
748             /* Refresh everything */
749             FontTypeChange(hDlg, SizeList, ConInfo);
750 
751             return TRUE;
752         }
753 
754         case WM_DESTROY:
755         {
756             if (SizeList)
757                 HeapFree(GetProcessHeap(), 0, SizeList);
758             return (INT_PTR)TRUE;
759         }
760 
761         case WM_DRAWITEM:
762         {
763             LPDRAWITEMSTRUCT drawItem = (LPDRAWITEMSTRUCT)lParam;
764 
765             if (drawItem->CtlID == IDC_STATIC_SELECT_FONT_PREVIEW)
766                 PaintText(drawItem, ConInfo, Screen);
767 
768             return TRUE;
769         }
770 
771         case WM_DISPLAYCHANGE:
772         {
773             /* Retransmit to the preview window */
774             SendDlgItemMessageW(hDlg, IDC_STATIC_FONT_WINDOW_PREVIEW,
775                                 WM_DISPLAYCHANGE, wParam, lParam);
776             break;
777         }
778 
779 #if 0
780         case PSM_QUERYSIBLINGS:
781         {
782             /*
783              * If this is a notification from the "Options" dialog because we
784              * changed the code page, treat it using the WM_FONTCHANGE case,
785              * otherwise ignore it.
786              */
787             if (wParam != IDL_CODEPAGE)
788                 return FALSE;
789 
790             /* Fall through */
791         }
792 #endif
793 
794         case WM_FONTCHANGE:
795         {
796             /* The pool of font resources has changed, re-enumerate the fonts */
797             HWND hFontList = GetDlgItem(hDlg, IDC_LBOX_FONTTYPE);
798 
799             /* Initialize the font list */
800             FaceNameList_Initialize(hFontList, ConInfo->CodePage);
801 
802             /* Select the current font */
803             FaceNameList_SelectFont(hDlg, hFontList,
804                                     SizeList,
805                                     ConInfo->FaceName,
806                                     ConInfo->FontFamily,
807                                     ConInfo->FontWeight,
808                                     ConInfo->FontSize);
809 
810             /* Refresh everything */
811             FontTypeChange(hDlg, SizeList, ConInfo);
812             break;
813         }
814 
815         case WM_NOTIFY:
816         {
817             switch (((LPNMHDR)lParam)->code)
818             {
819                 case PSN_APPLY:
820                 {
821                     ApplyConsoleInfo(hDlg);
822                     return TRUE;
823                 }
824             }
825 
826             break;
827         }
828 
829         case WM_COMMAND:
830         {
831             if (HIWORD(wParam) == LBN_SELCHANGE /* || CBN_SELCHANGE */)
832             {
833                 switch (LOWORD(wParam))
834                 {
835                     case IDC_LBOX_FONTTYPE:
836                     {
837                         /* Change the property sheet state only if the font has really changed */
838                         if (FontTypeChange(hDlg, SizeList, ConInfo))
839                             PropSheet_Changed(GetParent(hDlg), hDlg);
840                         break;
841                     }
842 
843                     case IDC_LBOX_FONTSIZE:
844                     case IDC_CBOX_FONTSIZE:
845                     {
846                         /* Change the property sheet state only if the font has really changed */
847                         if (FontSizeChange(hDlg, SizeList, ConInfo))
848                             PropSheet_Changed(GetParent(hDlg), hDlg);
849                         break;
850                     }
851                 }
852             }
853             /* NOTE: CBN_EDITUPDATE is sent first, and is followed by CBN_EDITCHANGE */
854             else if (HIWORD(wParam) == CBN_EDITUPDATE && LOWORD(wParam) == IDC_CBOX_FONTSIZE)
855             {
856                 ULONG FontSize;
857                 PWCHAR pszNext = NULL;
858                 WCHAR szFontSize[100];
859                 WCHAR szMessage[260];
860 
861                 /* Read the ComboBox edit string, as the user has entered a custom size */
862                 GetWindowTextW(SizeList->hWndTTSizeList, szFontSize, ARRAYSIZE(szFontSize));
863 
864                 /* Validate the font size */
865                 FontSize = wcstoul(szFontSize, &pszNext, 10);
866                 if ((FontSize == 0) || (*pszNext))
867                 {
868                     // FIXME: Localize!
869                     StringCchPrintfW(szMessage, ARRAYSIZE(szMessage), L"\"%s\" is not a valid font size.", szFontSize);
870                     MessageBoxW(hDlg, szMessage, L"Error", MB_ICONINFORMATION | MB_OK);
871                 }
872                 /**/SizeList->bIsTTSizeDirty = TRUE;/**/
873             }
874             else if (HIWORD(wParam) == CBN_KILLFOCUS && LOWORD(wParam) == IDC_CBOX_FONTSIZE)
875             {
876                 /* Change the property sheet state only if the font has really changed */
877                 if (FontSizeChange(hDlg, SizeList, ConInfo))
878                     PropSheet_Changed(GetParent(hDlg), hDlg);
879             }
880             else
881             if (HIWORD(wParam) == BN_CLICKED)
882             {
883                 switch (LOWORD(wParam))
884                 {
885                 case IDC_CHECK_BOLD_FONTS:
886                 {
887                     if (IsDlgButtonChecked(hDlg, IDC_CHECK_BOLD_FONTS) == BST_CHECKED)
888                         ConInfo->FontWeight = FW_BOLD;
889                     else
890                         ConInfo->FontWeight = FW_NORMAL;
891 
892                     FontTypeChange(hDlg, SizeList, ConInfo);
893                     PropSheet_Changed(GetParent(hDlg), hDlg);
894                     break;
895                 }
896 
897                 case IDC_RADIO_PIXEL_UNIT:
898                 case IDC_RADIO_POINT_UNIT:
899                 {
900                     SizeList->TTSizePixelUnit = (LOWORD(wParam) == IDC_RADIO_PIXEL_UNIT);
901 
902                     /* The call is valid only for TrueType fonts */
903                     if (CurrentFontType != TRUETYPE_FONTTYPE)
904                         break;
905 
906                     /* Change the property sheet state only if the font has really changed */
907                     if (FontSizeChange(hDlg, SizeList, ConInfo))
908                         PropSheet_Changed(GetParent(hDlg), hDlg);
909                     break;
910                 }
911                 }
912             }
913 
914             break;
915         }
916 
917         default:
918             break;
919     }
920 
921     return FALSE;
922 }
923