//
// WGRP.CPP
// Widths Group
//
// Copyright Microsoft 1998-
//

// PRECOMP
#include "precomp.h"


static const TCHAR szWGClassName[] = "T126WB_WGRP";


WbWidthsGroup::WbWidthsGroup()
{
    int     i;

    m_hwnd  = NULL;
    m_uLast = 0;

    //
    // Calculate the height of each item in the list--it's the max of the
    // pen widths + slop space
    //
    m_cyItem = 0;
    for (i = 0; i < NUM_OF_WIDTHS; i++)
    {
        m_cyItem = max(m_cyItem, g_PenWidths[i]);
    }
    m_cyItem += 2 * ::GetSystemMetrics(SM_CYEDGE);
}


WbWidthsGroup::~WbWidthsGroup()
{
    if (m_hwnd != NULL)
    {
        ::DestroyWindow(m_hwnd);
        ASSERT(m_hwnd == NULL);
    }

    ::UnregisterClass(szWGClassName, g_hInstance);
}



BOOL WbWidthsGroup::Create(HWND hwndParent, LPCRECT lprect)
{
    WNDCLASSEX      wc;

    // Register our class
    ZeroMemory(&wc, sizeof(wc));
    wc.cbSize           = sizeof(wc);
    wc.style            = 0;
    wc.lpfnWndProc      = WGWndProc;
    wc.hInstance        = g_hInstance;
    wc.hCursor          = ::LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = (HBRUSH)(COLOR_BTNFACE + 1);
    wc.lpszClassName    = szWGClassName;

    if (!::RegisterClassEx(&wc))
    {
        ERROR_OUT(("WbWidthsGroup::Create register class failed"));
        return(FALSE);
    }

    ASSERT(!m_hwnd);

    if (!::CreateWindowEx(WS_EX_STATICEDGE, szWGClassName, NULL,
        WS_CHILD | WS_CLIPSIBLINGS, lprect->left, lprect->top,
        lprect->right - lprect->left, lprect->bottom - lprect->top,
        hwndParent, (HMENU)IDM_WIDTH, g_hInstance, this))
    {
        ERROR_OUT(("Can't create WbWidthsGroup"));
        return(FALSE);
    }

    return(TRUE);
}



//
// WGWndProc()
// Message handler for width window
//
LRESULT CALLBACK WGWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    LRESULT lResult = 0;
    WbWidthsGroup * pwg = (WbWidthsGroup *)::GetWindowLongPtr(hwnd, GWLP_USERDATA);

    switch (message)
    {
        case WM_NCCREATE:
            pwg = (WbWidthsGroup *)(((LPCREATESTRUCT)lParam)->lpCreateParams);
            ASSERT(pwg);

            pwg->m_hwnd = hwnd;
            ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pwg);
            goto DefWndProc;
            break;

        case WM_NCDESTROY:
            ASSERT(pwg);
            pwg->m_hwnd = NULL;
            break;

        case WM_PAINT:
            ASSERT(pwg);
            pwg->OnPaint();
            break;

        case WM_LBUTTONDOWN:
            ASSERT(pwg);
            pwg->OnLButtonDown((short)LOWORD(lParam), (short)HIWORD(lParam));
            break;

        case WM_NOTIFY:
            // Pass up to main window
            lResult = ::SendMessage(g_pMain->m_hwnd, message, wParam, lParam);
            break;

        default:
DefWndProc:
            lResult = DefWindowProc(hwnd, message, wParam, lParam);
            break;
    }

    return(lResult);
}



void WbWidthsGroup::GetNaturalSize(LPSIZE lpsize)
{
    lpsize->cy = ::GetSystemMetrics(SM_CYEDGE) +
        (NUM_OF_WIDTHS * m_cyItem);

    if (m_hwnd != NULL)
    {
        RECT    rect;

        ::GetWindowRect(m_hwnd, &rect);
        rect.right -= rect.left;
        lpsize->cx = max(WIDTHBAR_WIDTH, rect.right);
    }
    else
    {
        lpsize->cx = WIDTHBAR_WIDTH;
    }
}



void WbWidthsGroup::PushDown(UINT uiIndex)
{
    if( (uiIndex < NUM_OF_WIDTHS))
    {
        //
        // We really should just invalidate the last selected item, if one,
        // and the new selected item, if one.  But heck, there are only 4
        // items, no big deal to paint.
        //
        m_uLast = uiIndex;
        ::InvalidateRect(m_hwnd, NULL, TRUE);
    }
}




void WbWidthsGroup::OnPaint(void)
{
    PAINTSTRUCT ps;
    int         i;
    RECT        rect;
    int         cx, cy;
    int         nPenWidth;
    HBRUSH      hOldBrush;

    ::BeginPaint(m_hwnd, &ps);

    ::GetClientRect(m_hwnd, &rect);
    cx = ::GetSystemMetrics(SM_CXEDGE);
    cy = m_cyItem / 2;

    // First, fill the background of the selected item
    hOldBrush = SelectBrush(ps.hdc, ::GetSysColorBrush(COLOR_3DHILIGHT));

    ::PatBlt(ps.hdc, rect.left, m_uLast * m_cyItem,
        rect.right - rect.left, m_cyItem, PATCOPY);

    rect.right -= rect.left + 2*cx;

    // Now, use the black brush
    SelectBrush(ps.hdc, ::GetStockObject(BLACK_BRUSH));

    for (i = 0; i < NUM_OF_WIDTHS; i++)
    {
        nPenWidth = g_PenWidths[i];

        ::PatBlt(ps.hdc, cx, rect.top + (m_cyItem - nPenWidth) / 2,
            rect.right, nPenWidth, PATCOPY);

        rect.top += m_cyItem;
    }

    SelectBrush(ps.hdc, hOldBrush);

    // Finish painting
    ::EndPaint(m_hwnd, &ps);
}



//
// ItemFromPoint()
// Returns which item, in the client, is under the point.
//
int WbWidthsGroup::ItemFromPoint(int x, int y) const
{
    int iItem;

    iItem = y / m_cyItem;

    // If it's in the border above the first item, pin it.
    if (iItem < 0)
        iItem = 0;

    // If it's in the border below the last item, pin it.
    if (iItem >= (IDM_WIDTHS_END - IDM_WIDTHS_START))
        iItem = (IDM_WIDTHS_END - IDM_WIDTHS_START - 1);

    return(iItem + IDM_WIDTHS_START);
}


//
// GetItemRect()
// Gets the client-relative rectangle of an item
//
void WbWidthsGroup::GetItemRect(int iItem, LPRECT lprc) const
{
    ::GetClientRect(m_hwnd, lprc);

    lprc->top = (iItem - IDM_WIDTHS_START) * m_cyItem;
    lprc->bottom = lprc->top + m_cyItem;
}


//
// OnLButtonDown()
//
void WbWidthsGroup::OnLButtonDown(int x, int y)
{
    int iItem;

    iItem = ItemFromPoint(x, y);
    ::PostMessage(g_pMain->m_hwnd, WM_COMMAND,
                    (WPARAM)MAKELONG(iItem, BN_CLICKED),
                    (LPARAM)m_hwnd);
}