xref: /reactos/dll/cpl/desk/preview.c (revision 8a978a17)
1 /*
2  * PROJECT:     ReactOS Desktop Control Panel
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        dll/cpl/desk/preview.c
5  * PURPOSE:     Draws the preview control
6  * COPYRIGHT:   Copyright 2006, 2007 Eric Kohl
7  */
8 
9 #include "desk.h"
10 
11 static const TCHAR szPreviewWndClass[] = TEXT("PreviewWndClass");
12 
13 typedef struct _PREVIEW_DATA
14 {
15     HDC hdcPreview;
16 
17     HWND hwndParent;
18 
19     COLOR_SCHEME Scheme;
20 
21     HBRUSH hbrScrollbar;
22     HBRUSH hbrDesktop;
23     HBRUSH hbrWindow;
24 
25     INT cxEdge;
26     INT cyEdge;
27 
28     INT cySizeFrame;
29 
30     INT cyCaption;
31     INT cyBorder;
32     INT cyMenu;
33     INT cxScrollbar;
34 
35     RECT rcDesktop;
36     RECT rcInactiveFrame;
37     RECT rcInactiveCaption;
38     RECT rcInactiveCaptionButtons;
39 
40     RECT rcActiveFrame;
41     RECT rcActiveCaption;
42     RECT rcActiveCaptionButtons;
43     RECT rcActiveMenuBar;
44     RECT rcSelectedMenuItem;
45     RECT rcActiveClient;
46     RECT rcActiveScroll;
47 
48     RECT rcDialogFrame;
49     RECT rcDialogCaption;
50     RECT rcDialogCaptionButtons;
51     RECT rcDialogClient;
52 
53     RECT rcDialogButton;
54 
55     LPTSTR lpInAct;
56     LPTSTR lpAct;
57     LPTSTR lpWinTxt;
58     LPTSTR lpMessBox;
59     LPTSTR lpMessText;
60     LPTSTR lpButText;
61 
62     HFONT hCaptionFont;
63     HFONT hMenuFont;
64     HFONT hMessageFont;
65     HFONT hClientFont;
66 
67     HMENU hMenu;
68 
69 } PREVIEW_DATA, *PPREVIEW_DATA;
70 
71 
72 static VOID UpdatePreviewTheme(HWND hwnd, PPREVIEW_DATA pPreviewData, COLOR_SCHEME *scheme)
73 {
74     if (pPreviewData->hbrScrollbar != NULL)
75         DeleteObject(pPreviewData->hbrScrollbar);
76     pPreviewData->hbrScrollbar = CreateSolidBrush(scheme->crColor[COLOR_SCROLLBAR]);
77     if (pPreviewData->hbrDesktop != NULL)
78         DeleteObject(pPreviewData->hbrDesktop);
79 
80     pPreviewData->hbrDesktop = CreateSolidBrush(scheme->crColor[COLOR_DESKTOP]);
81     if (pPreviewData->hbrWindow != NULL)
82         DeleteObject(pPreviewData->hbrWindow);
83     pPreviewData->hbrWindow = CreateSolidBrush(scheme->crColor[COLOR_WINDOW]);
84 
85     pPreviewData->cxEdge = 2;                                       /* SM_CXEDGE */
86     pPreviewData->cyEdge = 2;                                       /* SM_CYEDGE */
87 
88     pPreviewData->cySizeFrame = scheme->ncMetrics.iBorderWidth;     /* SM_CYSIZEFRAME */
89 
90     pPreviewData->cyCaption = scheme->ncMetrics.iCaptionHeight+1;   /* SM_CYCAPTION */
91     pPreviewData->cyMenu = scheme->ncMetrics.iMenuHeight -1;        /* SM_CYMENU */
92     pPreviewData->cxScrollbar = scheme->ncMetrics.iScrollWidth;     /* SM_CXVSCROLL */
93     pPreviewData->cyBorder = scheme->ncMetrics.iBorderWidth;        /* SM_CYBORDER */
94 
95     if (pPreviewData->hCaptionFont != NULL)
96         DeleteObject(pPreviewData->hCaptionFont);
97     pPreviewData->hCaptionFont = CreateFontIndirect(&scheme->ncMetrics.lfCaptionFont);
98 
99     if (pPreviewData->hMenuFont != NULL)
100         DeleteObject(pPreviewData->hMenuFont);
101     pPreviewData->hMenuFont = CreateFontIndirect(&scheme->ncMetrics.lfMenuFont);
102 
103     if (pPreviewData->hMessageFont != NULL)
104         DeleteObject(pPreviewData->hMessageFont);
105     pPreviewData->hMessageFont = CreateFontIndirect(&scheme->ncMetrics.lfMessageFont);
106 
107     pPreviewData->Scheme = *scheme;
108     InvalidateRect(hwnd, NULL, FALSE);
109 }
110 
111 static VOID
112 OnCreate(HWND hwnd, PPREVIEW_DATA pPreviewData)
113 {
114     COLOR_SCHEME *scheme;
115 
116     pPreviewData->hClientFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
117 
118     /* Load and modify the menu */
119     pPreviewData->hMenu = LoadMenu(hApplet, MAKEINTRESOURCE(IDR_PREVIEW_MENU));
120     EnableMenuItem(pPreviewData->hMenu,
121                    1, MF_BYPOSITION | MF_GRAYED);
122     HiliteMenuItem(hwnd, pPreviewData->hMenu,
123                    2, MF_BYPOSITION | MF_HILITE);
124 
125 //    GetMenuItemRect(hwnd, pPreviewData->hMenu,
126 //                    2, &pPreviewData->rcSelectedMenuItem);
127 
128     AllocAndLoadString(&pPreviewData->lpInAct, hApplet, IDS_INACTWIN);
129     AllocAndLoadString(&pPreviewData->lpAct, hApplet, IDS_ACTWIN);
130     AllocAndLoadString(&pPreviewData->lpWinTxt, hApplet, IDS_WINTEXT);
131     AllocAndLoadString(&pPreviewData->lpMessBox, hApplet, IDS_MESSBOX);
132     AllocAndLoadString(&pPreviewData->lpMessText, hApplet, IDS_MESSTEXT);
133     AllocAndLoadString(&pPreviewData->lpButText, hApplet, IDS_BUTTEXT);
134 
135     scheme = &pPreviewData->Scheme;
136     LoadCurrentScheme(scheme);
137 
138     UpdatePreviewTheme(hwnd, pPreviewData, scheme);
139 }
140 
141 
142 static VOID
143 CalculateItemSize(PPREVIEW_DATA pPreviewData)
144 {
145     int width, height;
146 
147     /* Calculate the inactive window rectangle */
148     pPreviewData->rcInactiveFrame.left = pPreviewData->rcDesktop.left + 8;
149     pPreviewData->rcInactiveFrame.top = pPreviewData->rcDesktop.top + 8;
150     pPreviewData->rcInactiveFrame.right = pPreviewData->rcDesktop.right - 25;
151     pPreviewData->rcInactiveFrame.bottom = pPreviewData->rcDesktop.bottom - 30;
152 
153     /* Calculate the inactive caption rectangle */
154     pPreviewData->rcInactiveCaption.left = pPreviewData->rcInactiveFrame.left + pPreviewData->cxEdge + pPreviewData->cySizeFrame + 1;
155     pPreviewData->rcInactiveCaption.top = pPreviewData->rcInactiveFrame.top + pPreviewData->cyEdge + pPreviewData->cySizeFrame + 1;
156     pPreviewData->rcInactiveCaption.right = pPreviewData->rcInactiveFrame.right - pPreviewData->cxEdge - pPreviewData->cySizeFrame - 1;
157     pPreviewData->rcInactiveCaption.bottom = pPreviewData->rcInactiveCaption.top + pPreviewData->cyCaption - pPreviewData->cyBorder;
158 
159     /* Calculate the inactive caption buttons rectangle */
160     pPreviewData->rcInactiveCaptionButtons.left = pPreviewData->rcInactiveCaption.right - 2 - 2 - 3 * 16;
161     pPreviewData->rcInactiveCaptionButtons.top = pPreviewData->rcInactiveCaption.top + 2;
162     pPreviewData->rcInactiveCaptionButtons.right = pPreviewData->rcInactiveCaption.right - 2;
163     pPreviewData->rcInactiveCaptionButtons.bottom = pPreviewData->rcInactiveCaption.bottom - 2;
164 
165     /* Calculate the active window rectangle */
166     pPreviewData->rcActiveFrame.left = pPreviewData->rcInactiveFrame.left + 3 + pPreviewData->cySizeFrame;
167     pPreviewData->rcActiveFrame.top = pPreviewData->rcInactiveCaption.bottom + 1;
168     pPreviewData->rcActiveFrame.right = pPreviewData->rcDesktop.right - 10;
169     pPreviewData->rcActiveFrame.bottom = pPreviewData->rcDesktop.bottom - 25;
170 
171     /* Calculate the active caption rectangle */
172     pPreviewData->rcActiveCaption.left = pPreviewData->rcActiveFrame.left + pPreviewData->cxEdge + pPreviewData->cySizeFrame + 1;
173     pPreviewData->rcActiveCaption.top = pPreviewData->rcActiveFrame.top + pPreviewData->cxEdge + pPreviewData->cySizeFrame + 1;
174     pPreviewData->rcActiveCaption.right = pPreviewData->rcActiveFrame.right - pPreviewData->cxEdge - pPreviewData->cySizeFrame - 1;
175     pPreviewData->rcActiveCaption.bottom = pPreviewData->rcActiveCaption.top + pPreviewData->cyCaption - pPreviewData->cyBorder;
176 
177     /* Calculate the active caption buttons rectangle */
178     pPreviewData->rcActiveCaptionButtons.left = pPreviewData->rcActiveCaption.right - 2 - 2 - 3 * 16;
179     pPreviewData->rcActiveCaptionButtons.top = pPreviewData->rcActiveCaption.top + 2;
180     pPreviewData->rcActiveCaptionButtons.right = pPreviewData->rcActiveCaption.right - 2;
181     pPreviewData->rcActiveCaptionButtons.bottom = pPreviewData->rcActiveCaption.bottom - 2;
182 
183     /* Calculate the active menu bar rectangle */
184     pPreviewData->rcActiveMenuBar.left = pPreviewData->rcActiveFrame.left + pPreviewData->cxEdge + pPreviewData->cySizeFrame + 1;
185     pPreviewData->rcActiveMenuBar.top = pPreviewData->rcActiveCaption.bottom + 1;
186     pPreviewData->rcActiveMenuBar.right = pPreviewData->rcActiveFrame.right - pPreviewData->cxEdge - pPreviewData->cySizeFrame - 1;
187     pPreviewData->rcActiveMenuBar.bottom = pPreviewData->rcActiveMenuBar.top + pPreviewData->cyMenu + 1;
188 
189     /* Calculate the active client rectangle */
190     pPreviewData->rcActiveClient.left = pPreviewData->rcActiveFrame.left + pPreviewData->cxEdge + pPreviewData->cySizeFrame + 1;
191     pPreviewData->rcActiveClient.top = pPreviewData->rcActiveMenuBar.bottom;
192     pPreviewData->rcActiveClient.right = pPreviewData->rcActiveFrame.right - pPreviewData->cxEdge - pPreviewData->cySizeFrame - 1;
193     pPreviewData->rcActiveClient.bottom = pPreviewData->rcActiveFrame.bottom - pPreviewData->cyEdge - pPreviewData->cySizeFrame - 1;
194 
195     /* Calculate the active scroll rectangle */
196     pPreviewData->rcActiveScroll.left = pPreviewData->rcActiveClient.right - 2 - pPreviewData->cxScrollbar;
197     pPreviewData->rcActiveScroll.top = pPreviewData->rcActiveClient.top + 2;
198     pPreviewData->rcActiveScroll.right = pPreviewData->rcActiveClient.right - 2;
199     pPreviewData->rcActiveScroll.bottom = pPreviewData->rcActiveClient.bottom - 2;
200 
201 
202     /* Dialog window */
203     pPreviewData->rcDialogFrame.left = pPreviewData->rcActiveClient.left + 4;
204     pPreviewData->rcDialogFrame.top = (pPreviewData->rcDesktop.bottom * 60) / 100;
205     pPreviewData->rcDialogFrame.right = (pPreviewData->rcDesktop.right * 65) / 100;
206     pPreviewData->rcDialogFrame.bottom = pPreviewData->rcDesktop.bottom - 5;
207 
208     /* Calculate the dialog caption rectangle */
209     pPreviewData->rcDialogCaption.left = pPreviewData->rcDialogFrame.left + 3;
210     pPreviewData->rcDialogCaption.top = pPreviewData->rcDialogFrame.top + 3;
211     pPreviewData->rcDialogCaption.right = pPreviewData->rcDialogFrame.right - 3;
212     pPreviewData->rcDialogCaption.bottom = pPreviewData->rcDialogFrame.top + pPreviewData->cyCaption + 1 + 1;
213 
214     /* Calculate the inactive caption buttons rectangle */
215     pPreviewData->rcDialogCaptionButtons.left = pPreviewData->rcDialogCaption.right - 2 - 16;
216     pPreviewData->rcDialogCaptionButtons.top = pPreviewData->rcDialogCaption.top + 2;
217     pPreviewData->rcDialogCaptionButtons.right = pPreviewData->rcDialogCaption.right - 2;
218     pPreviewData->rcDialogCaptionButtons.bottom = pPreviewData->rcDialogCaption.bottom - 2;
219 
220     /* Calculate the dialog client rectangle */
221     pPreviewData->rcDialogClient.left = pPreviewData->rcDialogFrame.left + 3;
222     pPreviewData->rcDialogClient.top = pPreviewData->rcDialogCaption.bottom + 1;
223     pPreviewData->rcDialogClient.right = pPreviewData->rcDialogFrame.right - 3;
224     pPreviewData->rcDialogClient.bottom = pPreviewData->rcDialogFrame.bottom - 3;
225 
226     /* Calculate the dialog button rectangle */
227     width = 80;
228     height = 28;
229 
230     pPreviewData->rcDialogButton.left =
231         (pPreviewData->rcDialogClient.right + pPreviewData->rcDialogClient.left - width) / 2;
232     pPreviewData->rcDialogButton.right = pPreviewData->rcDialogButton.left + width;
233     pPreviewData->rcDialogButton.bottom = pPreviewData->rcDialogClient.bottom - 2;
234     pPreviewData->rcDialogButton.top = pPreviewData->rcDialogButton.bottom - height;
235 }
236 
237 
238 static VOID
239 OnSize(INT cx, INT cy, PPREVIEW_DATA pPreviewData)
240 {
241     /* Get Desktop rectangle */
242     pPreviewData->rcDesktop.left = 0;
243     pPreviewData->rcDesktop.top = 0;
244     pPreviewData->rcDesktop.right = cx;
245     pPreviewData->rcDesktop.bottom = cy;
246 
247     CalculateItemSize(pPreviewData);
248 }
249 
250 static VOID
251 OnPaint(HWND hwnd, PPREVIEW_DATA pPreviewData)
252 {
253     PAINTSTRUCT ps;
254     HFONT hOldFont;
255     HDC hdc;
256     RECT rc;
257     COLOR_SCHEME *scheme;
258 
259     scheme = &pPreviewData->Scheme;
260 
261     hdc = BeginPaint(hwnd, &ps);
262 
263     if (pPreviewData->hdcPreview)
264     {
265         BitBlt(hdc,0,0, pPreviewData->rcDesktop.right, pPreviewData->rcDesktop.bottom, pPreviewData->hdcPreview, 0,0, SRCCOPY);
266         EndPaint(hwnd, &ps);
267         return;
268     }
269 
270     /* Desktop */
271     FillRect(hdc, &pPreviewData->rcDesktop, pPreviewData->hbrDesktop);
272 
273     /* Inactive Window */
274     MyDrawEdge(hdc, &pPreviewData->rcInactiveFrame, EDGE_RAISED, BF_RECT | BF_MIDDLE | MY_BF_INACTIVEBORDER, scheme);
275     SetTextColor(hdc, scheme->crColor[COLOR_INACTIVECAPTIONTEXT]);
276     MyDrawCaptionTemp(NULL, hdc, &pPreviewData->rcInactiveCaption,  pPreviewData->hCaptionFont,
277                       NULL, pPreviewData->lpInAct, DC_GRADIENT | DC_ICON | DC_TEXT, scheme);
278     MyDrawCaptionButtons(hdc, &pPreviewData->rcInactiveCaption, TRUE, pPreviewData->cyCaption - 2, scheme);
279 
280     /* Active Window */
281     MyDrawEdge(hdc, &pPreviewData->rcActiveFrame, EDGE_RAISED, BF_RECT | BF_MIDDLE | MY_BF_ACTIVEBORDER, scheme);
282     SetTextColor(hdc, scheme->crColor[COLOR_CAPTIONTEXT]);
283     MyDrawCaptionTemp(NULL, hdc, &pPreviewData->rcActiveCaption, pPreviewData->hCaptionFont,
284                       NULL, pPreviewData->lpAct, DC_ACTIVE | DC_GRADIENT | DC_ICON | DC_TEXT, scheme);
285     MyDrawCaptionButtons(hdc, &pPreviewData->rcActiveCaption, TRUE, pPreviewData->cyCaption - 2, scheme);
286 
287     /* Draw the menu bar */
288     MyDrawMenuBarTemp(hwnd, hdc, &pPreviewData->rcActiveMenuBar,
289                       pPreviewData->hMenu,
290                       pPreviewData->hMenuFont, scheme);
291 
292     /* Draw the client area */
293     CopyRect(&rc, &pPreviewData->rcActiveClient);
294     MyDrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_ADJUST, scheme);
295     FillRect(hdc, &rc, pPreviewData->hbrWindow);
296 
297     /* Draw the client text */
298     CopyRect(&rc, &pPreviewData->rcActiveClient);
299     rc.left += 4;
300     rc.top += 2;
301     SetTextColor(hdc, scheme->crColor[COLOR_WINDOWTEXT]);
302     hOldFont = SelectObject(hdc, pPreviewData->hClientFont);
303     DrawText(hdc, pPreviewData->lpWinTxt, -1, &rc, DT_LEFT);
304     SelectObject(hdc, hOldFont);
305 
306     /* Draw the scroll bar */
307     MyDrawScrollbar(hdc, &pPreviewData->rcActiveScroll, pPreviewData->hbrScrollbar, scheme);
308 
309     /* Dialog Window */
310     MyDrawEdge(hdc, &pPreviewData->rcDialogFrame, EDGE_RAISED, BF_RECT | BF_MIDDLE, scheme);
311     SetTextColor(hdc, scheme->crColor[COLOR_WINDOW]);
312     MyDrawCaptionTemp(NULL, hdc, &pPreviewData->rcDialogCaption, pPreviewData->hCaptionFont,
313                       NULL, pPreviewData->lpMessBox, DC_ACTIVE | DC_GRADIENT | DC_ICON | DC_TEXT, scheme);
314     MyDrawCaptionButtons(hdc, &pPreviewData->rcDialogCaption, FALSE, pPreviewData->cyCaption - 2, scheme);
315 
316     /* Draw the dialog text */
317     CopyRect(&rc, &pPreviewData->rcDialogClient);
318     rc.left += 4;
319     rc.top += 2;
320     SetTextColor(hdc, scheme->crColor[COLOR_WINDOWTEXT]);
321     hOldFont = SelectObject(hdc, pPreviewData->hMessageFont);
322     DrawText(hdc, pPreviewData->lpMessText, -1, &rc, DT_LEFT);
323     SelectObject(hdc, hOldFont);
324 
325     /* Draw Button */
326     MyDrawFrameControl(hdc, &pPreviewData->rcDialogButton, DFC_BUTTON, DFCS_BUTTONPUSH, scheme);
327     CopyRect(&rc, &pPreviewData->rcDialogButton);
328     SetTextColor(hdc, scheme->crColor[COLOR_BTNTEXT]);
329     hOldFont = SelectObject(hdc, pPreviewData->hMessageFont);
330     DrawText(hdc, pPreviewData->lpButText, -1, &rc, DT_VCENTER | DT_CENTER | DT_SINGLELINE);
331     SelectObject(hdc, hOldFont);
332 
333     EndPaint(hwnd, &ps);
334 }
335 
336 
337 static VOID
338 OnLButtonDown(HWND hwnd, int xPos, int yPos, PPREVIEW_DATA pPreviewData)
339 {
340     UINT type = IDX_DESKTOP;
341     POINT pt;
342 
343     pt.x = xPos;
344     pt.y = yPos;
345 
346     if (PtInRect(&pPreviewData->rcInactiveFrame, pt))
347         type = IDX_INACTIVE_BORDER;
348 
349     if (PtInRect(&pPreviewData->rcInactiveCaption, pt))
350         type = IDX_INACTIVE_CAPTION;
351 
352     if (PtInRect(&pPreviewData->rcInactiveCaptionButtons, pt))
353         type = IDX_CAPTION_BUTTON;
354 
355     if (PtInRect(&pPreviewData->rcActiveFrame, pt))
356         type = IDX_ACTIVE_BORDER;
357 
358     if (PtInRect(&pPreviewData->rcActiveCaption, pt))
359         type = IDX_ACTIVE_CAPTION;
360 
361     if (PtInRect(&pPreviewData->rcActiveCaptionButtons, pt))
362         type = IDX_CAPTION_BUTTON;
363 
364 //    if (PtInRect(&pPreviewData->rcSelectedMenuItem, pt))
365 //        type = IDX_SELECTION;
366 
367     if (PtInRect(&pPreviewData->rcActiveMenuBar, pt))
368         type = IDX_MENU;
369 
370     if (PtInRect(&pPreviewData->rcActiveClient, pt))
371         type = IDX_WINDOW;
372 
373     if (PtInRect(&pPreviewData->rcActiveScroll, pt))
374         type = IDX_SCROLLBAR;
375 
376     if (PtInRect(&pPreviewData->rcDialogFrame, pt))
377         type = IDX_DIALOG;
378 
379     if (PtInRect(&pPreviewData->rcDialogCaption, pt))
380         type = IDX_ACTIVE_CAPTION;
381 
382     if (PtInRect(&pPreviewData->rcDialogCaptionButtons, pt))
383         type = IDX_CAPTION_BUTTON;
384 
385     if (PtInRect(&pPreviewData->rcDialogButton, pt))
386         type = IDX_3D_OBJECTS;
387 
388     SendMessage(GetParent(hwnd),
389                 WM_COMMAND,
390                 MAKEWPARAM(GetWindowLongPtrW(hwnd, GWLP_ID), 0),
391                 (LPARAM)type);
392 }
393 
394 
395 static VOID
396 OnDestroy(PPREVIEW_DATA pPreviewData)
397 {
398     DeleteObject(pPreviewData->hbrScrollbar);
399     DeleteObject(pPreviewData->hbrDesktop);
400     DeleteObject(pPreviewData->hbrWindow);
401 
402     DeleteObject(pPreviewData->hCaptionFont);
403     DeleteObject(pPreviewData->hMenuFont);
404     DeleteObject(pPreviewData->hMessageFont);
405 
406     DestroyMenu(pPreviewData->hMenu);
407 
408     LocalFree((HLOCAL)pPreviewData->lpInAct);
409     LocalFree((HLOCAL)pPreviewData->lpAct);
410     LocalFree((HLOCAL)pPreviewData->lpWinTxt);
411     LocalFree((HLOCAL)pPreviewData->lpMessBox);
412     LocalFree((HLOCAL)pPreviewData->lpMessText);
413     LocalFree((HLOCAL)pPreviewData->lpButText);
414 }
415 
416 
417 static LRESULT CALLBACK
418 PreviewWndProc(HWND hwnd,
419                UINT uMsg,
420                WPARAM wParam,
421                LPARAM lParam)
422 {
423     PPREVIEW_DATA pPreviewData;
424 
425     pPreviewData = (PPREVIEW_DATA)GetWindowLongPtr(hwnd, GWLP_USERDATA);
426 
427     switch (uMsg)
428     {
429         case WM_CREATE:
430             pPreviewData = (PPREVIEW_DATA)HeapAlloc(GetProcessHeap(),
431                                                     HEAP_ZERO_MEMORY,
432                                                     sizeof(PREVIEW_DATA));
433             if (!pPreviewData)
434                 return -1;
435 
436             SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pPreviewData);
437             OnCreate(hwnd, pPreviewData);
438             break;
439 
440         case WM_SIZE:
441             OnSize(LOWORD(lParam), HIWORD(lParam), pPreviewData);
442             break;
443 
444         case WM_PAINT:
445             OnPaint(hwnd, pPreviewData);
446             break;
447 
448         case WM_LBUTTONDOWN:
449             OnLButtonDown(hwnd, LOWORD(lParam), HIWORD(lParam), pPreviewData);
450             break;
451 
452         case WM_DESTROY:
453             OnDestroy(pPreviewData);
454             HeapFree(GetProcessHeap(), 0, pPreviewData);
455             break;
456 
457         case PVM_UPDATETHEME:
458             UpdatePreviewTheme(hwnd, pPreviewData, (COLOR_SCHEME *)lParam);
459             CalculateItemSize(pPreviewData);
460             InvalidateRect(hwnd, NULL, FALSE);
461             break;
462 
463         case PVM_SETSIZE:
464             SchemeSetMetric(&pPreviewData->Scheme, wParam, lParam);
465             pPreviewData->cySizeFrame = pPreviewData->Scheme.ncMetrics.iBorderWidth;  /* SM_CYSIZEFRAME */
466             pPreviewData->cyCaption = pPreviewData->Scheme.ncMetrics.iCaptionHeight+1;      /* SM_CYCAPTION */
467             pPreviewData->cyMenu = pPreviewData->Scheme.ncMetrics.iMenuHeight -1;            /* SM_CYMENU */
468             pPreviewData->cxScrollbar = pPreviewData->Scheme.ncMetrics.iScrollWidth;     /* SM_CXVSCROLL */
469             pPreviewData->cyBorder = pPreviewData->Scheme.ncMetrics.iBorderWidth;        /* SM_CYBORDER */
470             CalculateItemSize(pPreviewData);
471             InvalidateRect(hwnd, NULL, FALSE);
472             break;
473 
474         case PVM_SETFONT:
475         {
476             PLOGFONTW plfFont;
477             HFONT* phFont;
478 
479             switch(wParam)
480             {
481             case FONT_CAPTION:   phFont = &pPreviewData->hCaptionFont; break;
482             case FONT_MENU:      phFont = &pPreviewData->hMenuFont; break;
483             case FONT_MESSAGE:   phFont = &pPreviewData->hMessageFont; break;
484             default:  return TRUE;
485             }
486 
487             plfFont = SchemeGetFont(&pPreviewData->Scheme, wParam);
488             memcpy(plfFont, (PVOID)lParam, sizeof(LOGFONTW));
489 
490             DeleteObject(*phFont);
491             *phFont = CreateFontIndirect(plfFont);
492 
493             InvalidateRect(hwnd, NULL, FALSE);
494             break;
495         }
496 
497         case PVM_SETCOLOR:
498             pPreviewData->Scheme.crColor[wParam] = lParam;
499             switch(wParam)
500             {
501                 case COLOR_SCROLLBAR:
502                     DeleteObject(pPreviewData->hbrScrollbar);
503                     pPreviewData->hbrScrollbar = CreateSolidBrush(pPreviewData->Scheme.crColor[wParam]);
504                     break;
505                 case COLOR_DESKTOP:
506                     DeleteObject(pPreviewData->hbrDesktop);
507                     pPreviewData->hbrDesktop = CreateSolidBrush(pPreviewData->Scheme.crColor[wParam]);
508                     break;
509                 case COLOR_WINDOW:
510                     DeleteObject(pPreviewData->hbrWindow);
511                     pPreviewData->hbrWindow = CreateSolidBrush(pPreviewData->Scheme.crColor[wParam]);
512                     break;
513             }
514 
515             CalculateItemSize(pPreviewData);
516             InvalidateRect(hwnd, NULL, FALSE);
517             break;
518 
519         case PVM_GETSIZE:
520             return SchemeGetMetric(&pPreviewData->Scheme, wParam);
521         case PVM_GETFONT:
522             return (LRESULT)SchemeGetFont(&pPreviewData->Scheme, wParam);
523         case PVM_GETCOLOR:
524             return pPreviewData->Scheme.crColor[wParam];
525 
526         case PVM_SET_HDC_PREVIEW:
527             pPreviewData->hdcPreview = (HDC)lParam;
528             InvalidateRect(hwnd, NULL, FALSE);
529             break;
530 
531         default:
532             return DefWindowProc(hwnd, uMsg, wParam, lParam);
533     }
534     return FALSE;
535 }
536 
537 
538 BOOL
539 RegisterPreviewControl(IN HINSTANCE hInstance)
540 {
541     WNDCLASSEX wc = {0};
542 
543     wc.cbSize = sizeof(wc);
544     wc.lpfnWndProc = PreviewWndProc;
545     wc.hInstance = hInstance;
546     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
547     wc.hbrBackground = (HBRUSH)NULL;
548     wc.lpszClassName = szPreviewWndClass;
549 
550     return RegisterClassEx(&wc) != (ATOM)0;
551 }
552 
553 
554 VOID
555 UnregisterPreviewControl(IN HINSTANCE hInstance)
556 {
557     UnregisterClass(szPreviewWndClass, hInstance);
558 }
559