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