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