269 lines
7.9 KiB
C++
269 lines
7.9 KiB
C++
// 14 april 2016
|
|
#include "uipriv_windows.h"
|
|
|
|
struct fontDialog {
|
|
HWND hwnd;
|
|
HWND familyCombobox;
|
|
HWND styleCombobox;
|
|
HWND sizeCombobox;
|
|
// TODO desc;
|
|
fontCollection *fc;
|
|
IDWriteFontFamily **families;
|
|
UINT32 nFamilies;
|
|
};
|
|
|
|
static LRESULT cbAddString(HWND cb, WCHAR *str)
|
|
{
|
|
LRESULT lr;
|
|
|
|
lr = SendMessageW(cb, CB_ADDSTRING, 0, (LPARAM) str);
|
|
if (lr == (LRESULT) CB_ERR || lr == (LRESULT) CB_ERRSPACE)
|
|
logLastError("error adding item to combobox in cbAddString()");
|
|
return lr;
|
|
}
|
|
|
|
static LRESULT cbInsertStringAtTop(HWND cb, WCHAR *str)
|
|
{
|
|
LRESULT lr;
|
|
|
|
lr = SendMessageW(cb, CB_INSERTSTRING, 0, (LPARAM) str);
|
|
if (lr == (LRESULT) CB_ERR || lr == (LRESULT) CB_ERRSPACE)
|
|
logLastError("error inserting item to combobox in cbInsertStringAtTop()");
|
|
return lr;
|
|
}
|
|
|
|
static void wipeStylesBox(struct fontDialog *f)
|
|
{
|
|
IDWriteFont *font;
|
|
LRESULT i, n;
|
|
|
|
n = SendMessageW(f->styleCombobox, CB_GETCOUNT, 0, 0);
|
|
if (n == (LRESULT) CB_ERR)
|
|
logLastError("error getting combobox item count in wipeStylesBox()");
|
|
for (i = 0; i < n; i++) {
|
|
font = (IDWriteFont *) SendMessageW(f->styleCombobox, CB_GETITEMDATA, (WPARAM) i, 0);
|
|
if (font == (IDWriteFont *) CB_ERR)
|
|
logLastError("error getting font to release it in wipeStylesBox()");
|
|
font->Release();
|
|
}
|
|
SendMessageW(f->styleCombobox, CB_RESETCONTENT, 0, 0);
|
|
}
|
|
|
|
static WCHAR *fontStyleName(struct fontDialog *f, IDWriteFont *font)
|
|
{
|
|
IDWriteLocalizedStrings *str;
|
|
BOOL exists;
|
|
WCHAR *wstr;
|
|
HRESULT hr;
|
|
|
|
// first try this; if this is present, use it...
|
|
hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_PREFERRED_SUBFAMILY_NAMES, &str, &exists);
|
|
if (hr != S_OK)
|
|
logHRESULT("error getting preferred subfamily string in fontStyleName()", hr);
|
|
if (exists)
|
|
goto good;
|
|
|
|
// ...otherwise this font is good enough to be part of the main one on GDI as well, so try that name
|
|
hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES, &str, &exists);
|
|
if (hr != S_OK)
|
|
logHRESULT("error getting Win32 subfamily string in fontStyleName()", hr);
|
|
// TODO what if !exists?
|
|
|
|
good:
|
|
wstr = fontCollectionCorrectString(f->fc, str);
|
|
str->Release();
|
|
return wstr;
|
|
}
|
|
|
|
static void familyChanged(struct fontDialog *f)
|
|
{
|
|
LRESULT n;
|
|
IDWriteFontList *specifics;
|
|
IDWriteFont *specific;
|
|
UINT32 i, ns;
|
|
WCHAR *label;
|
|
LRESULT pos;
|
|
HRESULT hr;
|
|
|
|
wipeStylesBox(f);
|
|
|
|
n = SendMessageW(f->familyCombobox, CB_GETCURSEL, 0, 0);
|
|
if (n == (LRESULT) CB_ERR)
|
|
return; // TODO restore previous selection
|
|
|
|
// TODO figure out what the correct sort order is
|
|
hr = f->families[n]->GetMatchingFonts(
|
|
DWRITE_FONT_WEIGHT_NORMAL,
|
|
DWRITE_FONT_STRETCH_NORMAL,
|
|
DWRITE_FONT_STYLE_NORMAL,
|
|
&specifics);
|
|
if (hr != S_OK)
|
|
logHRESULT("error getting styles for font in familyChanged()", hr);
|
|
|
|
// TODO test mutliple streteches; all the fonts I have have only one stretch value
|
|
ns = specifics->GetFontCount();
|
|
for (i = 0; i < ns; i++) {
|
|
hr = specifics->GetFont(i, &specific);
|
|
if (hr != S_OK)
|
|
logHRESULT("error getting font for filling styles box in familyChanged()", hr);
|
|
label = fontStyleName(f, specific);
|
|
pos = cbAddString(f->styleCombobox, label);
|
|
uiFree(label);
|
|
if (SendMessageW(f->styleCombobox, CB_SETITEMDATA, (WPARAM) pos, (LPARAM) specific) == (LRESULT) CB_ERR)
|
|
logLastError("error setting font data in styles box in familyChanged()");
|
|
}
|
|
|
|
// TODO do we preserve style selection?
|
|
}
|
|
|
|
static struct fontDialog *beginFontDialog(HWND hwnd, LPARAM lParam)
|
|
{
|
|
struct fontDialog *f;
|
|
UINT32 i;
|
|
WCHAR *wname;
|
|
LRESULT ten;
|
|
HRESULT hr;
|
|
|
|
f = uiNew(struct fontDialog);
|
|
f->hwnd = hwnd;
|
|
|
|
f->familyCombobox = GetDlgItem(f->hwnd, rcFontFamilyCombobox);
|
|
if (f->familyCombobox == NULL)
|
|
logLastError("error getting font family combobox handle in beginFontDialog()");
|
|
f->styleCombobox = GetDlgItem(f->hwnd, rcFontStyleCombobox);
|
|
if (f->styleCombobox == NULL)
|
|
logLastError("error getting font style combobox handle in beginFontDialog()");
|
|
f->sizeCombobox = GetDlgItem(f->hwnd, rcFontSizeCombobox);
|
|
if (f->sizeCombobox == NULL)
|
|
logLastError("error getting font size combobox handle in beginFontDialog()");
|
|
|
|
f->fc = loadFontCollection();
|
|
f->nFamilies = f->fc->fonts->GetFontFamilyCount();
|
|
f->families = new IDWriteFontFamily *[f->nFamilies];
|
|
for (i = 0; i < f->nFamilies; i++) {
|
|
hr = f->fc->fonts->GetFontFamily(i, &(f->families[i]));
|
|
if (hr != S_OK)
|
|
logHRESULT("error getting font family in beginFontDialog()", hr);
|
|
wname = fontCollectionFamilyName(f->fc, f->families[i]);
|
|
cbAddString(f->familyCombobox, wname);
|
|
uiFree(wname);
|
|
}
|
|
|
|
// TODO all comboboxes should select on type; these already scroll on type but not select
|
|
|
|
// TODO behavior for the real thing:
|
|
// - if prior size is in list, select and scroll to it
|
|
// - if not, select nothing and don't scroll list at all (keep at top)
|
|
// we do 8 and 9 later
|
|
ten = cbAddString(f->sizeCombobox, L"10");
|
|
cbAddString(f->sizeCombobox, L"11");
|
|
cbAddString(f->sizeCombobox, L"12");
|
|
cbAddString(f->sizeCombobox, L"14");
|
|
cbAddString(f->sizeCombobox, L"16");
|
|
cbAddString(f->sizeCombobox, L"18");
|
|
cbAddString(f->sizeCombobox, L"20");
|
|
cbAddString(f->sizeCombobox, L"22");
|
|
cbAddString(f->sizeCombobox, L"24");
|
|
cbAddString(f->sizeCombobox, L"26");
|
|
cbAddString(f->sizeCombobox, L"28");
|
|
cbAddString(f->sizeCombobox, L"36");
|
|
cbAddString(f->sizeCombobox, L"48");
|
|
cbAddString(f->sizeCombobox, L"72");
|
|
if (SendMessageW(f->sizeCombobox, CB_SETCURSEL, (WPARAM) ten, 0) != ten)
|
|
logLastError("error selecting 10 in the size combobox in beginFontDialog()");
|
|
// if we just use CB_ADDSTRING 8 and 9 will appear at the bottom of the list due to lexicographical sorting
|
|
// if we use CB_INSERTSTRING instead it won't
|
|
cbInsertStringAtTop(f->sizeCombobox, L"9");
|
|
cbInsertStringAtTop(f->sizeCombobox, L"8");
|
|
// 10 moved because of the above; figure out where it is now
|
|
// we selected it earlier; getting the selection is easiest
|
|
ten = SendMessageW(f->sizeCombobox, CB_GETCURSEL, 0, 0);
|
|
// and finally put 10 at the top to imitate ChooseFont()
|
|
if (SendMessageW(f->sizeCombobox, CB_SETTOPINDEX, (WPARAM) ten, 0) != 0)
|
|
logLastError("error making 10 visible in the size combobox in beginFontDialog()");
|
|
|
|
// note: we can't add ES_NUMBER to the combobox entry (it seems to disable the entry instead?!), so we must do validation when the box is dmissed; TODO
|
|
|
|
// TODO actually select Arial
|
|
if (SendMessageW(f->familyCombobox, CB_SETCURSEL, (WPARAM) 0, 0) != 0)
|
|
logLastError("error selecting Arial in the family combobox in beginFontDialog()");
|
|
familyChanged(f);
|
|
|
|
return f;
|
|
}
|
|
|
|
static void endFontDialog(struct fontDialog *f, INT_PTR code)
|
|
{
|
|
UINT32 i;
|
|
|
|
wipeStylesBox(f);
|
|
for (i = 0; i < f->nFamilies; i++)
|
|
f->families[i]->Release();
|
|
delete[] f->families;
|
|
fontCollectionFree(f->fc);
|
|
if (EndDialog(f->hwnd, code) == 0)
|
|
logLastError("error ending font dialog in endFontDialog()");
|
|
uiFree(f);
|
|
}
|
|
|
|
static INT_PTR tryFinishDialog(struct fontDialog *f, WPARAM wParam)
|
|
{
|
|
// cancelling
|
|
if (LOWORD(wParam) != IDOK) {
|
|
endFontDialog(f, 1);
|
|
return TRUE;
|
|
}
|
|
|
|
// TODO
|
|
|
|
endFontDialog(f, 2);
|
|
return TRUE;
|
|
}
|
|
|
|
static INT_PTR CALLBACK fontDialogDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
struct fontDialog *f;
|
|
|
|
f = (struct fontDialog *) GetWindowLongPtrW(hwnd, DWLP_USER);
|
|
if (f == NULL) {
|
|
if (uMsg == WM_INITDIALOG) {
|
|
f = beginFontDialog(hwnd, lParam);
|
|
SetWindowLongPtrW(hwnd, DWLP_USER, (LONG_PTR) f);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
switch (uMsg) {
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam)) {
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
if (HIWORD(wParam) != BN_CLICKED)
|
|
return FALSE;
|
|
return tryFinishDialog(f, wParam);
|
|
case rcFontFamilyCombobox:
|
|
if (HIWORD(wParam) != CBN_SELCHANGE)
|
|
return FALSE;
|
|
familyChanged(f);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void showFontDialog(HWND parent)
|
|
{
|
|
switch (DialogBoxParamW(hInstance, MAKEINTRESOURCE(rcFontDialog), parent, fontDialogDlgProc, (LPARAM) NULL)) {
|
|
case 1:
|
|
// TODO cancel
|
|
break;
|
|
case 2:
|
|
// TODO OK
|
|
break;
|
|
default:
|
|
logLastError("error running font dialog in showFontDialog()");
|
|
}
|
|
}
|