STATUS.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:28k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples. 
  3. *       Copyright (C) 1993-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. /****************************** Module Header *******************************
  11. * Module Name: STATUS.C
  12. *
  13. * Status line handler.
  14. *
  15. * Functions:
  16. *
  17. * StatusInit()
  18. * StatusCreate()
  19. * StatusHeight()
  20. * StatusAlloc()
  21. * StatusAddItem()
  22. * StatusCreateTools()
  23. * StatusDeleteTools()
  24. * StatusWndProc()
  25. * StatusResize()
  26. * StatusCalcHeight()
  27. * StatusCalcWidth()
  28. * StatusGetItem()
  29. * LowerRect()
  30. * RaiseRect()
  31. * StatusPaint()
  32. * BottomRight()
  33. * TopLeft()
  34. * StatusButtonDown()
  35. * StatusButtonUp()
  36. * InitDC()
  37. *
  38. * Comments:
  39. *
  40. ****************************************************************************/
  41. #include <windows.h>
  42. #include <string.h>
  43. #include "gutils.h"
  44. /* --- data structures ------------------------------------------------- */
  45. #define SF_MAXLABEL     80   /* no more than 80 in an item within the bar */
  46.                              /* Is this adequate for long pathnames on a
  47.                                 hi-res screen?
  48.                              */
  49. typedef struct statel {
  50.         int type;                       /* SF_BUTTON or SF_STATIC */
  51.         int flags;                      /* SF_VAR => variable width
  52.                                            SF_LEFT=> left aligned (else right)
  53.                                            SF_RAISE=> paint as 'raised' 3d rect
  54.                                            SF_LOWER=> paint as lowered 3D rect
  55.                                            SF_SZMIN=>together with SF_VAR
  56.                                                      allows minimum size for
  57.                                                      var sized item
  58.                                            SF_SZMAX=>see SZMIN and use nouse
  59.                                         */
  60.         int id;                         /* control id */
  61.         int width;                      /* width of control in chars */
  62.         char text[SF_MAXLABEL+1];       /* null-term string for label */
  63.         RECT rc;                        /* used by status.c */
  64. } STATEL, FAR * PSTATEL;
  65. typedef struct itemlist {
  66.         int nitems;
  67.         PSTATEL statels;
  68.         int selitem;                    /* used by status.c */
  69.         BOOL isselected;                /* used by status.c */
  70. } ILIST, FAR * PILIST;
  71. /* prototypes of routines in this module */
  72. void StatusCreateTools(void);
  73. void StatusDeleteTools(void);
  74. long APIENTRY StatusWndProc(HWND, UINT, UINT, LONG);
  75. void StatusResize(HWND hWnd, PILIST pilist);
  76. int StatusCalcHeight(HWND hWnd, PSTATEL ip);
  77. int StatusCalcWidth(HWND hWnd, PSTATEL ip);
  78. PSTATEL StatusGetItem(PILIST plist, int id);
  79. void LowerRect(HDC hDC, LPRECT rcp);
  80. void RaiseRect(HDC hDC, LPRECT rcp);
  81. void StatusPaint(HWND hWnd, PILIST iplistp);
  82. void BottomRight(HDC hDC, LPRECT rcp, HPEN hpen, BOOL bCorners);
  83. void TopLeft(HDC hDC, LPRECT rcp, HPEN hpen, BOOL bCorners);
  84. void StatusButtonDown(HDC hDC, PSTATEL ip);
  85. void StatusButtonUp(HDC hDC, PSTATEL ip);
  86. void InitDC(HDC hdc);
  87. /*--global data---------------------------------------------------------*/
  88. HPEN hpenHilight, hpenLowlight;
  89. HPEN hpenBlack, hpenNeutral;
  90. HBRUSH hbrBackground; /* pieces and board */
  91. HFONT hFont;
  92. int status_charheight, status_charwidth;
  93. /* default pt size for font (tenths of a pt) */
  94. #define         DEF_PTSIZE      80
  95. /***************************************************************************
  96.  * Function: StatusInit
  97.  *
  98.  * Purpose:
  99.  *
  100.  * Create window class
  101.  */
  102. BOOL
  103. StatusInit(HANDLE hInstance)
  104. {
  105.         WNDCLASS    wc;
  106.         BOOL resp;
  107.         TEXTMETRIC tm;
  108.         HDC hDC;
  109.         StatusCreateTools();
  110.         wc.style = CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS;
  111.         wc.lpfnWndProc = (WNDPROC) StatusWndProc;
  112.         wc.cbClsExtra = 0;
  113.         wc.cbWndExtra = sizeof(HANDLE);
  114.         wc.hInstance = hInstance;
  115.         wc.hIcon = NULL;
  116.         wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  117.         wc.hbrBackground = hbrBackground;
  118.         wc.lpszClassName = (LPSTR) "gdstatusclass";
  119.         wc.lpszMenuName = NULL;
  120.         resp = RegisterClass(&wc);
  121.         hDC = GetDC(NULL);
  122.         InitDC(hDC);
  123.         GetTextMetrics(hDC, &tm);
  124.         status_charheight = (int)(tm.tmHeight + tm.tmExternalLeading);
  125.         status_charwidth = (int)tm.tmAveCharWidth;
  126.         ReleaseDC(NULL, hDC);
  127.         return(resp);
  128. }
  129. /*
  130. /***************************************************************************
  131.  * Function: StatusCreate
  132.  *
  133.  * Purpose:
  134.  *
  135.  * Create and show the window
  136.  */
  137. HWND APIENTRY
  138. StatusCreate(HANDLE hInst, HWND hParent, int id, LPRECT rcp, HANDLE hmem)
  139. {
  140.         HWND hWnd;
  141.         /* create a child window of status class */
  142.         hWnd = CreateWindow("gdstatusclass",
  143.                         NULL,
  144.                         WS_CHILD | WS_VISIBLE,
  145.                         rcp->left,
  146.                         rcp->top,
  147.                         (rcp->right - rcp->left),
  148.                         (rcp->bottom - rcp->top),
  149.                         hParent,
  150.                         (HANDLE) id,
  151.                         hInst,
  152.                         (LPVOID) hmem);
  153.         return(hWnd);
  154. }
  155. /***************************************************************************
  156.  * Function: StatusHeight
  157.  *
  158.  * Purpose:
  159.  *
  160.  * Return default height of this window 
  161.  */
  162. int APIENTRY
  163. StatusHeight(HANDLE hmem)
  164. /* The window has a number of items which are arranged horizontally,
  165.    so the window height is the maximum of the individual heights
  166. */
  167. {
  168.         PILIST plist;
  169.         int i;
  170.         int sz;
  171.         int maxsize = 0;
  172.         plist = (PILIST) GlobalLock(hmem);
  173.         if (plist != NULL) {
  174.                 for (i = 0; i<plist->nitems; i++) {
  175.                         sz = StatusCalcHeight(NULL, &plist->statels[i]);
  176.                         maxsize = max(sz, maxsize);
  177.                 }
  178.         }
  179.         GlobalUnlock(hmem);
  180.         if (maxsize > 0) {
  181.                 return(maxsize + 4);
  182.         } else {
  183.                 return(status_charheight + 4);
  184.         }
  185. }
  186. /***************************************************************************
  187.  * Function: StatusAlloc
  188.  *
  189.  * Purpose:
  190.  *
  191.  * Alloc the plist struct and return handle to caller 
  192.  */
  193. HANDLE FAR PASCAL
  194. StatusAlloc(int nitems)
  195. {
  196.         HANDLE hmem;
  197.         PILIST pilist;
  198.         LPSTR chp;
  199.         hmem = GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,
  200.                 sizeof(ILIST) + (sizeof(STATEL) * nitems));
  201.         chp = GlobalLock(hmem);
  202.         if (chp == NULL) {
  203.                 return(NULL);
  204.         }
  205.         pilist = (PILIST) chp;
  206.         pilist->nitems = nitems;
  207.         pilist->statels = (PSTATEL) &chp[sizeof(ILIST)];
  208.         GlobalUnlock(hmem);
  209.         return(hmem);
  210. }
  211. /***************************************************************************
  212.  * Function: StatusAddItem
  213.  *
  214.  * Purpose:
  215.  *
  216.  * Insert an item into the plist 
  217.  */
  218. BOOL FAR PASCAL
  219. StatusAddItem(HANDLE hmem, int itemnr, int type, int flags, int id,
  220.         int width, LPSTR text)
  221. {
  222.         PILIST pilist;
  223.         PSTATEL pel;
  224.         pilist = (PILIST) GlobalLock(hmem);
  225.         if ((pilist == NULL) || (itemnr >= pilist->nitems)) {
  226.                 GlobalUnlock(hmem);
  227.                 return(FALSE);
  228.         }
  229.         pel = &pilist->statels[itemnr];
  230.         pel->type = type;
  231.         pel->flags = flags;
  232.         pel->id = id;
  233.         pel->width = width;
  234.         if (text == NULL) {
  235.                 pel->text[0] = '';
  236.         } else {
  237.                 lstrcpy(pel->text, text);
  238.         }
  239.         GlobalUnlock(hmem);
  240.         return(TRUE);
  241. }
  242. /***************************************************************************
  243.  * Function: InitDC
  244.  *
  245.  * Purpose:
  246.  *
  247.  * Initialize colors and font
  248.  */ 
  249. void
  250. InitDC(HDC hdc)
  251. {
  252.         SetBkColor(hdc, RGB(192,192,192));
  253.         SelectObject(hdc, hbrBackground);
  254.         SelectObject(hdc, hFont);
  255. }
  256. /***************************************************************************
  257.  * Function: StatusCreateTools
  258.  *
  259.  * Purpose:
  260.  *
  261.  * Create Pens and brushes
  262.  */ 
  263. void
  264. StatusCreateTools()
  265. {
  266.     LOGFONT lf;
  267.     HDC hdc;
  268.     int scale;
  269.     hbrBackground = CreateSolidBrush(RGB(192,192,192));
  270.     hpenHilight = CreatePen(0, 1, RGB(255, 255, 255));
  271.     hpenLowlight = CreatePen(0, 1, RGB(128, 128, 128));
  272.     hpenNeutral = CreatePen(0, 1, RGB(192, 192, 192));
  273.     hpenBlack = CreatePen(0, 1, RGB(0, 0, 0));
  274.     hdc = GetDC(NULL);
  275.     scale = GetDeviceCaps(hdc, LOGPIXELSY);
  276.     ReleaseDC(NULL, hdc);
  277.     lf.lfHeight = -MulDiv(DEF_PTSIZE, scale, 720);
  278.     lf.lfWidth = 0;
  279.     lf.lfEscapement = 0;
  280.     lf.lfOrientation = 0;
  281.     lf.lfWeight = FW_REGULAR;
  282.     lf.lfItalic = 0;
  283.     lf.lfUnderline = 0;
  284.     lf.lfStrikeOut = 0;
  285.     lf.lfCharSet = ANSI_CHARSET;
  286.     lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
  287.     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  288.     lf.lfQuality = PROOF_QUALITY;
  289.     lf.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
  290.     lf.lfFaceName[0] = '';
  291. #ifdef COMPLEX
  292.     hFont = CreateFontIndirect(&lf);
  293. #else
  294.     hFont = GetStockObject(SYSTEM_FONT);
  295. #endif
  296. }
  297. /***************************************************************************
  298.  * Function: StatusDeleteTools
  299.  *
  300.  * Purpose:
  301.  *
  302.  * Delete brushes and pens
  303.  */
  304. void
  305. StatusDeleteTools()
  306. {
  307.     DeleteObject(hbrBackground);
  308.     DeleteObject(hpenHilight);
  309.     DeleteObject(hpenLowlight);
  310.     DeleteObject(hpenBlack);
  311.     DeleteObject(hpenNeutral);
  312. #ifdef COMPLEX
  313.     DeleteObject(hFont);
  314. #endif
  315. }
  316. /***************************************************************************
  317.  * Function: StatusWndProc
  318.  *
  319.  * Purpose:
  320.  *
  321.  * Main winproc for status windows
  322.  *
  323.  * handles create/destroy and paint requests
  324.  */
  325. long FAR PASCAL
  326. StatusWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam)
  327. {
  328.     HANDLE hitems;
  329.     PSTATEL ip;
  330.     PILIST plist;
  331.     CREATESTRUCT FAR * cp;
  332.     int i;
  333.     HDC hDC;
  334.     RECT rc;
  335.     POINT pt;
  336.     switch(message) {
  337.     case WM_CREATE:
  338.         cp = (CREATESTRUCT FAR *) lParam;
  339.         hitems = (HANDLE) (LONG) cp->lpCreateParams;
  340.         SetWindowLong(hWnd, 0,  (LONG)hitems);
  341.         plist = (PILIST) GlobalLock(hitems);
  342.         if (plist != NULL) {
  343.                 plist->selitem = -1;
  344.                 GlobalUnlock(hitems);
  345.         }
  346.         break;
  347.     case WM_SIZE:
  348.         hitems = (HANDLE) GetWindowLong(hWnd, 0);
  349.         plist = (PILIST) GlobalLock(hitems);
  350.         if (plist != NULL) {
  351.                 StatusResize(hWnd, plist);
  352.                 GlobalUnlock(hitems);
  353.         }
  354.         break;
  355.     case WM_PAINT:
  356.         hitems = (HANDLE) GetWindowLong(hWnd, 0);
  357.         plist = (PILIST) GlobalLock(hitems);
  358.         StatusPaint(hWnd, plist);
  359.         GlobalUnlock(hitems);
  360.         break;
  361.     case WM_LBUTTONUP:
  362.         hitems = (HANDLE) GetWindowLong(hWnd, 0);
  363.         plist = (PILIST) GlobalLock(hitems);
  364.         pt.x = LOWORD(lParam);
  365.         pt.y = HIWORD(lParam);
  366.         if (plist == NULL) {
  367.                 break;
  368.         }
  369.         if (plist->selitem != -1) {
  370.                 ip = &plist->statels[plist->selitem];
  371.                 if (plist->isselected) {
  372.                         hDC = GetDC(hWnd);
  373.                         InitDC(hDC);
  374.                         StatusButtonUp(hDC, ip);
  375.                         ReleaseDC(hWnd, hDC);
  376.                 }
  377.                 plist->selitem = -1;
  378.                 ReleaseCapture();
  379.                 if (PtInRect(&ip->rc, pt)) {
  380.                         SendMessage(GetParent(hWnd), WM_COMMAND,
  381.                                 MAKELONG(ip->id, WM_LBUTTONUP), (LONG)hWnd);
  382.                 }
  383.         }
  384.         GlobalUnlock(hitems);
  385.         break;
  386.     case WM_LBUTTONDOWN:
  387.         hitems = (HANDLE) GetWindowLong(hWnd, 0);
  388.         plist = (PILIST) GlobalLock(hitems);
  389.         if (plist == NULL) {
  390.                 break;
  391.         }
  392.         pt.x = LOWORD(lParam);
  393.         pt.y = HIWORD(lParam);
  394.         if (plist->selitem == -1) {
  395.                 for (i = 0; i< plist->nitems; i++) {
  396.                         ip = &plist->statels[i];
  397.                         if (PtInRect(&ip->rc, pt)) {
  398.                                 if (ip->type != SF_BUTTON) {
  399.                                         break;
  400.                                 }
  401.                                 plist->selitem = i;
  402.                                 SetCapture(hWnd);
  403.                                 plist->isselected = TRUE;
  404.                                 hDC = GetDC(hWnd);
  405.                                 InitDC(hDC);
  406.                                 StatusButtonDown(hDC, ip);
  407.                                 ReleaseDC(hWnd, hDC);
  408.                                 break;
  409.                         }
  410.                 }
  411.         }
  412.         GlobalUnlock(hitems);
  413.         break;
  414.     case WM_MOUSEMOVE:
  415.         hitems = (HANDLE) GetWindowLong(hWnd, 0);
  416.         plist = (PILIST) GlobalLock(hitems);
  417.         if (plist == NULL) {
  418.                 break;
  419.         }
  420.         pt.x = LOWORD(lParam);
  421.         pt.y = HIWORD(lParam);
  422.         if (plist->selitem != -1) {
  423.                 ip = &plist->statels[plist->selitem];
  424.                 if (PtInRect(&ip->rc, pt)) {
  425.                         if (!plist->isselected) {
  426.                                 hDC = GetDC(hWnd);
  427.                                 InitDC(hDC);
  428.                                 StatusButtonDown(hDC, ip);
  429.                                 ReleaseDC(hWnd, hDC);
  430.                                 plist->isselected = TRUE;
  431.                         }
  432.                 } else {
  433.                         if(plist->isselected) {
  434.                                 hDC = GetDC(hWnd);
  435.                                 InitDC(hDC);
  436.                                 StatusButtonUp(hDC, ip);
  437.                                 ReleaseDC(hWnd, hDC);
  438.                                 plist->isselected = FALSE;
  439.                         }
  440.                 }
  441.         }
  442.         GlobalUnlock(hitems);
  443.         break;
  444.     case WM_DESTROY:
  445.         hitems = (HANDLE) GetWindowLong(hWnd, 0);
  446.         GlobalUnlock(hitems);
  447.         GlobalFree(hitems);
  448.         SetWindowLong(hWnd, 0, 0L);
  449.         break;
  450.     case SM_NEW:
  451.         hitems = (HANDLE) GetWindowLong(hWnd, 0);
  452.         if (hitems != NULL) {
  453.                 GlobalFree(hitems);
  454.         }
  455.         hitems = (HANDLE) wParam;
  456.         if (hitems == NULL) {
  457.                 SetWindowLong(hWnd, 0, 0L);
  458.                 InvalidateRect(hWnd, NULL, TRUE);
  459.                 break;
  460.         }
  461.         plist = (PILIST) GlobalLock(hitems);
  462.         if (plist == NULL) {
  463.                 SetWindowLong(hWnd, 0, 0L);
  464.                 InvalidateRect(hWnd, NULL, TRUE);
  465.                 break;
  466.         }
  467.         plist->selitem = -1;
  468.         StatusResize(hWnd, plist);
  469.         GlobalUnlock(hitems);
  470.         SetWindowLong(hWnd, 0, (LONG)hitems);
  471.         InvalidateRect(hWnd, NULL, TRUE);
  472.         break;
  473.     case SM_SETTEXT:
  474.         hitems = (HANDLE) GetWindowLong(hWnd, 0);
  475.         if (hitems == NULL) {
  476.                 break;
  477.         }
  478.         plist = (PILIST) GlobalLock(hitems);
  479.         ip = StatusGetItem(plist, wParam);
  480.         if (ip != NULL) {
  481.                 if (lParam == 0) {
  482.                         ip->text[0] = '';
  483.                 } else {
  484.                         strncpy(ip->text, (LPSTR) lParam, SF_MAXLABEL);
  485.                         ip->text[SF_MAXLABEL] = '';
  486.                 }
  487.                 /* if this is a variable width field, we need to redo
  488.                  * all size calcs in case the field width has changed.
  489.                  * in that case, we need to repaint the entire window
  490.                  * and not just this field - so set rc to indicate the
  491.                  * area to be redrawn.
  492.                  */
  493.                 if (ip->flags & SF_VAR) {
  494.                         StatusResize(hWnd, plist);
  495.                         GetClientRect(hWnd, &rc);
  496.                         RedrawWindow(hWnd, &rc, NULL,
  497.                                 RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW);
  498.                 } else {
  499.                         /* instead of just invalidating the window, we can
  500.                          * force the window to be repainted now. This is
  501.                          * essential for status updates during a busy
  502.                          * loop when no messages are being processed,
  503.                          * but we should still update the user on what's
  504.                          * happening.
  505.                          */
  506.                         RedrawWindow(hWnd, &ip->rc, NULL,
  507.                                 RDW_INVALIDATE|RDW_NOERASE|RDW_UPDATENOW);
  508.                 }
  509.         }
  510.         GlobalUnlock(hitems);
  511.         break;
  512.     default:
  513.         return(DefWindowProc(hWnd, message, wParam, lParam));
  514.     }
  515.     return 0;
  516. }
  517. /***************************************************************************
  518.  * Function: StatusResize
  519.  *
  520.  * Purpose:
  521.  *
  522.  * Position the labels and buttons within the status window 
  523.  */
  524. void
  525. StatusResize(HWND hWnd, PILIST iplistp)
  526. {
  527.         RECT rc;
  528.         int curpos_right, curpos_left;
  529.         int height, width;
  530.         int i;
  531.         PSTATEL ip;
  532.         if (iplistp == NULL) {
  533.                 return;
  534.         }
  535.         GetClientRect(hWnd, &rc);
  536.         curpos_left = rc.left + status_charwidth / 2;
  537.         curpos_right = rc.right - (status_charwidth / 2);
  538.         /* loop through all items setting their position rects.
  539.          * items are flagged as being left or right. We place them
  540.          * in order starting at the left and the right, with a single
  541.          * char's width between each item
  542.          */
  543.         for (i = 0; i < iplistp->nitems; i++) {
  544.                 ip = &iplistp->statels[i];
  545.                 width = StatusCalcWidth(hWnd, ip);
  546.                 height = StatusCalcHeight(hWnd, ip);
  547.                 ip->rc.top = (rc.bottom - height) / 2;
  548.                 ip->rc.bottom = ip->rc.top + height;
  549.                 /* see if  this item fits. Items that partially fit
  550.                  * are placed reduced in size.
  551.                  */
  552.                 if (ip->flags & SF_LEFT) {
  553.                         if (curpos_left+width >= curpos_right) {
  554.                                 /* doesn't completely fit-does it partly? */
  555.                                 if ((curpos_left + 1) >= curpos_right){
  556.                                         /* no - this item does not fit */
  557.                                         ip->rc.left = 0;
  558.                                         ip->rc.right = 0;
  559.                                 } else {
  560.                                         /* partial fit */
  561.                                         ip->rc.left = curpos_left;
  562.                                         ip->rc.right = curpos_right - 1;
  563.                                         curpos_left = curpos_right;
  564.                                 }
  565.                         } else {
  566.                                 /* complete fit */
  567.                                 ip->rc.left = curpos_left;
  568.                                 ip->rc.right = curpos_left + width;
  569.                                 curpos_left += width + 1;
  570.                         }
  571.                 } else {
  572.                         /* same size check for right-aligned items */
  573.                         if (curpos_right-width <= curpos_left) {
  574.                                 /* partial fit ? */
  575.                                 if (curpos_right <= curpos_left+1) {
  576.                                         ip->rc.left = 0;
  577.                                         ip->rc.right = 0;
  578.                                 } else {
  579.                                         /* yes - partial fit */
  580.                                         ip->rc.left = curpos_left + 1;
  581.                                         ip->rc.right = curpos_right;
  582.                                         curpos_right = curpos_left;
  583.                                 }
  584.                         } else {
  585.                                 /* complete fit */
  586.                                 ip->rc.right = curpos_right;
  587.                                 ip->rc.left = curpos_right - width;
  588.                                 curpos_right -= (width + 1);
  589.                         }
  590.                 }
  591.         }
  592. }
  593. /***************************************************************************
  594.  * Function: StatusPaint
  595.  *
  596.  * Purpose:
  597.  *
  598.  * Paint the status window
  599.  */
  600. void
  601. StatusPaint(HWND hWnd, PILIST iplistp)
  602. {
  603.         RECT rc;
  604.         HDC hDC;
  605.         PAINTSTRUCT ps;
  606.         int i;
  607.         PSTATEL ip;
  608.         HPEN hpenOld;
  609.         GetClientRect(hWnd, &rc);
  610.         hDC = BeginPaint(hWnd, &ps);
  611.         InitDC(hDC);
  612.         RaiseRect(hDC, &rc);
  613.         if (iplistp == NULL) {
  614.                 EndPaint(hWnd, &ps);
  615.                 return;
  616.         }
  617.         for (i =0; i < iplistp->nitems; i++) {
  618.                 ip = &iplistp->statels[i];
  619.                 if (ip->rc.left == ip->rc.right) {
  620.                         continue;
  621.                 }
  622.                 if (ip->type == SF_STATIC) {
  623.                         if (ip->flags & SF_RAISE) {
  624.                                 RaiseRect(hDC, &ip->rc);
  625.                         } else if (ip->flags & SF_LOWER) {
  626.                                 LowerRect(hDC, &ip->rc);
  627.                         }
  628.                         rc = ip->rc;
  629.                         rc.left += (status_charwidth / 2);
  630.                         rc.right--;
  631.                         rc.top++;
  632.                         rc.bottom--;
  633.                         hpenOld = SelectObject(hDC, hpenNeutral);
  634.                         Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
  635.                         SelectObject(hDC, hpenOld);
  636.                         DrawText(hDC, ip->text, lstrlen(ip->text), &rc,
  637.                                         DT_LEFT | DT_VCENTER);
  638.                 } else {
  639.                         StatusButtonUp(hDC, ip);
  640.                 }
  641.         }
  642.         EndPaint(hWnd, &ps);
  643. }
  644. /***************************************************************************
  645.  * Function: RaiseRect
  646.  *
  647.  * Purpose:
  648.  *
  649.  */
  650. void
  651. RaiseRect(HDC hDC, LPRECT rcp)
  652. {
  653.         TopLeft(hDC, rcp, hpenHilight, FALSE);
  654.         BottomRight(hDC, rcp, hpenLowlight, FALSE);
  655. }
  656. /***************************************************************************
  657.  * Function: LowerRect
  658.  *
  659.  * Purpose:
  660.  *
  661.  */ 
  662. void
  663. LowerRect(HDC hDC, LPRECT rcp)
  664. {
  665.         TopLeft(hDC, rcp, hpenLowlight, FALSE);
  666.         BottomRight(hDC, rcp, hpenHilight, FALSE);
  667. }
  668. /***************************************************************************
  669.  * Function: StatusButtonUp
  670.  *
  671.  * Purpose:
  672.  *
  673.  */
  674. void
  675. StatusButtonUp(HDC hDC, PSTATEL ip)
  676. {
  677.         RECT rc;
  678.         HPEN hpenOld;
  679.         rc = ip->rc;
  680.         TopLeft(hDC, &rc, hpenBlack, TRUE);
  681.         BottomRight(hDC, &rc, hpenBlack, FALSE);
  682.         rc.top++;
  683.         rc.bottom--;
  684.         rc.left++;
  685.         rc.right--;
  686.         TopLeft(hDC, &rc, hpenHilight, FALSE);
  687.         BottomRight(hDC, &rc, hpenLowlight, TRUE);
  688.         rc.top++;
  689.         rc.bottom--;
  690.         rc.left++;
  691.         rc.right--;
  692.         BottomRight(hDC, &rc, hpenLowlight, TRUE);
  693.         rc.bottom--;
  694.         rc.right--;
  695.         hpenOld = SelectObject(hDC, hpenNeutral);
  696.         Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
  697.         SelectObject(hDC, hpenOld);
  698.         DrawText(hDC, ip->text, lstrlen(ip->text), &rc, DT_CENTER | DT_VCENTER);
  699. }
  700. /***************************************************************************
  701.  * Function: StatusButtonDown
  702.  *
  703.  * Purpose:
  704.  *
  705.  */
  706. void
  707. StatusButtonDown(HDC hDC, PSTATEL ip)
  708. {
  709.         RECT rc;
  710.         HPEN hpenOld;
  711.         rc = ip->rc;
  712.         TopLeft(hDC, &rc, hpenBlack, TRUE);
  713.         BottomRight(hDC, &rc, hpenBlack, FALSE);
  714.         rc.top++;
  715.         rc.bottom--;
  716.         rc.left++;
  717.         rc.right--;
  718.         TopLeft(hDC, &rc, hpenLowlight, TRUE);
  719.         rc.top++;
  720.         rc.left++;
  721.         TopLeft(hDC, &rc, hpenNeutral, TRUE);
  722.         rc.top++;
  723.         rc.left++;
  724.         TopLeft(hDC, &rc, hpenNeutral, TRUE);
  725.         rc.top++;
  726.         rc.left++;
  727.         hpenOld = SelectObject(hDC, hpenNeutral);
  728.         Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
  729.         SelectObject(hDC, hpenOld);
  730.         DrawText(hDC, ip->text, lstrlen(ip->text), &rc, DT_CENTER | DT_VCENTER);
  731. }
  732. /***************************************************************************
  733.  * Function: TopLeft
  734.  *
  735.  * Purpose:
  736.  *
  737.  */
  738. void
  739. TopLeft(HDC hDC, LPRECT rcp, HPEN hpen, BOOL bCorners)
  740. {
  741.         HPEN hpenOld;
  742.         int x, y;
  743.         hpenOld = SelectObject(hDC, hpen);
  744.         x = rcp->right - 1;
  745.         y = rcp->bottom;
  746.         if (!bCorners) {
  747.                 x--;
  748.                 y--;
  749.         }
  750.         MoveToEx(hDC, x, rcp->top, NULL);
  751.         LineTo(hDC, rcp->left, rcp->top);
  752.         LineTo(hDC, rcp->left, y);
  753.         SelectObject(hDC, hpenOld);
  754. }
  755. /***************************************************************************
  756.  * Function: BottomRight
  757.  *
  758.  * Purpose:
  759.  *
  760.  */
  761. void
  762. BottomRight(HDC hDC, LPRECT rcp, HPEN hpen, BOOL bCorners)
  763. {
  764.         HPEN hpenOld;
  765.         int x, y;
  766.         hpenOld = SelectObject(hDC, hpen);
  767.         x = rcp->left - 1;
  768.         y = rcp->top;
  769.         if (!bCorners) {
  770.                 x++;
  771.                 y++;
  772.         }
  773.         MoveToEx(hDC, rcp->right-1, y, NULL);
  774.         LineTo(hDC, rcp->right-1, rcp->bottom-1);
  775.         LineTo(hDC, x, rcp->bottom-1);
  776.         SelectObject(hDC, hpenOld);
  777. }
  778. /***************************************************************************
  779.  * Function: StatusGetItem
  780.  *
  781.  * Purpose:
  782.  *
  783.  */
  784. PSTATEL
  785. StatusGetItem(PILIST plist, int id)
  786. {
  787.         int i;
  788.         if (plist == NULL) {
  789.                 return(NULL);
  790.         }
  791.         for (i = 0; i < plist->nitems; i++) {
  792.                 if (plist->statels[i].id == id) {
  793.                         return(&plist->statels[i]);
  794.                 }
  795.         }
  796.         return(NULL);
  797. }
  798. /***************************************************************************
  799.  * Function: StatusCalcWidth
  800.  *
  801.  * Purpose:
  802.  *
  803.  * Calculate the width of a given field. This is the width in characters
  804.  * multiplied by the average character width, plus a few units for
  805.  * borders.
  806.  *
  807.  * If SF_VAR is set, this field size varies depending on the text, so
  808.  * we use GetTextExtent for the field size. If SF_VAR is selected, the caller
  809.  * can specify that the size is not to exceed the (width * avecharwidth)
  810.  * size (using SF_SZMAX) or that it is not be less than it (SF_SZMIN).
  811.  */
  812. int
  813. StatusCalcWidth(HWND hWnd, PSTATEL ip)
  814. {
  815.         int ch_size, t_size;
  816.         SIZE sz;
  817.         HDC hDC;
  818.         ch_size = ip->width * status_charwidth;
  819.         if (ip->flags & SF_VAR) {
  820.                 hDC = GetDC(hWnd);
  821.                 InitDC(hDC);
  822.                 GetTextExtentPoint(hDC, ip->text, lstrlen(ip->text), &sz);
  823.                 ReleaseDC(hWnd, hDC);
  824.                 t_size = sz.cx;
  825.                 /*
  826.                  * check this size against min/max size if
  827.                  * requested
  828.                  */
  829.                 if (ip->flags & SF_SZMIN) {
  830.                         if (ch_size > t_size) {
  831.                                 t_size = ch_size;
  832.                         }
  833.                 }
  834.                 if (ip->flags & SF_SZMAX) {
  835.                         if (ch_size < t_size) {
  836.                                 t_size = ch_size;
  837.                         }
  838.                 }
  839.                 ch_size = t_size;
  840.         }
  841.         if (ch_size != 0) {
  842.                 if (ip->type == SF_BUTTON) {
  843.                         return(ch_size+6);
  844.                 } else {
  845.                         return(ch_size+4);
  846.                 }
  847.         } else {
  848.                 return(0);
  849.         }
  850. }
  851. /***************************************************************************
  852.  * Function: StatusCalcHeight
  853.  *
  854.  * Purpose:
  855.  *
  856.  * Calculate the height of a given field
  857.  */
  858. int
  859. StatusCalcHeight(HWND hWnd, PSTATEL ip)
  860. {
  861.         int size;
  862.         size = status_charheight;
  863.         if (ip->type == SF_BUTTON) {
  864.                 return(size + 6);
  865.         } else {
  866.                 return(size + 2);
  867.         }
  868. }