mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
561 lines
14 KiB
C
561 lines
14 KiB
C
/*
|
|
* PROJECT: ReactOS Font Viewer
|
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
|
* PURPOSE: Display class
|
|
* COPYRIGHT: Copyright 2007 Timo Kreuzer <timo.kreuzer@reactos.org>
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#include <stdio.h>
|
|
#include <malloc.h>
|
|
|
|
#define SPACING1 8
|
|
#define SPACING2 5
|
|
|
|
extern INT g_NumFonts;
|
|
extern WCHAR g_FontTitle[];
|
|
|
|
const WCHAR g_szFontDisplayClassName[] = L"FontDisplayClass";
|
|
LRESULT CALLBACK DisplayProc(HWND, UINT, WPARAM, LPARAM);
|
|
|
|
/* Internal data storage type */
|
|
typedef struct
|
|
{
|
|
int nPageHeight;
|
|
WCHAR szTypeFaceName[LF_FULLFACESIZE];
|
|
WCHAR szFormat[MAX_FORMAT];
|
|
WCHAR szString[MAX_STRING];
|
|
|
|
HFONT hCaptionFont;
|
|
HFONT hCharSetFont;
|
|
HFONT hSizeFont;
|
|
HFONT hFonts[MAX_SIZES];
|
|
int nSizes[MAX_SIZES];
|
|
int nHeights[MAX_SIZES];
|
|
} DISPLAYDATA;
|
|
|
|
/* This is the only public function, it registers the class */
|
|
BOOL
|
|
Display_InitClass(HINSTANCE hInstance)
|
|
{
|
|
WNDCLASSEXW wincl;
|
|
|
|
/* Set the fontdisplay window class structure */
|
|
wincl.cbSize = sizeof(WNDCLASSEX);
|
|
wincl.style = CS_DBLCLKS;
|
|
wincl.lpfnWndProc = DisplayProc;
|
|
wincl.cbClsExtra = 0;
|
|
wincl.cbWndExtra = 0;
|
|
wincl.hInstance = hInstance;
|
|
wincl.hIcon = NULL;
|
|
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
|
|
wincl.hbrBackground = GetStockObject(WHITE_BRUSH);
|
|
wincl.lpszMenuName = NULL;
|
|
wincl.lpszClassName = g_szFontDisplayClassName;
|
|
wincl.hIconSm = NULL;
|
|
|
|
/* Register the window class, and if it fails return FALSE */
|
|
if (!RegisterClassExW (&wincl))
|
|
{
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
Display_DrawText(HDC hDC, DISPLAYDATA* pData, int nYPos)
|
|
{
|
|
HFONT hOldFont;
|
|
TEXTMETRIC tm;
|
|
int i, y;
|
|
WCHAR szSize[5];
|
|
WCHAR szCaption[LF_FULLFACESIZE + 20];
|
|
|
|
/* This is the location on the DC where we draw */
|
|
y = -nYPos;
|
|
|
|
hOldFont = SelectObject(hDC, pData->hCaptionFont);
|
|
GetTextMetrics(hDC, &tm);
|
|
|
|
swprintf(szCaption, L"%s%s", pData->szTypeFaceName, pData->szFormat);
|
|
TextOutW(hDC, 0, y, szCaption, (INT)wcslen(szCaption));
|
|
y += tm.tmHeight + SPACING1;
|
|
|
|
/* Draw a separation Line */
|
|
SelectObject(hDC, GetStockObject(BLACK_PEN));
|
|
MoveToEx(hDC, 0, y, NULL);
|
|
LineTo(hDC, 10000, y);
|
|
y += SPACING2;
|
|
|
|
/* TODO: Output font info */
|
|
|
|
/* Output Character set */
|
|
SelectObject(hDC, pData->hCharSetFont);
|
|
GetTextMetrics(hDC, &tm);
|
|
swprintf(szCaption, L"abcdefghijklmnopqrstuvwxyz");
|
|
TextOutW(hDC, 0, y, szCaption, (INT)wcslen(szCaption));
|
|
y += tm.tmHeight + 1;
|
|
|
|
swprintf(szCaption, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
|
TextOutW(hDC, 0, y, szCaption, (INT)wcslen(szCaption));
|
|
y += tm.tmHeight + 1;
|
|
|
|
swprintf(szCaption, L"0123456789.:,;(\"~!@#$%%^&*')");
|
|
TextOutW(hDC, 0, y, szCaption, (INT)wcslen(szCaption));
|
|
y += tm.tmHeight + 1;
|
|
|
|
/* Draw a separation Line */
|
|
SelectObject(hDC, GetStockObject(BLACK_PEN));
|
|
MoveToEx(hDC, 0, y, NULL);
|
|
LineTo(hDC, 10000, y);
|
|
y += SPACING2;
|
|
|
|
/* Output the strings for different sizes */
|
|
for (i = 0; i < MAX_SIZES; i++)
|
|
{
|
|
SelectObject(hDC, pData->hFonts[i]);
|
|
TextOutW(hDC, 20, y, pData->szString, (INT)wcslen(pData->szString));
|
|
GetTextMetrics(hDC, &tm);
|
|
y += tm.tmHeight + 1;
|
|
SelectObject(hDC, pData->hSizeFont);
|
|
swprintf(szSize, L"%d", pData->nSizes[i]);
|
|
TextOutW(hDC, 0, y - 13 - tm.tmDescent, szSize, (INT)wcslen(szSize));
|
|
}
|
|
SelectObject(hDC, hOldFont);
|
|
|
|
return y;
|
|
}
|
|
|
|
static int
|
|
CALLBACK
|
|
EnumFontFamProcW(
|
|
const LOGFONTW *lpelfe,
|
|
const TEXTMETRICW *lptm,
|
|
DWORD FontType,
|
|
LPARAM lParam)
|
|
{
|
|
PNEWTEXTMETRICW pntmw = (PNEWTEXTMETRICW)lptm;
|
|
PBOOL pfOpenType = (PBOOL)lParam;
|
|
|
|
if (FontType & TRUETYPE_FONTTYPE)
|
|
{
|
|
if (pntmw->ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
|
|
{
|
|
*pfOpenType = TRUE;
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static LRESULT
|
|
Display_SetTypeFace(HWND hwnd, PLOGFONTW pLogFont)
|
|
{
|
|
DISPLAYDATA* pData;
|
|
TEXTMETRIC tm;
|
|
HDC hDC;
|
|
RECT rect;
|
|
SCROLLINFO si;
|
|
int i;
|
|
LOGFONTW logfont;
|
|
BOOL fOpenType;
|
|
BYTE Buffer[512];
|
|
LPOUTLINETEXTMETRICW pOTM = (LPOUTLINETEXTMETRICW)Buffer;
|
|
LPWSTR pch;
|
|
|
|
/* Set the new type face name */
|
|
pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
lstrcpynW(pData->szTypeFaceName, pLogFont->lfFaceName,
|
|
ARRAYSIZE(pData->szTypeFaceName));
|
|
|
|
/* Create the new fonts */
|
|
hDC = GetDC(hwnd);
|
|
DeleteObject(pData->hCharSetFont);
|
|
|
|
logfont = *pLogFont;
|
|
logfont.lfHeight = -MulDiv(16, GetDeviceCaps(GetDC(NULL), LOGPIXELSY), 72);
|
|
pData->hCharSetFont = CreateFontIndirectW(&logfont);
|
|
|
|
/* Get font format */
|
|
SelectObject(hDC, pData->hCharSetFont);
|
|
GetTextMetrics(hDC, &tm);
|
|
if (tm.tmPitchAndFamily & TMPF_TRUETYPE)
|
|
{
|
|
if (GetOutlineTextMetricsW(hDC, sizeof(Buffer), pOTM))
|
|
{
|
|
LPBYTE pb = Buffer;
|
|
pb += (WORD)(DWORD_PTR)pOTM->otmpStyleName;
|
|
pch = (LPWSTR)pb;
|
|
if (*pch)
|
|
{
|
|
lstrcatW(pData->szTypeFaceName, L" ");
|
|
lstrcatW(pData->szTypeFaceName, pch);
|
|
}
|
|
}
|
|
|
|
fOpenType = FALSE;
|
|
EnumFontFamiliesExW(hDC, &logfont,
|
|
EnumFontFamProcW, (LPARAM)&fOpenType, 0);
|
|
|
|
if (fOpenType)
|
|
swprintf(pData->szFormat, L" (OpenType)");
|
|
else
|
|
swprintf(pData->szFormat, L" (TrueType)");
|
|
}
|
|
else if (tm.tmPitchAndFamily & TMPF_VECTOR)
|
|
{
|
|
swprintf(pData->szFormat, L" (Vector)");
|
|
}
|
|
else
|
|
{
|
|
swprintf(pData->szFormat, L" (Raster)");
|
|
}
|
|
|
|
for (i = 0; i < MAX_SIZES; i++)
|
|
{
|
|
DeleteObject(pData->hFonts[i]);
|
|
logfont.lfHeight = -MulDiv(pData->nSizes[i], GetDeviceCaps(hDC, LOGPIXELSY), 72);
|
|
pData->hFonts[i] = CreateFontIndirectW(&logfont);
|
|
}
|
|
|
|
/* Calculate new page dimensions */
|
|
pData->nPageHeight = Display_DrawText(hDC, pData, 0);
|
|
ReleaseDC(hwnd, hDC);
|
|
|
|
/* Set the vertical scrolling range and page size */
|
|
GetClientRect(hwnd, &rect);
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;
|
|
si.nMin = 0;
|
|
si.nMax = pData->nPageHeight;
|
|
si.nPage = rect.bottom;
|
|
si.nPos = 0;
|
|
si.nTrackPos = 0;
|
|
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static LRESULT
|
|
Display_SetString(HWND hwnd, LPCWSTR pszString)
|
|
{
|
|
DISPLAYDATA* pData;
|
|
|
|
pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
lstrcpynW(pData->szString, pszString, ARRAYSIZE(pData->szString));
|
|
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static LRESULT
|
|
Display_OnCreate(HWND hwnd)
|
|
{
|
|
DISPLAYDATA* pData;
|
|
const int nSizes[MAX_SIZES] = {8, 12, 18, 24, 36, 48, 60, 72};
|
|
int i;
|
|
LOGFONTW LogFont = {50, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
|
|
ANSI_CHARSET, OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
|
|
DEFAULT_PITCH , L"MS Shell Dlg"};
|
|
|
|
/* Create data structure */
|
|
pData = malloc(sizeof(DISPLAYDATA));
|
|
ZeroMemory(pData, sizeof(DISPLAYDATA));
|
|
|
|
/* Set the window's GWLP_USERDATA to our data structure */
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pData);
|
|
|
|
for (i = 0; i < MAX_SIZES; i++)
|
|
{
|
|
pData->nSizes[i] = nSizes[i];
|
|
}
|
|
|
|
pData->hCaptionFont = CreateFontIndirectW(&LogFont);
|
|
LogFont.lfHeight = 12;
|
|
pData->hSizeFont = CreateFontIndirectW(&LogFont);
|
|
|
|
Display_SetString(hwnd,
|
|
L"Jackdaws love my big sphinx of quartz. 1234567890");
|
|
|
|
Display_SetTypeFace(hwnd, &LogFont);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static LRESULT
|
|
Display_OnPaint(HWND hwnd)
|
|
{
|
|
DISPLAYDATA* pData;
|
|
PAINTSTRUCT ps;
|
|
SCROLLINFO si;
|
|
|
|
pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
|
|
/* Get the Scroll position */
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_POS;
|
|
GetScrollInfo(hwnd, SB_VERT, &si);
|
|
|
|
BeginPaint(hwnd, &ps);
|
|
|
|
/* Erase background */
|
|
FillRect(ps.hdc, &ps.rcPaint, GetStockObject(WHITE_BRUSH));
|
|
|
|
/* Draw the text */
|
|
Display_DrawText(ps.hdc, pData, si.nPos);
|
|
|
|
EndPaint(hwnd, &ps);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static LRESULT
|
|
Display_OnSize(HWND hwnd)
|
|
{
|
|
RECT rect;
|
|
SCROLLINFO si;
|
|
int nOldPos;
|
|
|
|
GetClientRect(hwnd, &rect);
|
|
|
|
/* Get the old scroll pos */
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_POS;
|
|
GetScrollInfo(hwnd, SB_VERT, &si);
|
|
nOldPos = si.nPos;
|
|
|
|
/* Set the new page size */
|
|
si.fMask = SIF_PAGE;
|
|
si.nPage = rect.bottom;
|
|
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
|
|
|
|
/* Get the new scroll pos */
|
|
si.fMask = SIF_POS;
|
|
GetScrollInfo(hwnd, SB_VERT, &si);
|
|
|
|
/* If they don't match ... */
|
|
if (nOldPos != si.nPos)
|
|
{
|
|
/* ... scroll the window */
|
|
ScrollWindowEx(hwnd, 0, nOldPos - si.nPos, NULL, NULL, NULL, NULL, SW_INVALIDATE);
|
|
UpdateWindow(hwnd);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static LRESULT
|
|
Display_OnVScroll(HWND hwnd, WPARAM wParam)
|
|
{
|
|
SCROLLINFO si;
|
|
int nPos;
|
|
|
|
si.cbSize = sizeof(si);
|
|
si.fMask = SIF_POS | SIF_RANGE | SIF_TRACKPOS;
|
|
GetScrollInfo(hwnd, SB_VERT, &si);
|
|
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case SB_PAGEUP:
|
|
nPos = si.nPos - 50;
|
|
break;
|
|
case SB_PAGEDOWN:
|
|
nPos = si.nPos + 50;
|
|
break;
|
|
case SB_LINEUP:
|
|
nPos = si.nPos - 10;
|
|
break;
|
|
case SB_LINEDOWN:
|
|
nPos = si.nPos + 10;
|
|
break;
|
|
case SB_THUMBTRACK:
|
|
case SB_THUMBPOSITION:
|
|
nPos = si.nTrackPos;
|
|
break;
|
|
default:
|
|
nPos = si.nPos;
|
|
}
|
|
|
|
nPos = max(nPos, si.nMin);
|
|
nPos = min(nPos, si.nMax);
|
|
if (nPos != si.nPos)
|
|
{
|
|
ScrollWindowEx(hwnd, 0, si.nPos - nPos, NULL, NULL, NULL, NULL, SW_INVALIDATE);
|
|
si.cbSize = sizeof(si);
|
|
si.nPos = nPos;
|
|
si.fMask = SIF_POS;
|
|
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
|
|
UpdateWindow(hwnd);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static LRESULT
|
|
Display_OnDestroy(HWND hwnd)
|
|
{
|
|
DISPLAYDATA* pData;
|
|
int i;
|
|
|
|
pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
|
|
/* Delete the fonts */
|
|
DeleteObject(pData->hCaptionFont);
|
|
DeleteObject(pData->hCharSetFont);
|
|
DeleteObject(pData->hSizeFont);
|
|
|
|
for (i = 0; i < MAX_SIZES; i++)
|
|
{
|
|
DeleteObject(pData->hFonts[i]);
|
|
}
|
|
|
|
/* Free the data structure */
|
|
free(pData);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT
|
|
Display_OnPrint(HWND hwnd)
|
|
{
|
|
PRINTDLG pfont;
|
|
TEXTMETRIC tm;
|
|
int copies, yPos;
|
|
|
|
/* Clears the memory before using it */
|
|
ZeroMemory(&pfont, sizeof(pfont));
|
|
|
|
pfont.lStructSize = sizeof(pfont);
|
|
pfont.hwndOwner = hwnd;
|
|
pfont.hDevMode = NULL;
|
|
pfont.hDevNames = NULL;
|
|
pfont.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC;
|
|
pfont.nCopies = 1;
|
|
pfont.nFromPage = 0xFFFF;
|
|
pfont.nToPage = 0xFFFF;
|
|
pfont.nMinPage = 1;
|
|
pfont.nMaxPage = 0xFFFF;
|
|
|
|
/* Opens up the print dialog box */
|
|
if (PrintDlg(&pfont))
|
|
{
|
|
DOCINFO docinfo;
|
|
#if 0
|
|
DISPLAYDATA* pData;
|
|
|
|
pData = malloc(sizeof(DISPLAYDATA));
|
|
ZeroMemory(pData, sizeof(DISPLAYDATA));
|
|
|
|
/* Sets up the font layout */
|
|
pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
#endif
|
|
docinfo.cbSize = sizeof(DOCINFO);
|
|
docinfo.lpszDocName = L"Printing Font";
|
|
docinfo.lpszOutput = NULL;
|
|
docinfo.lpszDatatype = NULL;
|
|
docinfo.fwType = 0;
|
|
|
|
/* We start printing */
|
|
StartDoc(pfont.hDC, &docinfo);
|
|
|
|
/* Grabs the text metrics for the printer */
|
|
GetTextMetrics(pfont.hDC, &tm);
|
|
|
|
/* Start out with 0 for the y position for the page */
|
|
yPos = 0;
|
|
|
|
/* Starts out with the current page */
|
|
StartPage(pfont.hDC);
|
|
|
|
/* Used when printing for more than one copy */
|
|
for (copies = 0; copies < pfont.nCopies; copies++)
|
|
{
|
|
/* Test output */
|
|
TextOutW(pfont.hDC, 10, yPos, L"Testing...1...2...3", 19);
|
|
|
|
/* TODO: Determine if using Display_DrawText() will work for both rendering out to the
|
|
window and to the printer output */
|
|
#if 0
|
|
Display_DrawText(pfont.hDC, pData, yPos);
|
|
#endif
|
|
|
|
/* Ends the current page */
|
|
EndPage(pfont.hDC);
|
|
|
|
/* If we are making more than one copy, start a new page */
|
|
if (copies != pfont.nCopies)
|
|
{
|
|
yPos = 0;
|
|
StartPage(pfont.hDC);
|
|
}
|
|
}
|
|
|
|
/* The printing is now over */
|
|
EndDoc(pfont.hDC);
|
|
|
|
DeleteDC(pfont.hDC);
|
|
#if 0
|
|
/* Frees the memory since we no longer need it for now */
|
|
free(pData);
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LRESULT
|
|
Display_GetFullName(HWND hwnd, INT length, PWSTR ptr)
|
|
{
|
|
DISPLAYDATA *pData;
|
|
INT len;
|
|
|
|
pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
|
|
len = wcslen(pData->szTypeFaceName) + wcslen(pData->szFormat) + 2;
|
|
|
|
if (ptr != NULL && length >= len)
|
|
{
|
|
swprintf(ptr, L"%s%s", pData->szTypeFaceName, pData->szFormat);
|
|
}
|
|
|
|
return (LRESULT)len;
|
|
}
|
|
|
|
LRESULT CALLBACK
|
|
DisplayProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
case WM_CREATE:
|
|
return Display_OnCreate(hwnd);
|
|
|
|
case WM_PAINT:
|
|
return Display_OnPaint(hwnd);
|
|
|
|
case WM_SIZE:
|
|
return Display_OnSize(hwnd);
|
|
|
|
case WM_VSCROLL:
|
|
return Display_OnVScroll(hwnd, wParam);
|
|
|
|
case FVM_SETTYPEFACE:
|
|
return Display_SetTypeFace(hwnd, (PLOGFONTW)lParam);
|
|
|
|
case FVM_SETSTRING:
|
|
return Display_SetString(hwnd, (WCHAR *)lParam);
|
|
|
|
case FVM_GETFULLNAME:
|
|
return Display_GetFullName(hwnd, (INT)wParam, (PWSTR)lParam);
|
|
|
|
case WM_DESTROY:
|
|
return Display_OnDestroy(hwnd);
|
|
|
|
default:
|
|
return DefWindowProcW(hwnd, message, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|