
/******************************************************************************\
*       This is a part of the Microsoft Source Code Samples. 
*       Copyright (C) 1993 Microsoft Corporation.
*       All rights reserved. 
*       This source code is only intended as a supplement to 
*       Microsoft Development Tools and/or WinHelp documentation.
*       See these sources for detailed information regarding the 
*       Microsoft samples programs.
\******************************************************************************/

/****************************** Module Header *******************************
* Module Name: STATUS.C
*
* Status line handler.
*
* Functions:
*
* StatusInit()
* StatusCreate()
* StatusHeight()
* StatusAlloc()
* StatusAddItem()
* StatusCreateTools()
* StatusDeleteTools()
* StatusWndProc()
* StatusResize()
* StatusCalcHeight()
* StatusCalcWidth()
* StatusGetItem()
* LowerRect()
* RaiseRect()
* StatusPaint()
* BottomRight()
* TopLeft()
* StatusButtonDown()
* StatusButtonUp()
* InitDC()
*
* Comments:
*
****************************************************************************/

#include <windows.h>
#include <string.h>

#include "gutils.h"


/* --- data structures ------------------------------------------------- */
#define SF_MAXLABEL     80   /* no more than 80 in an item within the bar */
                             /* Is this adequate for long pathnames on a
                                hi-res screen?
                             */

typedef struct statel {
        int type;                       /* SF_BUTTON or SF_STATIC */
        int flags;                      /* SF_VAR => variable width
                                           SF_LEFT=> left aligned (else right)
                                           SF_RAISE=> paint as 'raised' 3d rect
                                           SF_LOWER=> paint as lowered 3D rect
                                           SF_SZMIN=>together with SF_VAR
                                                     allows minimum size for
                                                     var sized item
                                           SF_SZMAX=>see SZMIN and use nouse
                                        */
        int id;                         /* control id */
        int width;                      /* width of control in chars */
        char text[SF_MAXLABEL+1];       /* null-term string for label */

        RECT rc;                        /* used by status.c */
} STATEL, FAR * PSTATEL;

typedef struct itemlist {
        int nitems;
        PSTATEL statels;

        int selitem;                    /* used by status.c */
        BOOL isselected;                /* used by status.c */
} ILIST, FAR * PILIST;

/* prototypes of routines in this module */

void StatusCreateTools(void);
void StatusDeleteTools(void);
long APIENTRY StatusWndProc(HWND, UINT, UINT, LONG);
void StatusResize(HWND hWnd, PILIST pilist);
int StatusCalcHeight(HWND hWnd, PSTATEL ip);
int StatusCalcWidth(HWND hWnd, PSTATEL ip);
PSTATEL StatusGetItem(PILIST plist, int id);
void LowerRect(HDC hDC, LPRECT rcp);
void RaiseRect(HDC hDC, LPRECT rcp);
void StatusPaint(HWND hWnd, PILIST iplistp);
void BottomRight(HDC hDC, LPRECT rcp, HPEN hpen, BOOL bCorners);
void TopLeft(HDC hDC, LPRECT rcp, HPEN hpen, BOOL bCorners);
void StatusButtonDown(HDC hDC, PSTATEL ip);
void StatusButtonUp(HDC hDC, PSTATEL ip);
void InitDC(HDC hdc);


/*--global data---------------------------------------------------------*/

HPEN hpenHilight, hpenLowlight;
HPEN hpenBlack, hpenNeutral;
HBRUSH hbrBackground; /* pieces and board */
HFONT hFont;
int status_charheight, status_charwidth;

/* default pt size for font (tenths of a pt) */
#define         DEF_PTSIZE      80

/***************************************************************************
 * Function: StatusInit
 *
 * Purpose:
 *
 * Create window class
 */
BOOL
StatusInit(HANDLE hInstance)
{
        WNDCLASS    wc;
        BOOL resp;
        TEXTMETRIC tm;
        HDC hDC;


        StatusCreateTools();

        wc.style = CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS;
        wc.lpfnWndProc = (WNDPROC) StatusWndProc;
        wc.cbClsExtra = 0;
        wc.cbWndExtra = sizeof(HANDLE);
        wc.hInstance = hInstance;
        wc.hIcon = NULL;
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground = hbrBackground;
        wc.lpszClassName = (LPSTR) "gdstatusclass";
        wc.lpszMenuName = NULL;

        resp = RegisterClass(&wc);

        hDC = GetDC(NULL);
        InitDC(hDC);
        GetTextMetrics(hDC, &tm);
        status_charheight = (int)(tm.tmHeight + tm.tmExternalLeading);
        status_charwidth = (int)tm.tmAveCharWidth;
        ReleaseDC(NULL, hDC);

        return(resp);
}

/*
/***************************************************************************
 * Function: StatusCreate
 *
 * Purpose:
 *
 * Create and show the window
 */
HWND APIENTRY
StatusCreate(HANDLE hInst, HWND hParent, int id, LPRECT rcp, HANDLE hmem)
{

        HWND hWnd;

        /* create a child window of status class */


        hWnd = CreateWindow("gdstatusclass",
                        NULL,
                        WS_CHILD | WS_VISIBLE,
                        rcp->left,
                        rcp->top,
                        (rcp->right - rcp->left),
                        (rcp->bottom - rcp->top),
                        hParent,
                        (HANDLE) id,
                        hInst,
                        (LPVOID) hmem);

        return(hWnd);
}

/***************************************************************************
 * Function: StatusHeight
 *
 * Purpose:
 *
 * Return default height of this window 
 */
int APIENTRY
StatusHeight(HANDLE hmem)
/* The window has a number of items which are arranged horizontally,
   so the window height is the maximum of the individual heights
*/
{
        PILIST plist;
        int i;
        int sz;
        int maxsize = 0;

        plist = (PILIST) GlobalLock(hmem);
        if (plist != NULL) {
                for (i = 0; i<plist->nitems; i++) {
                        sz = StatusCalcHeight(NULL, &plist->statels[i]);
                        maxsize = max(sz, maxsize);
                }
        }
        GlobalUnlock(hmem);
        if (maxsize > 0) {
                return(maxsize + 4);
        } else {
                return(status_charheight + 4);
        }
}

/***************************************************************************
 * Function: StatusAlloc
 *
 * Purpose:
 *
 * Alloc the plist struct and return handle to caller 
 */
HANDLE FAR PASCAL
StatusAlloc(int nitems)
{
        HANDLE hmem;
        PILIST pilist;
        LPSTR chp;

        hmem = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,
                sizeof(ILIST) + (sizeof(STATEL) * nitems));
        chp = GlobalLock(hmem);
        if (chp == NULL) {
                return(NULL);
        }

        pilist = (PILIST) chp;
        pilist->nitems = nitems;
        pilist->statels = (PSTATEL) &chp[sizeof(ILIST)];
        GlobalUnlock(hmem);

        return(hmem);
}


/***************************************************************************
 * Function: StatusAddItem
 *
 * Purpose:
 *
 * Insert an item into the plist 
 */
BOOL FAR PASCAL
StatusAddItem(HANDLE hmem, int itemnr, int type, int flags, int id,
        int width, LPSTR text)
{
        PILIST pilist;
        PSTATEL pel;

        pilist = (PILIST) GlobalLock(hmem);
        if ((pilist == NULL) || (itemnr >= pilist->nitems)) {
                GlobalUnlock(hmem);
                return(FALSE);
        }
        pel = &pilist->statels[itemnr];
        pel->type = type;
        pel->flags = flags;
        pel->id = id;
        pel->width = width;
        if (text == NULL) {
                pel->text[0] = '\0';
        } else {
                lstrcpy(pel->text, text);
        }


        GlobalUnlock(hmem);
        return(TRUE);
}

/***************************************************************************
 * Function: InitDC
 *
 * Purpose:
 *
 * Initialize colors and font
 */ 
void
InitDC(HDC hdc)
{
        SetBkColor(hdc, RGB(192,192,192));
        SelectObject(hdc, hbrBackground);
        SelectObject(hdc, hFont);
}


/***************************************************************************
 * Function: StatusCreateTools
 *
 * Purpose:
 *
 * Create Pens and brushes
 */ 
void
StatusCreateTools()
{
    LOGFONT lf;
    HDC hdc;
    int scale;

    hbrBackground = CreateSolidBrush(RGB(192,192,192));
    hpenHilight = CreatePen(0, 1, RGB(255, 255, 255));
    hpenLowlight = CreatePen(0, 1, RGB(128, 128, 128));
    hpenNeutral = CreatePen(0, 1, RGB(192, 192, 192));
    hpenBlack = CreatePen(0, 1, RGB(0, 0, 0));

    hdc = GetDC(NULL);
    scale = GetDeviceCaps(hdc, LOGPIXELSY);
    ReleaseDC(NULL, hdc);

    lf.lfHeight = -MulDiv(DEF_PTSIZE, scale, 720);
    lf.lfWidth = 0;
    lf.lfEscapement = 0;
    lf.lfOrientation = 0;
    lf.lfWeight = FW_REGULAR;
    lf.lfItalic = 0;
    lf.lfUnderline = 0;
    lf.lfStrikeOut = 0;
    lf.lfCharSet = ANSI_CHARSET;
    lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
    lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
    lf.lfQuality = PROOF_QUALITY;
    lf.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
    lf.lfFaceName[0] = '\0';
#ifdef COMPLEX
    hFont = CreateFontIndirect(&lf);
#else
    hFont = GetStockObject(SYSTEM_FONT);
#endif



}

/***************************************************************************
 * Function: StatusDeleteTools
 *
 * Purpose:
 *
 * Delete brushes and pens
 */
void
StatusDeleteTools()
{
    DeleteObject(hbrBackground);
    DeleteObject(hpenHilight);
    DeleteObject(hpenLowlight);
    DeleteObject(hpenBlack);
    DeleteObject(hpenNeutral);

#ifdef COMPLEX
    DeleteObject(hFont);
#endif
}

/***************************************************************************
 * Function: StatusWndProc
 *
 * Purpose:
 *
 * Main winproc for status windows
 *
 * handles create/destroy and paint requests
 */

long FAR PASCAL
StatusWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam)
{
    HANDLE hitems;
    PSTATEL ip;
    PILIST plist;
    CREATESTRUCT FAR * cp;
    int i;
    HDC hDC;
    RECT rc;
    POINT pt;

    switch(message) {

    case WM_CREATE:
        cp = (CREATESTRUCT FAR *) lParam;
        hitems = (HANDLE) (LONG) cp->lpCreateParams;
        SetWindowLong(hWnd, 0,  (LONG)hitems);
        plist = (PILIST) GlobalLock(hitems);
        if (plist != NULL) {
                plist->selitem = -1;
                GlobalUnlock(hitems);
        }
        break;

    case WM_SIZE:
        hitems = (HANDLE) GetWindowLong(hWnd, 0);
        plist = (PILIST) GlobalLock(hitems);
        if (plist != NULL) {
                StatusResize(hWnd, plist);
                GlobalUnlock(hitems);
        }
        break;

    case WM_PAINT:
        hitems = (HANDLE) GetWindowLong(hWnd, 0);
        plist = (PILIST) GlobalLock(hitems);
        StatusPaint(hWnd, plist);
        GlobalUnlock(hitems);

        break;

    case WM_LBUTTONUP:
        hitems = (HANDLE) GetWindowLong(hWnd, 0);
        plist = (PILIST) GlobalLock(hitems);
        pt.x = LOWORD(lParam);
        pt.y = HIWORD(lParam);

        if (plist == NULL) {
                break;
        }
        if (plist->selitem != -1) {
                ip = &plist->statels[plist->selitem];
                if (plist->isselected) {
                        hDC = GetDC(hWnd);
                        InitDC(hDC);
                        StatusButtonUp(hDC, ip);
                        ReleaseDC(hWnd, hDC);
                }
                plist->selitem = -1;
                ReleaseCapture();
                if (PtInRect(&ip->rc, pt)) {
                        SendMessage(GetParent(hWnd), WM_COMMAND,
                                MAKELONG(ip->id, WM_LBUTTONUP), (LONG)hWnd);
                }
        }
        GlobalUnlock(hitems);
        break;

    case WM_LBUTTONDOWN:
        hitems = (HANDLE) GetWindowLong(hWnd, 0);
        plist = (PILIST) GlobalLock(hitems);
        if (plist == NULL) {
                break;
        }
        pt.x = LOWORD(lParam);
        pt.y = HIWORD(lParam);
        if (plist->selitem == -1) {
                for (i = 0; i< plist->nitems; i++) {
                        ip = &plist->statels[i];
                        if (PtInRect(&ip->rc, pt)) {
                                if (ip->type != SF_BUTTON) {
                                        break;
                                }
                                plist->selitem = i;
                                SetCapture(hWnd);

                                plist->isselected = TRUE;
                                hDC = GetDC(hWnd);
                                InitDC(hDC);
                                StatusButtonDown(hDC, ip);
                                ReleaseDC(hWnd, hDC);
                                break;
                        }
                }
        }
        GlobalUnlock(hitems);
        break;

    case WM_MOUSEMOVE:
        hitems = (HANDLE) GetWindowLong(hWnd, 0);
        plist = (PILIST) GlobalLock(hitems);
        if (plist == NULL) {
                break;
        }
        pt.x = LOWORD(lParam);
        pt.y = HIWORD(lParam);
        if (plist->selitem != -1) {
                ip = &plist->statels[plist->selitem];
                if (PtInRect(&ip->rc, pt)) {
                        if (!plist->isselected) {
                                hDC = GetDC(hWnd);
                                InitDC(hDC);
                                StatusButtonDown(hDC, ip);
                                ReleaseDC(hWnd, hDC);
                                plist->isselected = TRUE;
                        }
                } else {
                        if(plist->isselected) {
                                hDC = GetDC(hWnd);
                                InitDC(hDC);
                                StatusButtonUp(hDC, ip);
                                ReleaseDC(hWnd, hDC);
                                plist->isselected = FALSE;
                        }
                }
        }
        GlobalUnlock(hitems);
        break;


    case WM_DESTROY:

        hitems = (HANDLE) GetWindowLong(hWnd, 0);
        GlobalUnlock(hitems);
        GlobalFree(hitems);

        SetWindowLong(hWnd, 0, 0L);
        break;

    case SM_NEW:
        hitems = (HANDLE) GetWindowLong(hWnd, 0);
        if (hitems != NULL) {
                GlobalFree(hitems);
        }
        hitems = (HANDLE) wParam;
        if (hitems == NULL) {
                SetWindowLong(hWnd, 0, 0L);
                InvalidateRect(hWnd, NULL, TRUE);
                break;
        }
        plist = (PILIST) GlobalLock(hitems);
        if (plist == NULL) {
                SetWindowLong(hWnd, 0, 0L);
                InvalidateRect(hWnd, NULL, TRUE);
                break;
        }
        plist->selitem = -1;
        StatusResize(hWnd, plist);
        GlobalUnlock(hitems);
        SetWindowLong(hWnd, 0, (LONG)hitems);
        InvalidateRect(hWnd, NULL, TRUE);
        break;

    case SM_SETTEXT:
        hitems = (HANDLE) GetWindowLong(hWnd, 0);
        if (hitems == NULL) {
                break;
        }
        plist = (PILIST) GlobalLock(hitems);
        ip = StatusGetItem(plist, wParam);
        if (ip != NULL) {
                if (lParam == 0) {
                        ip->text[0] = '\0';
                } else {
                        strncpy(ip->text, (LPSTR) lParam, SF_MAXLABEL);
                        ip->text[SF_MAXLABEL] = '\0';
                }

                /* if this is a variable width field, we need to redo
                 * all size calcs in case the field width has changed.
                 * in that case, we need to repaint the entire window
                 * and not just this field - so set rc to indicate the
                 * area to be redrawn.
                 */
                if (ip->flags & SF_VAR) {
                        StatusResize(hWnd, plist);
                        GetClientRect(hWnd, &rc);
                        RedrawWindow(hWnd, &rc, NULL,
                                RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW);
                } else {
                        /* instead of just invalidating the window, we can
                         * force the window to be repainted now. This is
                         * essential for status updates during a busy
                         * loop when no messages are being processed,
                         * but we should still update the user on what's
                         * happening.
                         */
                        RedrawWindow(hWnd, &ip->rc, NULL,
                                RDW_INVALIDATE|RDW_NOERASE|RDW_UPDATENOW);
                }

        }
        GlobalUnlock(hitems);
        break;

    default:
        return(DefWindowProc(hWnd, message, wParam, lParam));
    }
    return 0;
}

/***************************************************************************
 * Function: StatusResize
 *
 * Purpose:
 *
 * Position the labels and buttons within the status window 
 */
void
StatusResize(HWND hWnd, PILIST iplistp)
{
        RECT rc;
        int curpos_right, curpos_left;
        int height, width;
        int i;
        PSTATEL ip;


        if (iplistp == NULL) {
                return;
        }
        GetClientRect(hWnd, &rc);
        curpos_left = rc.left + status_charwidth / 2;
        curpos_right = rc.right - (status_charwidth / 2);

        /* loop through all items setting their position rects.
         * items are flagged as being left or right. We place them
         * in order starting at the left and the right, with a single
         * char's width between each item
         */
        for (i = 0; i < iplistp->nitems; i++) {
                ip = &iplistp->statels[i];

                width = StatusCalcWidth(hWnd, ip);
                height = StatusCalcHeight(hWnd, ip);
                ip->rc.top = (rc.bottom - height) / 2;
                ip->rc.bottom = ip->rc.top + height;

                /* see if  this item fits. Items that partially fit
                 * are placed reduced in size.
                 */
                if (ip->flags & SF_LEFT) {

                        if (curpos_left+width >= curpos_right) {
                                /* doesn't completely fit-does it partly? */
                                if ((curpos_left + 1) >= curpos_right){

                                        /* no - this item does not fit */
                                        ip->rc.left = 0;
                                        ip->rc.right = 0;
                                } else {
                                        /* partial fit */
                                        ip->rc.left = curpos_left;
                                        ip->rc.right = curpos_right - 1;
                                        curpos_left = curpos_right;
                                }
                        } else {
                                /* complete fit */
                                ip->rc.left = curpos_left;
                                ip->rc.right = curpos_left + width;
                                curpos_left += width + 1;
                        }
                } else {

                        /* same size check for right-aligned items */
                        if (curpos_right-width <= curpos_left) {

                                /* partial fit ? */
                                if (curpos_right <= curpos_left+1) {
                                        ip->rc.left = 0;
                                        ip->rc.right = 0;
                                } else {
                                        /* yes - partial fit */
                                        ip->rc.left = curpos_left + 1;
                                        ip->rc.right = curpos_right;
                                        curpos_right = curpos_left;
                                }
                        } else {
                                /* complete fit */
                                ip->rc.right = curpos_right;
                                ip->rc.left = curpos_right - width;
                                curpos_right -= (width + 1);
                        }
                }
        }
}


/***************************************************************************
 * Function: StatusPaint
 *
 * Purpose:
 *
 * Paint the status window
 */
void
StatusPaint(HWND hWnd, PILIST iplistp)
{
        RECT rc;
        HDC hDC;
        PAINTSTRUCT ps;
        int i;
        PSTATEL ip;
        HPEN hpenOld;

        GetClientRect(hWnd, &rc);
        hDC = BeginPaint(hWnd, &ps);
        InitDC(hDC);

        RaiseRect(hDC, &rc);
        if (iplistp == NULL) {
                EndPaint(hWnd, &ps);
                return;
        }
        for (i =0; i < iplistp->nitems; i++) {
                ip = &iplistp->statels[i];

                if (ip->rc.left == ip->rc.right) {
                        continue;
                }
                if (ip->type == SF_STATIC) {
                        if (ip->flags & SF_RAISE) {
                                RaiseRect(hDC, &ip->rc);
                        } else if (ip->flags & SF_LOWER) {
                                LowerRect(hDC, &ip->rc);
                        }
                        rc = ip->rc;
                        rc.left += (status_charwidth / 2);
                        rc.right--;
                        rc.top++;
                        rc.bottom--;
                        hpenOld = SelectObject(hDC, hpenNeutral);
                        Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
                        SelectObject(hDC, hpenOld);
                        DrawText(hDC, ip->text, lstrlen(ip->text), &rc,
                                        DT_LEFT | DT_VCENTER);
                } else {
                        StatusButtonUp(hDC, ip);
                }
        }

        EndPaint(hWnd, &ps);
}

/***************************************************************************
 * Function: RaiseRect
 *
 * Purpose:
 *
 */
void
RaiseRect(HDC hDC, LPRECT rcp)
{
        TopLeft(hDC, rcp, hpenHilight, FALSE);
        BottomRight(hDC, rcp, hpenLowlight, FALSE);
}

/***************************************************************************
 * Function: LowerRect
 *
 * Purpose:
 *
 */ 
void
LowerRect(HDC hDC, LPRECT rcp)
{
        TopLeft(hDC, rcp, hpenLowlight, FALSE);
        BottomRight(hDC, rcp, hpenHilight, FALSE);
}

/***************************************************************************
 * Function: StatusButtonUp
 *
 * Purpose:
 *
 */
void
StatusButtonUp(HDC hDC, PSTATEL ip)
{
        RECT rc;
        HPEN hpenOld;

        rc = ip->rc;
        TopLeft(hDC, &rc, hpenBlack, TRUE);
        BottomRight(hDC, &rc, hpenBlack, FALSE);

        rc.top++;
        rc.bottom--;
        rc.left++;
        rc.right--;
        TopLeft(hDC, &rc, hpenHilight, FALSE);
        BottomRight(hDC, &rc, hpenLowlight, TRUE);

        rc.top++;
        rc.bottom--;
        rc.left++;
        rc.right--;
        BottomRight(hDC, &rc, hpenLowlight, TRUE);
        rc.bottom--;
        rc.right--;
        hpenOld = SelectObject(hDC, hpenNeutral);
        Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
        SelectObject(hDC, hpenOld);
        DrawText(hDC, ip->text, lstrlen(ip->text), &rc, DT_CENTER | DT_VCENTER);
}

/***************************************************************************
 * Function: StatusButtonDown
 *
 * Purpose:
 *
 */
void
StatusButtonDown(HDC hDC, PSTATEL ip)
{
        RECT rc;
        HPEN hpenOld;

        rc = ip->rc;
        TopLeft(hDC, &rc, hpenBlack, TRUE);
        BottomRight(hDC, &rc, hpenBlack, FALSE);

        rc.top++;
        rc.bottom--;
        rc.left++;
        rc.right--;
        TopLeft(hDC, &rc, hpenLowlight, TRUE);
        rc.top++;
        rc.left++;
        TopLeft(hDC, &rc, hpenNeutral, TRUE);
        rc.top++;
        rc.left++;
        TopLeft(hDC, &rc, hpenNeutral, TRUE);
        rc.top++;
        rc.left++;
        hpenOld = SelectObject(hDC, hpenNeutral);
        Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
        SelectObject(hDC, hpenOld);
        DrawText(hDC, ip->text, lstrlen(ip->text), &rc, DT_CENTER | DT_VCENTER);
}

/***************************************************************************
 * Function: TopLeft
 *
 * Purpose:
 *
 */
void
TopLeft(HDC hDC, LPRECT rcp, HPEN hpen, BOOL bCorners)
{
        HPEN hpenOld;
        int x, y;

        hpenOld = SelectObject(hDC, hpen);
        x = rcp->right - 1;
        y = rcp->bottom;
        if (!bCorners) {
                x--;
                y--;
        }
        MoveToEx(hDC, x, rcp->top, NULL);
        LineTo(hDC, rcp->left, rcp->top);
        LineTo(hDC, rcp->left, y);
        SelectObject(hDC, hpenOld);
}

/***************************************************************************
 * Function: BottomRight
 *
 * Purpose:
 *
 */
void
BottomRight(HDC hDC, LPRECT rcp, HPEN hpen, BOOL bCorners)
{
        HPEN hpenOld;
        int x, y;

        hpenOld = SelectObject(hDC, hpen);
        x = rcp->left - 1;
        y = rcp->top;
        if (!bCorners) {
                x++;
                y++;
        }
        MoveToEx(hDC, rcp->right-1, y, NULL);
        LineTo(hDC, rcp->right-1, rcp->bottom-1);
        LineTo(hDC, x, rcp->bottom-1);
        SelectObject(hDC, hpenOld);
}

/***************************************************************************
 * Function: StatusGetItem
 *
 * Purpose:
 *
 */
PSTATEL
StatusGetItem(PILIST plist, int id)
{
        int i;

        if (plist == NULL) {
                return(NULL);
        }
        for (i = 0; i < plist->nitems; i++) {
                if (plist->statels[i].id == id) {
                        return(&plist->statels[i]);
                }
        }
        return(NULL);
}

/***************************************************************************
 * Function: StatusCalcWidth
 *
 * Purpose:
 *
 * Calculate the width of a given field. This is the width in characters
 * multiplied by the average character width, plus a few units for
 * borders.
 *
 * If SF_VAR is set, this field size varies depending on the text, so
 * we use GetTextExtent for the field size. If SF_VAR is selected, the caller
 * can specify that the size is not to exceed the (width * avecharwidth)
 * size (using SF_SZMAX) or that it is not be less than it (SF_SZMIN).
 */
int
StatusCalcWidth(HWND hWnd, PSTATEL ip)
{
        int ch_size, t_size;
        SIZE sz;
        HDC hDC;

        ch_size = ip->width * status_charwidth;
        if (ip->flags & SF_VAR) {
                hDC = GetDC(hWnd);
                InitDC(hDC);
                GetTextExtentPoint(hDC, ip->text, lstrlen(ip->text), &sz);
                ReleaseDC(hWnd, hDC);
                t_size = sz.cx;

                /*
                 * check this size against min/max size if
                 * requested
                 */

                if (ip->flags & SF_SZMIN) {
                        if (ch_size > t_size) {
                                t_size = ch_size;
                        }
                }
                if (ip->flags & SF_SZMAX) {
                        if (ch_size < t_size) {
                                t_size = ch_size;
                        }
                }
                ch_size = t_size;
        }

        if (ch_size != 0) {
                if (ip->type == SF_BUTTON) {
                        return(ch_size+6);
                } else {
                        return(ch_size+4);
                }
        } else {
                return(0);
        }
}

/***************************************************************************
 * Function: StatusCalcHeight
 *
 * Purpose:
 *
 * Calculate the height of a given field
 */
int
StatusCalcHeight(HWND hWnd, PSTATEL ip)
{
        int size;

        size = status_charheight;
        if (ip->type == SF_BUTTON) {
                return(size + 6);
        } else {
                return(size + 2);
        }
}
