1 /* 2 * fontview display class 3 * 4 * display.c 5 * 6 * Copyright (C) 2007 Timo Kreuzer <timo <dot> kreuzer <at> reactos <dot> org> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License along 19 * with this program; if not, write to the Free Software Foundation, Inc., 20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 */ 22 23 #include "precomp.h" 24 25 #include <stdio.h> 26 #include <malloc.h> 27 28 #define SPACING1 8 29 #define SPACING2 5 30 31 extern INT g_NumFonts; 32 extern WCHAR g_FontTitle[]; 33 34 const WCHAR g_szFontDisplayClassName[] = L"FontDisplayClass"; 35 LRESULT CALLBACK DisplayProc(HWND, UINT, WPARAM, LPARAM); 36 37 /* Internal data storage type */ 38 typedef struct 39 { 40 int nPageHeight; 41 WCHAR szTypeFaceName[LF_FULLFACESIZE]; 42 WCHAR szFormat[MAX_FORMAT]; 43 WCHAR szString[MAX_STRING]; 44 45 HFONT hCaptionFont; 46 HFONT hCharSetFont; 47 HFONT hSizeFont; 48 HFONT hFonts[MAX_SIZES]; 49 int nSizes[MAX_SIZES]; 50 int nHeights[MAX_SIZES]; 51 } DISPLAYDATA; 52 53 /* This is the only public function, it registers the class */ 54 BOOL 55 Display_InitClass(HINSTANCE hInstance) 56 { 57 WNDCLASSEXW wincl; 58 59 /* Set the fontdisplay window class structure */ 60 wincl.cbSize = sizeof(WNDCLASSEX); 61 wincl.style = CS_DBLCLKS; 62 wincl.lpfnWndProc = DisplayProc; 63 wincl.cbClsExtra = 0; 64 wincl.cbWndExtra = 0; 65 wincl.hInstance = hInstance; 66 wincl.hIcon = NULL; 67 wincl.hCursor = LoadCursor (NULL, IDC_ARROW); 68 wincl.hbrBackground = GetStockObject(WHITE_BRUSH); 69 wincl.lpszMenuName = NULL; 70 wincl.lpszClassName = g_szFontDisplayClassName; 71 wincl.hIconSm = NULL; 72 73 /* Register the window class, and if it fails return FALSE */ 74 if (!RegisterClassExW (&wincl)) 75 { 76 return FALSE; 77 } 78 return TRUE; 79 } 80 81 static int 82 Display_DrawText(HDC hDC, DISPLAYDATA* pData, int nYPos) 83 { 84 HFONT hOldFont; 85 TEXTMETRIC tm; 86 int i, y; 87 WCHAR szSize[5]; 88 WCHAR szCaption[LF_FULLFACESIZE + 20]; 89 90 /* This is the location on the DC where we draw */ 91 y = -nYPos; 92 93 hOldFont = SelectObject(hDC, pData->hCaptionFont); 94 GetTextMetrics(hDC, &tm); 95 96 swprintf(szCaption, L"%s%s", pData->szTypeFaceName, pData->szFormat); 97 TextOutW(hDC, 0, y, szCaption, (INT)wcslen(szCaption)); 98 y += tm.tmHeight + SPACING1; 99 100 /* Draw a separation Line */ 101 SelectObject(hDC, GetStockObject(BLACK_PEN)); 102 MoveToEx(hDC, 0, y, NULL); 103 LineTo(hDC, 10000, y); 104 y += SPACING2; 105 106 /* TODO: Output font info */ 107 108 /* Output Character set */ 109 SelectObject(hDC, pData->hCharSetFont); 110 GetTextMetrics(hDC, &tm); 111 swprintf(szCaption, L"abcdefghijklmnopqrstuvwxyz"); 112 TextOutW(hDC, 0, y, szCaption, (INT)wcslen(szCaption)); 113 y += tm.tmHeight + 1; 114 115 swprintf(szCaption, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 116 TextOutW(hDC, 0, y, szCaption, (INT)wcslen(szCaption)); 117 y += tm.tmHeight + 1; 118 119 swprintf(szCaption, L"0123456789.:,;(\"~!@#$%%^&*')"); 120 TextOutW(hDC, 0, y, szCaption, (INT)wcslen(szCaption)); 121 y += tm.tmHeight + 1; 122 123 /* Draw a separation Line */ 124 SelectObject(hDC, GetStockObject(BLACK_PEN)); 125 MoveToEx(hDC, 0, y, NULL); 126 LineTo(hDC, 10000, y); 127 y += SPACING2; 128 129 /* Output the strings for different sizes */ 130 for (i = 0; i < MAX_SIZES; i++) 131 { 132 SelectObject(hDC, pData->hFonts[i]); 133 TextOutW(hDC, 20, y, pData->szString, (INT)wcslen(pData->szString)); 134 GetTextMetrics(hDC, &tm); 135 y += tm.tmHeight + 1; 136 SelectObject(hDC, pData->hSizeFont); 137 swprintf(szSize, L"%d", pData->nSizes[i]); 138 TextOutW(hDC, 0, y - 13 - tm.tmDescent, szSize, (INT)wcslen(szSize)); 139 } 140 SelectObject(hDC, hOldFont); 141 142 return y; 143 } 144 145 static int 146 CALLBACK 147 EnumFontFamProcW( 148 const LOGFONTW *lpelfe, 149 const TEXTMETRICW *lptm, 150 DWORD FontType, 151 LPARAM lParam) 152 { 153 PNEWTEXTMETRICW pntmw = (PNEWTEXTMETRICW)lptm; 154 PBOOL pfOpenType = (PBOOL)lParam; 155 156 if (FontType & TRUETYPE_FONTTYPE) 157 { 158 if (pntmw->ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) 159 { 160 *pfOpenType = TRUE; 161 return FALSE; 162 } 163 } 164 return TRUE; 165 } 166 167 static LRESULT 168 Display_SetTypeFace(HWND hwnd, PLOGFONTW pLogFont) 169 { 170 DISPLAYDATA* pData; 171 TEXTMETRIC tm; 172 HDC hDC; 173 RECT rect; 174 SCROLLINFO si; 175 int i; 176 LOGFONTW logfont; 177 BOOL fOpenType; 178 BYTE Buffer[512]; 179 LPOUTLINETEXTMETRICW pOTM = (LPOUTLINETEXTMETRICW)Buffer; 180 LPWSTR pch; 181 182 /* Set the new type face name */ 183 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA); 184 lstrcpynW(pData->szTypeFaceName, pLogFont->lfFaceName, 185 ARRAYSIZE(pData->szTypeFaceName)); 186 187 /* Create the new fonts */ 188 hDC = GetDC(hwnd); 189 DeleteObject(pData->hCharSetFont); 190 191 logfont = *pLogFont; 192 logfont.lfHeight = -MulDiv(16, GetDeviceCaps(GetDC(NULL), LOGPIXELSY), 72); 193 pData->hCharSetFont = CreateFontIndirectW(&logfont); 194 195 /* Get font format */ 196 SelectObject(hDC, pData->hCharSetFont); 197 GetTextMetrics(hDC, &tm); 198 if (tm.tmPitchAndFamily & TMPF_TRUETYPE) 199 { 200 if (GetOutlineTextMetricsW(hDC, sizeof(Buffer), pOTM)) 201 { 202 LPBYTE pb = Buffer; 203 pb += (WORD)(DWORD_PTR)pOTM->otmpStyleName; 204 pch = (LPWSTR)pb; 205 if (*pch) 206 { 207 lstrcatW(pData->szTypeFaceName, L" "); 208 lstrcatW(pData->szTypeFaceName, pch); 209 } 210 } 211 212 fOpenType = FALSE; 213 EnumFontFamiliesExW(hDC, &logfont, 214 EnumFontFamProcW, (LPARAM)&fOpenType, 0); 215 216 if (fOpenType) 217 swprintf(pData->szFormat, L" (OpenType)"); 218 else 219 swprintf(pData->szFormat, L" (TrueType)"); 220 } 221 else if (tm.tmPitchAndFamily & TMPF_VECTOR) 222 { 223 swprintf(pData->szFormat, L" (Vector)"); 224 } 225 else 226 { 227 swprintf(pData->szFormat, L" (Raster)"); 228 } 229 230 for (i = 0; i < MAX_SIZES; i++) 231 { 232 DeleteObject(pData->hFonts[i]); 233 logfont.lfHeight = -MulDiv(pData->nSizes[i], GetDeviceCaps(hDC, LOGPIXELSY), 72); 234 pData->hFonts[i] = CreateFontIndirectW(&logfont); 235 } 236 237 /* Calculate new page dimensions */ 238 pData->nPageHeight = Display_DrawText(hDC, pData, 0); 239 ReleaseDC(hwnd, hDC); 240 241 /* Set the vertical scrolling range and page size */ 242 GetClientRect(hwnd, &rect); 243 si.cbSize = sizeof(si); 244 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS; 245 si.nMin = 0; 246 si.nMax = pData->nPageHeight; 247 si.nPage = rect.bottom; 248 si.nPos = 0; 249 si.nTrackPos = 0; 250 SetScrollInfo(hwnd, SB_VERT, &si, TRUE); 251 252 return 0; 253 } 254 255 static LRESULT 256 Display_SetString(HWND hwnd, LPCWSTR pszString) 257 { 258 DISPLAYDATA* pData; 259 260 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA); 261 lstrcpynW(pData->szString, pszString, ARRAYSIZE(pData->szString)); 262 263 InvalidateRect(hwnd, NULL, TRUE); 264 265 return 0; 266 } 267 268 static LRESULT 269 Display_OnCreate(HWND hwnd) 270 { 271 DISPLAYDATA* pData; 272 const int nSizes[MAX_SIZES] = {8, 12, 18, 24, 36, 48, 60, 72}; 273 int i; 274 LOGFONTW LogFont = {50, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, 275 ANSI_CHARSET, OUT_DEFAULT_PRECIS, 276 CLIP_DEFAULT_PRECIS, PROOF_QUALITY, 277 DEFAULT_PITCH , L"MS Shell Dlg"}; 278 279 /* Create data structure */ 280 pData = malloc(sizeof(DISPLAYDATA)); 281 ZeroMemory(pData, sizeof(DISPLAYDATA)); 282 283 /* Set the window's GWLP_USERDATA to our data structure */ 284 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pData); 285 286 for (i = 0; i < MAX_SIZES; i++) 287 { 288 pData->nSizes[i] = nSizes[i]; 289 } 290 291 pData->hCaptionFont = CreateFontIndirectW(&LogFont); 292 LogFont.lfHeight = 12; 293 pData->hSizeFont = CreateFontIndirectW(&LogFont); 294 295 Display_SetString(hwnd, 296 L"Jackdaws love my big sphinx of quartz. 1234567890"); 297 298 Display_SetTypeFace(hwnd, &LogFont); 299 300 return 0; 301 } 302 303 static LRESULT 304 Display_OnPaint(HWND hwnd) 305 { 306 DISPLAYDATA* pData; 307 PAINTSTRUCT ps; 308 SCROLLINFO si; 309 310 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA); 311 312 /* Get the Scroll position */ 313 si.cbSize = sizeof(si); 314 si.fMask = SIF_POS; 315 GetScrollInfo(hwnd, SB_VERT, &si); 316 317 BeginPaint(hwnd, &ps); 318 319 /* Erase background */ 320 FillRect(ps.hdc, &ps.rcPaint, GetStockObject(WHITE_BRUSH)); 321 322 /* Draw the text */ 323 Display_DrawText(ps.hdc, pData, si.nPos); 324 325 EndPaint(hwnd, &ps); 326 327 return 0; 328 } 329 330 static LRESULT 331 Display_OnSize(HWND hwnd) 332 { 333 RECT rect; 334 SCROLLINFO si; 335 int nOldPos; 336 337 GetClientRect(hwnd, &rect); 338 339 /* Get the old scroll pos */ 340 si.cbSize = sizeof(si); 341 si.fMask = SIF_POS; 342 GetScrollInfo(hwnd, SB_VERT, &si); 343 nOldPos = si.nPos; 344 345 /* Set the new page size */ 346 si.fMask = SIF_PAGE; 347 si.nPage = rect.bottom; 348 SetScrollInfo(hwnd, SB_VERT, &si, TRUE); 349 350 /* Get the new scroll pos */ 351 si.fMask = SIF_POS; 352 GetScrollInfo(hwnd, SB_VERT, &si); 353 354 /* If they don't match ... */ 355 if (nOldPos != si.nPos) 356 { 357 /* ... scroll the window */ 358 ScrollWindowEx(hwnd, 0, nOldPos - si.nPos, NULL, NULL, NULL, NULL, SW_INVALIDATE); 359 UpdateWindow(hwnd); 360 } 361 362 return 0; 363 } 364 365 static LRESULT 366 Display_OnVScroll(HWND hwnd, WPARAM wParam) 367 { 368 SCROLLINFO si; 369 int nPos; 370 371 si.cbSize = sizeof(si); 372 si.fMask = SIF_POS | SIF_RANGE | SIF_TRACKPOS; 373 GetScrollInfo(hwnd, SB_VERT, &si); 374 375 switch(LOWORD(wParam)) 376 { 377 case SB_PAGEUP: 378 nPos = si.nPos - 50; 379 break; 380 case SB_PAGEDOWN: 381 nPos = si.nPos + 50; 382 break; 383 case SB_LINEUP: 384 nPos = si.nPos - 10; 385 break; 386 case SB_LINEDOWN: 387 nPos = si.nPos + 10; 388 break; 389 case SB_THUMBTRACK: 390 case SB_THUMBPOSITION: 391 nPos = si.nTrackPos; 392 break; 393 default: 394 nPos = si.nPos; 395 } 396 397 nPos = max(nPos, si.nMin); 398 nPos = min(nPos, si.nMax); 399 if (nPos != si.nPos) 400 { 401 ScrollWindowEx(hwnd, 0, si.nPos - nPos, NULL, NULL, NULL, NULL, SW_INVALIDATE); 402 si.cbSize = sizeof(si); 403 si.nPos = nPos; 404 si.fMask = SIF_POS; 405 SetScrollInfo(hwnd, SB_VERT, &si, TRUE); 406 UpdateWindow(hwnd); 407 } 408 409 return 0; 410 } 411 412 static LRESULT 413 Display_OnDestroy(HWND hwnd) 414 { 415 DISPLAYDATA* pData; 416 int i; 417 418 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA); 419 420 /* Delete the fonts */ 421 DeleteObject(pData->hCaptionFont); 422 DeleteObject(pData->hCharSetFont); 423 DeleteObject(pData->hSizeFont); 424 425 for (i = 0; i < MAX_SIZES; i++) 426 { 427 DeleteObject(pData->hFonts[i]); 428 } 429 430 /* Free the data structure */ 431 free(pData); 432 433 return 0; 434 } 435 436 LRESULT 437 Display_OnPrint(HWND hwnd) 438 { 439 PRINTDLG pfont; 440 TEXTMETRIC tm; 441 int copies, yPos; 442 443 /* Clears the memory before using it */ 444 ZeroMemory(&pfont, sizeof(pfont)); 445 446 pfont.lStructSize = sizeof(pfont); 447 pfont.hwndOwner = hwnd; 448 pfont.hDevMode = NULL; 449 pfont.hDevNames = NULL; 450 pfont.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC; 451 pfont.nCopies = 1; 452 pfont.nFromPage = 0xFFFF; 453 pfont.nToPage = 0xFFFF; 454 pfont.nMinPage = 1; 455 pfont.nMaxPage = 0xFFFF; 456 457 /* Opens up the print dialog box */ 458 if (PrintDlg(&pfont)) 459 { 460 DOCINFO docinfo; 461 #if 0 462 DISPLAYDATA* pData; 463 464 pData = malloc(sizeof(DISPLAYDATA)); 465 ZeroMemory(pData, sizeof(DISPLAYDATA)); 466 467 /* Sets up the font layout */ 468 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA); 469 #endif 470 docinfo.cbSize = sizeof(DOCINFO); 471 docinfo.lpszDocName = L"Printing Font"; 472 docinfo.lpszOutput = NULL; 473 docinfo.lpszDatatype = NULL; 474 docinfo.fwType = 0; 475 476 /* We start printing */ 477 StartDoc(pfont.hDC, &docinfo); 478 479 /* Grabs the text metrics for the printer */ 480 GetTextMetrics(pfont.hDC, &tm); 481 482 /* Start out with 0 for the y position for the page */ 483 yPos = 0; 484 485 /* Starts out with the current page */ 486 StartPage(pfont.hDC); 487 488 /* Used when printing for more than one copy */ 489 for (copies = 0; copies < pfont.nCopies; copies++) 490 { 491 /* Test output */ 492 TextOutW(pfont.hDC, 10, yPos, L"Testing...1...2...3", 19); 493 494 /* TODO: Determine if using Display_DrawText() will work for both rendering out to the 495 window and to the printer output */ 496 #if 0 497 Display_DrawText(pfont.hDC, pData, yPos); 498 #endif 499 500 /* Ends the current page */ 501 EndPage(pfont.hDC); 502 503 /* If we are making more than one copy, start a new page */ 504 if (copies != pfont.nCopies) 505 { 506 yPos = 0; 507 StartPage(pfont.hDC); 508 } 509 } 510 511 /* The printing is now over */ 512 EndDoc(pfont.hDC); 513 514 DeleteDC(pfont.hDC); 515 #if 0 516 /* Frees the memory since we no longer need it for now */ 517 free(pData); 518 #endif 519 } 520 521 return 0; 522 } 523 524 LRESULT 525 Display_GetFullName(HWND hwnd, INT length, PWSTR ptr) 526 { 527 DISPLAYDATA *pData; 528 INT len; 529 530 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA); 531 532 len = wcslen(pData->szTypeFaceName) + wcslen(pData->szFormat) + 2; 533 534 if (ptr != NULL && length >= len) 535 { 536 swprintf(ptr, L"%s%s", pData->szTypeFaceName, pData->szFormat); 537 } 538 539 return (LRESULT)len; 540 } 541 542 LRESULT CALLBACK 543 DisplayProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 544 { 545 switch (message) 546 { 547 case WM_CREATE: 548 return Display_OnCreate(hwnd); 549 550 case WM_PAINT: 551 return Display_OnPaint(hwnd); 552 553 case WM_SIZE: 554 return Display_OnSize(hwnd); 555 556 case WM_VSCROLL: 557 return Display_OnVScroll(hwnd, wParam); 558 559 case FVM_SETTYPEFACE: 560 return Display_SetTypeFace(hwnd, (PLOGFONTW)lParam); 561 562 case FVM_SETSTRING: 563 return Display_SetString(hwnd, (WCHAR *)lParam); 564 565 case FVM_GETFULLNAME: 566 return Display_GetFullName(hwnd, (INT)wParam, (PWSTR)lParam); 567 568 case WM_DESTROY: 569 return Display_OnDestroy(hwnd); 570 571 default: 572 return DefWindowProcW(hwnd, message, wParam, lParam); 573 } 574 575 return 0; 576 } 577 578