sync with trunk r46493
[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 <windows.h>
24 #include <stdio.h>
25
26 #include "display.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, 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 hOldFont = SelectObject(hDC, pData->hCharSetFont);
107 GetTextMetrics(hDC, &tm);
108 swprintf(szCaption, L"abcdefghijklmnopqrstuvwxyz");
109 TextOutW(hDC, 0, y, szCaption, wcslen(szCaption));
110 y += tm.tmHeight + 1;
111
112 swprintf(szCaption, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
113 TextOutW(hDC, 0, y, szCaption, wcslen(szCaption));
114 y += tm.tmHeight + 1;
115
116 swprintf(szCaption, L"0123456789.:,;(\"~!@#$%^&*')");
117 TextOutW(hDC, 0, y, szCaption, 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, 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, wcslen(szSize));
136 }
137 SelectObject(hDC, hOldFont);
138
139 return y;
140 }
141
142 static LRESULT
143 Display_SetTypeFace(HWND hwnd, PEXTLOGFONTW pExtLogFont)
144 {
145 DISPLAYDATA* pData;
146 TEXTMETRIC tm;
147 HDC hDC;
148 RECT rect;
149 SCROLLINFO si;
150 int i;
151 LOGFONTW logfont;
152
153 /* Set the new type face name */
154 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
155 _snwprintf(pData->szTypeFaceName, LF_FULLFACESIZE, pExtLogFont->elfFullName);
156
157 /* Create the new fonts */
158 hDC = GetDC(hwnd);
159 DeleteObject(pData->hCharSetFont);
160
161 logfont = pExtLogFont->elfLogFont;
162 logfont.lfHeight = -MulDiv(16, GetDeviceCaps(GetDC(NULL), LOGPIXELSY), 72);
163 pData->hCharSetFont = CreateFontIndirectW(&logfont);
164
165 /* Get font format */
166 // FIXME: Get the real font format (OpenType?)
167 SelectObject(hDC, pData->hCharSetFont);
168 GetTextMetrics(hDC, &tm);
169 if ((tm.tmPitchAndFamily & TMPF_TRUETYPE) == TMPF_TRUETYPE)
170 {
171 swprintf(pData->szFormat, L" (TrueType)");
172 }
173
174 for (i = 0; i < MAX_SIZES; i++)
175 {
176 DeleteObject(pData->hFonts[i]);
177 logfont.lfHeight = -MulDiv(pData->nSizes[i], GetDeviceCaps(hDC, LOGPIXELSY), 72);
178 pData->hFonts[i] = CreateFontIndirectW(&logfont);
179 }
180
181 /* Calculate new page dimensions */
182 pData->nPageHeight = Display_DrawText(hDC, pData, 0);
183 ReleaseDC(hwnd, hDC);
184
185 /* Set the vertical scrolling range and page size */
186 GetClientRect(hwnd, &rect);
187 si.cbSize = sizeof(si);
188 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;
189 si.nMin = 0;
190 si.nMax = pData->nPageHeight;
191 si.nPage = rect.bottom;
192 si.nPos = 0;
193 si.nTrackPos = 0;
194 SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
195
196 return 0;
197 }
198
199 static LRESULT
200 Display_SetString(HWND hwnd, LPARAM lParam)
201 {
202 DISPLAYDATA* pData;
203
204 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
205 _snwprintf(pData->szString, MAX_STRING, (WCHAR*)lParam);
206
207 // FIXME: redraw the window
208
209 return 0;
210 }
211
212 static LRESULT
213 Display_OnCreate(HWND hwnd)
214 {
215 DISPLAYDATA* pData;
216 const int nSizes[MAX_SIZES] = {8, 12, 18, 24, 36, 48, 60, 72};
217 int i;
218 EXTLOGFONTW ExtLogFont = {{50, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
219 ANSI_CHARSET, OUT_DEFAULT_PRECIS,
220 CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
221 DEFAULT_PITCH , L"Ms Shell Dlg"},
222 L"Ms Shell Dlg"};
223
224 /* Create data structure */
225 pData = malloc(sizeof(DISPLAYDATA));
226 ZeroMemory(pData, sizeof(DISPLAYDATA));
227
228 /* Set the window's GWLP_USERDATA to our data structure */
229 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pData);
230
231 for (i = 0; i < MAX_SIZES; i++)
232 {
233 pData->nSizes[i] = nSizes[i];
234 }
235
236 pData->hCaptionFont = CreateFontIndirectW(&ExtLogFont.elfLogFont);
237 ExtLogFont.elfLogFont.lfHeight = 12;
238 pData->hSizeFont = CreateFontIndirectW(&ExtLogFont.elfLogFont);
239
240 Display_SetString(hwnd, (LPARAM)L"Jackdaws love my big sphinx of quartz. 1234567890");
241
242 Display_SetTypeFace(hwnd, &ExtLogFont);
243
244 return 0;
245 }
246
247 static LRESULT
248 Display_OnPaint(HWND hwnd)
249 {
250 DISPLAYDATA* pData;
251 PAINTSTRUCT ps;
252 SCROLLINFO si;
253
254 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
255
256 /* Get the Scroll position */
257 si.cbSize = sizeof(si);
258 si.fMask = SIF_POS;
259 GetScrollInfo(hwnd, SB_VERT, &si);
260
261 BeginPaint(hwnd, &ps);
262
263 /* Erase background */
264 FillRect(ps.hdc, &ps.rcPaint, GetStockObject(WHITE_BRUSH));
265
266 /* Draw the text */
267 Display_DrawText(ps.hdc, pData, si.nPos);
268
269 EndPaint(hwnd, &ps);
270
271 return 0;
272 }
273
274 static LRESULT
275 Display_OnSize(HWND hwnd)
276 {
277 RECT rect;
278 SCROLLINFO si;
279 int nOldPos;
280
281 GetClientRect(hwnd, &rect);
282
283 /* Get the old scroll pos */
284 si.cbSize = sizeof(si);
285 si.fMask = SIF_POS;
286 GetScrollInfo(hwnd, SB_VERT, &si);
287 nOldPos = si.nPos;
288
289 /* Set the new page size */
290 si.fMask = SIF_PAGE;
291 si.nPage = rect.bottom;
292 SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
293
294 /* Get the new scroll pos */
295 si.fMask = SIF_POS;
296 GetScrollInfo(hwnd, SB_VERT, &si);
297
298 /* If they don't match ... */
299 if (nOldPos != si.nPos)
300 {
301 /* ... scroll the window */
302 ScrollWindowEx(hwnd, 0, nOldPos - si.nPos, NULL, NULL, NULL, NULL, SW_INVALIDATE);
303 UpdateWindow(hwnd);
304 }
305
306 return 0;
307 }
308
309 static LRESULT
310 Display_OnVScroll(HWND hwnd, WPARAM wParam)
311 {
312 SCROLLINFO si;
313 int nPos;
314
315 si.cbSize = sizeof(si);
316 si.fMask = SIF_POS | SIF_RANGE | SIF_TRACKPOS;
317 GetScrollInfo(hwnd, SB_VERT, &si);
318
319 switch(LOWORD(wParam))
320 {
321 case SB_PAGEUP:
322 nPos = si.nPos - 50;
323 break;
324 case SB_PAGEDOWN:
325 nPos = si.nPos + 50;
326 break;
327 case SB_LINEUP:
328 nPos = si.nPos - 10;
329 break;
330 case SB_LINEDOWN:
331 nPos = si.nPos + 10;
332 break;
333 case SB_THUMBTRACK:
334 case SB_THUMBPOSITION:
335 nPos = si.nTrackPos;
336 break;
337 default:
338 nPos = si.nPos;
339 }
340
341 nPos = max(nPos, si.nMin);
342 nPos = min(nPos, si.nMax);
343 if (nPos != si.nPos)
344 {
345 ScrollWindowEx(hwnd, 0, si.nPos - nPos, NULL, NULL, NULL, NULL, SW_INVALIDATE);
346 si.cbSize = sizeof(si);
347 si.nPos = nPos;
348 si.fMask = SIF_POS;
349 SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
350 UpdateWindow(hwnd);
351 }
352
353 return 0;
354 }
355
356 static LRESULT
357 Display_OnDestroy(HWND hwnd)
358 {
359 DISPLAYDATA* pData;
360 int i;
361
362 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
363
364 /* Delete the fonts */
365 DeleteObject(pData->hCaptionFont);
366 DeleteObject(pData->hCharSetFont);
367 DeleteObject(pData->hSizeFont);
368
369 for (i = 0; i < MAX_SIZES; i++)
370 {
371 DeleteObject(pData->hFonts[i]);
372 }
373
374 /* Free the data structure */
375 free(pData);
376
377 return 0;
378 }
379
380 LRESULT CALLBACK
381 DisplayProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
382 {
383 switch (message)
384 {
385 case WM_CREATE:
386 return Display_OnCreate(hwnd);
387
388 case WM_PAINT:
389 return Display_OnPaint(hwnd);
390
391 case WM_SIZE:
392 return Display_OnSize(hwnd);
393
394 case WM_VSCROLL:
395 return Display_OnVScroll(hwnd, wParam);
396
397 case FVM_SETTYPEFACE:
398 return Display_SetTypeFace(hwnd, (PEXTLOGFONTW)lParam);
399
400 case FVM_SETSTRING:
401 return Display_SetString(hwnd, lParam);
402
403 case WM_DESTROY:
404 return Display_OnDestroy(hwnd);
405
406 default:
407 return DefWindowProcW(hwnd, message, wParam, lParam);
408 }
409
410 return 0;
411 }
412