home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / windiff / status.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  29KB  |  979 lines

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