/* * PROJECT: ReactOS Console Configuration DLL * LICENSE: GPL - See COPYING in the top level directory * FILE: dll/win32/console/font.c * PURPOSE: Font dialog * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org) * Hermes Belusca-Maito (hermes.belusca@sfr.fr) */ #include "console.h" #define NDEBUG #include // // Some temporary code for future reference... // #if 0 /* * This code comes from PuTTY */ { CHOOSEFONT cf; LOGFONT lf; HDC hdc; FontSpec *fs = (FontSpec *)c->data; hdc = GetDC(0); lf.lfHeight = -MulDiv(fs->height, GetDeviceCaps(hdc, LOGPIXELSY), 72); ReleaseDC(0, hdc); lf.lfWidth = lf.lfEscapement = lf.lfOrientation = 0; lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0; lf.lfWeight = (fs->isbold ? FW_BOLD : 0); lf.lfCharSet = fs->charset; lf.lfOutPrecision = OUT_DEFAULT_PRECIS; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfQuality = DEFAULT_QUALITY; lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; strncpy(lf.lfFaceName, fs->name, sizeof(lf.lfFaceName) - 1); lf.lfFaceName[sizeof(lf.lfFaceName) - 1] = '\0'; cf.lStructSize = sizeof(cf); cf.hwndOwner = dp->hwnd; cf.lpLogFont = &lf; cf.Flags = (dp->fixed_pitch_fonts ? CF_FIXEDPITCHONLY : 0) | CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS; if (ChooseFont(&cf)) { fs = fontspec_new(lf.lfFaceName, (lf.lfWeight == FW_BOLD), cf.iPointSize / 10, lf.lfCharSet); dlg_fontsel_set(ctrl, dp, fs); fontspec_free(fs); ctrl->generic.handler(ctrl, dp, dp->data, EVENT_VALCHANGE); } } /* * This code is from consrv. */ { if (!GetTextMetricsW(drawItem->hDC, &Metrics)) { DPRINT1("PaintText: GetTextMetrics failed\n"); SelectObject(drawItem->hDC, OldFont); DeleteObject(Font); return; } GuiData->CharWidth = Metrics.tmMaxCharWidth; GuiData->CharHeight = Metrics.tmHeight + Metrics.tmExternalLeading; /* Measure real char width more precisely if possible */ if (GetTextExtentPoint32W(drawItem->hDC, L"R", 1, &CharSize)) GuiData->CharWidth = CharSize.cx; } /* * See also: Display_SetTypeFace in applications/fontview/display.c */ #endif /* * Font pixel heights for TrueType fonts */ static SHORT TrueTypePoints[] = { // 8, 9, 10, 11, 12, 14, 16, 18, 20, // 22, 24, 26, 28, 36, 48, 72 5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 24, 28, 36, 72 }; static BOOL CALLBACK EnumFontNamesProc(PLOGFONTW lplf, PNEWTEXTMETRICW lpntm, DWORD FontType, LPARAM lParam) { HWND hwndCombo = (HWND)lParam; LPWSTR pszName = lplf->lfFaceName; /* Record the font's attributes (Fixedwidth and Truetype) */ // BOOL fFixed = ((lplf->lfPitchAndFamily & 0x03) == FIXED_PITCH); // BOOL fTrueType = (lplf->lfOutPrecision == OUT_STROKE_PRECIS); /* * According to: http://support.microsoft.com/kb/247815 * the criteria for console-eligible fonts are: * - The font must be a fixed-pitch font. * - The font cannot be an italic font. * - The font cannot have a negative A or C space. * - If it is a TrueType font, it must be FF_MODERN. * - If it is not a TrueType font, it must be OEM_CHARSET. * * Non documented: vertical fonts are forbidden (their name start with a '@'). * * Additional criteria for Asian installations: * - If it is not a TrueType font, the face name must be "Terminal". * - If it is an Asian TrueType font, it must also be an Asian character set. * * To install additional TrueType fonts to be available for the console, * add entries of type REG_SZ named "0", "00" etc... in: * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont * The names of the fonts listed there should match those in: * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts */ /* * In ReactOS, we relax some criteria: * - We allow fixed-pitch FF_MODERN (Monospace) TrueType fonts * that can be italic and have negative A or C space. * - If it is not a TrueType font, it can be from another character set * than OEM_CHARSET. * - We do not support Asian criteria at the moment. * - We do not look into the magic registry key mentioned above. */ /* Reject variable width fonts */ if (((lplf->lfPitchAndFamily & 0x03) != FIXED_PITCH) #if 0 /* Reject italic and TrueType fonts with negative A or C space */ || (lplf->lfItalic) || !(lpntm->ntmFlags & NTM_NONNEGATIVE_AC) #endif ) { DPRINT1("Font '%S' rejected because it%s (lfPitchAndFamily = %d).\n", pszName, !(lplf->lfPitchAndFamily & FIXED_PITCH) ? "'s not FIXED_PITCH" : (!(lpntm->ntmFlags & NTM_NONNEGATIVE_AC) ? " has negative A or C space" : " is broken"), lplf->lfPitchAndFamily); return TRUE; } /* Reject TrueType fonts that are not FF_MODERN */ if ((FontType == TRUETYPE_FONTTYPE) && ((lplf->lfPitchAndFamily & 0xF0) != FF_MODERN)) { DPRINT1("TrueType font '%S' rejected because it's not FF_MODERN (lfPitchAndFamily = %d)\n", pszName, lplf->lfPitchAndFamily); return TRUE; } /* Reject non-TrueType fonts that are not OEM */ #if 0 if ((FontType != TRUETYPE_FONTTYPE) && (lplf->lfCharSet != OEM_CHARSET)) { DPRINT1("Non-TrueType font '%S' rejected because it's not OEM_CHARSET %d\n", pszName, lplf->lfCharSet); return TRUE; } #else // Improved criterium if ((FontType != TRUETYPE_FONTTYPE) && ((lplf->lfCharSet != ANSI_CHARSET) && (lplf->lfCharSet != DEFAULT_CHARSET) && (lplf->lfCharSet != OEM_CHARSET))) { DPRINT1("Non-TrueType font '%S' rejected because it's not ANSI_CHARSET or DEFAULT_CHARSET or OEM_CHARSET (lfCharSet = %d)\n", pszName, lplf->lfCharSet); return TRUE; } #endif /* Reject fonts that are vertical (tategaki) */ if (pszName[0] == L'@') { DPRINT1("Font '%S' rejected because it's vertical\n", pszName); return TRUE; } #if 0 // For Asian installations only /* Reject non-TrueType fonts that are not Terminal */ if ((FontType != TRUETYPE_FONTTYPE) && (wcscmp(pszName, L"Terminal") != 0)) { DPRINT1("Non-TrueType font '%S' rejected because it's not Terminal\n", pszName); return TRUE; } // TODO: Asian TrueType font must also be an Asian character set. #endif /* Make sure the font doesn't already exist in the list */ if (SendMessageW(hwndCombo, LB_FINDSTRINGEXACT, 0, (LPARAM)pszName) == LB_ERR) { /* Add the font */ INT idx = (INT)SendMessageW(hwndCombo, LB_ADDSTRING, 0, (LPARAM)pszName); DPRINT1("Add font '%S' (lfPitchAndFamily = %d)\n", pszName, lplf->lfPitchAndFamily); /* Store this information in the list-item's userdata area */ // SendMessageW(hwndCombo, LB_SETITEMDATA, idx, MAKEWPARAM(fFixed, fTrueType)); SendMessageW(hwndCombo, LB_SETITEMDATA, idx, (WPARAM)FontType); } return TRUE; } static BOOL CALLBACK EnumFontSizesProc(PLOGFONTW lplf, PNEWTEXTMETRICW lpntm, DWORD FontType, LPARAM lParam) { HWND hwndCombo = (HWND)lParam; WCHAR FontSize[100]; if (FontType != TRUETYPE_FONTTYPE) { // int logsize = lpntm->tmHeight - lpntm->tmInternalLeading; // LONG pointsize = MulDiv(logsize, 72, GetDeviceCaps(hdc, LOGPIXELSY)); // swprintf(FontSize, L"%2d (%d x %d)", pointsize, lplf->lfWidth, lplf->lfHeight); swprintf(FontSize, L"%d x %d", lplf->lfWidth, lplf->lfHeight); /* Make sure the size doesn't already exist in the list */ if (SendMessageW(hwndCombo, LB_FINDSTRINGEXACT, 0, (LPARAM)FontSize) == LB_ERR) { /* Add the size */ INT idx = (INT)SendMessageW(hwndCombo, LB_ADDSTRING, 0, (LPARAM)FontSize); /* * Store this information in the list-item's userdata area. * Format: * Width = FontSize.X = LOWORD(FontSize); * Height = FontSize.Y = HIWORD(FontSize); */ SendMessageW(hwndCombo, LB_SETITEMDATA, idx, MAKEWPARAM(lplf->lfWidth, lplf->lfHeight)); } return TRUE; } else { ULONG i; for (i = 0; i < sizeof(TrueTypePoints) / sizeof(TrueTypePoints[0]); ++i) { swprintf(FontSize, L"%2d", TrueTypePoints[i]); /* Make sure the size doesn't already exist in the list */ if (SendMessageW(hwndCombo, LB_FINDSTRINGEXACT, 0, (LPARAM)FontSize) == LB_ERR) { /* Add the size */ INT idx = (INT)SendMessageW(hwndCombo, LB_ADDSTRING, 0, (LPARAM)FontSize); /* * Store this information in the list-item's userdata area. * Format: * Width = FontSize.X = LOWORD(FontSize); * Height = FontSize.Y = HIWORD(FontSize); */ SendMessageW(hwndCombo, LB_SETITEMDATA, idx, MAKEWPARAM(0, TrueTypePoints[i])); } } return FALSE; } } static VOID FontSizeChange(HWND hwndDlg, PGUI_CONSOLE_INFO GuiInfo); static VOID FontTypeChange(HWND hwndDlg, PGUI_CONSOLE_INFO GuiInfo) { INT Length, nSel; LPWSTR FaceName; HDC hDC; LOGFONTW lf; nSel = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE, LB_GETCURSEL, 0, 0); if (nSel == LB_ERR) return; Length = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE, LB_GETTEXTLEN, nSel, 0); if (Length == LB_ERR) return; FaceName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (Length + 1) * sizeof(WCHAR)); if (FaceName == NULL) return; Length = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE, LB_GETTEXT, nSel, (LPARAM)FaceName); FaceName[Length] = '\0'; Length = min(Length/*wcslen(FaceName) + 1*/, LF_FACESIZE); // wcsnlen wcsncpy(GuiInfo->FaceName, FaceName, LF_FACESIZE); GuiInfo->FaceName[Length] = L'\0'; DPRINT1("GuiInfo->FaceName = '%S'\n", GuiInfo->FaceName); /* Enumerate the available sizes for the selected font */ ZeroMemory(&lf, sizeof(lf)); lf.lfCharSet = DEFAULT_CHARSET; // OEM_CHARSET; // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; wcsncpy(lf.lfFaceName, FaceName, LF_FACESIZE); lf.lfFaceName[Length] = L'\0'; hDC = GetDC(NULL); EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFontSizesProc, (LPARAM)GetDlgItem(hwndDlg, IDC_LBOX_FONTSIZE), 0); ReleaseDC(NULL, hDC); HeapFree(GetProcessHeap(), 0, FaceName); // TODO: Select a default font size???? FontSizeChange(hwndDlg, GuiInfo); // InvalidateRect(GetDlgItem(hwndDlg, IDC_STATIC_FONT_WINDOW_PREVIEW), NULL, TRUE); // InvalidateRect(GetDlgItem(hwndDlg, IDC_STATIC_SELECT_FONT_PREVIEW), NULL, TRUE); } static VOID FontSizeChange(HWND hwndDlg, PGUI_CONSOLE_INFO GuiInfo) { INT nSel; ULONG FontSize; WCHAR FontSizeStr[20]; nSel = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTSIZE, LB_GETCURSEL, 0, 0); if (nSel == LB_ERR) return; /* * Format: * Width = FontSize.X = LOWORD(FontSize); * Height = FontSize.Y = HIWORD(FontSize); */ FontSize = (ULONG)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTSIZE, LB_GETITEMDATA, nSel, 0); if (FontSize == LB_ERR) return; GuiInfo->FontSize.X = LOWORD(FontSize); GuiInfo->FontSize.Y = HIWORD(FontSize); DPRINT1("GuiInfo->FontSize = (%d x %d)\n", GuiInfo->FontSize.X, GuiInfo->FontSize.Y); InvalidateRect(GetDlgItem(hwndDlg, IDC_STATIC_FONT_WINDOW_PREVIEW), NULL, TRUE); InvalidateRect(GetDlgItem(hwndDlg, IDC_STATIC_SELECT_FONT_PREVIEW), NULL, TRUE); swprintf(FontSizeStr, L"%2d", GuiInfo->FontSize.X); SetWindowText(GetDlgItem(hwndDlg, IDC_FONT_SIZE_X), FontSizeStr); swprintf(FontSizeStr, L"%2d", GuiInfo->FontSize.Y); SetWindowText(GetDlgItem(hwndDlg, IDC_FONT_SIZE_Y), FontSizeStr); } INT_PTR CALLBACK FontProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { PCONSOLE_PROPS pConInfo = (PCONSOLE_PROPS)GetWindowLongPtr(hwndDlg, DWLP_USER); PGUI_CONSOLE_INFO GuiInfo = (pConInfo ? pConInfo->TerminalInfo.TermInfo : NULL); UNREFERENCED_PARAMETER(wParam); switch (uMsg) { case WM_INITDIALOG: { HDC hDC; LOGFONTW lf; INT idx; pConInfo = (PCONSOLE_PROPS)((LPPROPSHEETPAGE)lParam)->lParam; GuiInfo = pConInfo->TerminalInfo.TermInfo; SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pConInfo); ZeroMemory(&lf, sizeof(lf)); lf.lfCharSet = DEFAULT_CHARSET; // OEM_CHARSET; // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; hDC = GetDC(NULL); EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFontNamesProc, (LPARAM)GetDlgItem(hwndDlg, IDC_LBOX_FONTTYPE), 0); ReleaseDC(NULL, hDC); DPRINT1("GuiInfo->FaceName = '%S'\n", GuiInfo->FaceName); idx = (INT)SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE, LB_FINDSTRINGEXACT, 0, (LPARAM)GuiInfo->FaceName); if (idx != LB_ERR) SendDlgItemMessageW(hwndDlg, IDC_LBOX_FONTTYPE, LB_SETCURSEL, (WPARAM)idx, 0); FontTypeChange(hwndDlg, GuiInfo); return TRUE; } case WM_DRAWITEM: { LPDRAWITEMSTRUCT drawItem = (LPDRAWITEMSTRUCT)lParam; if (drawItem->CtlID == IDC_STATIC_FONT_WINDOW_PREVIEW) PaintConsole(drawItem, pConInfo); else if (drawItem->CtlID == IDC_STATIC_SELECT_FONT_PREVIEW) PaintText(drawItem, pConInfo, Screen); return TRUE; } case WM_NOTIFY: { switch (((LPNMHDR)lParam)->code) { case PSN_APPLY: { if (!pConInfo->AppliedConfig) { return ApplyConsoleInfo(hwndDlg, pConInfo); } else { /* Options have already been applied */ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); return TRUE; } break; } } break; } case WM_COMMAND: { switch (HIWORD(wParam)) { case LBN_SELCHANGE: { switch (LOWORD(wParam)) { case IDC_LBOX_FONTTYPE: { FontTypeChange(hwndDlg, GuiInfo); PropSheet_Changed(GetParent(hwndDlg), hwndDlg); break; } case IDC_LBOX_FONTSIZE: { FontSizeChange(hwndDlg, GuiInfo); PropSheet_Changed(GetParent(hwndDlg), hwndDlg); break; } } break; } } break; } default: break; } return FALSE; }