Notepad3/src/ChooseFont/ChooseFont.cpp

834 lines
30 KiB
C++

// 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 "ChooseFont.h"
#include "FontEnumeration.h"
#include "GdiTextRenderer.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:
explicit ChooseFontDialog(HWND hParent, const WCHAR* localeName, DPI_T dpi, LPCHOOSEFONT lpCFGDI);
virtual ~ChooseFontDialog();
ChooseFontDialog() = delete;
HRESULT GetTextFormat(IDWriteTextFormat** textFormat);
HRESULT GetTextFormat(IDWriteTextFormat* textFormatIn, IDWriteTextFormat** textFormatOut);
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;
HRESULT OnFontFamilySelect();
HRESULT OnFontFaceSelect();
HRESULT OnFontSizeSelect();
HRESULT OnFontFamilyNameEdit(HWND hwndFontFamilies);
HRESULT OnFontFaceNameEdit(HWND hwndFontFaces);
HRESULT OnFontSizeNameEdit(HWND hwndFontSizes);
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);
};
/******************************************************************
* *
* 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));
}
}
/******************************************************************
* *
* ChooseFontDialog::~ChooseFontDialog *
* *
* Clean up resources *
* *
******************************************************************/
ChooseFontDialog::~ChooseFontDialog()
{
SafeRelease(&m_fontCollection);
SafeRelease(&m_currentTextFormat);
SafeRelease(&m_renderTextFormat);
}
/******************************************************************
* *
* ChooseFontDialog::ChooseFontDialog *
* *
* Create and display the dialog initialized to default attributes *
* *
******************************************************************/
HRESULT ChooseFontDialog::GetTextFormat(IDWriteTextFormat** textFormat)
{
HRESULT hr = S_OK;
*textFormat = nullptr;
// Default to the system font collection
SafeRelease(&m_fontCollection);
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;
float const pointSize = static_cast<float>(m_chooseFontStruct->iPointSize) / 10.0f;
auto const fontWeight = static_cast<DWRITE_FONT_WEIGHT>(m_chooseFontStruct->lpLogFont->lfWeight); // TODO: mapping?
DWRITE_FONT_STYLE const fontStyle = (m_chooseFontStruct->lpLogFont->lfItalic ?
DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL);
DWRITE_FONT_STRETCH const fontStretch = DWRITE_FONT_STRETCH_NORMAL;
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<HRESULT>(DialogBoxParam(Globals.hLngResContainer, MAKEINTRESOURCE(IDD_MUI_CHOOSEFONT), m_parent, CFDialogProc, reinterpret_cast<LPARAM>(this)));
}
else {
hr = static_cast<HRESULT>(DialogBoxParam(g_hInstanceNP3, MAKEINTRESOURCE(IDD_MUI_CHOOSEFONT), m_parent, CFDialogProc, reinterpret_cast<LPARAM>(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)
{
HRESULT hr = S_OK;
*textFormatOut = nullptr;
SafeSet(&m_currentTextFormat, textFormatIn);
// Pull out the input font attributes
SafeRelease(&m_fontCollection);
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<HRESULT>(DialogBoxParam(Globals.hLngResContainer, MAKEINTRESOURCE(IDD_MUI_CHOOSEFONT), m_parent, CFDialogProc, reinterpret_cast<LPARAM>(this)));
}
else {
hr = static_cast<HRESULT>(DialogBoxParam(g_hInstanceNP3, MAKEINTRESOURCE(IDD_MUI_CHOOSEFONT), m_parent, CFDialogProc, reinterpret_cast<LPARAM>(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[100];
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<IDWriteFont*> 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> 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<ULONG>(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 fontFamilyName[100];
ComboBox_GetText(hwndFontFamilies, &fontFamilyName[0], _ARRAYSIZE(fontFamilyName));
// Try to find an exact match (case-insensitive)
int matchingFontFamily = ComboBox_FindStringExact(hwndFontFamilies, -1, fontFamilyName);
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, fontFamilyName, &fontFamily);
if (hr == S_OK) {
// 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, fontFamilyName);
// 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<ULONG>(ComboBox_GetItemData(hwndFontFaces, selectedFontFace));
// Get the font size
WCHAR fontSizeText[100];
GetWindowText(hwndFontSizes, &fontSizeText[0], _ARRAYSIZE(fontSizeText));
auto pointSize = static_cast<float>(wcstod(fontSizeText, nullptr));
if (pointSize <= 0.0f) { pointSize = 10.0f; }
FontFaceInfo 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);
// 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<float>((width * m_currentDPI.x) / GetDeviceCaps(sampleDC, LOGPIXELSX)),
static_cast<float>((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<ChooseFontDialog*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
if (this_ != nullptr) {
LPCFHOOKPROC hookFct = this_->m_chooseFontStruct->lpfnHook;
if (hookFct) {
(*hookFct)(hWnd, message, wParam, reinterpret_cast<LPARAM>(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;
HWND hwndFamilyNames = GetDlgItem(dialog, IDC_FONT_FAMILY_NAMES);
HWND hwndSizes = GetDlgItem(dialog, IDC_FONT_SIZE);
// Fill in the font family name list.
std::vector<std::wstring> 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 = round(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());
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,
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 pointSize = textFormat->GetFontSize();
DWRITE_FONT_WEIGHT const fontWeight = textFormat->GetFontWeight();
DWRITE_FONT_STYLE const fontStyle = textFormat->GetFontStyle();
StringCchCopy(lpCF->lpLogFont->lfFaceName, LF_FACESIZE, fontFamilyName);
lpCF->lpLogFont->lfHeight = -MulDiv(static_cast<int>(lround(pointSize)), GetDeviceCaps(lpCF->hDC, LOGPIXELSY), 72);
lpCF->iPointSize = static_cast<INT>(lround(pointSize * 10.0f));
lpCF->lpLogFont->lfWeight = static_cast<LONG>(fontWeight);
lpCF->lpLogFont->lfItalic = static_cast<BYTE>((((fontStyle == DWRITE_FONT_STYLE_ITALIC) ||
(fontStyle == DWRITE_FONT_STYLE_OBLIQUE)) ? TRUE : FALSE));
lpCF->lpLogFont->lfQuality = static_cast<BYTE>(CLEARTYPE_QUALITY);
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);
SetChosenFontFromTextFormat(textFormatOut, lpCFGDI, dpi);
SafeRelease(&textFormatOut);
SafeRelease(&g_dwrite);
return true;
}
// ############################################################################