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