From 351fc59b9f4e240fce4893dedf2fef36ae36deca Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 16 Apr 2016 17:58:45 -0400 Subject: [PATCH] Started work on previewing samples of fonts in the new font dialog. This adds all the boilerplate, including sample positioning. Also tightens up the dialog a bit. Now just to implement the actual drawing. --- windows/fontdialog.cpp | 191 ++++++++++++++++++++++++++++++++++++++++- windows/resources.h | 1 + windows/resources.rc | 10 ++- 3 files changed, 197 insertions(+), 5 deletions(-) diff --git a/windows/fontdialog.cpp b/windows/fontdialog.cpp index f0bd0bf2..2dea2131 100644 --- a/windows/fontdialog.cpp +++ b/windows/fontdialog.cpp @@ -10,6 +10,8 @@ struct fontDialog { fontCollection *fc; IDWriteFontFamily **families; UINT32 nFamilies; + IDWriteGdiInterop *gdiInterop; + RECT sampleRect; }; static LRESULT cbAddString(HWND cb, WCHAR *str) @@ -113,7 +115,11 @@ static void familyChanged(struct fontDialog *f) logLastError("error setting font data in styles box in familyChanged()"); } - // TODO do we preserve style selection? + // 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) @@ -122,6 +128,7 @@ static struct fontDialog *beginFontDialog(HWND hwnd, LPARAM lParam) UINT32 i; WCHAR *wname; LRESULT ten; + HWND samplePlacement; HRESULT hr; f = uiNew(struct fontDialog); @@ -189,6 +196,19 @@ static struct fontDialog *beginFontDialog(HWND hwnd, LPARAM lParam) logLastError("error selecting Arial in the family combobox in beginFontDialog()"); 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; } @@ -196,6 +216,7 @@ static void endFontDialog(struct fontDialog *f, INT_PTR code) { UINT32 i; + f->gdiInterop->Release(); wipeStylesBox(f); for (i = 0; i < f->nFamilies; i++) f->families[i]->Release(); @@ -220,6 +241,169 @@ static INT_PTR tryFinishDialog(struct fontDialog *f, WPARAM wParam) 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(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; + + return target->DrawGlyphRun( + baselineOriginX, + baselineOriginY, + measuringMode, + glyphRun, + NULL, + RGB(0, 0, 0), + NULL); +} + +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 consider using Direct2D instead +static void doPaint(struct fontDialog *f) +{ + PAINTSTRUCT ps; + HDC dc; + IDWriteBitmapRenderTarget *target; + gdiRenderer *renderer; + 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); + + renderer = new gdiRenderer; + renderer->refcount = 1; + + // TODO actually draw + + 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()"); + + renderer->Release(); + target->Release(); + EndPaint(f->hwnd, &ps); +} + static INT_PTR CALLBACK fontDialogDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { struct fontDialog *f; @@ -236,6 +420,7 @@ static INT_PTR CALLBACK fontDialogDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, L switch (uMsg) { case WM_COMMAND: + SetWindowLongPtrW(f->hwnd, DWLP_MSGRESULT, 0); // just in case switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: @@ -249,6 +434,10 @@ static INT_PTR CALLBACK fontDialogDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, L return TRUE; } return FALSE; + case WM_PAINT: + doPaint(f); + SetWindowLongPtrW(f->hwnd, DWLP_MSGRESULT, 0); + return TRUE; } return FALSE; } diff --git a/windows/resources.h b/windows/resources.h index f2bec17e..5bcbb3d9 100644 --- a/windows/resources.h +++ b/windows/resources.h @@ -6,3 +6,4 @@ #define rcFontFamilyCombobox 1000 #define rcFontStyleCombobox 1001 #define rcFontSizeCombobox 1002 +#define rcFontSamplePlacement 1003 diff --git a/windows/resources.rc b/windows/resources.rc index 7b9ea1f7..c227c3b0 100644 --- a/windows/resources.rc +++ b/windows/resources.rc @@ -20,7 +20,8 @@ END // 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 // TODO look at localization -rcFontDialog DIALOGEX 13, 54, 243, 234 +// TODO 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" @@ -40,8 +41,9 @@ BEGIN CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS - GROUPBOX "Sample", -1, 114, 97, 120, 43, WS_GROUP + 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, 215, 45, 14, WS_GROUP - PUSHBUTTON "Cancel", IDCANCEL, 190, 215, 45, 14, WS_GROUP + DEFPUSHBUTTON "OK", IDOK, 141, 181, 45, 14, WS_GROUP + PUSHBUTTON "Cancel", IDCANCEL, 190, 181, 45, 14, WS_GROUP END