// encoding: UTF-8 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved // //---------------------------------------------------------------------------- #include #include "ChooseFont.h" #include "FontEnumeration.h" #include "GdiTextRenderer.h" #include "Scintilla.h" extern "C" { #include "../resource.h" #include "TypeDefs.h" } //---------------------------------------------------------------------------- IDWriteFactory* g_dwrite = nullptr; static HINSTANCE g_hInstanceNP3; extern "C" void CenterDlgInParent(HWND hDlg); //============================================================================= // // LoadLngString() // static int LoadLngStringW(UINT uID, LPWSTR lpBuffer, int nBufferMax) { const int nLen = LoadStringW(Globals.hLngResContainer, uID, lpBuffer, nBufferMax); return (nLen != 0) ? nLen : LoadStringW(g_hInstanceNP3, uID, lpBuffer, nBufferMax); } /****************************************************************** * * * The ChooseFontDialog class controls all the UI associated with * * the dialog and uses the support routines in FontEnumeration.cpp * * to enumerate fonts and get various information about each one. * * * ******************************************************************/ class ChooseFontDialog { public: ChooseFontDialog(HWND hParent, const WCHAR* localeName, DPI_T dpi, LPCHOOSEFONT lpCFGDI); ~ChooseFontDialog(); ChooseFontDialog() = delete; HRESULT GetTextFormat(IDWriteTextFormat** textFormat); HRESULT GetTextFormat(IDWriteTextFormat* textFormatIn, IDWriteTextFormat** textFormatOut); void GetFontStyle(LPWSTR fontStyle, size_t cchMax); private: HWND m_parent; HWND m_dialog; WCHAR m_localeName[LOCALE_NAME_MAX_LENGTH]; DPI_T m_currentDPI; LPCHOOSEFONT m_chooseFontStruct; IDWriteFontCollection* m_fontCollection; IDWriteTextFormat* m_currentTextFormat; IDWriteTextFormat* m_renderTextFormat; WCHAR m_fontStyle[LF_FULLFACESIZE]; HRESULT OnFontFamilySelect(); HRESULT OnFontFaceSelect(); HRESULT OnFontSizeSelect(); HRESULT OnFontFamilyNameEdit(HWND hwndFontFamilies); HRESULT OnFontFaceNameEdit(HWND hwnd); HRESULT OnFontSizeNameEdit(HWND hwnd); HRESULT DrawSampleText(HDC sampleDC); static INT_PTR CALLBACK CFDialogProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); BOOL OnInitDialog(HWND dialog, HWND hwndFocus, LPARAM lParam); void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify); void OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT* lpDrawItem); }; void ChooseFontDialog::GetFontStyle(LPWSTR fontStyle, size_t cchMax) { StringCchCopy(fontStyle, cchMax, m_fontStyle); } /****************************************************************** * * * ChooseFontDialog::ChooseFontDialog * * * * Prepare to display the dialog * * * ******************************************************************/ ChooseFontDialog::ChooseFontDialog(HWND hParent, const WCHAR* localeName, const DPI_T dpi, LPCHOOSEFONT lpCFGDI) : m_parent(hParent) , m_dialog(nullptr) , m_currentDPI(dpi) , m_chooseFontStruct(lpCFGDI) , m_fontCollection(nullptr) , m_currentTextFormat(nullptr) , m_renderTextFormat(nullptr) { if (localeName != nullptr) { StringCchCopy(m_localeName, _ARRAYSIZE(m_localeName), localeName); } else { // Default to the users' locale //GetUserDefaultLocaleName(&m_localeName[0], COUNTOF(m_localeName)); GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, &m_localeName[0], _ARRAYSIZE(m_localeName)); } StringCchCopy(m_fontStyle, _ARRAYSIZE(m_fontStyle), L""); } /****************************************************************** * * * ChooseFontDialog::~ChooseFontDialog * * * * Clean up resources * * * ******************************************************************/ ChooseFontDialog::~ChooseFontDialog() { SafeRelease(&m_fontCollection); SafeRelease(&m_currentTextFormat); SafeRelease(&m_renderTextFormat); } /****************************************************************** * * * ChooseFontDialog::GetTextFormat * * * * Create and display the dialog initialized to default attributes * * * ******************************************************************/ static DWRITE_FONT_WEIGHT GetFontWeightValue(LONG fontWeight) { if (fontWeight < 150) { return DWRITE_FONT_WEIGHT_THIN; } else if (fontWeight < 250) { return DWRITE_FONT_WEIGHT_EXTRA_LIGHT; // == DWRITE_FONT_WEIGHT_ULTRA_LIGHT } else if (fontWeight < 325) { return DWRITE_FONT_WEIGHT_LIGHT; } else if (fontWeight < 375) { return DWRITE_FONT_WEIGHT_SEMI_LIGHT; } else if (fontWeight < 450) { return DWRITE_FONT_WEIGHT_NORMAL; // == DWRITE_FONT_WEIGHT_REGULAR } else if (fontWeight < 550) { return DWRITE_FONT_WEIGHT_MEDIUM; } else if (fontWeight < 650) { return DWRITE_FONT_WEIGHT_SEMI_BOLD; // == DWRITE_FONT_WEIGHT_DEMI_BOLD } else if (fontWeight < 750) { return DWRITE_FONT_WEIGHT_BOLD; } else if (fontWeight < 850) { return DWRITE_FONT_WEIGHT_EXTRA_BOLD; // == DWRITE_FONT_WEIGHT_ULTRA_BOLD } else if (fontWeight < 950) { return DWRITE_FONT_WEIGHT_HEAVY; // == DWRITE_FONT_WEIGHT_BLACK } return DWRITE_FONT_WEIGHT_ULTRA_BLACK; // == DWRITE_FONT_WEIGHT_EXTRA_BLACK } static DWRITE_FONT_STYLE GetFontStyleValue(LPCWSTR const fontStyle, bool bItalic) { if (StrStrI(fontStyle, L"oblique")) { return DWRITE_FONT_STYLE_OBLIQUE; } else if (StrStrI(fontStyle, L"italic") || bItalic) { return DWRITE_FONT_STYLE_ITALIC; } return DWRITE_FONT_STYLE_NORMAL; } static DWRITE_FONT_STRETCH GetFontStrechValue(LPCWSTR const fontStyle) { if (StrStrI(fontStyle, L"condensed")) { return DWRITE_FONT_STRETCH_CONDENSED; } else if (StrStrI(fontStyle, L"extended")) { return DWRITE_FONT_STRETCH_EXPANDED; } else if (StrStrI(fontStyle, L"expanded")) { return DWRITE_FONT_STRETCH_EXPANDED; } return DWRITE_FONT_STRETCH_NORMAL; } HRESULT ChooseFontDialog::GetTextFormat(IDWriteTextFormat** textFormat) { *textFormat = nullptr; // Default to the system font collection SafeRelease(&m_fontCollection); HRESULT hr = g_dwrite->GetSystemFontCollection(&m_fontCollection); // Create a default text format if (SUCCEEDED(hr)) { SafeRelease(&m_currentTextFormat); const WCHAR* const fontFamilyName = m_chooseFontStruct->lpLogFont->lfFaceName; const WCHAR* const fontStyleStrg = m_chooseFontStruct->lpszStyle; float const pointSize = static_cast(m_chooseFontStruct->iPointSize) / 10.0f; DWRITE_FONT_WEIGHT const fontWeight = GetFontWeightValue(m_chooseFontStruct->lpLogFont->lfWeight); DWRITE_FONT_STYLE const fontStyle = GetFontStyleValue(fontStyleStrg, m_chooseFontStruct->lpLogFont->lfItalic); DWRITE_FONT_STRETCH const fontStretch = GetFontStrechValue(fontStyleStrg); hr = g_dwrite->CreateTextFormat( fontFamilyName, m_fontCollection, fontWeight, fontStyle, fontStretch, pointSize, m_localeName, &m_currentTextFormat); } // Open the dialog if (SUCCEEDED(hr)) { if (Globals.hLngResContainer) { hr = static_cast(DialogBoxParam(Globals.hLngResContainer, MAKEINTRESOURCE(IDD_MUI_CHOOSEFONT), m_parent, CFDialogProc, reinterpret_cast(this))); } else { hr = static_cast(DialogBoxParam(g_hInstanceNP3, MAKEINTRESOURCE(IDD_MUI_CHOOSEFONT), m_parent, CFDialogProc, reinterpret_cast(this))); } } // If all went well, and the user didn't cancel, return the new format. if (hr == S_OK) { *textFormat = SafeDetach(&m_currentTextFormat); } return hr; } /****************************************************************** * * * ChooseFontDialog::ChooseFontDialog * * * * Create and display the dialog initialized to attributes in an * * already existing text format. * * * ******************************************************************/ HRESULT ChooseFontDialog::GetTextFormat(IDWriteTextFormat* textFormatIn, IDWriteTextFormat** textFormatOut) { *textFormatOut = nullptr; SafeSet(&m_currentTextFormat, textFormatIn); // Pull out the input font attributes SafeRelease(&m_fontCollection); HRESULT hr = m_currentTextFormat->GetFontCollection(&m_fontCollection); if (SUCCEEDED(hr)) { hr = m_currentTextFormat->GetLocaleName(&m_localeName[0], _ARRAYSIZE(m_localeName)); } // Open the dialog if (SUCCEEDED(hr)) { if (Globals.hLngResContainer) { hr = static_cast(DialogBoxParam(Globals.hLngResContainer, MAKEINTRESOURCE(IDD_MUI_CHOOSEFONT), m_parent, CFDialogProc, reinterpret_cast(this))); } else { hr = static_cast(DialogBoxParam(g_hInstanceNP3, MAKEINTRESOURCE(IDD_MUI_CHOOSEFONT), m_parent, CFDialogProc, reinterpret_cast(this))); } } // If all went well, and the user didn't cancel, return the new format. if (hr == S_OK) { *textFormatOut = SafeDetach(&m_currentTextFormat); } return hr; } /****************************************************************** * * * ChooseFontDialog::OnFontFamilySelect * * * * Update the font face list to match the newly select font family * * * ******************************************************************/ HRESULT ChooseFontDialog::OnFontFamilySelect() { HRESULT hr = S_OK; HWND hwndFontFamilyNames = GetDlgItem(m_dialog, IDC_FONT_FAMILY_NAMES); HWND hwndFontFaceNames = GetDlgItem(m_dialog, IDC_FONT_FACE_NAMES); int currentSelection = ComboBox_GetCurSel(hwndFontFamilyNames); // Get the font family name WCHAR fontFamilyName[128]; UINT32 fontFamilyNameLength = ComboBox_GetLBTextLen(hwndFontFamilyNames, currentSelection) + 1; if (fontFamilyNameLength > _ARRAYSIZE(fontFamilyName)) { hr = E_NOT_SUFFICIENT_BUFFER; } if (SUCCEEDED(hr)) { ComboBox_GetLBText(hwndFontFamilyNames, currentSelection, &fontFamilyName[0]); } // Get the face names for the new font family IDWriteFontFamily* fontFamily = nullptr; std::vector fonts; // Get the font variants for this family if (currentSelection != CB_ERR) { hr = GetFonts(m_fontCollection, fontFamilyName, fonts); } // Initialize the face name list std::vector fontFaceInfo; if (SUCCEEDED(hr)) { ComboBox_ResetContent(hwndFontFaceNames); GetFontFaceInfo(fonts, m_localeName, fontFaceInfo); } if (SUCCEEDED(hr)) { for (size_t i = 0; i != fontFaceInfo.size(); ++i) { int fontFaceIndex = ComboBox_AddString(hwndFontFaceNames, fontFaceInfo[i].fontFaceName); ComboBox_SetItemData(hwndFontFaceNames, fontFaceIndex, fontFaceInfo[i].PackedFontAttributes()); } } // Select the best fit font face for the current attributes if (SUCCEEDED(hr)) { FontFaceInfo desiredAttributes( L"", m_currentTextFormat->GetFontWeight(), m_currentTextFormat->GetFontStyle(), m_currentTextFormat->GetFontStretch()); int selectedFontFaceName = 0; ULONG bestFitAttributes = GetBestFontAttributes(m_fontCollection, fontFamilyName, desiredAttributes); int fontFaceCount = ComboBox_GetCount(hwndFontFaceNames); for (int i = 0; i != fontFaceCount; ++i) { if (static_cast(ComboBox_GetItemData(hwndFontFaceNames, i)) == bestFitAttributes) { selectedFontFaceName = i; break; } } ComboBox_SetCurSel(hwndFontFaceNames, selectedFontFaceName); OnFontFaceSelect(); } // Release the held font list. for (auto& font : fonts) { SafeRelease(&font); } SafeRelease(&fontFamily); return hr; } /****************************************************************** * * * ChooseFontDialog::OnFontFaceSelect * * * * Record the new font face selection and redraw the sample text. * * * ******************************************************************/ HRESULT ChooseFontDialog::OnFontFaceSelect() { HRESULT hr = S_OK; // Signal the sample text window to redraw itself. InvalidateRect(GetDlgItem(m_dialog, IDC_SAMPLE_BOX), nullptr, false); return hr; } /****************************************************************** * * * ChooseFontDialog::OnFontSizeSelect * * * * Record the new font size and redraw the sample text. * * * ******************************************************************/ HRESULT ChooseFontDialog::OnFontSizeSelect() { HRESULT hr = S_OK; // Signal the sample text window to redraw itself. InvalidateRect(GetDlgItem(m_dialog, IDC_SAMPLE_BOX), nullptr, false); return hr; } /****************************************************************** * * * ChooseFontDialog::OnFontFamilyNameEdit * * * * Watch what is typed into the edit portion of the font family * * combo and automatically select a name if a match is found. As * * an added feature, also match against localized forms of the * * family name. For example the user can type "Meiryo" on a * * Japanese system and it will be found even though it's displayed * * using a localized variant of the name. * * * ******************************************************************/ HRESULT ChooseFontDialog::OnFontFamilyNameEdit(HWND hwndFontFamilies) { HRESULT hr = S_OK; // Save the state of the edit box selection DWORD editSelection = ComboBox_GetEditSel(hwndFontFamilies); int editSelectionBegin = LOWORD(editSelection); int editSelectionEnd = HIWORD(editSelection); // Get the text in the edit portion of the combo WCHAR fontFullName[128]; ComboBox_GetText(hwndFontFamilies, &fontFullName[0], _ARRAYSIZE(fontFullName)); // Try to find an exact match (case-insensitive) WCHAR fontFamilyName[128]; StringCchCopyW(fontFamilyName, ARRAYSIZE(fontFamilyName), fontFullName); int matchingFontFamily = CB_ERR; PTSTR pSpc = NULL; do { //matchingFontFamily = ComboBox_FindStringExact(hwndFontFamilies, -1, fontFullName); matchingFontFamily = ComboBox_FindString(hwndFontFamilies, -1, fontFamilyName); if (matchingFontFamily == CB_ERR) { pSpc = StrRChrIW(fontFamilyName, NULL, L' '); if (pSpc != NULL) { *pSpc = L'\0'; } } } while ((matchingFontFamily == CB_ERR) && (pSpc != NULL)); bool usedAltMatch = false; if (matchingFontFamily == CB_ERR) { // If a match isn't found, scan all for alternate forms in the font // collection. IDWriteFontFamily* fontFamily = nullptr; hr = GetFontFamily(m_fontCollection, fontFullName, &fontFamily); if (SUCCEEDED(hr)) { // If a match is found, get the family name localized to the locale // we're using in the combo box and match against that. usedAltMatch = true; std::wstring localFontFamilyName; hr = GetFontFamilyName(fontFamily, m_localeName, localFontFamilyName); if (SUCCEEDED(hr)) { matchingFontFamily = ComboBox_FindStringExact(hwndFontFamilies, -1, localFontFamilyName.c_str()); } } else if (hr == DWRITE_E_NOFONT) { // Ignore DWRITE_E_NOFONT errors hr = S_OK; } SafeRelease(&fontFamily); } // Process the match, if any if (SUCCEEDED(hr) && matchingFontFamily != CB_ERR) { ComboBox_SetCurSel(hwndFontFamilies, matchingFontFamily); // SetCurSel will update the edit text to match the text of the // selected item. If we matched against an alternate name put that // name back. if (usedAltMatch) { ComboBox_SetText(hwndFontFamilies, fontFullName); } // Reset the edit selection to what is was before SetCurSel. ComboBox_SetEditSel(hwndFontFamilies, editSelectionBegin, editSelectionEnd); hr = OnFontFamilySelect(); } return hr; } /****************************************************************** * * * ChooseFontDialog::OnFontFaceNameEdit * * * * Watch what is typed into the edit portion of the font face * * combo and automatically select a name if a match is found. * * * ******************************************************************/ HRESULT ChooseFontDialog::OnFontFaceNameEdit(HWND hwnd) { HRESULT hr = S_OK; // Save the state of the edit box selection DWORD editSelection = ComboBox_GetEditSel(hwnd); int editSelectionBegin = LOWORD(editSelection); int editSelectionEnd = HIWORD(editSelection); // Try to find the currently typed text WCHAR text[100]; ComboBox_GetText(hwnd, &text[0], _ARRAYSIZE(text)); int selectedItem = ComboBox_FindStringExact(hwnd, -1, text); if (selectedItem != CB_ERR) { // If text is found, select the corresponding list item, put the // selection state back to what it was originally, and redraw the // sample text ComboBox_SetCurSel(hwnd, selectedItem); ComboBox_SetEditSel(hwnd, editSelectionBegin, editSelectionEnd); hr = OnFontFaceSelect(); } return hr; } /****************************************************************** * * * ChooseFontDialog::OnFontSizeNameEdit * * * * Watch what is typed into the edit portion of the font size * * combo and automatically select a name if a match is found. * * * ******************************************************************/ HRESULT ChooseFontDialog::OnFontSizeNameEdit(HWND hwnd) { HRESULT hr = S_OK; // Save the state of the edit box selection DWORD editSelection = ComboBox_GetEditSel(hwnd); int editSelectionBegin = LOWORD(editSelection); int editSelectionEnd = HIWORD(editSelection); // Try to find the currently typed text WCHAR text[100]; ComboBox_GetText(hwnd, &text[0], _ARRAYSIZE(text)); int selectedItem = ComboBox_FindStringExact(hwnd, -1, text); if (selectedItem != CB_ERR) { // If text is found, select the corresponding list item, put the // selection state back to what it was originally, and redraw the // sample text ComboBox_SetCurSel(hwnd, selectedItem); ComboBox_SetEditSel(hwnd, editSelectionBegin, editSelectionEnd); } hr = OnFontSizeSelect(); return hr; } /****************************************************************** * * * ChooseFontDialog::DrawSampleText * * * ******************************************************************/ HRESULT ChooseFontDialog::DrawSampleText(HDC sampleDC) { static WCHAR sampleText[256] = { L'\0' }; if (sampleText[0] == L'\0') { LoadLngStringW(IDS_MUI_EXAMPLE_TEXT, sampleText, _ARRAYSIZE(sampleText)); } HRESULT hr = S_OK; HWND hwndFontFamilies = GetDlgItem(m_dialog, IDC_FONT_FAMILY_NAMES); HWND hwndFontFaces = GetDlgItem(m_dialog, IDC_FONT_FACE_NAMES); HWND hwndFontSizes = GetDlgItem(m_dialog, IDC_FONT_SIZE); HWND hwndSampleBox = GetDlgItem(m_dialog, IDC_SAMPLE_BOX); // Get the currently selected font family. If there isn't one, then just // don't update the text format and continue to use whatever we had before int selectedFontFamily = ComboBox_GetCurSel(hwndFontFamilies); if (selectedFontFamily != CB_ERR) { // Get the font family name WCHAR fontFamilyName[100]; GetWindowText(hwndFontFamilies, &fontFamilyName[0], _ARRAYSIZE(fontFamilyName)); // Get the font face attributes int selectedFontFace = ComboBox_GetCurSel(hwndFontFaces); auto packedAttributes = static_cast(ComboBox_GetItemData(hwndFontFaces, selectedFontFace)); // Get the full font style ComboBox_GetText(hwndFontFaces, m_fontStyle, _ARRAYSIZE(m_fontStyle)); // Get the font size WCHAR fontSizeText[100]; GetWindowText(hwndFontSizes, &fontSizeText[0], _ARRAYSIZE(fontSizeText)); auto pointSize = static_cast(wcstod(fontSizeText, nullptr)); if (pointSize <= 0.0f) { pointSize = 10.0f; } FontFaceInfo const fontFaceInfo(fontFamilyName, packedAttributes); // Recreate current text format object SafeRelease(&m_currentTextFormat); hr = g_dwrite->CreateTextFormat( fontFamilyName, m_fontCollection, fontFaceInfo.fontWeight, fontFaceInfo.fontStyle, fontFaceInfo.fontStretch, pointSize, m_localeName, &m_currentTextFormat); if (SUCCEEDED(hr)) { // Create the rendering text format object float dipSize = (pointSize * m_currentDPI.y) / 72.0f; SafeRelease(&m_renderTextFormat); hr = g_dwrite->CreateTextFormat( fontFamilyName, m_fontCollection, fontFaceInfo.fontWeight, fontFaceInfo.fontStyle, fontFaceInfo.fontStretch, dipSize, m_localeName, &m_renderTextFormat); } } // Get the size of the sample box RECT sampleBounds = {}; GetClientRect(hwndSampleBox, &sampleBounds); UINT width = sampleBounds.right - sampleBounds.left; UINT height = sampleBounds.bottom - sampleBounds.top; // Layout the sample text using the text format and UI bounds (converted to DIPs) IDWriteTextLayout* textLayout = nullptr; if (SUCCEEDED(hr)) { hr = g_dwrite->CreateTextLayout( sampleText, _ARRAYSIZE(sampleText) - 1, m_renderTextFormat, static_cast((width * m_currentDPI.x) / GetDeviceCaps(sampleDC, LOGPIXELSX)), static_cast((height * m_currentDPI.y) / GetDeviceCaps(sampleDC, LOGPIXELSY)), &textLayout); } // Create a DWrite surface to render to GdiTextRenderer* textRenderer = nullptr; if (SUCCEEDED(hr)) { textRenderer = SafeAcquire(new(std::nothrow) GdiTextRenderer()); if (textRenderer != nullptr) { hr = textRenderer->Initialize(m_dialog, sampleDC, width, height); } else { hr = E_FAIL; } } if (SUCCEEDED(hr)) { // Fill the DWrite surface with the background color HDC dwriteDC = textRenderer->GetDC(); SetDCBrushColor(dwriteDC, GetSysColor(COLOR_BTNFACE)); FillRect(dwriteDC, &sampleBounds, GetStockBrush(DC_BRUSH)); // Draw the text onto the DWrite surface hr = textLayout->Draw(nullptr, textRenderer, 0, 0); // Copy the DWrite surface to the sample on screen BitBlt( sampleDC, 0, 0, width, height, dwriteDC, 0, 0, SRCCOPY | NOMIRRORBITMAP); } SafeRelease(&textRenderer); SafeRelease(&textLayout); return hr; } /****************************************************************** * * * ChooseFontDialog::WndProc * * * * Dispatch window message to the appropriate hander * * * ******************************************************************/ INT_PTR CALLBACK ChooseFontDialog::CFDialogProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_INITDIALOG) { SetWindowLongPtr(hWnd, GWLP_USERDATA, lParam); } auto this_ = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); if (this_ != nullptr) { LPCFHOOKPROC hookFct = this_->m_chooseFontStruct->lpfnHook; if (hookFct) { (*hookFct)(hWnd, message, wParam, reinterpret_cast(this_->m_chooseFontStruct)); } switch (message) { HANDLE_MSG(hWnd, WM_INITDIALOG, this_->OnInitDialog); HANDLE_MSG(hWnd, WM_COMMAND, this_->OnCommand); HANDLE_MSG(hWnd, WM_DRAWITEM, this_->OnDrawItem); } } return FALSE; } /****************************************************************** * * * ChooseFontDialog::OnInitDialog * * * * Initialize the dialog by enumerating the font families and * * setting up a hardcoded list of standard font sizes. * * * ******************************************************************/ BOOL ChooseFontDialog::OnInitDialog(HWND dialog, HWND hwndFocus, LPARAM lParam) { m_dialog = dialog; SET_NP3_DLG_ICON_SMALL(dialog); HWND hwndFamilyNames = GetDlgItem(dialog, IDC_FONT_FAMILY_NAMES); HWND hwndSizes = GetDlgItem(dialog, IDC_FONT_SIZE); // Fill in the font family name list. std::vector fontFamilyNames; if (FAILED(GetFontFamilyNames(m_fontCollection, m_localeName, fontFamilyNames))) { return FALSE; } for (size_t i = 0; i != fontFamilyNames.size(); ++i) { ComboBox_AddString(hwndFamilyNames, fontFamilyNames[i].c_str()); } // Fill in the hardcoded font sizes static const float FontSizes[] = { 1.5, 2.5, 3.5, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 8.5, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.5, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 28, 30, 36, 48, 60, 72, 84, 96 }; WCHAR sizeName[100]; sizeName[0] = '\0'; for (int i = 0; i != _ARRAYSIZE(FontSizes); ++i) { StringCchPrintf(sizeName, _ARRAYSIZE(sizeName), L"%.3G", FontSizes[i]); ComboBox_AddString(hwndSizes, sizeName); } // Select the current size float fCurFontSize = roundf(m_currentTextFormat->GetFontSize() * 10.0f) / 10.0f; StringCchPrintf(sizeName, _ARRAYSIZE(sizeName), L"%.3G", fCurFontSize); SetWindowText(hwndSizes, sizeName); if (CB_ERR == ComboBox_SelectString(hwndSizes, -1, sizeName)) { SetWindowText(hwndSizes, sizeName); } // Select the font family specified in the input text format. int selectedFontFamily = CB_ERR; std::wstring fontFamilyName; if (SUCCEEDED(GetFontFamilyNameFromFormat(m_currentTextFormat, fontFamilyName))) { selectedFontFamily = ComboBox_SelectString(hwndFamilyNames, -1, fontFamilyName.c_str()); } if (selectedFontFamily == CB_ERR) { SetWindowText(hwndFamilyNames, fontFamilyName.c_str()); OnFontFamilyNameEdit(hwndFamilyNames); } OnFontFamilySelect(); CenterDlgInParent(m_dialog); return TRUE; } /****************************************************************** * * * ChooseFontDialog::OnCommand * * * * Dispatch button clicks, changing listbox selections, etc. * * * ******************************************************************/ void ChooseFontDialog::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) { if (id == IDCANCEL && codeNotify == BN_CLICKED) { EndDialog(hwnd, S_FALSE); } else if (id == IDOK && codeNotify == BN_CLICKED) { EndDialog(hwnd, S_OK); } else if (id == IDC_FONT_FAMILY_NAMES && codeNotify == CBN_SELCHANGE) { OnFontFamilySelect(); } else if (id == IDC_FONT_FAMILY_NAMES && codeNotify == CBN_EDITCHANGE) { OnFontFamilyNameEdit(hwndCtl); } else if (id == IDC_FONT_FACE_NAMES && codeNotify == CBN_SELCHANGE) { OnFontFaceSelect(); } else if (id == IDC_FONT_FACE_NAMES && codeNotify == CBN_EDITCHANGE) { OnFontFaceNameEdit(hwndCtl); } else if (id == IDC_FONT_SIZE && codeNotify == CBN_SELCHANGE) { OnFontSizeSelect(); } else if (id == IDC_FONT_SIZE && codeNotify == CBN_EDITCHANGE) { OnFontSizeNameEdit(hwndCtl); } } /****************************************************************** * * * ChooseFontDialog::OnDrawItem * * * * Redraw the sample text whenever it's window needs updating * * * ******************************************************************/ void ChooseFontDialog::OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT* lpDrawItem) { DrawSampleText(lpDrawItem->hDC); } // ############################################################################ // ############################################################################ static void SetChosenFontFromTextFormat( IDWriteTextFormat* textFormat, LPCWSTR fontStyleStrg, LPCHOOSEFONT lpCF, const DPI_T dpi) { if (textFormat != nullptr) { WCHAR fontFamilyName[100]; HDC hdc = GetDC(lpCF->hwndOwner); textFormat->GetFontFamilyName(&fontFamilyName[0], _ARRAYSIZE(fontFamilyName)); float const fFontSize = textFormat->GetFontSize(); DWRITE_FONT_WEIGHT const fontWeight = textFormat->GetFontWeight(); DWRITE_FONT_STYLE const fontStyle = textFormat->GetFontStyle(); //DWRITE_FONT_STRETCH const fontStretch = textFormat->GetFontStretch(); // copy font family name here, will be corrected on post processing step StringCchCopy(lpCF->lpLogFont->lfFaceName, LF_FACESIZE, fontFamilyName); // family name only here lpCF->iPointSize = static_cast(lroundf(fFontSize * 10.0f)); lpCF->lpLogFont->lfHeight = -MulDiv(static_cast(lround(fFontSize * SC_FONT_SIZE_MULTIPLIER)), GetDeviceCaps(hdc, LOGPIXELSY), 72 * SC_FONT_SIZE_MULTIPLIER); lpCF->lpLogFont->lfWeight = fontWeight; lpCF->lpLogFont->lfItalic = static_cast((fontStyle != DWRITE_FONT_STYLE_NORMAL) ? TRUE : FALSE); //~lpCF->lpLogFont->lfQuality = static_cast(CLEARTYPE_QUALITY); StringCchCopy(lpCF->lpszStyle, LF_FULLFACESIZE, fontStyleStrg ? fontStyleStrg : L""); ReleaseDC(lpCF->hwndOwner, hdc); } } // ============================================================================ extern "C" bool ChooseFontDirectWrite(HWND hwnd, const WCHAR* localeName, DPI_T dpi, LPCHOOSEFONT lpCFGDI) { if (!lpCFGDI) { return false; } // The Microsoft Security Development Lifecycle recommends that all // applications include the following call to ensure that heap corruptions // do not go unnoticed and therefore do not introduce opportunities // for security exploits. HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0); if (dpi.x == 0) { dpi.x = dpi.y = USER_DEFAULT_SCREEN_DPI; } g_hInstanceNP3 = lpCFGDI->hInstance; DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), (IUnknown **)&g_dwrite); IDWriteTextFormat* textFormatOut = nullptr; ChooseFontDialog chooseFont(hwnd, localeName, dpi, lpCFGDI); chooseFont.GetTextFormat(&textFormatOut); WCHAR fontStyle[LF_FULLFACESIZE] = { L'\0' }; chooseFont.GetFontStyle(fontStyle, _ARRAYSIZE(fontStyle)); SetChosenFontFromTextFormat(textFormatOut, fontStyle, lpCFGDI, dpi); SafeRelease(&textFormatOut); SafeRelease(&g_dwrite); return true; } // ############################################################################