[DESK.CPL]
[reactos.git] / reactos / dll / cpl / desk / preview.c
index ae83c1b..c4a8d16 100644 (file)
-/*\r
- * PROJECT:     ReactOS Timedate Control Panel\r
- * LICENSE:     GPL - See COPYING in the top level directory\r
- * FILE:        lib/cpl/desk/preview.c\r
- * PURPOSE:     Draws the preview control\r
- * COPYRIGHT:   Copyright 2006 Eric Kohl\r
- */\r
-\r
-#include "desk.h"\r
-#include "preview.h"\r
-\r
-static const TCHAR szPreviewWndClass[] = TEXT("PreviewWndClass");\r
-\r
-typedef struct _PREVIEW_DATA\r
-{\r
-    HWND hwndParent;\r
-\r
-    DWORD clrDesktop;\r
-    HBRUSH hbrDesktop;\r
-\r
-    DWORD clrWindow;\r
-    HBRUSH hbrWindow;\r
-\r
-    DWORD clrScrollbar;\r
-    HBRUSH hbrScrollbar;\r
-\r
-    DWORD clrActiveCaptionText;\r
-    DWORD clrInactiveCaptionText;\r
-    DWORD clrWindowText;\r
-    DWORD clrButtonText;\r
-\r
-    INT cxEdge;\r
-    INT cyEdge;\r
-\r
-    INT cyCaption;\r
-\r
-    RECT rcDesktop;\r
-    RECT rcInactiveFrame;\r
-    RECT rcInactiveCaption;\r
-\r
-    RECT rcActiveFrame;\r
-    RECT rcActiveCaption;\r
-    RECT rcActiveMenuBar;\r
-    RECT rcSelectedMenuItem;\r
-    RECT rcActiveClient;\r
-    RECT rcActiveScroll;\r
-\r
-    RECT rcDialogFrame;\r
-    RECT rcDialogCaption;\r
-    RECT rcDialogClient;\r
-\r
-    RECT rcDialogButton;\r
-\r
-    LPTSTR lpInAct;\r
-    LPTSTR lpAct;\r
-    LPTSTR lpWinTxt;\r
-    LPTSTR lpMessBox;\r
-    LPTSTR lpMessText;\r
-    LPTSTR lpButText;\r
-\r
-    LOGFONT lfCaptionFont;\r
-    LOGFONT lfMenuFont;\r
-    LOGFONT lfMessageFont;\r
-\r
-    HFONT hCaptionFont;\r
-    HFONT hMenuFont;\r
-    HFONT hMessageFont;\r
-\r
-    HMENU hMenu;\r
-\r
-} PREVIEW_DATA, *PPREVIEW_DATA;\r
-\r
-\r
-\r
-static VOID\r
-DrawCaptionButtons(HDC hdc, LPRECT lpRect, BOOL bMinMax)\r
-{\r
-    RECT rc3;\r
-    RECT rc4;\r
-    RECT rc5;\r
-\r
-    rc3.left = lpRect->right - 2 - 16;\r
-    rc3.top = lpRect->top + 2;\r
-    rc3.right = lpRect->right - 2;\r
-    rc3.bottom = lpRect->bottom - 2;\r
-\r
-    DrawFrameControl(hdc, &rc3, DFC_CAPTION, DFCS_CAPTIONCLOSE);\r
-\r
-    if (bMinMax)\r
-    {\r
-        rc4.left = rc3.left - 16 - 2;\r
-        rc4.top = rc3.top;\r
-        rc4.right = rc3.right - 16 - 2;\r
-        rc4.bottom = rc3.bottom;\r
-\r
-        DrawFrameControl(hdc, &rc4, DFC_CAPTION, DFCS_CAPTIONMAX);\r
-\r
-        rc5.left = rc4.left - 16;\r
-        rc5.top = rc4.top;\r
-        rc5.right = rc4.right - 16;\r
-        rc5.bottom = rc4.bottom;\r
-\r
-        DrawFrameControl(hdc, &rc5, DFC_CAPTION, DFCS_CAPTIONMIN);\r
-    }\r
-}\r
-\r
-static VOID\r
-DrawScrollbar(HDC hdc, LPRECT rc, HBRUSH hbrScrollbar)\r
-{\r
-    RECT rcTop;\r
-    RECT rcBottom;\r
-    RECT rcMiddle;\r
-    int width;\r
-\r
-    width = rc->right - rc->left;\r
-\r
-    rcTop.left = rc->left;\r
-    rcTop.right = rc->right;\r
-    rcTop.top = rc->top;\r
-    rcTop.bottom = rc->top + width;\r
-\r
-    rcMiddle.left = rc->left;\r
-    rcMiddle.right = rc->right;\r
-    rcMiddle.top = rc->top + width;\r
-    rcMiddle.bottom = rc->bottom - width;\r
-\r
-    rcBottom.left = rc->left;\r
-    rcBottom.right = rc->right;\r
-    rcBottom.top = rc->bottom - width;\r
-    rcBottom.bottom = rc->bottom;\r
-\r
-    DrawFrameControl(hdc, &rcTop, DFC_SCROLL, DFCS_SCROLLUP);\r
-    DrawFrameControl(hdc, &rcBottom, DFC_SCROLL, DFCS_SCROLLDOWN);\r
-\r
-    FillRect(hdc, &rcMiddle, hbrScrollbar);\r
-}\r
-\r
-\r
-static VOID\r
-OnCreate(HWND hwnd, PPREVIEW_DATA pPreviewData)\r
-{\r
-    NONCLIENTMETRICS NonClientMetrics;\r
-\r
-    pPreviewData->clrScrollbar = GetSysColor(COLOR_SCROLLBAR);\r
-    pPreviewData->hbrScrollbar = CreateSolidBrush(pPreviewData->clrScrollbar);\r
-\r
-    pPreviewData->clrDesktop = GetSysColor(COLOR_DESKTOP);\r
-    pPreviewData->hbrDesktop = CreateSolidBrush(pPreviewData->clrDesktop);\r
-    pPreviewData->clrWindow = GetSysColor(COLOR_WINDOW);\r
-    pPreviewData->hbrWindow = CreateSolidBrush(pPreviewData->clrWindow);\r
-\r
-    pPreviewData->clrActiveCaptionText = GetSysColor(COLOR_CAPTIONTEXT);\r
-    pPreviewData->clrInactiveCaptionText = GetSysColor(COLOR_INACTIVECAPTIONTEXT);\r
-    pPreviewData->clrWindowText = GetSysColor(COLOR_WINDOWTEXT);\r
-    pPreviewData->clrButtonText = GetSysColor(COLOR_BTNTEXT);\r
-\r
-    pPreviewData->cxEdge = GetSystemMetrics(SM_CXEDGE);\r
-    pPreviewData->cyEdge = GetSystemMetrics(SM_CXEDGE);\r
-\r
-    pPreviewData->cyCaption = 20; //GetSystemMetrics(SM_CYCAPTION);\r
-\r
-    /* load font info */\r
-    NonClientMetrics.cbSize = sizeof(NONCLIENTMETRICS);\r
-    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &NonClientMetrics, 0);\r
-\r
-    pPreviewData->lfCaptionFont = NonClientMetrics.lfCaptionFont;\r
-    pPreviewData->hCaptionFont = CreateFontIndirect(&pPreviewData->lfCaptionFont);\r
-\r
-    pPreviewData->lfMenuFont = NonClientMetrics.lfMenuFont;\r
-    pPreviewData->hMenuFont = CreateFontIndirect(&pPreviewData->lfMenuFont);\r
-\r
-    pPreviewData->lfMessageFont = NonClientMetrics.lfMessageFont;\r
-    pPreviewData->hMessageFont = CreateFontIndirect(&pPreviewData->lfMessageFont);\r
-\r
-    /* Load and modify the menu */\r
-    pPreviewData->hMenu = LoadMenu(hApplet, MAKEINTRESOURCE(IDR_PREVIEW_MENU));\r
-    EnableMenuItem(pPreviewData->hMenu, ID_MENU_DISABLED,\r
-                   MF_BYCOMMAND | MF_DISABLED);\r
-    HiliteMenuItem(hwnd, pPreviewData->hMenu,\r
-                   ID_MENU_SELECTED, MF_BYCOMMAND | MF_HILITE);\r
-\r
-//    GetMenuItemRect(hwnd, pPreviewData->hMenu,\r
-//                    ID_MENU_SELECTED, &pPreviewData->rcSelectedMenuItem);\r
-\r
-\r
-    AllocAndLoadString(&pPreviewData->lpInAct, hApplet, IDS_INACTWIN);\r
-    AllocAndLoadString(&pPreviewData->lpAct, hApplet, IDS_ACTWIN);\r
-    AllocAndLoadString(&pPreviewData->lpWinTxt, hApplet, IDS_WINTEXT);\r
-    AllocAndLoadString(&pPreviewData->lpMessBox, hApplet, IDS_MESSBOX);\r
-    AllocAndLoadString(&pPreviewData->lpMessText, hApplet, IDS_MESSTEXT);\r
-    AllocAndLoadString(&pPreviewData->lpButText, hApplet, IDS_BUTTEXT);\r
-}\r
-\r
-\r
-static VOID\r
-OnSize(INT cx, INT cy, PPREVIEW_DATA pPreviewData)\r
-{\r
-    int width, height;\r
-\r
-    /* Get Desktop rectangle */\r
-    pPreviewData->rcDesktop.left = 0;\r
-    pPreviewData->rcDesktop.top = 0;\r
-    pPreviewData->rcDesktop.right = cx;\r
-    pPreviewData->rcDesktop.bottom = cy;\r
-\r
-    /* Calculate the inactive window rectangle */\r
-    pPreviewData->rcInactiveFrame.left = pPreviewData->rcDesktop.left + 8;\r
-    pPreviewData->rcInactiveFrame.top = pPreviewData->rcDesktop.top + 8;\r
-    pPreviewData->rcInactiveFrame.right = pPreviewData->rcDesktop.right - 25;\r
-    pPreviewData->rcInactiveFrame.bottom = pPreviewData->rcDesktop.bottom - 30;\r
-\r
-    /* Calculate the inactive caption rectangle */\r
-    pPreviewData->rcInactiveCaption.left = pPreviewData->rcInactiveFrame.left + pPreviewData->cxEdge + 1/*3*/ + 1;\r
-    pPreviewData->rcInactiveCaption.top = pPreviewData->rcInactiveFrame.top + pPreviewData->cyEdge + 1/*3*/ + 1;\r
-    pPreviewData->rcInactiveCaption.right = pPreviewData->rcInactiveFrame.right - pPreviewData->cxEdge - 1/*3*/ - 1;\r
-    pPreviewData->rcInactiveCaption.bottom = pPreviewData->rcInactiveFrame.top + pPreviewData->cyCaption /*20*/ + 2;\r
-\r
-    /* Calculate the active window rectangle */\r
-    pPreviewData->rcActiveFrame.left = pPreviewData->rcInactiveFrame.left + 3 + 1;\r
-    pPreviewData->rcActiveFrame.top = pPreviewData->rcInactiveCaption.bottom + 1;\r
-    pPreviewData->rcActiveFrame.right = pPreviewData->rcDesktop.right - 10;\r
-    pPreviewData->rcActiveFrame.bottom = pPreviewData->rcDesktop.bottom - 25;\r
-\r
-    /* Calculate the active caption rectangle */\r
-    pPreviewData->rcActiveCaption.left = pPreviewData->rcActiveFrame.left + 3 + 1;\r
-    pPreviewData->rcActiveCaption.top = pPreviewData->rcActiveFrame.top + 3 + 1;\r
-    pPreviewData->rcActiveCaption.right = pPreviewData->rcActiveFrame.right - 3 - 1;\r
-    pPreviewData->rcActiveCaption.bottom = pPreviewData->rcActiveFrame.top + pPreviewData->cyCaption/*20*/ + 2;\r
-\r
-    /* Calculate the active menu bar rectangle */\r
-    pPreviewData->rcActiveMenuBar.left = pPreviewData->rcActiveFrame.left + 3 + 1;\r
-    pPreviewData->rcActiveMenuBar.top = pPreviewData->rcActiveCaption.bottom + 1;\r
-    pPreviewData->rcActiveMenuBar.right = pPreviewData->rcActiveFrame.right - 3 - 1;\r
-    pPreviewData->rcActiveMenuBar.bottom = pPreviewData->rcActiveMenuBar.top + 20;\r
-\r
-    /* Calculate the active client rectangle */\r
-    pPreviewData->rcActiveClient.left = pPreviewData->rcActiveFrame.left + 3 + 1;\r
-    pPreviewData->rcActiveClient.top = pPreviewData->rcActiveMenuBar.bottom; // + 1;\r
-    pPreviewData->rcActiveClient.right = pPreviewData->rcActiveFrame.right - 3 - 1;\r
-    pPreviewData->rcActiveClient.bottom = pPreviewData->rcActiveFrame.bottom - 3 - 1;\r
-\r
-    /* Calculate the active scroll rectangle */\r
-    pPreviewData->rcActiveScroll.left = pPreviewData->rcActiveClient.right - 2 - 16;\r
-    pPreviewData->rcActiveScroll.top = pPreviewData->rcActiveClient.top + 2;\r
-    pPreviewData->rcActiveScroll.right = pPreviewData->rcActiveClient.right - 2;\r
-    pPreviewData->rcActiveScroll.bottom = pPreviewData->rcActiveClient.bottom - 2;\r
-\r
-\r
-    /* Dialog window */\r
-    pPreviewData->rcDialogFrame.left = pPreviewData->rcActiveClient.left + 4;\r
-    pPreviewData->rcDialogFrame.top = (pPreviewData->rcDesktop.bottom * 60) / 100;\r
-    pPreviewData->rcDialogFrame.right = (pPreviewData->rcDesktop.right * 65) / 100;\r
-    pPreviewData->rcDialogFrame.bottom = pPreviewData->rcDesktop.bottom - 5;\r
-\r
-    /* Calculate the dialog caption rectangle */\r
-    pPreviewData->rcDialogCaption.left = pPreviewData->rcDialogFrame.left + 3;\r
-    pPreviewData->rcDialogCaption.top = pPreviewData->rcDialogFrame.top + 3;\r
-    pPreviewData->rcDialogCaption.right = pPreviewData->rcDialogFrame.right - 3;\r
-    pPreviewData->rcDialogCaption.bottom = pPreviewData->rcDialogFrame.top + 20 + 1;\r
-\r
-    /* Calculate the dialog client rectangle */\r
-    pPreviewData->rcDialogClient.left = pPreviewData->rcDialogFrame.left + 3;\r
-    pPreviewData->rcDialogClient.top = pPreviewData->rcDialogCaption.bottom + 1;\r
-    pPreviewData->rcDialogClient.right = pPreviewData->rcDialogFrame.right - 3;\r
-    pPreviewData->rcDialogClient.bottom = pPreviewData->rcDialogFrame.bottom - 3;\r
-\r
-    /* Calculate the dialog button rectangle */\r
-    width = 80;\r
-    height = 28;\r
-\r
-    pPreviewData->rcDialogButton.left =\r
-        (pPreviewData->rcDialogClient.right + pPreviewData->rcDialogClient.left - width) / 2;\r
-    pPreviewData->rcDialogButton.right = pPreviewData->rcDialogButton.left + width;\r
-    pPreviewData->rcDialogButton.bottom = pPreviewData->rcDialogClient.bottom - 2;\r
-    pPreviewData->rcDialogButton.top = pPreviewData->rcDialogButton.bottom - height;\r
-}\r
-\r
-\r
-static VOID\r
-OnPaint(HWND hwnd, PPREVIEW_DATA pPreviewData)\r
-{\r
-    PAINTSTRUCT ps;\r
-    HFONT hOldFont;\r
-    HDC hdc;\r
-    RECT rc;\r
-\r
-    hdc = BeginPaint(hwnd, &ps);\r
-\r
-    /* Desktop */\r
-    FillRect(hdc, &pPreviewData->rcDesktop, pPreviewData->hbrDesktop);\r
-\r
-    /* Inactive Window */\r
-    DrawEdge(hdc, &pPreviewData->rcInactiveFrame, EDGE_RAISED, BF_RECT | BF_MIDDLE);\r
-    SetTextColor(hdc, pPreviewData->clrInactiveCaptionText);\r
-    DrawCaptionTemp(NULL, hdc, &pPreviewData->rcInactiveCaption,  pPreviewData->hCaptionFont,\r
-                    NULL, pPreviewData->lpInAct, DC_GRADIENT | DC_ICON | DC_TEXT);\r
-    DrawCaptionButtons(hdc, &pPreviewData->rcInactiveCaption, TRUE);\r
-\r
-    /* Active Window */\r
-    DrawEdge(hdc, &pPreviewData->rcActiveFrame, EDGE_RAISED, BF_RECT | BF_MIDDLE);\r
-    SetTextColor(hdc, pPreviewData->clrActiveCaptionText);\r
-    DrawCaptionTemp(NULL, hdc, &pPreviewData->rcActiveCaption, pPreviewData->hCaptionFont,\r
-                    NULL, pPreviewData->lpAct, DC_ACTIVE | DC_GRADIENT | DC_ICON | DC_TEXT);\r
-    DrawCaptionButtons(hdc, &pPreviewData->rcActiveCaption, TRUE);\r
-\r
-    /* FIXME: Draw the menu bar */\r
-    DrawMenuBarTemp(hwnd, hdc, &pPreviewData->rcActiveMenuBar,\r
-                    pPreviewData->hMenu /*HMENU hMenu*/,\r
-                    pPreviewData->hMessageFont /*HFONT hFont*/);\r
-\r
-    /* Draw the client area */\r
-    CopyRect(&rc, &pPreviewData->rcActiveClient);\r
-    DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_ADJUST);\r
-    FillRect(hdc, &rc, pPreviewData->hbrWindow);\r
-\r
-    /* Draw the client text */\r
-    CopyRect(&rc, &pPreviewData->rcActiveClient);\r
-    rc.left += 4;\r
-    rc.top += 2;\r
-    SetTextColor(hdc, pPreviewData->clrWindowText);\r
-    hOldFont = SelectObject(hdc, pPreviewData->hMessageFont);\r
-    DrawText(hdc, pPreviewData->lpWinTxt, lstrlen(pPreviewData->lpWinTxt), &rc, DT_LEFT);\r
-    SelectObject(hdc, hOldFont);\r
-\r
-    /* Draw the scroll bar */\r
-    DrawScrollbar(hdc, &pPreviewData->rcActiveScroll, pPreviewData->hbrScrollbar);\r
-\r
-    /* Dialog Window */\r
-    DrawEdge(hdc, &pPreviewData->rcDialogFrame, EDGE_RAISED, BF_RECT | BF_MIDDLE);\r
-    SetTextColor(hdc, pPreviewData->clrActiveCaptionText);\r
-    DrawCaptionTemp(NULL, hdc, &pPreviewData->rcDialogCaption, pPreviewData->hCaptionFont,\r
-                    NULL, pPreviewData->lpMessBox, DC_ACTIVE | DC_GRADIENT | DC_ICON | DC_TEXT);\r
-    DrawCaptionButtons(hdc, &pPreviewData->rcDialogCaption, FALSE);\r
-\r
-    /* Draw the dialog text */\r
-    CopyRect(&rc, &pPreviewData->rcDialogClient);\r
-    rc.left += 4;\r
-    rc.top += 2;\r
-    SetTextColor(hdc, RGB(0,0,0));\r
-    hOldFont = SelectObject(hdc, pPreviewData->hMessageFont);\r
-    DrawText(hdc, pPreviewData->lpMessText, lstrlen(pPreviewData->lpMessText), &rc, DT_LEFT);\r
-    SelectObject(hdc, hOldFont);\r
-\r
-    /* Draw Button */\r
-    DrawFrameControl(hdc, &pPreviewData->rcDialogButton, DFC_BUTTON, DFCS_BUTTONPUSH);\r
-    CopyRect(&rc, &pPreviewData->rcDialogButton);\r
-    SetTextColor(hdc, pPreviewData->clrButtonText);\r
-    hOldFont = SelectObject(hdc, pPreviewData->hMessageFont);\r
-    DrawText(hdc, pPreviewData->lpButText, lstrlen(pPreviewData->lpButText), &rc, DT_VCENTER | DT_CENTER | DT_SINGLELINE);\r
-    SelectObject(hdc, hOldFont);\r
-\r
-    EndPaint(hwnd, &ps);\r
-}\r
-\r
-\r
-static VOID\r
-OnLButtonDown(HWND hwnd, int xPos, int yPos, PPREVIEW_DATA pPreviewData)\r
-{\r
-    UINT type = IDX_DESKTOP;\r
-    POINT pt;\r
-\r
-    pt.x = xPos;\r
-    pt.y = yPos;\r
-\r
-    if (PtInRect(&pPreviewData->rcInactiveFrame, pt))\r
-        type = IDX_INACTIVE_BORDER;\r
-\r
-    if (PtInRect(&pPreviewData->rcInactiveCaption, pt))\r
-        type = IDX_INACTIVE_CAPTION;\r
-\r
-\r
-    if (PtInRect(&pPreviewData->rcActiveFrame, pt))\r
-        type = IDX_ACTIVE_BORDER;\r
-\r
-    if (PtInRect(&pPreviewData->rcActiveCaption, pt))\r
-        type = IDX_ACTIVE_CAPTION;\r
-\r
-    if (PtInRect(&pPreviewData->rcActiveMenuBar, pt))\r
-        type = IDX_MENU;\r
-\r
-//    if (PtInRect(&pPreviewData->rcSelectedMenuItem, pt))\r
-//        type = IDX_SELECTION;\r
-\r
-    if (PtInRect(&pPreviewData->rcActiveClient, pt))\r
-        type = IDX_WINDOW;\r
-\r
-    if (PtInRect(&pPreviewData->rcActiveScroll, pt))\r
-        type = IDX_SCROLLBAR;\r
-\r
-\r
-    if (PtInRect(&pPreviewData->rcDialogFrame, pt))\r
-        type = IDX_DIALOG;\r
-\r
-    if (PtInRect(&pPreviewData->rcDialogCaption, pt))\r
-        type = IDX_ACTIVE_CAPTION;\r
-\r
-    if (PtInRect(&pPreviewData->rcDialogButton, pt))\r
-        type = IDX_3D_OBJECTS;\r
-\r
-    SendMessage(GetParent(hwnd), WM_USER, 0, type);\r
-}\r
-\r
-\r
-static VOID\r
-OnDestroy(PPREVIEW_DATA pPreviewData)\r
-{\r
-    DeleteObject(pPreviewData->hbrScrollbar);\r
-    DeleteObject(pPreviewData->hbrDesktop);\r
-    DeleteObject(pPreviewData->hbrWindow);\r
-\r
-    DeleteObject(pPreviewData->hCaptionFont);\r
-    DeleteObject(pPreviewData->hMenuFont);\r
-    DeleteObject(pPreviewData->hMessageFont);\r
-\r
-    DestroyMenu(pPreviewData->hMenu);\r
-\r
-    LocalFree((HLOCAL)pPreviewData->lpInAct);\r
-    LocalFree((HLOCAL)pPreviewData->lpAct);\r
-    LocalFree((HLOCAL)pPreviewData->lpWinTxt);\r
-    LocalFree((HLOCAL)pPreviewData->lpMessBox);\r
-    LocalFree((HLOCAL)pPreviewData->lpMessText);\r
-    LocalFree((HLOCAL)pPreviewData->lpButText);\r
-}\r
-\r
-\r
-static LRESULT CALLBACK\r
-PreviewWndProc(HWND hwnd,\r
-               UINT uMsg,\r
-               WPARAM wParam,\r
-               LPARAM lParam)\r
-{\r
-    PPREVIEW_DATA pPreviewData;\r
-\r
-    pPreviewData = (PPREVIEW_DATA)GetWindowLongPtr(hwnd, GWLP_USERDATA);\r
-\r
-    switch (uMsg)\r
-    {\r
-        case WM_CREATE:\r
-            pPreviewData = (PPREVIEW_DATA)HeapAlloc(GetProcessHeap(),\r
-                                                    HEAP_ZERO_MEMORY,\r
-                                                    sizeof(PREVIEW_DATA));\r
-            if (!pPreviewData)\r
-                return -1;\r
-\r
-            SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pPreviewData);\r
-            OnCreate(hwnd, pPreviewData);\r
-            break;\r
-\r
-        case WM_SIZE:\r
-            OnSize(LOWORD(lParam), HIWORD(lParam), pPreviewData);\r
-            break;\r
-\r
-        case WM_PAINT:\r
-            OnPaint(hwnd, pPreviewData);\r
-            break;\r
-\r
-        case WM_LBUTTONDOWN:\r
-            OnLButtonDown(hwnd, LOWORD(lParam), HIWORD(lParam), pPreviewData);\r
-            break;\r
-\r
-        case WM_DESTROY:\r
-            OnDestroy(pPreviewData);\r
-            HeapFree(GetProcessHeap(), 0, pPreviewData);\r
-            break;\r
-\r
-        default:\r
-            DefWindowProc(hwnd,\r
-                          uMsg,\r
-                          wParam,\r
-                          lParam);\r
-    }\r
-\r
-    return TRUE;\r
-}\r
-\r
-\r
-BOOL\r
-RegisterPreviewControl(IN HINSTANCE hInstance)\r
-{\r
-    WNDCLASSEX wc = {0};\r
-\r
-    wc.cbSize = sizeof(WNDCLASSEX);\r
-    wc.lpfnWndProc = PreviewWndProc;\r
-    wc.hInstance = hInstance;\r
-    wc.hCursor = LoadCursor(NULL, IDC_ARROW);\r
-    wc.hbrBackground = (HBRUSH)NULL; //(COLOR_BTNFACE + 1);\r
-    wc.lpszClassName = szPreviewWndClass;\r
-\r
-    return RegisterClassEx(&wc) != (ATOM)0;\r
-}\r
-\r
-\r
-VOID\r
-UnregisterPreviewControl(IN HINSTANCE hInstance)\r
-{\r
-    UnregisterClass(szPreviewWndClass,\r
-                    hInstance);\r
-}\r
+/*
+ * PROJECT:     ReactOS Desktop Control Panel
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        lib/cpl/desk/preview.c
+ * PURPOSE:     Draws the preview control
+ * COPYRIGHT:   Copyright 2006, 2007 Eric Kohl
+ */
+
+#include "desk.h"
+#include "theme.h"
+#include "preview.h"
+#include "draw.h"
+
+static const TCHAR szPreviewWndClass[] = TEXT("PreviewWndClass");
+
+typedef struct _PREVIEW_DATA
+{
+    HWND hwndParent;
+
+    THEME Theme;
+
+    HBRUSH hbrScrollbar;
+    HBRUSH hbrDesktop;
+    HBRUSH hbrWindow;
+
+    INT cxEdge;
+    INT cyEdge;
+
+    INT cySizeFrame;
+
+    INT cyCaption;
+    INT cyBorder;
+    INT cyMenu;
+    INT cxScrollbar;
+
+    RECT rcDesktop;
+    RECT rcInactiveFrame;
+    RECT rcInactiveCaption;
+    RECT rcInactiveCaptionButtons;
+
+    RECT rcActiveFrame;
+    RECT rcActiveCaption;
+    RECT rcActiveCaptionButtons;
+    RECT rcActiveMenuBar;
+    RECT rcSelectedMenuItem;
+    RECT rcActiveClient;
+    RECT rcActiveScroll;
+
+    RECT rcDialogFrame;
+    RECT rcDialogCaption;
+    RECT rcDialogCaptionButtons;
+    RECT rcDialogClient;
+
+    RECT rcDialogButton;
+
+    LPTSTR lpInAct;
+    LPTSTR lpAct;
+    LPTSTR lpWinTxt;
+    LPTSTR lpMessBox;
+    LPTSTR lpMessText;
+    LPTSTR lpButText;
+
+    HFONT hCaptionFont;
+    HFONT hMenuFont;
+    HFONT hMessageFont;
+    HFONT hClientFont;
+
+    HMENU hMenu;
+
+} PREVIEW_DATA, *PPREVIEW_DATA;
+
+
+static VOID UpdatePreviewTheme(HWND hwnd, PPREVIEW_DATA pPreviewData, THEME *theme)
+{
+    if (pPreviewData->hbrScrollbar != NULL)
+        DeleteObject(pPreviewData->hbrScrollbar);
+    pPreviewData->hbrScrollbar = CreateSolidBrush(theme->crColor[COLOR_SCROLLBAR]);
+    if (pPreviewData->hbrDesktop != NULL)
+        DeleteObject(pPreviewData->hbrDesktop);
+    pPreviewData->hbrDesktop = CreateSolidBrush(theme->crColor[COLOR_DESKTOP]);
+    if (pPreviewData->hbrWindow != NULL)
+        DeleteObject(pPreviewData->hbrWindow);
+    pPreviewData->hbrWindow = CreateSolidBrush(theme->crColor[COLOR_WINDOW]);
+
+    pPreviewData->cxEdge = theme->Size[SIZE_EDGE_X] - 2;        /* SM_CXEDGE */
+    pPreviewData->cyEdge = theme->Size[SIZE_EDGE_Y] - 2;        /* SM_CYEDGE */
+
+    pPreviewData->cySizeFrame = theme->Size[SIZE_FRAME_Y] - 1;  /* SM_CYSIZEFRAME */
+
+    pPreviewData->cyCaption = theme->Size[SIZE_CAPTION_Y];      /* SM_CYCAPTION */
+    pPreviewData->cyMenu = theme->Size[SIZE_MENU_Y];            /* SM_CYMENU */
+    pPreviewData->cxScrollbar = theme->Size[SIZE_SCROLL_X];     /* SM_CXVSCROLL */
+    pPreviewData->cyBorder = theme->Size[SIZE_BORDER_Y];        /* SM_CYBORDER */
+
+    if (pPreviewData->hCaptionFont != NULL)
+        DeleteObject(pPreviewData->hCaptionFont);
+    pPreviewData->hCaptionFont = CreateFontIndirect(&theme->lfFont[FONT_CAPTION]);
+
+    if (pPreviewData->hMenuFont != NULL)
+        DeleteObject(pPreviewData->hMenuFont);
+    pPreviewData->hMenuFont = CreateFontIndirect(&theme->lfFont[FONT_MENU]);
+
+    if (pPreviewData->hMessageFont != NULL)
+        DeleteObject(pPreviewData->hMessageFont);
+    pPreviewData->hMessageFont = CreateFontIndirect(&theme->lfFont[FONT_DIALOG]);
+
+    pPreviewData->Theme = *theme;
+    InvalidateRect(hwnd, NULL, FALSE);
+}
+
+static VOID
+OnCreate(HWND hwnd, PPREVIEW_DATA pPreviewData)
+{
+    THEME *theme;
+
+    pPreviewData->hClientFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+
+    /* Load and modify the menu */
+    pPreviewData->hMenu = LoadMenu(hApplet, MAKEINTRESOURCE(IDR_PREVIEW_MENU));
+    EnableMenuItem(pPreviewData->hMenu,
+                   1, MF_BYPOSITION | MF_GRAYED);
+    HiliteMenuItem(hwnd, pPreviewData->hMenu,
+                   2, MF_BYPOSITION | MF_HILITE);
+
+//    GetMenuItemRect(hwnd, pPreviewData->hMenu,
+//                    2, &pPreviewData->rcSelectedMenuItem);
+
+    AllocAndLoadString(&pPreviewData->lpInAct, hApplet, IDS_INACTWIN);
+    AllocAndLoadString(&pPreviewData->lpAct, hApplet, IDS_ACTWIN);
+    AllocAndLoadString(&pPreviewData->lpWinTxt, hApplet, IDS_WINTEXT);
+    AllocAndLoadString(&pPreviewData->lpMessBox, hApplet, IDS_MESSBOX);
+    AllocAndLoadString(&pPreviewData->lpMessText, hApplet, IDS_MESSTEXT);
+    AllocAndLoadString(&pPreviewData->lpButText, hApplet, IDS_BUTTEXT);
+
+    theme = &pPreviewData->Theme;
+    LoadCurrentTheme(theme);
+
+    UpdatePreviewTheme(hwnd, pPreviewData, theme);
+}
+
+
+static VOID
+CalculateItemSize(PPREVIEW_DATA pPreviewData)
+{
+    int width, height;
+
+    /* Calculate the inactive window rectangle */
+    pPreviewData->rcInactiveFrame.left = pPreviewData->rcDesktop.left + 8;
+    pPreviewData->rcInactiveFrame.top = pPreviewData->rcDesktop.top + 8;
+    pPreviewData->rcInactiveFrame.right = pPreviewData->rcDesktop.right - 25;
+    pPreviewData->rcInactiveFrame.bottom = pPreviewData->rcDesktop.bottom - 30;
+
+    /* Calculate the inactive caption rectangle */
+    pPreviewData->rcInactiveCaption.left = pPreviewData->rcInactiveFrame.left + pPreviewData->cxEdge + pPreviewData->cySizeFrame + 1;
+    pPreviewData->rcInactiveCaption.top = pPreviewData->rcInactiveFrame.top + pPreviewData->cyEdge + pPreviewData->cySizeFrame + 1;
+    pPreviewData->rcInactiveCaption.right = pPreviewData->rcInactiveFrame.right - pPreviewData->cxEdge - pPreviewData->cySizeFrame - 1;
+    pPreviewData->rcInactiveCaption.bottom = pPreviewData->rcInactiveCaption.top + pPreviewData->cyCaption - pPreviewData->cyBorder;
+
+    /* Calculate the inactive caption buttons rectangle */
+    pPreviewData->rcInactiveCaptionButtons.left = pPreviewData->rcInactiveCaption.right - 2 - 2 - 3 * 16;
+    pPreviewData->rcInactiveCaptionButtons.top = pPreviewData->rcInactiveCaption.top + 2;
+    pPreviewData->rcInactiveCaptionButtons.right = pPreviewData->rcInactiveCaption.right - 2;
+    pPreviewData->rcInactiveCaptionButtons.bottom = pPreviewData->rcInactiveCaption.bottom - 2;
+
+    /* Calculate the active window rectangle */
+    pPreviewData->rcActiveFrame.left = pPreviewData->rcInactiveFrame.left + 3 + pPreviewData->cySizeFrame;
+    pPreviewData->rcActiveFrame.top = pPreviewData->rcInactiveCaption.bottom + 1;
+    pPreviewData->rcActiveFrame.right = pPreviewData->rcDesktop.right - 10;
+    pPreviewData->rcActiveFrame.bottom = pPreviewData->rcDesktop.bottom - 25;
+
+    /* Calculate the active caption rectangle */
+    pPreviewData->rcActiveCaption.left = pPreviewData->rcActiveFrame.left + pPreviewData->cxEdge + pPreviewData->cySizeFrame + 1;
+    pPreviewData->rcActiveCaption.top = pPreviewData->rcActiveFrame.top + pPreviewData->cxEdge + pPreviewData->cySizeFrame + 1;
+    pPreviewData->rcActiveCaption.right = pPreviewData->rcActiveFrame.right - pPreviewData->cxEdge - pPreviewData->cySizeFrame - 1;
+    pPreviewData->rcActiveCaption.bottom = pPreviewData->rcActiveCaption.top + pPreviewData->cyCaption - pPreviewData->cyBorder;
+
+    /* Calculate the active caption buttons rectangle */
+    pPreviewData->rcActiveCaptionButtons.left = pPreviewData->rcActiveCaption.right - 2 - 2 - 3 * 16;
+    pPreviewData->rcActiveCaptionButtons.top = pPreviewData->rcActiveCaption.top + 2;
+    pPreviewData->rcActiveCaptionButtons.right = pPreviewData->rcActiveCaption.right - 2;
+    pPreviewData->rcActiveCaptionButtons.bottom = pPreviewData->rcActiveCaption.bottom - 2;
+
+    /* Calculate the active menu bar rectangle */
+    pPreviewData->rcActiveMenuBar.left = pPreviewData->rcActiveFrame.left + pPreviewData->cxEdge + pPreviewData->cySizeFrame + 1;
+    pPreviewData->rcActiveMenuBar.top = pPreviewData->rcActiveCaption.bottom + 1;
+    pPreviewData->rcActiveMenuBar.right = pPreviewData->rcActiveFrame.right - pPreviewData->cxEdge - pPreviewData->cySizeFrame - 1;
+    pPreviewData->rcActiveMenuBar.bottom = pPreviewData->rcActiveMenuBar.top + pPreviewData->cyMenu + 1;
+
+    /* Calculate the active client rectangle */
+    pPreviewData->rcActiveClient.left = pPreviewData->rcActiveFrame.left + pPreviewData->cxEdge + pPreviewData->cySizeFrame + 1;
+    pPreviewData->rcActiveClient.top = pPreviewData->rcActiveMenuBar.bottom;
+    pPreviewData->rcActiveClient.right = pPreviewData->rcActiveFrame.right - pPreviewData->cxEdge - pPreviewData->cySizeFrame - 1;
+    pPreviewData->rcActiveClient.bottom = pPreviewData->rcActiveFrame.bottom - pPreviewData->cyEdge - pPreviewData->cySizeFrame - 1;
+
+    /* Calculate the active scroll rectangle */
+    pPreviewData->rcActiveScroll.left = pPreviewData->rcActiveClient.right - 2 - pPreviewData->cxScrollbar;
+    pPreviewData->rcActiveScroll.top = pPreviewData->rcActiveClient.top + 2;
+    pPreviewData->rcActiveScroll.right = pPreviewData->rcActiveClient.right - 2;
+    pPreviewData->rcActiveScroll.bottom = pPreviewData->rcActiveClient.bottom - 2;
+
+
+    /* Dialog window */
+    pPreviewData->rcDialogFrame.left = pPreviewData->rcActiveClient.left + 4;
+    pPreviewData->rcDialogFrame.top = (pPreviewData->rcDesktop.bottom * 60) / 100;
+    pPreviewData->rcDialogFrame.right = (pPreviewData->rcDesktop.right * 65) / 100;
+    pPreviewData->rcDialogFrame.bottom = pPreviewData->rcDesktop.bottom - 5;
+
+    /* Calculate the dialog caption rectangle */
+    pPreviewData->rcDialogCaption.left = pPreviewData->rcDialogFrame.left + 3;
+    pPreviewData->rcDialogCaption.top = pPreviewData->rcDialogFrame.top + 3;
+    pPreviewData->rcDialogCaption.right = pPreviewData->rcDialogFrame.right - 3;
+    pPreviewData->rcDialogCaption.bottom = pPreviewData->rcDialogFrame.top + pPreviewData->cyCaption + 1 + 1;
+
+    /* Calculate the inactive caption buttons rectangle */
+    pPreviewData->rcDialogCaptionButtons.left = pPreviewData->rcDialogCaption.right - 2 - 16;
+    pPreviewData->rcDialogCaptionButtons.top = pPreviewData->rcDialogCaption.top + 2;
+    pPreviewData->rcDialogCaptionButtons.right = pPreviewData->rcDialogCaption.right - 2;
+    pPreviewData->rcDialogCaptionButtons.bottom = pPreviewData->rcDialogCaption.bottom - 2;
+
+    /* Calculate the dialog client rectangle */
+    pPreviewData->rcDialogClient.left = pPreviewData->rcDialogFrame.left + 3;
+    pPreviewData->rcDialogClient.top = pPreviewData->rcDialogCaption.bottom + 1;
+    pPreviewData->rcDialogClient.right = pPreviewData->rcDialogFrame.right - 3;
+    pPreviewData->rcDialogClient.bottom = pPreviewData->rcDialogFrame.bottom - 3;
+
+    /* Calculate the dialog button rectangle */
+    width = 80;
+    height = 28;
+
+    pPreviewData->rcDialogButton.left =
+        (pPreviewData->rcDialogClient.right + pPreviewData->rcDialogClient.left - width) / 2;
+    pPreviewData->rcDialogButton.right = pPreviewData->rcDialogButton.left + width;
+    pPreviewData->rcDialogButton.bottom = pPreviewData->rcDialogClient.bottom - 2;
+    pPreviewData->rcDialogButton.top = pPreviewData->rcDialogButton.bottom - height;
+}
+
+
+static VOID
+OnSize(INT cx, INT cy, PPREVIEW_DATA pPreviewData)
+{
+    /* Get Desktop rectangle */
+    pPreviewData->rcDesktop.left = 0;
+    pPreviewData->rcDesktop.top = 0;
+    pPreviewData->rcDesktop.right = cx;
+    pPreviewData->rcDesktop.bottom = cy;
+
+    CalculateItemSize(pPreviewData);
+}
+
+static VOID
+OnPaint(HWND hwnd, PPREVIEW_DATA pPreviewData)
+{
+    PAINTSTRUCT ps;
+    HFONT hOldFont;
+    HDC hdc;
+    RECT rc;
+    THEME *theme;
+
+    theme = &pPreviewData->Theme;
+
+    hdc = BeginPaint(hwnd, &ps);
+
+    /* Desktop */
+    FillRect(hdc, &pPreviewData->rcDesktop, pPreviewData->hbrDesktop);
+
+    /* Inactive Window */
+    MyDrawEdge(hdc, &pPreviewData->rcInactiveFrame, EDGE_RAISED, BF_RECT | BF_MIDDLE, theme);
+    SetTextColor(hdc, theme->crColor[COLOR_INACTIVECAPTIONTEXT]);
+    MyDrawCaptionTemp(NULL, hdc, &pPreviewData->rcInactiveCaption,  pPreviewData->hCaptionFont,
+                      NULL, pPreviewData->lpInAct, DC_GRADIENT | DC_ICON | DC_TEXT, theme);
+    MyDrawCaptionButtons(hdc, &pPreviewData->rcInactiveCaption, TRUE, pPreviewData->cyCaption - 2, theme);
+
+    /* Active Window */
+    MyDrawEdge(hdc, &pPreviewData->rcActiveFrame, EDGE_RAISED, BF_RECT | BF_MIDDLE, theme);
+    SetTextColor(hdc, theme->crColor[COLOR_CAPTIONTEXT]);
+    MyDrawCaptionTemp(NULL, hdc, &pPreviewData->rcActiveCaption, pPreviewData->hCaptionFont,
+                      NULL, pPreviewData->lpAct, DC_ACTIVE | DC_GRADIENT | DC_ICON | DC_TEXT, theme);
+    MyDrawCaptionButtons(hdc, &pPreviewData->rcActiveCaption, TRUE, pPreviewData->cyCaption - 2, theme);
+
+    /* Draw the menu bar */
+    MyDrawMenuBarTemp(hwnd, hdc, &pPreviewData->rcActiveMenuBar,
+                      pPreviewData->hMenu,
+                      pPreviewData->hMenuFont, theme);
+
+    /* Draw the client area */
+    CopyRect(&rc, &pPreviewData->rcActiveClient);
+    MyDrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_ADJUST, theme);
+    FillRect(hdc, &rc, pPreviewData->hbrWindow);
+
+    /* Draw the client text */
+    CopyRect(&rc, &pPreviewData->rcActiveClient);
+    rc.left += 4;
+    rc.top += 2;
+    SetTextColor(hdc, theme->crColor[COLOR_WINDOWTEXT]);
+    hOldFont = SelectObject(hdc, pPreviewData->hClientFont);
+    DrawText(hdc, pPreviewData->lpWinTxt, -1, &rc, DT_LEFT);
+    SelectObject(hdc, hOldFont);
+
+    /* Draw the scroll bar */
+    MyDrawScrollbar(hdc, &pPreviewData->rcActiveScroll, pPreviewData->hbrScrollbar, theme);
+
+    /* Dialog Window */
+    MyDrawEdge(hdc, &pPreviewData->rcDialogFrame, EDGE_RAISED, BF_RECT | BF_MIDDLE, theme);
+    SetTextColor(hdc, theme->crColor[COLOR_WINDOW]);
+    MyDrawCaptionTemp(NULL, hdc, &pPreviewData->rcDialogCaption, pPreviewData->hCaptionFont,
+                      NULL, pPreviewData->lpMessBox, DC_ACTIVE | DC_GRADIENT | DC_ICON | DC_TEXT, theme);
+    MyDrawCaptionButtons(hdc, &pPreviewData->rcDialogCaption, FALSE, pPreviewData->cyCaption - 2, theme);
+
+    /* Draw the dialog text */
+    CopyRect(&rc, &pPreviewData->rcDialogClient);
+    rc.left += 4;
+    rc.top += 2;
+    SetTextColor(hdc, theme->crColor[COLOR_BTNTEXT]);
+    hOldFont = SelectObject(hdc, pPreviewData->hMessageFont);
+    DrawText(hdc, pPreviewData->lpMessText, -1, &rc, DT_LEFT);
+    SelectObject(hdc, hOldFont);
+
+    /* Draw Button */
+    MyDrawFrameControl(hdc, &pPreviewData->rcDialogButton, DFC_BUTTON, DFCS_BUTTONPUSH, theme);
+    CopyRect(&rc, &pPreviewData->rcDialogButton);
+    SetTextColor(hdc, theme->crColor[COLOR_BTNTEXT]);
+    hOldFont = SelectObject(hdc, pPreviewData->hMessageFont);
+    DrawText(hdc, pPreviewData->lpButText, -1, &rc, DT_VCENTER | DT_CENTER | DT_SINGLELINE);
+    SelectObject(hdc, hOldFont);
+
+    EndPaint(hwnd, &ps);
+}
+
+
+static VOID
+OnLButtonDown(HWND hwnd, int xPos, int yPos, PPREVIEW_DATA pPreviewData)
+{
+    UINT type = IDX_DESKTOP;
+    POINT pt;
+
+    pt.x = xPos;
+    pt.y = yPos;
+
+    if (PtInRect(&pPreviewData->rcInactiveFrame, pt))
+        type = IDX_INACTIVE_BORDER;
+
+    if (PtInRect(&pPreviewData->rcInactiveCaption, pt))
+        type = IDX_INACTIVE_CAPTION;
+
+    if (PtInRect(&pPreviewData->rcInactiveCaptionButtons, pt))
+        type = IDX_CAPTION_BUTTON;
+
+    if (PtInRect(&pPreviewData->rcActiveFrame, pt))
+        type = IDX_ACTIVE_BORDER;
+
+    if (PtInRect(&pPreviewData->rcActiveCaption, pt))
+        type = IDX_ACTIVE_CAPTION;
+
+    if (PtInRect(&pPreviewData->rcActiveCaptionButtons, pt))
+        type = IDX_CAPTION_BUTTON;
+
+//    if (PtInRect(&pPreviewData->rcSelectedMenuItem, pt))
+//        type = IDX_SELECTION;
+
+    if (PtInRect(&pPreviewData->rcActiveMenuBar, pt))
+        type = IDX_MENU;
+
+    if (PtInRect(&pPreviewData->rcActiveClient, pt))
+        type = IDX_WINDOW;
+
+    if (PtInRect(&pPreviewData->rcActiveScroll, pt))
+        type = IDX_SCROLLBAR;
+
+    if (PtInRect(&pPreviewData->rcDialogFrame, pt))
+        type = IDX_DIALOG;
+
+    if (PtInRect(&pPreviewData->rcDialogCaption, pt))
+        type = IDX_ACTIVE_CAPTION;
+
+    if (PtInRect(&pPreviewData->rcDialogCaptionButtons, pt))
+        type = IDX_CAPTION_BUTTON;
+
+    if (PtInRect(&pPreviewData->rcDialogButton, pt))
+        type = IDX_3D_OBJECTS;
+
+    SendMessage(GetParent(hwnd),
+                WM_COMMAND,
+                MAKEWPARAM(GetWindowLongPtrW(hwnd, GWLP_ID), 0),
+                (LPARAM)type);
+}
+
+
+static VOID
+OnDestroy(PPREVIEW_DATA pPreviewData)
+{
+    DeleteObject(pPreviewData->hbrScrollbar);
+    DeleteObject(pPreviewData->hbrDesktop);
+    DeleteObject(pPreviewData->hbrWindow);
+
+    DeleteObject(pPreviewData->hCaptionFont);
+    DeleteObject(pPreviewData->hMenuFont);
+    DeleteObject(pPreviewData->hMessageFont);
+
+    DestroyMenu(pPreviewData->hMenu);
+
+    LocalFree((HLOCAL)pPreviewData->lpInAct);
+    LocalFree((HLOCAL)pPreviewData->lpAct);
+    LocalFree((HLOCAL)pPreviewData->lpWinTxt);
+    LocalFree((HLOCAL)pPreviewData->lpMessBox);
+    LocalFree((HLOCAL)pPreviewData->lpMessText);
+    LocalFree((HLOCAL)pPreviewData->lpButText);
+}
+
+
+static LRESULT CALLBACK
+PreviewWndProc(HWND hwnd,
+               UINT uMsg,
+               WPARAM wParam,
+               LPARAM lParam)
+{
+    PPREVIEW_DATA pPreviewData;
+
+    pPreviewData = (PPREVIEW_DATA)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+    switch (uMsg)
+    {
+        case WM_CREATE:
+            pPreviewData = (PPREVIEW_DATA)HeapAlloc(GetProcessHeap(),
+                                                    HEAP_ZERO_MEMORY,
+                                                    sizeof(PREVIEW_DATA));
+            if (!pPreviewData)
+                return -1;
+
+            SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pPreviewData);
+            OnCreate(hwnd, pPreviewData);
+            break;
+
+        case WM_SIZE:
+            OnSize(LOWORD(lParam), HIWORD(lParam), pPreviewData);
+            break;
+
+        case WM_PAINT:
+            OnPaint(hwnd, pPreviewData);
+            break;
+
+        case WM_LBUTTONDOWN:
+            OnLButtonDown(hwnd, LOWORD(lParam), HIWORD(lParam), pPreviewData);
+            break;
+
+        case WM_DESTROY:
+            OnDestroy(pPreviewData);
+            HeapFree(GetProcessHeap(), 0, pPreviewData);
+            break;
+
+        case PVM_GETCYCAPTION:
+            return pPreviewData->cyCaption;
+
+        case PVM_SETCYCAPTION:
+            if ((INT)lParam > 0)
+            {
+                pPreviewData->cyCaption = (INT)lParam;
+                CalculateItemSize(pPreviewData);
+                InvalidateRect(hwnd, NULL, FALSE);
+            }
+            break;
+
+        case PVM_GETCYMENU:
+            return pPreviewData->cyMenu;
+
+        case PVM_SETCYMENU:
+            if ((INT)lParam > 0)
+            {
+                pPreviewData->cyMenu = (INT)lParam;
+                CalculateItemSize(pPreviewData);
+                InvalidateRect(hwnd, NULL, FALSE);
+            }
+            break;
+
+        case PVM_GETCXSCROLLBAR:
+            return pPreviewData->cxScrollbar;
+
+        case PVM_SETCXSCROLLBAR:
+            if ((INT)lParam > 0)
+            {
+                pPreviewData->cxScrollbar = (INT)lParam;
+                CalculateItemSize(pPreviewData);
+                InvalidateRect(hwnd, NULL, FALSE);
+            }
+            break;
+
+        case PVM_GETCYSIZEFRAME:
+            return pPreviewData->cySizeFrame;
+
+        case PVM_SETCYSIZEFRAME:
+            if ((INT)lParam > 0)
+            {
+                pPreviewData->cySizeFrame = (INT)lParam;
+                CalculateItemSize(pPreviewData);
+                InvalidateRect(hwnd, NULL, FALSE);
+            }
+            break;
+
+        case PVM_UPDATETHEME:
+            UpdatePreviewTheme(hwnd, pPreviewData, (THEME *)lParam);
+            break;
+
+        default:
+            return DefWindowProc(hwnd, uMsg, wParam, lParam);
+    }
+    return FALSE;
+}
+
+
+BOOL
+RegisterPreviewControl(IN HINSTANCE hInstance)
+{
+    WNDCLASSEX wc = {0};
+
+    wc.cbSize = sizeof(WNDCLASSEX);
+    wc.lpfnWndProc = PreviewWndProc;
+    wc.hInstance = hInstance;
+    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+    wc.hbrBackground = (HBRUSH)NULL;
+    wc.lpszClassName = szPreviewWndClass;
+
+    return RegisterClassEx(&wc) != (ATOM)0;
+}
+
+
+VOID
+UnregisterPreviewControl(IN HINSTANCE hInstance)
+{
+    UnregisterClass(szPreviewWndClass, hInstance);
+}