588 lines
17 KiB
C++
588 lines
17 KiB
C++
// 14 april 2016
|
|
#include "uipriv_windows.h"
|
|
|
|
struct fontDialog {
|
|
HWND hwnd;
|
|
HWND familyCombobox;
|
|
HWND styleCombobox;
|
|
HWND sizeCombobox;
|
|
|
|
// TODO desc;
|
|
|
|
fontCollection *fc;
|
|
|
|
IDWriteGdiInterop *gdiInterop;
|
|
RECT sampleRect;
|
|
|
|
// 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;
|
|
LRESULT curSize;
|
|
};
|
|
|
|
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 LRESULT cbGetItemData(HWND cb, WPARAM item)
|
|
{
|
|
LRESULT data;
|
|
|
|
data = SendMessageW(cb, CB_GETITEMDATA, item, 0);
|
|
if (data == (LRESULT) CB_ERR)
|
|
logLastError("error getting combobox item data for font dialog in cbGetItemData()");
|
|
return data;
|
|
}
|
|
|
|
static void cbSetItemData(HWND cb, WPARAM item, LPARAM data)
|
|
{
|
|
if (SendMessageW(cb, CB_SETITEMDATA, item, data) == (LRESULT) CB_ERR)
|
|
logLastError("error setting combobox item data in cbSetItemData()");
|
|
}
|
|
|
|
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) != 0)
|
|
logLastError("error selecting combobox item in cbSetCurSel()");
|
|
}
|
|
|
|
static LRESULT cbGetCount(HWND cb)
|
|
{
|
|
LRESULT n;
|
|
|
|
n = SendMessageW(cb, CB_GETCOUNT, 0, 0);
|
|
if (n == (LRESULT) CB_ERR)
|
|
logLastError("error getting combobox item count in cbGetCount()");
|
|
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 void wipeStylesBox(struct fontDialog *f)
|
|
{
|
|
cbWipeAndReleaseData(f->styleCombobox);
|
|
}
|
|
|
|
static WCHAR *fontStyleName(struct fontDialog *f, IDWriteFont *font)
|
|
{
|
|
IDWriteLocalizedStrings *str;
|
|
BOOL exists;
|
|
WCHAR *wstr;
|
|
HRESULT hr;
|
|
|
|
hr = font->GetFaceNames(&str);
|
|
if (hr != S_OK)
|
|
logHRESULT("error getting font style name for font dialog in fontStyleName()", hr);
|
|
wstr = fontCollectionCorrectString(f->fc, str);
|
|
str->Release();
|
|
return wstr;
|
|
}
|
|
|
|
static void familyChanged(struct fontDialog *f)
|
|
{
|
|
LRESULT pos;
|
|
BOOL selected;
|
|
IDWriteFontFamily *family;
|
|
IDWriteFont *font;
|
|
UINT32 i, n;
|
|
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));
|
|
|
|
// TODO test mutliple streteches; all the fonts I have have only one stretch value?
|
|
wipeStylesBox(f);
|
|
n = family->GetFontCount();
|
|
for (i = 0; i < n; i++) {
|
|
hr = family->GetFont(i, &font);
|
|
if (hr != S_OK)
|
|
logHRESULT("error getting font for filling styles box in familyChanged()", hr);
|
|
label = fontStyleName(f, font);
|
|
pos = cbAddString(f->styleCombobox, label);
|
|
uiFree(label);
|
|
cbSetItemData(f->styleCombobox, (WPARAM) pos, (LPARAM) font);
|
|
}
|
|
|
|
// TODO how do we preserve style selection? the real thing seems to have a very elaborate method of doing so
|
|
// TODO check error
|
|
SendMessageW(f->styleCombobox, CB_SETCURSEL, 0, 0);
|
|
// TODO refine this a bit
|
|
InvalidateRect(f->hwnd, NULL, TRUE/*TODO*/);
|
|
}
|
|
|
|
static struct fontDialog *beginFontDialog(HWND hwnd, LPARAM lParam)
|
|
{
|
|
struct fontDialog *f;
|
|
UINT32 i, nFamilies;
|
|
IDWriteFontFamily *family;
|
|
WCHAR *wname;
|
|
LRESULT pos, ten;
|
|
HWND samplePlacement;
|
|
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();
|
|
nFamilies = f->fc->fonts->GetFontFamilyCount();
|
|
for (i = 0; i < nFamilies; i++) {
|
|
hr = f->fc->fonts->GetFontFamily(i, &family);
|
|
if (hr != S_OK)
|
|
logHRESULT("error getting font family in beginFontDialog()", hr);
|
|
wname = fontCollectionFamilyName(f->fc, family);
|
|
pos = cbAddString(f->familyCombobox, wname);
|
|
uiFree(wname);
|
|
cbSetItemData(f->familyCombobox, (WPARAM) pos, (LPARAM) family);
|
|
}
|
|
|
|
// 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
|
|
cbSetCurSel(f->familyCombobox, 0);
|
|
familyChanged(f);
|
|
|
|
hr = dwfactory->GetGdiInterop(&(f->gdiInterop));
|
|
if (hr != S_OK)
|
|
logHRESULT("error getting GDI interop for font dialog in beginFontDialog()", hr);
|
|
|
|
samplePlacement = GetDlgItem(f->hwnd, rcFontSamplePlacement);
|
|
if (samplePlacement == NULL)
|
|
logLastError("error getting sample placement static control handle in beginFontDialog()");
|
|
if (GetWindowRect(samplePlacement, &(f->sampleRect)) == 0)
|
|
logLastError("error getting sample placement in beginFontDialog()");
|
|
mapWindowRect(NULL, f->hwnd, &(f->sampleRect));
|
|
if (DestroyWindow(samplePlacement) == 0)
|
|
logLastError("error getting rid of the sample placement static control in beginFontDialog()");
|
|
|
|
return f;
|
|
}
|
|
|
|
static void endFontDialog(struct fontDialog *f, INT_PTR code)
|
|
{
|
|
f->gdiInterop->Release();
|
|
wipeStylesBox(f);
|
|
cbWipeAndReleaseData(f->familyCombobox);
|
|
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;
|
|
}
|
|
|
|
class gdiRenderer : public IDWriteTextRenderer {
|
|
public:
|
|
ULONG refcount;
|
|
|
|
// IUnknown
|
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
|
STDMETHODIMP_(ULONG) AddRef();
|
|
STDMETHODIMP_(ULONG) Release();
|
|
|
|
// IDWritePixelSnapping
|
|
STDMETHODIMP GetCurrentTransform(void *clientDrawingContext, DWRITE_MATRIX *transform);
|
|
STDMETHODIMP GetPixelsPerDip(void *clientDrawingContext, FLOAT *pixelsPerDip);
|
|
STDMETHODIMP IsPixelSnappingDisabled(void *clientDrawingContext, BOOL *isDisabled);
|
|
|
|
// IDWriteTextRenderer
|
|
STDMETHODIMP DrawGlyphRun(
|
|
void *clientDrawingContext,
|
|
FLOAT baselineOriginX,
|
|
FLOAT baselineOriginY,
|
|
DWRITE_MEASURING_MODE measuringMode,
|
|
const DWRITE_GLYPH_RUN *glyphRun,
|
|
const DWRITE_GLYPH_RUN_DESCRIPTION *glyphRunDescription,
|
|
IUnknown *clientDrawingEffect);
|
|
STDMETHODIMP DrawInlineObject(void *clientDrawingContext, FLOAT originX, FLOAT originY, IDWriteInlineObject *inlineObject, BOOL isSideways, BOOL isRightToLeft, IUnknown *clientDrawingEffect);
|
|
STDMETHODIMP DrawStrikethrough(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_STRIKETHROUGH *strikethrough, IUnknown *clientDrawingEffect);
|
|
STDMETHODIMP DrawUnderline(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_UNDERLINE *underline, IUnknown *clientDrawingEffect);
|
|
};
|
|
|
|
STDMETHODIMP gdiRenderer::QueryInterface(REFIID riid, void **ppv)
|
|
{
|
|
if (ppv == NULL)
|
|
return E_POINTER;
|
|
if (riid == IID_IUnknown ||
|
|
riid == __uuidof (IDWritePixelSnapping) ||
|
|
riid == __uuidof (IDWriteTextRenderer)) {
|
|
*ppv = static_cast<IDWriteTextRenderer *>(this);
|
|
this->AddRef();
|
|
return S_OK;
|
|
}
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) gdiRenderer::AddRef()
|
|
{
|
|
this->refcount++;
|
|
return this->refcount;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) gdiRenderer::Release()
|
|
{
|
|
this->refcount--;
|
|
if (this->refcount == 0) {
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return this->refcount;
|
|
}
|
|
|
|
STDMETHODIMP gdiRenderer::GetCurrentTransform(void *clientDrawingContext, DWRITE_MATRIX *transform)
|
|
{
|
|
IDWriteBitmapRenderTarget *target = (IDWriteBitmapRenderTarget *) clientDrawingContext;
|
|
|
|
return target->GetCurrentTransform(transform);
|
|
}
|
|
|
|
STDMETHODIMP gdiRenderer::GetPixelsPerDip(void *clientDrawingContext, FLOAT *pixelsPerDip)
|
|
{
|
|
IDWriteBitmapRenderTarget *target = (IDWriteBitmapRenderTarget *) clientDrawingContext;
|
|
|
|
if (pixelsPerDip == NULL)
|
|
return E_POINTER;
|
|
*pixelsPerDip = target->GetPixelsPerDip();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP gdiRenderer::IsPixelSnappingDisabled(void *clientDrawingContext, BOOL *isDisabled)
|
|
{
|
|
// TODO this is the MSDN recommendation
|
|
if (isDisabled == NULL)
|
|
return E_POINTER;
|
|
*isDisabled = FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP gdiRenderer::DrawGlyphRun(
|
|
void *clientDrawingContext,
|
|
FLOAT baselineOriginX,
|
|
FLOAT baselineOriginY,
|
|
DWRITE_MEASURING_MODE measuringMode,
|
|
const DWRITE_GLYPH_RUN *glyphRun,
|
|
const DWRITE_GLYPH_RUN_DESCRIPTION *glyphRunDescription,
|
|
IUnknown *clientDrawingEffect)
|
|
{
|
|
IDWriteBitmapRenderTarget *target = (IDWriteBitmapRenderTarget *) clientDrawingContext;
|
|
RECT dirtyRect;
|
|
IDWriteRenderingParams *rp;
|
|
HRESULT hr;
|
|
|
|
// TODO I cannot believe this is required; we really do need to switch to Direct2D
|
|
hr = dwfactory->CreateRenderingParams(&rp);
|
|
if (hr != S_OK)
|
|
return hr;
|
|
hr = target->DrawGlyphRun(
|
|
baselineOriginX,
|
|
baselineOriginY,
|
|
measuringMode,
|
|
glyphRun,
|
|
rp,
|
|
RGB(0, 0, 0),
|
|
&dirtyRect);
|
|
rp->Release();
|
|
if (hr != S_OK)
|
|
return hr;
|
|
if (SetBoundsRect(target->GetMemoryDC(), &dirtyRect, DCB_ACCUMULATE) == 0)
|
|
// TODO
|
|
return E_FAIL;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP gdiRenderer::DrawInlineObject(void *clientDrawingContext, FLOAT originX, FLOAT originY, IDWriteInlineObject *inlineObject, BOOL isSideways, BOOL isRightToLeft, IUnknown *clientDrawingEffect)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP gdiRenderer::DrawStrikethrough(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_STRIKETHROUGH *strikethrough, IUnknown *clientDrawingEffect)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP gdiRenderer::DrawUnderline(void *clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_UNDERLINE *underline, IUnknown *clientDrawingEffect)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// TODO rename this function
|
|
// TODO consider using Direct2D instead
|
|
static void doPaint(struct fontDialog *f)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC dc;
|
|
IDWriteBitmapRenderTarget *target;
|
|
gdiRenderer *renderer;
|
|
LRESULT i;
|
|
IDWriteFont *font;
|
|
IDWriteLocalizedStrings *sampleStrings;
|
|
BOOL exists;
|
|
WCHAR *sample;
|
|
WCHAR *family;
|
|
WCHAR *wsize;
|
|
double size;
|
|
IDWriteTextFormat *format;
|
|
IDWriteTextLayout *layout;
|
|
HDC memoryDC;
|
|
RECT memoryRect;
|
|
HRESULT hr;
|
|
|
|
dc = BeginPaint(f->hwnd, &ps);
|
|
if (dc == NULL)
|
|
logLastError("error beginning font dialog redraw in doPaint()");
|
|
|
|
hr = f->gdiInterop->CreateBitmapRenderTarget(dc,
|
|
f->sampleRect.right - f->sampleRect.left, f->sampleRect.bottom - f->sampleRect.top,
|
|
&target);
|
|
if (hr != S_OK)
|
|
logHRESULT("error creating bitmap render target for font dialog in doPaint()", hr);
|
|
|
|
// TODO why is this needed?
|
|
// TODO error check
|
|
{
|
|
RECT rdraw;
|
|
|
|
rdraw.left = 0;
|
|
rdraw.top = 0;
|
|
rdraw.right = f->sampleRect.right - f->sampleRect.left;
|
|
rdraw.bottom = f->sampleRect.bottom - f->sampleRect.top;
|
|
FillRect(target->GetMemoryDC(), &rdraw, GetSysColorBrush(COLOR_BTNFACE));
|
|
}
|
|
|
|
renderer = new gdiRenderer;
|
|
renderer->refcount = 1;
|
|
|
|
i = SendMessageW(f->styleCombobox, CB_GETCURSEL, 0, 0);
|
|
if (i == (LRESULT) CB_ERR)
|
|
{EndPaint(f->hwnd,&ps);return;} // TODO something more appropriate
|
|
font = (IDWriteFont *) SendMessageW(f->styleCombobox, CB_GETITEMDATA, (WPARAM) i, 0);
|
|
if (font == (IDWriteFont *) CB_ERR)
|
|
logLastError("error getting font to draw font dialog sample in doPaint()");
|
|
// TOOD allow for a fallback
|
|
hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_SAMPLE_TEXT, &sampleStrings, &exists);
|
|
if (hr != S_OK)
|
|
exists = FALSE;
|
|
if (exists) {
|
|
sample = fontCollectionCorrectString(f->fc, sampleStrings);
|
|
sampleStrings->Release();
|
|
} else
|
|
sample = L"TODO get this from GTK+ instead of AaBbYyZz";
|
|
// TODO get this from the currently selected item
|
|
family = windowText(f->familyCombobox);
|
|
// TODO but NOT this
|
|
wsize = windowText(f->sizeCombobox);
|
|
// TODO error check?
|
|
size = _wtof(wsize);
|
|
uiFree(wsize);
|
|
|
|
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
|
|
size * (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("error creating IDWriteTextFormat for font dialog sample in doPaint()", hr);
|
|
uiFree(family);
|
|
|
|
hr = dwfactory->CreateTextLayout(sample, wcslen(sample),
|
|
format,
|
|
// FLOAT is float, not double, so this should work... TODO
|
|
// TODO we don't want wrapping here
|
|
FLT_MAX, FLT_MAX,
|
|
&layout);
|
|
if (hr != S_OK)
|
|
logHRESULT("error creating IDWriteTextLayout for font dialog sample in doPaint()", hr);
|
|
|
|
hr = layout->Draw(target,
|
|
renderer,
|
|
0, 0);
|
|
if (hr != S_OK)
|
|
logHRESULT("error drawing font dialog sample text in doPaint()", hr);
|
|
|
|
memoryDC = target->GetMemoryDC();
|
|
if (GetBoundsRect(memoryDC, &memoryRect, 0) == 0)
|
|
logLastError("error getting size of memory DC for font dialog in doPaint()");
|
|
if (BitBlt(dc,
|
|
f->sampleRect.left, f->sampleRect.top,
|
|
memoryRect.right - memoryRect.left, memoryRect.bottom - memoryRect.top,
|
|
memoryDC,
|
|
0, 0,
|
|
SRCCOPY | NOMIRRORBITMAP) == 0)
|
|
logLastError("error blitting sample text to font dialog in doPaint()");
|
|
|
|
layout->Release();
|
|
format->Release();
|
|
if (exists)
|
|
uiFree(sample);
|
|
renderer->Release();
|
|
target->Release();
|
|
EndPaint(f->hwnd, &ps);
|
|
}
|
|
|
|
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)
|
|
return FALSE;
|
|
familyChanged(f);
|
|
return TRUE;
|
|
// TODO
|
|
case rcFontStyleCombobox:
|
|
case rcFontSizeCombobox:
|
|
if (HIWORD(wParam) != CBN_SELCHANGE)
|
|
return FALSE;
|
|
// TODO error check; refine
|
|
InvalidateRect(f->hwnd, NULL, TRUE);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
case WM_PAINT:
|
|
doPaint(f);
|
|
SetWindowLongPtrW(f->hwnd, DWLP_MSGRESULT, 0);
|
|
return TRUE;
|
|
}
|
|
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()");
|
|
}
|
|
}
|