#include "stdafx.h"
#pragma hdrstop

class CCompPreview
{
public:
protected:
    HWND _hwnd;
    HBITMAP _hbmMonitor;
    HDC _hdcCompMemory;
    int _iScreenWidth;
    int _iScreenHeight;
    int _iXBorders;
    int _iYBorders;

    static LRESULT CALLBACK CompPreviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
    friend BOOL RegisterCompPreviewClass(void);

    LONG _OnCreate(HWND hwnd);
    void _OnDestroy(void);
    void _OnPaint(void);
    void _RecalcMetrics(void);
};

void CCompPreview::_RecalcMetrics(void)
{
    RECT rect;
    SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, FALSE);
    _iScreenWidth = rect.right - rect.left;
    _iScreenHeight = rect.bottom - rect.top;
    _iXBorders = (2 * GET_CXSIZE);
    _iYBorders = (GET_CYSIZE + GET_CYCAPTION);
}

LONG CCompPreview::_OnCreate(HWND hwnd)
{
    LONG lRet = 0;

    _hwnd = hwnd;
    SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);

    HDC hdc = GetDC(NULL);
    _hdcCompMemory = CreateCompatibleDC(hdc);
    ReleaseDC(NULL, hdc);

    _hbmMonitor = LoadMonitorBitmap();

    if (_hbmMonitor == NULL)
    {
        lRet = -1;
    }

    _RecalcMetrics();  //Initialize the screen width and height etc.,

    return lRet;
}

void CCompPreview::_OnDestroy()
{
    if (_hbmMonitor)
    {
        DeleteObject(_hbmMonitor);
    }
    if (_hdcCompMemory)
    {
        DeleteDC(_hdcCompMemory);
    }
    delete this;
}

void CCompPreview::_OnPaint()
{
    PAINTSTRUCT     ps;
    BITMAP          bm;
    RECT            rc;

    BeginPaint(_hwnd,&ps);
    if (_hbmMonitor)
    {
        DWORD dwDefWidth = (_iScreenWidth / (COMPONENT_PER_ROW + 1)) - _iXBorders;
        DWORD dwDefHeight = (_iScreenHeight / (COMPONENT_PER_COL + 1)) - _iYBorders;

        //
        // Select the monitor bitmap into an hdc.
        //
        HBITMAP hbmOld = (HBITMAP)SelectObject(_hdcCompMemory, _hbmMonitor);

        //
        // Get the size of the bitmap and of our window.
        //
        GetClientRect(_hwnd, &rc);
        GetObject(_hbmMonitor, sizeof(bm), &bm);

        //
        // Center the bitmap in the window.
        //
        rc.left = ( rc.right - bm.bmWidth ) / 2;
        rc.top = ( rc.bottom - bm.bmHeight ) / 2;
        BitBlt(ps.hdc, rc.left, rc.top, bm.bmWidth, bm.bmHeight, _hdcCompMemory,
            0, 0, SRCCOPY);

        SelectObject(_hdcCompMemory, hbmOld);

        //
        // From now on, only paint in the "monitor" area of the bitmap.
        //
        IntersectClipRect(ps.hdc, rc.left + MON_X, rc.top + MON_Y, rc.left + MON_X + MON_DX, rc.top + MON_Y + MON_DY);

        //
        // Determine who the selected component is.
        //
        int iSelectedComponent;
        SendMessage(GetParent(_hwnd), WM_COMP_GETCURSEL, 0, (LPARAM)&iSelectedComponent);

        //
        // Create two new brush/pen combos, and remember the original
        // brush & pen.
        //
        HBRUSH hbrushActComp = CreateSolidBrush(GetSysColor(COLOR_ACTIVECAPTION));
        HPEN hpenActComp = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_CAPTIONTEXT));

        HBRUSH hbrushComp = CreateSolidBrush(GetSysColor(COLOR_INACTIVECAPTION));
        HPEN hpenComp = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_INACTIVECAPTIONTEXT));

        HBRUSH hbrushOld = (HBRUSH)SelectObject(ps.hdc, hbrushComp);
        HPEN hpenOld = (HPEN)SelectObject(ps.hdc, hpenComp);

        int iPrimaryMonitorX = -GetSystemMetrics(SM_XVIRTUALSCREEN);
        int iPrimaryMonitorY = -GetSystemMetrics(SM_YVIRTUALSCREEN);
        int iPrimaryMonitorCX = GetSystemMetrics(SM_CXSCREEN);
        int iPrimaryMonitorCY = GetSystemMetrics(SM_CYSCREEN);
        //
        // Draw each component in the "monitor" area of the bitmap.
        //
        int i, cComp;
        g_pActiveDeskAdv->GetDesktopItemCount(&cComp, 0);
        for (i=0; i < cComp; i++)
        {
            COMPONENT comp;
            comp.dwSize = sizeof(COMPONENT);
            if (SUCCEEDED(g_pActiveDeskAdv->GetDesktopItem(i, &comp, 0)) && (comp.fChecked))
            {
                // FEATURE: We show only components in the primary monitor in IE v4.01
                if (comp.cpPos.iLeft < iPrimaryMonitorX
                        || comp.cpPos.iLeft > iPrimaryMonitorX + iPrimaryMonitorCX
                        || comp.cpPos.iTop < iPrimaryMonitorY
                        || comp.cpPos.iTop > iPrimaryMonitorY + iPrimaryMonitorCY)
                {
                    continue;
                }

                // If the width or Height is -1, then we don't know what the actual
                // size is going to be. So, we try to give a default size here for comp
                // in the preview bitmap.
                DWORD dwCompWidth = (comp.cpPos.dwWidth == COMPONENT_DEFAULT_WIDTH)? dwDefWidth : comp.cpPos.dwWidth;
                DWORD dwCompHeight = (comp.cpPos.dwHeight == COMPONENT_DEFAULT_HEIGHT)? dwDefHeight : comp.cpPos.dwHeight;

                if (i == iSelectedComponent)
                {
                    SelectObject(ps.hdc, hbrushActComp);
                    SelectObject(ps.hdc, hpenActComp);
                }

                int nLeft = rc.left + MON_X + MulDiv(comp.cpPos.iLeft - iPrimaryMonitorX, MON_DX, GetDeviceCaps(_hdcCompMemory, HORZRES));
                int nTop = rc.top + MON_Y + MulDiv(comp.cpPos.iTop - iPrimaryMonitorY, MON_DY, GetDeviceCaps(_hdcCompMemory, VERTRES));
                int nRight = rc.left + MON_X + MulDiv((comp.cpPos.iLeft - iPrimaryMonitorX) + dwCompWidth, MON_DX, GetDeviceCaps(_hdcCompMemory, HORZRES));
                int nBottom = rc.top + MON_Y + MulDiv((comp.cpPos.iTop - iPrimaryMonitorY)+ dwCompHeight, MON_DY, GetDeviceCaps(_hdcCompMemory, VERTRES));

                Rectangle(ps.hdc, nLeft, nTop, nRight, nBottom);

                if (i == iSelectedComponent)
                {
                    SelectObject(ps.hdc, hbrushComp);
                    SelectObject(ps.hdc, hpenComp);
                }
            }
        }

        SelectObject(ps.hdc, hpenOld);
        SelectObject(ps.hdc, hbrushOld);

        DeleteObject(hpenComp);
        DeleteObject(hbrushComp);
        DeleteObject(hpenActComp);
        DeleteObject(hbrushActComp);
    }

    EndPaint(_hwnd,&ps);
}

LRESULT CALLBACK CCompPreview::CompPreviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    CCompPreview *pcp = (CCompPreview *)GetWindowLongPtr(hwnd, GWLP_USERDATA);

    switch(message)
    {
    case WM_CREATE:
        pcp = new CCompPreview();
        return pcp ? pcp->_OnCreate(hwnd) : -1;

    case WM_DESTROY:
        pcp->_OnDestroy();
        break;

    case WM_PAINT:
        pcp->_OnPaint();
        return 0;

    case WM_DISPLAYCHANGE:
    case WM_WININICHANGE:
        pcp->_RecalcMetrics();
        break;

//  98/09/01 vtan #190588: WM_SYSCOLORCHANGE is passed when the desktop
//  background color is changed. This message is passed to the property
//  sheet common control which sends the message through to all the
//  children. The message is now processed here. The old monitor background
//  bitmap is discarded and a new one created with the current (new)
//  setting.

    case WM_SYSCOLORCHANGE:
        if (pcp->_hbmMonitor != NULL)
        {
            DeleteObject(pcp->_hbmMonitor);
            pcp->_hbmMonitor = LoadMonitorBitmap();
        }
        break;
    }
    return DefWindowProc(hwnd,message,wParam,lParam);
}

BOOL RegisterCompPreviewClass(void)
{
    WNDCLASS wc;

    if (!GetClassInfo(HINST_THISDLL, c_szComponentPreview, &wc)) {
        wc.style = 0;
        wc.lpfnWndProc = CCompPreview::CompPreviewWndProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = 0;
        wc.hInstance = HINST_THISDLL;
        wc.hIcon = NULL;
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
        wc.lpszMenuName = NULL;
        wc.lpszClassName = c_szComponentPreview;

        if (!RegisterClass(&wc))
            return FALSE;
    }

    return TRUE;
}
