[CONSOLE.CPL][CONSRV]
[reactos.git] / dll / cpl / console / font.c
1 /*
2 * PROJECT: ReactOS Console Configuration DLL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/console/font.c
5 * PURPOSE: Font dialog
6 * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 #include "console.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15
16 //
17 // Some temporary code for future reference...
18 //
19 #if 0
20 /*
21 * This code comes from PuTTY
22 */
23 {
24 CHOOSEFONT cf;
25 LOGFONT lf;
26 HDC hdc;
27 FontSpec *fs = (FontSpec *)c->data;
28
29 hdc = GetDC(0);
30 lf.lfHeight = -MulDiv(fs->height,
31 GetDeviceCaps(hdc, LOGPIXELSY), 72);
32 ReleaseDC(0, hdc);
33 lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0;
34 lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0;
35 lf.lfWeight = (fs->isbold ? FW_BOLD : 0);
36 lf.lfCharSet = fs->charset;
37 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
38 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
39 lf.lfQuality = DEFAULT_QUALITY;
40 lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
41 strncpy(lf.lfFaceName, fs->name,
42 sizeof(lf.lfFaceName) - 1);
43 lf.lfFaceName[sizeof(lf.lfFaceName) - 1] = '\0';
44
45 cf.lStructSize = sizeof(cf);
46 cf.hwndOwner = dp->hwnd;
47 cf.lpLogFont = &lf;
48 cf.Flags = (dp->fixed_pitch_fonts ? CF_FIXEDPITCHONLY : 0) |
49 CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
50
51 if (ChooseFont(&cf)) {
52 fs = fontspec_new(lf.lfFaceName, (lf.lfWeight == FW_BOLD),
53 cf.iPointSize / 10, lf.lfCharSet);
54 dlg_fontsel_set(ctrl, dp, fs);
55 fontspec_free(fs);
56
57 ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE);
58 }
59 }
60
61 /*
62 * This code is from consrv.
63 */
64 {
65 if (!GetTextMetricsW(drawItem->hDC, &Metrics))
66 {
67 DPRINT1("PaintText: GetTextMetrics failed\n");
68 SelectObject(drawItem->hDC, OldFont);
69 DeleteObject(Font);
70 return;
71 }
72 GuiData->CharWidth = Metrics.tmMaxCharWidth;
73 GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading;
74
75 /* Measure real char width more precisely if possible. */
76 if (GetTextExtentPoint32W(drawItem->hDC, L"R", 1, &CharSize))
77 GuiData->CharWidth = CharSize.cx;
78 }
79
80 /*
81 * See also: Display_SetTypeFace in applications/fontview/display.c
82 */
83 #endif
84
85
86 /*
87 * Font pixel heights for TrueType fonts
88 */
89 static SHORT TrueTypePoints[] =
90 {
91 // 8, 9, 10, 11, 12, 14, 16, 18, 20,
92 // 22, 24, 26, 28, 36, 48, 72
93 5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 24, 28, 36, 72
94 };
95
96 static BOOL CALLBACK
97 EnumFontNamesProc(PLOGFONTW lplf,
98 PNEWTEXTMETRICW lpntm,
99 DWORD FontType,
100 LPARAM lParam)
101 {
102 HWND hwndCombo = (HWND)lParam;
103 LPWSTR pszName = lplf->lfFaceName;
104
105 BOOL fFixed;
106 BOOL fTrueType;
107
108 /* Record the font's attributes (Fixedwidth and Truetype) */
109 fFixed = ((lplf->lfPitchAndFamily & 0x03) == FIXED_PITCH);
110 fTrueType = (lplf->lfOutPrecision == OUT_STROKE_PRECIS) ? TRUE : FALSE;
111
112 /*
113 * According to: http://support.microsoft.com/kb/247815
114 * the criteria for console-eligible fonts are:
115 * - The font must be a fixed-pitch font.
116 * - The font cannot be an italic font.
117 * - The font cannot have a negative A or C space.
118 * - If it is a TrueType font, it must be FF_MODERN.
119 * - If it is not a TrueType font, it must be OEM_CHARSET.
120 *
121 * Non documented: vertical fonts are forbidden (their name start with a '@').
122 *
123 * Additional criteria for Asian installations:
124 * - If it is not a TrueType font, the face name must be "Terminal".
125 * - If it is an Asian TrueType font, it must also be an Asian character set.
126 *
127 * To install additional TrueType fonts to be available for the console,
128 * add entries of type REG_SZ named "0", "00" etc... in:
129 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont
130 * The names of the fonts listed there should match those in:
131 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts
132 */
133
134 /*
135 * In ReactOS, we relax some criteria:
136 * - We allow fixed-pitch FF_MODERN (Monospace) TrueType fonts
137 * that can be italic and have negative A or C space.
138 * - If it is not a TrueType font, it can be from another character set
139 * than OEM_CHARSET.
140 * - We do not support Asian criteria at the moment.
141 * - We do not look into the magic registry key mentioned above.
142 */
143
144 /* Reject variable width fonts */
145 if (((lplf->lfPitchAndFamily & 0x03) != FIXED_PITCH)
146 #if 0 /* Reject italic and TrueType fonts with negative A or C space */
147 || (lplf->lfItalic)
148 || !(lpntm->ntmFlags & NTM_NONNEGATIVE_AC)
149 #endif
150 )
151 {
152 DPRINT1("Font '%S' rejected because it%s (lfPitchAndFamily = %d).\n",
153 pszName, !(lplf->lfPitchAndFamily & FIXED_PITCH) ? "'s not FIXED_PITCH" : (!(lpntm->ntmFlags & NTM_NONNEGATIVE_AC) ? " has negative A or C space" : " is broken"),
154 lplf->lfPitchAndFamily);
155 return TRUE;
156 }
157
158 /* Reject TrueType fonts that are not FF_MODERN */
159 if ((FontType == TRUETYPE_FONTTYPE) && ((lplf->lfPitchAndFamily & 0xF0) != FF_MODERN))
160 {
161 DPRINT1("TrueType font '%S' rejected because it's not FF_MODERN (lfPitchAndFamily = %d)\n", pszName, lplf->lfPitchAndFamily);
162 return TRUE;
163 }
164
165 /* Reject non-TrueType fonts that are not OEM */
166 #if 0
167 if ((FontType != TRUETYPE_FONTTYPE) && (lplf->lfCharSet != OEM_CHARSET))
168 {
169 DPRINT1("Non-TrueType font '%S' rejected because it's not OEM_CHARSET %d\n", pszName, lplf->lfCharSet);
170 return TRUE;
171 }
172 #else // Improved criterium
173 if ((FontType != TRUETYPE_FONTTYPE) &&
174 ((lplf->lfCharSet != ANSI_CHARSET) && (lplf->lfCharSet != DEFAULT_CHARSET) && (lplf->lfCharSet != OEM_CHARSET)))
175 {
176 DPRINT1("Non-TrueType font '%S' rejected because it's not ANSI_CHARSET or DEFAULT_CHARSET or OEM_CHARSET (lfCharSet = %d)\n", pszName, lplf->lfCharSet);
177 return TRUE;
178 }
179 #endif
180
181 /* Reject fonts that are vertical (tategaki) */
182 if (pszName[0] == L'@')
183 {
184 DPRINT1("Font '%S' rejected because it's vertical\n", pszName);
185 return TRUE;
186 }
187
188 #if 0 // For Asian installations only
189 /* Reject non-TrueType fonts that are not Terminal */
190 if ((FontType != TRUETYPE_FONTTYPE) && (wcscmp(pszName, L"Terminal") != 0))
191 {
192 DPRINT1("Non-TrueType font '%S' rejected because it's not Terminal\n", pszName);
193 return TRUE;
194 }
195
196 // TODO: Asian TrueType font must also be an Asian character set.
197 #endif
198
199 /* Make sure the font doesn't already exist in the list */
200 if (SendMessageW(hwndCombo, LB_FINDSTRINGEXACT, 0, (LPARAM)pszName) == LB_ERR)
201 {
202 /* Add the font */
203 INT idx = (INT)SendMessageW(hwndCombo, LB_ADDSTRING, 0, (LPARAM)pszName);
204
205 DPRINT1("Add font '%S' (lfPitchAndFamily = %d)\n", pszName, lplf->lfPitchAndFamily);
206
207 /* Store this information in the list-item's userdata area */
208 SendMessageW(hwndCombo, LB_SETITEMDATA, idx, MAKEWPARAM(fFixed, fTrueType));
209 }
210
211 return TRUE;
212 }
213
214 static BOOL CALLBACK
215 EnumFontSizesProc(PLOGFONTW lplf,
216 PNEWTEXTMETRICW lpntm,
217 DWORD FontType,
218 LPARAM lParam)
219 {
220 HWND hwndCombo = (HWND)lParam;
221 WCHAR FontSize[100];
222
223 if (FontType != TRUETYPE_FONTTYPE)
224 {
225 // int logsize = lpntm->tmHeight - lpntm->tmInternalLeading;
226 // LONG pointsize = MulDiv(logsize, 72, GetDeviceCaps(hdc, LOGPIXELSY));
227
228 // swprintf(FontSize, L"%2d (%d x %d)", pointsize, lplf->lfWidth, lplf->lfHeight);
229 swprintf(FontSize, L"%d x %d", lplf->lfWidth, lplf->lfHeight);
230
231 /* Make sure the size doesn't already exist in the list */
232 if (SendMessageW(hwndCombo, LB_FINDSTRINGEXACT, 0, (LPARAM)FontSize) == LB_ERR)
233 {
234 /* Add the size */
235 INT idx = (INT)SendMessageW(hwndCombo, LB_ADDSTRING, 0, (LPARAM)FontSize);
236
237 /*
238 * Store this information in the list-item's userdata area.
239 * Format:
240 * Width = FontSize.X = LOWORD(FontSize);
241 * Height = FontSize.Y = HIWORD(FontSize);
242 */
243 SendMessageW(hwndCombo, LB_SETITEMDATA, idx, MAKEWPARAM(lplf->lfWidth, lplf->lfHeight));
244 }
245
246 return TRUE;
247 }
248 else
249 {
250 int i;
251 for (i = 0; i < sizeof(TrueTypePoints) / sizeof(TrueTypePoints[0]); ++i)
252 {
253 swprintf(FontSize, L"%2d", TrueTypePoints[i]);
254
255 /* Make sure the size doesn't already exist in the list */
256 if (SendMessageW(hwndCombo, LB_FINDSTRINGEXACT, 0, (LPARAM)FontSize) == LB_ERR)
257 {
258 /* Add the size */
259 INT idx = (INT)SendMessageW(hwndCombo, LB_ADDSTRING, 0, (LPARAM)FontSize);
260
261 /*
262 * Store this information in the list-item's userdata area.
263 * Format:
264 * Width = FontSize.X = LOWORD(FontSize);
265 * Height = FontSize.Y = HIWORD(FontSize);
266 */
267 SendMessageW(hwndCombo, LB_SETITEMDATA, idx, MAKEWPARAM(0, TrueTypePoints[i]));
268 }
269 }
270
271 return FALSE;
272 }
273 }
274
275
276
277 static VOID
278 FontSizeChange(HWND hwndDlg,
279 PGUI_CONSOLE_INFO GuiInfo);
280
281 static VOID
282 FontTypeChange(HWND hwndDlg,
283 PGUI_CONSOLE_INFO GuiInfo)
284 {
285 INT Length, nSel;
286 LPWSTR FaceName;
287
288 HDC hDC;
289 LOGFONTW lf;
290
291 nSel = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE,
292 LB_GETCURSEL, 0, 0);
293 if (nSel == LB_ERR) return;
294
295 Length = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE,
296 LB_GETTEXTLEN, nSel, 0);
297 if (Length == LB_ERR) return;
298
299 FaceName = HeapAlloc(GetProcessHeap(),
300 HEAP_ZERO_MEMORY,
301 (Length + 1) * sizeof(WCHAR));
302 if (FaceName == NULL) return;
303
304 Length = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE,
305 LB_GETTEXT, nSel, (LPARAM)FaceName);
306 FaceName[Length] = '\0';
307
308 Length = min(Length/*wcslen(FaceName) + 1*/, LF_FACESIZE); // wcsnlen
309 wcsncpy(GuiInfo->FaceName, FaceName, LF_FACESIZE);
310 GuiInfo->FaceName[Length] = L'\0';
311 DPRINT1("GuiInfo->FaceName = '%S'\n", GuiInfo->FaceName);
312
313 /* Enumerate the available sizes for the selected font */
314 ZeroMemory(&lf, sizeof(lf));
315 lf.lfCharSet = DEFAULT_CHARSET; // OEM_CHARSET;
316 // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
317 wcsncpy(lf.lfFaceName, FaceName, LF_FACESIZE);
318 lf.lfFaceName[Length] = L'\0';
319
320 hDC = GetDC(NULL);
321 EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFontSizesProc,
322 (LPARAM)GetDlgItem(hwndDlg, IDC_LBOX_FONTSIZE), 0);
323 ReleaseDC(NULL, hDC);
324
325 HeapFree(GetProcessHeap(), 0, FaceName);
326
327 // TODO: Select a default font size????
328 FontSizeChange(hwndDlg, GuiInfo);
329
330 // InvalidateRect(GetDlgItem(hwndDlg, IDC_STATIC_FONT_WINDOW_PREVIEW), NULL, TRUE);
331 // InvalidateRect(GetDlgItem(hwndDlg, IDC_STATIC_SELECT_FONT_PREVIEW), NULL, TRUE);
332 }
333
334 static VOID
335 FontSizeChange(HWND hwndDlg,
336 PGUI_CONSOLE_INFO GuiInfo)
337 {
338 INT nSel;
339 ULONG FontSize;
340 WCHAR FontSizeStr[20];
341
342 nSel = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTSIZE,
343 LB_GETCURSEL, 0, 0);
344 if (nSel == LB_ERR) return;
345
346 /*
347 * Format:
348 * Width = FontSize.X = LOWORD(FontSize);
349 * Height = FontSize.Y = HIWORD(FontSize);
350 */
351 FontSize = (ULONG)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTSIZE,
352 LB_GETITEMDATA, nSel, 0);
353 if (FontSize == LB_ERR) return;
354
355 GuiInfo->FontSize.X = LOWORD(FontSize);
356 GuiInfo->FontSize.Y = HIWORD(FontSize);
357 DPRINT1("GuiInfo->FontSize = (%d x %d)\n", GuiInfo->FontSize.X, GuiInfo->FontSize.Y);
358
359 InvalidateRect(GetDlgItem(hwndDlg, IDC_STATIC_FONT_WINDOW_PREVIEW), NULL, TRUE);
360 InvalidateRect(GetDlgItem(hwndDlg, IDC_STATIC_SELECT_FONT_PREVIEW), NULL, TRUE);
361
362 swprintf(FontSizeStr, L"%2d", GuiInfo->FontSize.X);
363 SetWindowText(GetDlgItem(hwndDlg, IDC_FONT_SIZE_X), FontSizeStr);
364 swprintf(FontSizeStr, L"%2d", GuiInfo->FontSize.Y);
365 SetWindowText(GetDlgItem(hwndDlg, IDC_FONT_SIZE_Y), FontSizeStr);
366 }
367
368
369 INT_PTR
370 CALLBACK
371 FontProc(HWND hwndDlg,
372 UINT uMsg,
373 WPARAM wParam,
374 LPARAM lParam)
375 {
376 PCONSOLE_PROPS pConInfo = (PCONSOLE_PROPS)GetWindowLongPtr(hwndDlg, DWLP_USER);
377 PGUI_CONSOLE_INFO GuiInfo = (pConInfo ? pConInfo->TerminalInfo.TermInfo : NULL);
378
379 UNREFERENCED_PARAMETER(wParam);
380
381 switch (uMsg)
382 {
383 case WM_INITDIALOG:
384 {
385 HDC hDC;
386 LOGFONTW lf;
387 INT idx;
388
389 pConInfo = (PCONSOLE_PROPS)((LPPROPSHEETPAGE)lParam)->lParam;
390 GuiInfo = pConInfo->TerminalInfo.TermInfo;
391 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pConInfo);
392
393 ZeroMemory(&lf, sizeof(lf));
394 lf.lfCharSet = DEFAULT_CHARSET; // OEM_CHARSET;
395 // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
396
397 hDC = GetDC(NULL);
398 EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFontNamesProc,
399 (LPARAM)GetDlgItem(hwndDlg, IDC_LBOX_FONTTYPE), 0);
400 ReleaseDC(NULL, hDC);
401
402 DPRINT1("GuiInfo->FaceName = '%S'\n", GuiInfo->FaceName);
403 idx = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE,
404 LB_FINDSTRINGEXACT, 0, (LPARAM)GuiInfo->FaceName);
405 if (idx != LB_ERR) SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE,
406 LB_SETCURSEL, (WPARAM)idx, 0);
407
408 FontTypeChange(hwndDlg, GuiInfo);
409
410 return TRUE;
411 }
412
413 case WM_DRAWITEM:
414 {
415 LPDRAWITEMSTRUCT drawItem = (LPDRAWITEMSTRUCT)lParam;
416
417 if (drawItem->CtlID == IDC_STATIC_FONT_WINDOW_PREVIEW)
418 PaintConsole(drawItem, pConInfo);
419 else if (drawItem->CtlID == IDC_STATIC_SELECT_FONT_PREVIEW)
420 PaintText(drawItem, pConInfo, Screen);
421
422 return TRUE;
423 }
424
425 case WM_NOTIFY:
426 {
427 switch (((LPNMHDR)lParam)->code)
428 {
429 case PSN_APPLY:
430 {
431 if (!pConInfo->AppliedConfig)
432 {
433 return ApplyConsoleInfo(hwndDlg, pConInfo);
434 }
435 else
436 {
437 /* Options have already been applied */
438 SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
439 return TRUE;
440 }
441 break;
442 }
443 }
444
445 break;
446 }
447
448 case WM_COMMAND:
449 {
450 switch (HIWORD(wParam))
451 {
452 case LBN_SELCHANGE:
453 {
454 switch (LOWORD(wParam))
455 {
456 case IDC_LBOX_FONTTYPE:
457 {
458 FontTypeChange(hwndDlg, GuiInfo);
459 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
460 break;
461 }
462
463 case IDC_LBOX_FONTSIZE:
464 {
465 FontSizeChange(hwndDlg, GuiInfo);
466 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
467 break;
468 }
469 }
470
471 break;
472 }
473 }
474
475 break;
476 }
477
478 default:
479 break;
480 }
481
482 return FALSE;
483 }