[CONSOLE]
[reactos.git] / reactos / 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/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 */
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 /* Record the font's attributes (Fixedwidth and Truetype) */
106 // BOOL fFixed = ((lplf->lfPitchAndFamily & 0x03) == FIXED_PITCH);
107 // BOOL fTrueType = (lplf->lfOutPrecision == OUT_STROKE_PRECIS);
108
109 /*
110 * According to: http://support.microsoft.com/kb/247815
111 * the criteria for console-eligible fonts are:
112 * - The font must be a fixed-pitch font.
113 * - The font cannot be an italic font.
114 * - The font cannot have a negative A or C space.
115 * - If it is a TrueType font, it must be FF_MODERN.
116 * - If it is not a TrueType font, it must be OEM_CHARSET.
117 *
118 * Non documented: vertical fonts are forbidden (their name start with a '@').
119 *
120 * Additional criteria for Asian installations:
121 * - If it is not a TrueType font, the face name must be "Terminal".
122 * - If it is an Asian TrueType font, it must also be an Asian character set.
123 *
124 * To install additional TrueType fonts to be available for the console,
125 * add entries of type REG_SZ named "0", "00" etc... in:
126 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont
127 * The names of the fonts listed there should match those in:
128 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts
129 */
130
131 /*
132 * In ReactOS, we relax some criteria:
133 * - We allow fixed-pitch FF_MODERN (Monospace) TrueType fonts
134 * that can be italic and have negative A or C space.
135 * - If it is not a TrueType font, it can be from another character set
136 * than OEM_CHARSET.
137 * - We do not support Asian criteria at the moment.
138 * - We do not look into the magic registry key mentioned above.
139 */
140
141 /* Reject variable width fonts */
142 if (((lplf->lfPitchAndFamily & 0x03) != FIXED_PITCH)
143 #if 0 /* Reject italic and TrueType fonts with negative A or C space */
144 || (lplf->lfItalic)
145 || !(lpntm->ntmFlags & NTM_NONNEGATIVE_AC)
146 #endif
147 )
148 {
149 DPRINT1("Font '%S' rejected because it%s (lfPitchAndFamily = %d).\n",
150 pszName, !(lplf->lfPitchAndFamily & FIXED_PITCH) ? "'s not FIXED_PITCH" : (!(lpntm->ntmFlags & NTM_NONNEGATIVE_AC) ? " has negative A or C space" : " is broken"),
151 lplf->lfPitchAndFamily);
152 return TRUE;
153 }
154
155 /* Reject TrueType fonts that are not FF_MODERN */
156 if ((FontType == TRUETYPE_FONTTYPE) && ((lplf->lfPitchAndFamily & 0xF0) != FF_MODERN))
157 {
158 DPRINT1("TrueType font '%S' rejected because it's not FF_MODERN (lfPitchAndFamily = %d)\n",
159 pszName, lplf->lfPitchAndFamily);
160 return TRUE;
161 }
162
163 /* Reject non-TrueType fonts that are not OEM */
164 #if 0
165 if ((FontType != TRUETYPE_FONTTYPE) && (lplf->lfCharSet != OEM_CHARSET))
166 {
167 DPRINT1("Non-TrueType font '%S' rejected because it's not OEM_CHARSET %d\n",
168 pszName, lplf->lfCharSet);
169 return TRUE;
170 }
171 #else // Improved criterium
172 if ((FontType != TRUETYPE_FONTTYPE) &&
173 ((lplf->lfCharSet != ANSI_CHARSET) && (lplf->lfCharSet != DEFAULT_CHARSET) && (lplf->lfCharSet != OEM_CHARSET)))
174 {
175 DPRINT1("Non-TrueType font '%S' rejected because it's not ANSI_CHARSET or DEFAULT_CHARSET or OEM_CHARSET (lfCharSet = %d)\n",
176 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 SendMessageW(hwndCombo, LB_SETITEMDATA, idx, (WPARAM)FontType);
210 }
211
212 return TRUE;
213 }
214
215 static BOOL CALLBACK
216 EnumFontSizesProc(PLOGFONTW lplf,
217 PNEWTEXTMETRICW lpntm,
218 DWORD FontType,
219 LPARAM lParam)
220 {
221 HWND hwndCombo = (HWND)lParam;
222 WCHAR FontSize[100];
223
224 if (FontType != TRUETYPE_FONTTYPE)
225 {
226 // int logsize = lpntm->tmHeight - lpntm->tmInternalLeading;
227 // LONG pointsize = MulDiv(logsize, 72, GetDeviceCaps(hdc, LOGPIXELSY));
228
229 // swprintf(FontSize, L"%2d (%d x %d)", pointsize, lplf->lfWidth, lplf->lfHeight);
230 swprintf(FontSize, L"%d x %d", lplf->lfWidth, lplf->lfHeight);
231
232 /* Make sure the size doesn't already exist in the list */
233 if (SendMessageW(hwndCombo, LB_FINDSTRINGEXACT, 0, (LPARAM)FontSize) == LB_ERR)
234 {
235 /* Add the size */
236 INT idx = (INT)SendMessageW(hwndCombo, LB_ADDSTRING, 0, (LPARAM)FontSize);
237
238 /*
239 * Store this information in the list-item's userdata area.
240 * Format:
241 * Width = FontSize.X = LOWORD(FontSize);
242 * Height = FontSize.Y = HIWORD(FontSize);
243 */
244 SendMessageW(hwndCombo, LB_SETITEMDATA, idx, MAKEWPARAM(lplf->lfWidth, lplf->lfHeight));
245 }
246
247 return TRUE;
248 }
249 else
250 {
251 ULONG i;
252 for (i = 0; i < ARRAYSIZE(TrueTypePoints); ++i)
253 {
254 swprintf(FontSize, L"%2d", TrueTypePoints[i]);
255
256 /* Make sure the size doesn't already exist in the list */
257 if (SendMessageW(hwndCombo, LB_FINDSTRINGEXACT, 0, (LPARAM)FontSize) == LB_ERR)
258 {
259 /* Add the size */
260 INT idx = (INT)SendMessageW(hwndCombo, LB_ADDSTRING, 0, (LPARAM)FontSize);
261
262 /*
263 * Store this information in the list-item's userdata area.
264 * Format:
265 * Width = FontSize.X = LOWORD(FontSize);
266 * Height = FontSize.Y = HIWORD(FontSize);
267 */
268 SendMessageW(hwndCombo, LB_SETITEMDATA, idx, MAKEWPARAM(0, TrueTypePoints[i]));
269 }
270 }
271
272 return FALSE;
273 }
274 }
275
276
277 static VOID
278 FontSizeChange(HWND hwndDlg,
279 PCONSOLE_STATE_INFO pConInfo);
280
281 static VOID
282 FontTypeChange(HWND hwndDlg,
283 PCONSOLE_STATE_INFO pConInfo)
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 - 1); // wcsnlen
309 wcsncpy(pConInfo->FaceName, FaceName, LF_FACESIZE);
310 pConInfo->FaceName[Length] = L'\0';
311 DPRINT1("pConInfo->FaceName = '%S'\n", pConInfo->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, pConInfo);
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 PCONSOLE_STATE_INFO pConInfo)
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 pConInfo->FontSize.X = LOWORD(FontSize);
356 pConInfo->FontSize.Y = HIWORD(FontSize);
357 DPRINT1("pConInfo->FontSize = (%d x %d)\n", pConInfo->FontSize.X, pConInfo->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", pConInfo->FontSize.X);
363 SetWindowText(GetDlgItem(hwndDlg, IDC_FONT_SIZE_X), FontSizeStr);
364 swprintf(FontSizeStr, L"%2d", pConInfo->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 UNREFERENCED_PARAMETER(wParam);
377
378 switch (uMsg)
379 {
380 case WM_INITDIALOG:
381 {
382 HDC hDC;
383 LOGFONTW lf;
384 INT idx;
385
386 ZeroMemory(&lf, sizeof(lf));
387 lf.lfCharSet = DEFAULT_CHARSET; // OEM_CHARSET;
388 // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
389
390 hDC = GetDC(NULL);
391 EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFontNamesProc,
392 (LPARAM)GetDlgItem(hwndDlg, IDC_LBOX_FONTTYPE), 0);
393 ReleaseDC(NULL, hDC);
394
395 DPRINT1("ConInfo->FaceName = '%S'\n", ConInfo->FaceName);
396 idx = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE,
397 LB_FINDSTRINGEXACT, 0, (LPARAM)ConInfo->FaceName);
398 if (idx != LB_ERR) SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE,
399 LB_SETCURSEL, (WPARAM)idx, 0);
400
401 FontTypeChange(hwndDlg, ConInfo);
402
403 return TRUE;
404 }
405
406 case WM_DRAWITEM:
407 {
408 LPDRAWITEMSTRUCT drawItem = (LPDRAWITEMSTRUCT)lParam;
409
410 if (drawItem->CtlID == IDC_STATIC_FONT_WINDOW_PREVIEW)
411 PaintConsole(drawItem, ConInfo);
412 else if (drawItem->CtlID == IDC_STATIC_SELECT_FONT_PREVIEW)
413 PaintText(drawItem, ConInfo, Screen);
414
415 return TRUE;
416 }
417
418 case WM_NOTIFY:
419 {
420 switch (((LPNMHDR)lParam)->code)
421 {
422 case PSN_APPLY:
423 {
424 ApplyConsoleInfo(hwndDlg);
425 return TRUE;
426 }
427 }
428
429 break;
430 }
431
432 case WM_COMMAND:
433 {
434 switch (HIWORD(wParam))
435 {
436 case LBN_SELCHANGE:
437 {
438 switch (LOWORD(wParam))
439 {
440 case IDC_LBOX_FONTTYPE:
441 {
442 FontTypeChange(hwndDlg, ConInfo);
443 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
444 break;
445 }
446
447 case IDC_LBOX_FONTSIZE:
448 {
449 FontSizeChange(hwndDlg, ConInfo);
450 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
451 break;
452 }
453 }
454
455 break;
456 }
457 }
458
459 break;
460 }
461
462 default:
463 break;
464 }
465
466 return FALSE;
467 }