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