First Commit
This commit is contained in:
commit
ae0fab9400
424 files changed
+71006
No files matched your search
@@ -0,0 +1,787 @@
|
||||
// 14 april 2016
|
||||
#include "uipriv_windows.hpp"
|
||||
#include "attrstr.hpp"
|
||||
|
||||
// TODOs
|
||||
// - quote the Choose Font sample here for reference
|
||||
// - the Choose Font sample defaults to Regular/Italic/Bold/Bold Italic in some case (no styles?); do we? find out what the case is
|
||||
// - do we set initial family and style topmost as well?
|
||||
// - this should probably just handle IDWriteFonts
|
||||
// - localization?
|
||||
// - the Sample window overlaps the groupbox in a weird way (compare to the real ChooseFont() dialog)
|
||||
|
||||
struct fontDialog {
|
||||
HWND hwnd;
|
||||
HWND familyCombobox;
|
||||
HWND styleCombobox;
|
||||
HWND sizeCombobox;
|
||||
|
||||
struct fontDialogParams *params;
|
||||
|
||||
struct fontCollection *fc;
|
||||
|
||||
RECT sampleRect;
|
||||
HWND sampleBox;
|
||||
|
||||
// we store the current selections in case an invalid string is typed in (partial or nonexistent or invalid number)
|
||||
// on OK, these are what are read
|
||||
LRESULT curFamily;
|
||||
LRESULT curStyle;
|
||||
double curSize;
|
||||
|
||||
// these are finding the style that's closest to the previous one (these fields) when changing a font
|
||||
DWRITE_FONT_WEIGHT weight;
|
||||
DWRITE_FONT_STYLE style;
|
||||
DWRITE_FONT_STRETCH stretch;
|
||||
};
|
||||
|
||||
static LRESULT cbAddString(HWND cb, const WCHAR *str)
|
||||
{
|
||||
LRESULT lr;
|
||||
|
||||
lr = SendMessageW(cb, CB_ADDSTRING, 0, (LPARAM) str);
|
||||
if (lr == (LRESULT) CB_ERR || lr == (LRESULT) CB_ERRSPACE)
|
||||
logLastError(L"error adding item to combobox");
|
||||
return lr;
|
||||
}
|
||||
|
||||
static LRESULT cbInsertString(HWND cb, const WCHAR *str, WPARAM pos)
|
||||
{
|
||||
LRESULT lr;
|
||||
|
||||
lr = SendMessageW(cb, CB_INSERTSTRING, pos, (LPARAM) str);
|
||||
if (lr != (LRESULT) pos)
|
||||
logLastError(L"error inserting item to combobox");
|
||||
return lr;
|
||||
}
|
||||
|
||||
static LRESULT cbGetItemData(HWND cb, WPARAM item)
|
||||
{
|
||||
LRESULT data;
|
||||
|
||||
data = SendMessageW(cb, CB_GETITEMDATA, item, 0);
|
||||
if (data == (LRESULT) CB_ERR)
|
||||
logLastError(L"error getting combobox item data for font dialog");
|
||||
return data;
|
||||
}
|
||||
|
||||
static void cbSetItemData(HWND cb, WPARAM item, LPARAM data)
|
||||
{
|
||||
if (SendMessageW(cb, CB_SETITEMDATA, item, data) == (LRESULT) CB_ERR)
|
||||
logLastError(L"error setting combobox item data");
|
||||
}
|
||||
|
||||
static BOOL cbGetCurSel(HWND cb, LRESULT *sel)
|
||||
{
|
||||
LRESULT n;
|
||||
|
||||
n = SendMessageW(cb, CB_GETCURSEL, 0, 0);
|
||||
if (n == (LRESULT) CB_ERR)
|
||||
return FALSE;
|
||||
if (sel != NULL)
|
||||
*sel = n;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void cbSetCurSel(HWND cb, WPARAM item)
|
||||
{
|
||||
if (SendMessageW(cb, CB_SETCURSEL, item, 0) != (LRESULT) item)
|
||||
logLastError(L"error selecting combobox item");
|
||||
}
|
||||
|
||||
static LRESULT cbGetCount(HWND cb)
|
||||
{
|
||||
LRESULT n;
|
||||
|
||||
n = SendMessageW(cb, CB_GETCOUNT, 0, 0);
|
||||
if (n == (LRESULT) CB_ERR)
|
||||
logLastError(L"error getting combobox item count");
|
||||
return n;
|
||||
}
|
||||
|
||||
static void cbWipeAndReleaseData(HWND cb)
|
||||
{
|
||||
IUnknown *obj;
|
||||
LRESULT i, n;
|
||||
|
||||
n = cbGetCount(cb);
|
||||
for (i = 0; i < n; i++) {
|
||||
obj = (IUnknown *) cbGetItemData(cb, (WPARAM) i);
|
||||
obj->Release();
|
||||
}
|
||||
SendMessageW(cb, CB_RESETCONTENT, 0, 0);
|
||||
}
|
||||
|
||||
static WCHAR *cbGetItemText(HWND cb, WPARAM item)
|
||||
{
|
||||
LRESULT len;
|
||||
WCHAR *text;
|
||||
|
||||
// note: neither message includes the terminating L'\0'
|
||||
len = SendMessageW(cb, CB_GETLBTEXTLEN, item, 0);
|
||||
if (len == (LRESULT) CB_ERR)
|
||||
logLastError(L"error getting item text length from combobox");
|
||||
text = (WCHAR *) uiprivAlloc((len + 1) * sizeof (WCHAR), "WCHAR[]");
|
||||
if (SendMessageW(cb, CB_GETLBTEXT, item, (LPARAM) text) != len)
|
||||
logLastError(L"error getting item text from combobox");
|
||||
return text;
|
||||
}
|
||||
|
||||
static BOOL cbTypeToSelect(HWND cb, LRESULT *posOut, BOOL restoreAfter)
|
||||
{
|
||||
WCHAR *text;
|
||||
LRESULT pos;
|
||||
DWORD selStart, selEnd;
|
||||
|
||||
// start by saving the current selection as setting the item will change the selection
|
||||
SendMessageW(cb, CB_GETEDITSEL, (WPARAM) (&selStart), (LPARAM) (&selEnd));
|
||||
text = windowText(cb);
|
||||
pos = SendMessageW(cb, CB_FINDSTRINGEXACT, (WPARAM) (-1), (LPARAM) text);
|
||||
if (pos == (LRESULT) CB_ERR) {
|
||||
uiprivFree(text);
|
||||
return FALSE;
|
||||
}
|
||||
cbSetCurSel(cb, (WPARAM) pos);
|
||||
if (posOut != NULL)
|
||||
*posOut = pos;
|
||||
if (restoreAfter)
|
||||
if (SendMessageW(cb, WM_SETTEXT, 0, (LPARAM) text) != (LRESULT) TRUE)
|
||||
logLastError(L"error restoring old combobox text");
|
||||
uiprivFree(text);
|
||||
// and restore the selection like above
|
||||
// TODO isn't there a 32-bit version of this
|
||||
if (SendMessageW(cb, CB_SETEDITSEL, 0, MAKELPARAM(selStart, selEnd)) != (LRESULT) TRUE)
|
||||
logLastError(L"error restoring combobox edit selection");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void wipeStylesBox(struct fontDialog *f)
|
||||
{
|
||||
cbWipeAndReleaseData(f->styleCombobox);
|
||||
}
|
||||
|
||||
static WCHAR *fontStyleName(struct fontCollection *fc, IDWriteFont *font)
|
||||
{
|
||||
IDWriteLocalizedStrings *str;
|
||||
WCHAR *wstr;
|
||||
HRESULT hr;
|
||||
|
||||
hr = font->GetFaceNames(&str);
|
||||
if (hr != S_OK)
|
||||
logHRESULT(L"error getting font style name for font dialog", hr);
|
||||
wstr = uiprivFontCollectionCorrectString(fc, str);
|
||||
str->Release();
|
||||
return wstr;
|
||||
}
|
||||
|
||||
static void queueRedrawSampleText(struct fontDialog *f)
|
||||
{
|
||||
// TODO TRUE?
|
||||
invalidateRect(f->sampleBox, NULL, TRUE);
|
||||
}
|
||||
|
||||
static void styleChanged(struct fontDialog *f)
|
||||
{
|
||||
LRESULT pos;
|
||||
BOOL selected;
|
||||
IDWriteFont *font;
|
||||
|
||||
selected = cbGetCurSel(f->styleCombobox, &pos);
|
||||
if (!selected) // on deselect, do nothing
|
||||
return;
|
||||
f->curStyle = pos;
|
||||
|
||||
font = (IDWriteFont *) cbGetItemData(f->styleCombobox, (WPARAM) (f->curStyle));
|
||||
// these are for the nearest match when changing the family; see below
|
||||
f->weight = font->GetWeight();
|
||||
f->style = font->GetStyle();
|
||||
f->stretch = font->GetStretch();
|
||||
|
||||
queueRedrawSampleText(f);
|
||||
}
|
||||
|
||||
static void styleEdited(struct fontDialog *f)
|
||||
{
|
||||
if (cbTypeToSelect(f->styleCombobox, &(f->curStyle), FALSE))
|
||||
styleChanged(f);
|
||||
}
|
||||
|
||||
static void familyChanged(struct fontDialog *f)
|
||||
{
|
||||
LRESULT pos;
|
||||
BOOL selected;
|
||||
IDWriteFontFamily *family;
|
||||
IDWriteFont *font, *matchFont;
|
||||
DWRITE_FONT_WEIGHT weight;
|
||||
DWRITE_FONT_STYLE style;
|
||||
DWRITE_FONT_STRETCH stretch;
|
||||
UINT32 i, n;
|
||||
UINT32 matching;
|
||||
WCHAR *label;
|
||||
HRESULT hr;
|
||||
|
||||
selected = cbGetCurSel(f->familyCombobox, &pos);
|
||||
if (!selected) // on deselect, do nothing
|
||||
return;
|
||||
f->curFamily = pos;
|
||||
|
||||
family = (IDWriteFontFamily *) cbGetItemData(f->familyCombobox, (WPARAM) (f->curFamily));
|
||||
|
||||
// for the nearest style match
|
||||
// when we select a new family, we want the nearest style to the previously selected one to be chosen
|
||||
// this is how the Choose Font sample does it
|
||||
hr = family->GetFirstMatchingFont(
|
||||
f->weight,
|
||||
f->stretch,
|
||||
f->style,
|
||||
&matchFont);
|
||||
if (hr != S_OK)
|
||||
logHRESULT(L"error finding first matching font to previous style in font dialog", hr);
|
||||
// we can't just compare pointers; a "newly created" object comes out
|
||||
// the Choose Font sample appears to do this instead
|
||||
weight = matchFont->GetWeight();
|
||||
style = matchFont->GetStyle();
|
||||
stretch = matchFont->GetStretch();
|
||||
matchFont->Release();
|
||||
|
||||
// TODO test mutliple streteches; all the fonts I have have only one stretch value?
|
||||
wipeStylesBox(f);
|
||||
n = family->GetFontCount();
|
||||
matching = 0; // a safe/suitable default just in case
|
||||
for (i = 0; i < n; i++) {
|
||||
hr = family->GetFont(i, &font);
|
||||
if (hr != S_OK)
|
||||
logHRESULT(L"error getting font for filling styles box", hr);
|
||||
label = fontStyleName(f->fc, font);
|
||||
pos = cbAddString(f->styleCombobox, label);
|
||||
uiprivFree(label);
|
||||
cbSetItemData(f->styleCombobox, (WPARAM) pos, (LPARAM) font);
|
||||
if (font->GetWeight() == weight &&
|
||||
font->GetStyle() == style &&
|
||||
font->GetStretch() == stretch)
|
||||
matching = i;
|
||||
}
|
||||
|
||||
// and now, load the match
|
||||
cbSetCurSel(f->styleCombobox, (WPARAM) matching);
|
||||
styleChanged(f);
|
||||
}
|
||||
|
||||
// TODO search language variants like the sample does
|
||||
static void familyEdited(struct fontDialog *f)
|
||||
{
|
||||
if (cbTypeToSelect(f->familyCombobox, &(f->curFamily), FALSE))
|
||||
familyChanged(f);
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const WCHAR *text;
|
||||
double value;
|
||||
} defaultSizes[] = {
|
||||
{ L"8", 8 },
|
||||
{ L"9", 9 },
|
||||
{ L"10", 10 },
|
||||
{ L"11", 11 },
|
||||
{ L"12", 12 },
|
||||
{ L"14", 14 },
|
||||
{ L"16", 16 },
|
||||
{ L"18", 18 },
|
||||
{ L"20", 20 },
|
||||
{ L"22", 22 },
|
||||
{ L"24", 24 },
|
||||
{ L"26", 26 },
|
||||
{ L"28", 28 },
|
||||
{ L"36", 36 },
|
||||
{ L"48", 48 },
|
||||
{ L"72", 72 },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
static void sizeChanged(struct fontDialog *f)
|
||||
{
|
||||
LRESULT pos;
|
||||
BOOL selected;
|
||||
|
||||
selected = cbGetCurSel(f->sizeCombobox, &pos);
|
||||
if (!selected) // on deselect, do nothing
|
||||
return;
|
||||
f->curSize = defaultSizes[pos].value;
|
||||
queueRedrawSampleText(f);
|
||||
}
|
||||
|
||||
static void sizeEdited(struct fontDialog *f)
|
||||
{
|
||||
WCHAR *wsize;
|
||||
double size;
|
||||
|
||||
// handle type-to-selection
|
||||
if (cbTypeToSelect(f->sizeCombobox, NULL, FALSE)) {
|
||||
sizeChanged(f);
|
||||
return;
|
||||
}
|
||||
// selection not chosen, try to parse the typing
|
||||
wsize = windowText(f->sizeCombobox);
|
||||
// this is what the Choose Font dialog does; it swallows errors while the real ChooseFont() is not lenient (and only checks on OK)
|
||||
size = wcstod(wsize, NULL);
|
||||
// TODO free wsize? I forget already
|
||||
if (size <= 0) // don't change on invalid size
|
||||
return;
|
||||
f->curSize = size;
|
||||
queueRedrawSampleText(f);
|
||||
}
|
||||
|
||||
static void fontDialogDrawSampleText(struct fontDialog *f, ID2D1RenderTarget *rt)
|
||||
{
|
||||
D2D1_COLOR_F color;
|
||||
D2D1_BRUSH_PROPERTIES props;
|
||||
ID2D1SolidColorBrush *black;
|
||||
IDWriteFont *font;
|
||||
IDWriteLocalizedStrings *sampleStrings;
|
||||
BOOL exists;
|
||||
WCHAR *sample;
|
||||
WCHAR *family;
|
||||
IDWriteTextFormat *format;
|
||||
D2D1_RECT_F rect;
|
||||
HRESULT hr;
|
||||
|
||||
color.r = 0.0;
|
||||
color.g = 0.0;
|
||||
color.b = 0.0;
|
||||
color.a = 1.0;
|
||||
ZeroMemory(&props, sizeof (D2D1_BRUSH_PROPERTIES));
|
||||
props.opacity = 1.0;
|
||||
// identity matrix
|
||||
props.transform._11 = 1;
|
||||
props.transform._22 = 1;
|
||||
hr = rt->CreateSolidColorBrush(
|
||||
&color,
|
||||
&props,
|
||||
&black);
|
||||
if (hr != S_OK)
|
||||
logHRESULT(L"error creating solid brush", hr);
|
||||
|
||||
font = (IDWriteFont *) cbGetItemData(f->styleCombobox, (WPARAM) f->curStyle);
|
||||
hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT, &sampleStrings, &exists);
|
||||
if (hr != S_OK)
|
||||
exists = FALSE;
|
||||
if (exists) {
|
||||
sample = uiprivFontCollectionCorrectString(f->fc, sampleStrings);
|
||||
sampleStrings->Release();
|
||||
} else
|
||||
sample = (WCHAR *) L"The quick brown fox jumps over the lazy dog."; // TODO
|
||||
|
||||
// DirectWrite doesn't allow creating a text format from a font; we need to get this ourselves
|
||||
family = cbGetItemText(f->familyCombobox, f->curFamily);
|
||||
hr = dwfactory->CreateTextFormat(family,
|
||||
NULL,
|
||||
font->GetWeight(),
|
||||
font->GetStyle(),
|
||||
font->GetStretch(),
|
||||
// typographic points are 1/72 inch; this parameter is 1/96 inch
|
||||
// fortunately Microsoft does this too, in https://msdn.microsoft.com/en-us/library/windows/desktop/dd371554%28v=vs.85%29.aspx
|
||||
f->curSize * (96.0 / 72.0),
|
||||
// see http://stackoverflow.com/questions/28397971/idwritefactorycreatetextformat-failing and https://msdn.microsoft.com/en-us/library/windows/desktop/dd368203.aspx
|
||||
// TODO use the current locale again?
|
||||
L"",
|
||||
&format);
|
||||
if (hr != S_OK)
|
||||
logHRESULT(L"error creating IDWriteTextFormat", hr);
|
||||
uiprivFree(family);
|
||||
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = realGetSize(rt).width;
|
||||
rect.bottom = realGetSize(rt).height;
|
||||
rt->DrawText(sample, wcslen(sample),
|
||||
format,
|
||||
&rect,
|
||||
black,
|
||||
// TODO really?
|
||||
D2D1_DRAW_TEXT_OPTIONS_NONE,
|
||||
DWRITE_MEASURING_MODE_NATURAL);
|
||||
|
||||
format->Release();
|
||||
if (exists)
|
||||
uiprivFree(sample);
|
||||
black->Release();
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK fontDialogSampleSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
|
||||
{
|
||||
ID2D1RenderTarget *rt;
|
||||
struct fontDialog *f;
|
||||
|
||||
switch (uMsg) {
|
||||
case msgD2DScratchPaint:
|
||||
rt = (ID2D1RenderTarget *) lParam;
|
||||
f = (struct fontDialog *) dwRefData;
|
||||
fontDialogDrawSampleText(f, rt);
|
||||
return 0;
|
||||
case WM_NCDESTROY:
|
||||
if (RemoveWindowSubclass(hwnd, fontDialogSampleSubProc, uIdSubclass) == FALSE)
|
||||
logLastError(L"error removing font dialog sample text subclass");
|
||||
break;
|
||||
}
|
||||
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static void setupInitialFontDialogState(struct fontDialog *f)
|
||||
{
|
||||
WCHAR wsize[512]; // this should be way more than enough
|
||||
LRESULT pos;
|
||||
|
||||
// first let's load the size
|
||||
// the real font dialog:
|
||||
// - if the chosen font size is in the list, it selects that item AND makes it topmost
|
||||
// - if the chosen font size is not in the list, don't bother
|
||||
// we'll simulate it by setting the text to a %f representation, then pretending as if it was entered
|
||||
// TODO is 512 the correct number to pass to _snwprintf()?
|
||||
// TODO will this revert to scientific notation?
|
||||
_snwprintf(wsize, 512, L"%g", f->params->size);
|
||||
// TODO make this a setWindowText()
|
||||
if (SendMessageW(f->sizeCombobox, WM_SETTEXT, 0, (LPARAM) wsize) != (LRESULT) TRUE)
|
||||
logLastError(L"error setting size combobox to initial font size");
|
||||
sizeEdited(f);
|
||||
if (cbGetCurSel(f->sizeCombobox, &pos))
|
||||
if (SendMessageW(f->sizeCombobox, CB_SETTOPINDEX, (WPARAM) pos, 0) != 0)
|
||||
logLastError(L"error making chosen size topmost in the size combobox");
|
||||
|
||||
// now we set the family and style
|
||||
// we do this by first setting the previous style attributes, then simulating a font entered
|
||||
f->weight = f->params->font->GetWeight();
|
||||
f->style = f->params->font->GetStyle();
|
||||
f->stretch = f->params->font->GetStretch();
|
||||
if (SendMessageW(f->familyCombobox, WM_SETTEXT, 0, (LPARAM) (f->params->familyName)) != (LRESULT) TRUE)
|
||||
logLastError(L"error setting family combobox to initial font family");
|
||||
familyEdited(f);
|
||||
}
|
||||
|
||||
static struct fontDialog *beginFontDialog(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
struct fontDialog *f;
|
||||
UINT32 i, nFamilies;
|
||||
IDWriteFontFamily *family;
|
||||
WCHAR *wname;
|
||||
LRESULT pos;
|
||||
HWND samplePlacement;
|
||||
HRESULT hr;
|
||||
|
||||
f = uiprivNew(struct fontDialog);
|
||||
f->hwnd = hwnd;
|
||||
f->params = (struct fontDialogParams *) lParam;
|
||||
|
||||
f->familyCombobox = getDlgItem(f->hwnd, rcFontFamilyCombobox);
|
||||
f->styleCombobox = getDlgItem(f->hwnd, rcFontStyleCombobox);
|
||||
f->sizeCombobox = getDlgItem(f->hwnd, rcFontSizeCombobox);
|
||||
|
||||
f->fc = uiprivLoadFontCollection();
|
||||
nFamilies = f->fc->fonts->GetFontFamilyCount();
|
||||
for (i = 0; i < nFamilies; i++) {
|
||||
hr = f->fc->fonts->GetFontFamily(i, &family);
|
||||
if (hr != S_OK)
|
||||
logHRESULT(L"error getting font family", hr);
|
||||
wname = uiprivFontCollectionFamilyName(f->fc, family);
|
||||
pos = cbAddString(f->familyCombobox, wname);
|
||||
uiprivFree(wname);
|
||||
cbSetItemData(f->familyCombobox, (WPARAM) pos, (LPARAM) family);
|
||||
}
|
||||
|
||||
for (i = 0; defaultSizes[i].text != NULL; i++)
|
||||
cbInsertString(f->sizeCombobox, defaultSizes[i].text, (WPARAM) i);
|
||||
|
||||
samplePlacement = getDlgItem(f->hwnd, rcFontSamplePlacement);
|
||||
uiWindowsEnsureGetWindowRect(samplePlacement, &(f->sampleRect));
|
||||
mapWindowRect(NULL, f->hwnd, &(f->sampleRect));
|
||||
uiWindowsEnsureDestroyWindow(samplePlacement);
|
||||
f->sampleBox = newD2DScratch(f->hwnd, &(f->sampleRect), (HMENU) rcFontSamplePlacement, fontDialogSampleSubProc, (DWORD_PTR) f);
|
||||
|
||||
setupInitialFontDialogState(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
static void endFontDialog(struct fontDialog *f, INT_PTR code)
|
||||
{
|
||||
wipeStylesBox(f);
|
||||
cbWipeAndReleaseData(f->familyCombobox);
|
||||
uiprivFontCollectionFree(f->fc);
|
||||
if (EndDialog(f->hwnd, code) == 0)
|
||||
logLastError(L"error ending font dialog");
|
||||
uiprivFree(f);
|
||||
}
|
||||
|
||||
static INT_PTR tryFinishDialog(struct fontDialog *f, WPARAM wParam)
|
||||
{
|
||||
IDWriteFontFamily *family;
|
||||
|
||||
// cancelling
|
||||
if (LOWORD(wParam) != IDOK) {
|
||||
endFontDialog(f, 1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// OK
|
||||
uiprivDestroyFontDialogParams(f->params);
|
||||
f->params->font = (IDWriteFont *) cbGetItemData(f->styleCombobox, f->curStyle);
|
||||
// we need to save font from being destroyed with the combobox
|
||||
f->params->font->AddRef();
|
||||
f->params->size = f->curSize;
|
||||
family = (IDWriteFontFamily *) cbGetItemData(f->familyCombobox, f->curFamily);
|
||||
f->params->familyName = uiprivFontCollectionFamilyName(f->fc, family);
|
||||
f->params->styleName = fontStyleName(f->fc, f->params->font);
|
||||
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:
|
||||
SetWindowLongPtrW(f->hwnd, DWLP_MSGRESULT, 0); // just in case
|
||||
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) {
|
||||
familyChanged(f);
|
||||
return TRUE;
|
||||
}
|
||||
if (HIWORD(wParam) == CBN_EDITCHANGE) {
|
||||
familyEdited(f);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
case rcFontStyleCombobox:
|
||||
if (HIWORD(wParam) == CBN_SELCHANGE) {
|
||||
styleChanged(f);
|
||||
return TRUE;
|
||||
}
|
||||
if (HIWORD(wParam) == CBN_EDITCHANGE) {
|
||||
styleEdited(f);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
case rcFontSizeCombobox:
|
||||
if (HIWORD(wParam) == CBN_SELCHANGE) {
|
||||
sizeChanged(f);
|
||||
return TRUE;
|
||||
}
|
||||
if (HIWORD(wParam) == CBN_EDITCHANGE) {
|
||||
sizeEdited(f);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// because Windows doesn't really support resources in static libraries, we have to embed this directly; oh well
|
||||
/*
|
||||
// this is for our custom DirectWrite-based font dialog (see fontdialog.cpp)
|
||||
// this is based on the "New Font Dialog with Syslink" in Microsoft's font.dlg
|
||||
// LONGTERM look at localization
|
||||
// LONGTERM make it look tighter and nicer like the real one, including the actual heights of the font family and style comboboxes
|
||||
rcFontDialog DIALOGEX 13, 54, 243, 200
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_3DLOOK
|
||||
CAPTION "Font"
|
||||
FONT 9, "Segoe UI"
|
||||
BEGIN
|
||||
LTEXT "&Font:", -1, 7, 7, 98, 9
|
||||
COMBOBOX rcFontFamilyCombobox, 7, 16, 98, 76,
|
||||
CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL |
|
||||
CBS_SORT | WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS
|
||||
|
||||
LTEXT "Font st&yle:", -1, 114, 7, 74, 9
|
||||
COMBOBOX rcFontStyleCombobox, 114, 16, 74, 76,
|
||||
CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL |
|
||||
WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS
|
||||
|
||||
LTEXT "&Size:", -1, 198, 7, 36, 9
|
||||
COMBOBOX rcFontSizeCombobox, 198, 16, 36, 76,
|
||||
CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL |
|
||||
CBS_SORT | WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS
|
||||
|
||||
GROUPBOX "Sample", -1, 7, 97, 227, 70, WS_GROUP
|
||||
CTEXT "AaBbYyZz", rcFontSamplePlacement, 9, 106, 224, 60, SS_NOPREFIX | NOT WS_VISIBLE
|
||||
|
||||
DEFPUSHBUTTON "OK", IDOK, 141, 181, 45, 14, WS_GROUP
|
||||
PUSHBUTTON "Cancel", IDCANCEL, 190, 181, 45, 14, WS_GROUP
|
||||
END
|
||||
*/
|
||||
static const uint8_t data_rcFontDialog[] = {
|
||||
0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xC4, 0x00, 0xC8, 0x80,
|
||||
0x0A, 0x00, 0x0D, 0x00, 0x36, 0x00, 0xF3, 0x00,
|
||||
0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00,
|
||||
0x6F, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x00, 0x00,
|
||||
0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x53, 0x00,
|
||||
0x65, 0x00, 0x67, 0x00, 0x6F, 0x00, 0x65, 0x00,
|
||||
0x20, 0x00, 0x55, 0x00, 0x49, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x02, 0x50, 0x07, 0x00, 0x07, 0x00,
|
||||
0x62, 0x00, 0x09, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x82, 0x00, 0x26, 0x00, 0x46, 0x00,
|
||||
0x6F, 0x00, 0x6E, 0x00, 0x74, 0x00, 0x3A, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x41, 0x0B, 0x21, 0x50,
|
||||
0x07, 0x00, 0x10, 0x00, 0x62, 0x00, 0x4C, 0x00,
|
||||
0xE8, 0x03, 0x00, 0x00, 0xFF, 0xFF, 0x85, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x50,
|
||||
0x72, 0x00, 0x07, 0x00, 0x4A, 0x00, 0x09, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x82, 0x00,
|
||||
0x46, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x74, 0x00,
|
||||
0x20, 0x00, 0x73, 0x00, 0x74, 0x00, 0x26, 0x00,
|
||||
0x79, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x3A, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x41, 0x0A, 0x21, 0x50,
|
||||
0x72, 0x00, 0x10, 0x00, 0x4A, 0x00, 0x4C, 0x00,
|
||||
0xE9, 0x03, 0x00, 0x00, 0xFF, 0xFF, 0x85, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x50,
|
||||
0xC6, 0x00, 0x07, 0x00, 0x24, 0x00, 0x09, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x82, 0x00,
|
||||
0x26, 0x00, 0x53, 0x00, 0x69, 0x00, 0x7A, 0x00,
|
||||
0x65, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x41, 0x0B, 0x21, 0x50, 0xC6, 0x00, 0x10, 0x00,
|
||||
0x24, 0x00, 0x4C, 0x00, 0xEA, 0x03, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x07, 0x00, 0x02, 0x50, 0x07, 0x00, 0x61, 0x00,
|
||||
0xE3, 0x00, 0x46, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x80, 0x00, 0x53, 0x00, 0x61, 0x00,
|
||||
0x6D, 0x00, 0x70, 0x00, 0x6C, 0x00, 0x65, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x02, 0x40,
|
||||
0x09, 0x00, 0x6A, 0x00, 0xE0, 0x00, 0x3C, 0x00,
|
||||
0xEB, 0x03, 0x00, 0x00, 0xFF, 0xFF, 0x82, 0x00,
|
||||
0x41, 0x00, 0x61, 0x00, 0x42, 0x00, 0x62, 0x00,
|
||||
0x59, 0x00, 0x79, 0x00, 0x5A, 0x00, 0x7A, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x50,
|
||||
0x8D, 0x00, 0xB5, 0x00, 0x2D, 0x00, 0x0E, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00,
|
||||
0x4F, 0x00, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x03, 0x50, 0xBE, 0x00, 0xB5, 0x00,
|
||||
0x2D, 0x00, 0x0E, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0x80, 0x00, 0x43, 0x00, 0x61, 0x00,
|
||||
0x6E, 0x00, 0x63, 0x00, 0x65, 0x00, 0x6C, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
static_assert(ARRAYSIZE(data_rcFontDialog) == 476, "wrong size for resource rcFontDialog");
|
||||
|
||||
BOOL uiprivShowFontDialog(HWND parent, struct fontDialogParams *params)
|
||||
{
|
||||
switch (DialogBoxIndirectParamW(hInstance, (const DLGTEMPLATE *) data_rcFontDialog, parent, fontDialogDlgProc, (LPARAM) params)) {
|
||||
case 1: // cancel
|
||||
return FALSE;
|
||||
case 2: // ok
|
||||
// make the compiler happy by putting the return after the switch
|
||||
break;
|
||||
default:
|
||||
logLastError(L"error running font dialog");
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static IDWriteFontFamily *tryFindFamily(IDWriteFontCollection *fc, const WCHAR *name)
|
||||
{
|
||||
UINT32 index;
|
||||
BOOL exists;
|
||||
IDWriteFontFamily *family;
|
||||
HRESULT hr;
|
||||
|
||||
hr = fc->FindFamilyName(name, &index, &exists);
|
||||
if (hr != S_OK)
|
||||
logHRESULT(L"error finding font family for font dialog", hr);
|
||||
if (!exists)
|
||||
return NULL;
|
||||
hr = fc->GetFontFamily(index, &family);
|
||||
if (hr != S_OK)
|
||||
logHRESULT(L"error extracting found font family for font dialog", hr);
|
||||
return family;
|
||||
}
|
||||
|
||||
void uiprivLoadInitialFontDialogParams(struct fontDialogParams *params)
|
||||
{
|
||||
struct fontCollection *fc;
|
||||
IDWriteFontFamily *family;
|
||||
IDWriteFont *font;
|
||||
HRESULT hr;
|
||||
|
||||
// Our preferred font is Arial 10 Regular.
|
||||
// 10 comes from the official font dialog.
|
||||
// Arial Regular is a reasonable, if arbitrary, default; it's similar to the defaults on other systems.
|
||||
// If Arial isn't found, we'll use Helvetica and then MS Sans Serif as fallbacks, and if not, we'll just grab the first font family in the collection.
|
||||
|
||||
// We need the correct localized name for Regular (and possibly Arial too? let's say yes to be safe), so let's grab the strings from DirectWrite instead of hardcoding them.
|
||||
fc = uiprivLoadFontCollection();
|
||||
family = tryFindFamily(fc->fonts, L"Arial");
|
||||
if (family == NULL) {
|
||||
family = tryFindFamily(fc->fonts, L"Helvetica");
|
||||
if (family == NULL) {
|
||||
family = tryFindFamily(fc->fonts, L"MS Sans Serif");
|
||||
if (family == NULL) {
|
||||
hr = fc->fonts->GetFontFamily(0, &family);
|
||||
if (hr != S_OK)
|
||||
logHRESULT(L"error getting first font out of font collection (worst case scenario)", hr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// next part is simple: just get the closest match to regular
|
||||
hr = family->GetFirstMatchingFont(
|
||||
DWRITE_FONT_WEIGHT_NORMAL,
|
||||
DWRITE_FONT_STRETCH_NORMAL,
|
||||
DWRITE_FONT_STYLE_NORMAL,
|
||||
&font);
|
||||
if (hr != S_OK)
|
||||
logHRESULT(L"error getting Regular font from Arial", hr);
|
||||
|
||||
params->font = font;
|
||||
params->size = 10;
|
||||
params->familyName = uiprivFontCollectionFamilyName(fc, family);
|
||||
params->styleName = fontStyleName(fc, font);
|
||||
|
||||
// don't release font; we still need it
|
||||
family->Release();
|
||||
uiprivFontCollectionFree(fc);
|
||||
}
|
||||
|
||||
void uiprivDestroyFontDialogParams(struct fontDialogParams *params)
|
||||
{
|
||||
params->font->Release();
|
||||
uiprivFree(params->familyName);
|
||||
uiprivFree(params->styleName);
|
||||
}
|
||||
|
||||
WCHAR *uiprivFontDialogParamsToString(struct fontDialogParams *params)
|
||||
{
|
||||
WCHAR *text;
|
||||
|
||||
// TODO dynamically allocate
|
||||
text = (WCHAR *) uiprivAlloc(512 * sizeof (WCHAR), "WCHAR[]");
|
||||
_snwprintf(text, 512, L"%s %s %g",
|
||||
params->familyName,
|
||||
params->styleName,
|
||||
params->size);
|
||||
return text;
|
||||
}
|
||||
Reference in new issue
Block a user