[CLASS2]
[reactos.git] / base / applications / fontview / display.c
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