home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / gdi / fonts / fontview / status.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  14KB  |  376 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. #define NOMINMAX
  13. #include <windows.h>
  14.  
  15. #include <stdlib.h> // For 'abs'
  16.  
  17. #if !defined (APIENTRY)
  18. #define APIENTRY FAR PASCAL
  19. #endif
  20.  
  21. #define MAXSTATUS 10
  22. typedef struct _tagStatus {
  23.     HWND    hwnd;
  24.     int     iMaxWidth, iMinWidth, iGiveWidth;
  25. } Status;
  26. Status  statusField[MAXSTATUS];
  27.  
  28. HWND    hwndStatus;
  29. int    cntStatusField = 0;
  30. int    dyStatus, cxStatusBorder, cyStatusBorder, cxFrame, cyFrame, dyField;
  31. HFONT   hfontStatus;
  32. TEXTMETRIC tmStatusFont;
  33. HBRUSH hbrBtnFace;
  34.  
  35. LONG APIENTRY StatusProc      (HWND, UINT, UINT, LONG);
  36. LONG APIENTRY StatusFieldProc (HWND, UINT, UINT, LONG);
  37.  
  38. BOOL InitStatusBar (HANDLE hInstance)
  39. {
  40.     WNDCLASS    wndclass;
  41.  
  42.     hbrBtnFace = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  43.  
  44.     wndclass.style         = CS_HREDRAW | CS_VREDRAW;
  45.     wndclass.lpfnWndProc   = (WNDPROC)StatusProc;
  46.     wndclass.cbClsExtra    = 0;
  47.     wndclass.cbWndExtra    = 0;
  48.     wndclass.hInstance      = hInstance;
  49.     wndclass.hIcon     = NULL;
  50.     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
  51.     wndclass.hbrBackground = hbrBtnFace;
  52.     wndclass.lpszMenuName  = NULL;
  53.     wndclass.lpszClassName = "SamplerStatus";
  54.  
  55.     if (!RegisterClass (&wndclass))
  56.         return FALSE;
  57.  
  58.     wndclass.style         = CS_HREDRAW | CS_VREDRAW;
  59.     wndclass.lpfnWndProc   = (WNDPROC)StatusFieldProc;
  60.     wndclass.cbClsExtra    = 0;
  61.     wndclass.cbWndExtra    = 0;
  62.     wndclass.hInstance      = hInstance;
  63.     wndclass.hIcon     = NULL;
  64.     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
  65.     wndclass.hbrBackground = hbrBtnFace;
  66.     wndclass.lpszMenuName  = NULL;
  67.     wndclass.lpszClassName = "StatusField";
  68.  
  69.     if (!RegisterClass (&wndclass))
  70.         return FALSE;
  71.  
  72. }
  73.  
  74. BOOL CreateStatusBar (HWND hwnd, HANDLE hInst, int iId)
  75. {
  76.     cxStatusBorder = GetSystemMetrics (SM_CXBORDER);
  77.     cyStatusBorder = GetSystemMetrics (SM_CYBORDER);
  78.  
  79.     hwndStatus = CreateWindow ("SamplerStatus", "SamplerStatus",
  80.         WS_CHILD | WS_BORDER | WS_VISIBLE,
  81.         0, 0, 0, 0,
  82.         hwnd, (HMENU)iId, hInst, NULL);
  83.  
  84.     if (!hwndStatus) {
  85.         return FALSE;
  86.     }
  87.     return TRUE;
  88. }
  89.  
  90. int StatusBarHeight (HWND hwnd)
  91. {
  92.     RECT rect;
  93.     GetClientRect (hwndStatus, &rect);
  94.     return rect.bottom-rect.top;
  95.  
  96.     hwnd; // unreferenced formal parameter
  97. }
  98.  
  99. BOOL AdjustStatusBar (HWND hwnd)
  100. {
  101.     RECT rect;
  102.     GetClientRect (hwnd, &rect);
  103.     MoveWindow (hwndStatus,
  104.         rect.left-cxStatusBorder,
  105.         rect.bottom - dyStatus + cyStatusBorder,
  106.         rect.right - rect.left + (cxStatusBorder*2),
  107.         dyStatus,
  108.     TRUE);
  109.     return TRUE;
  110. }
  111.  
  112. HWND AddStatusField (HANDLE hInst, int iId, int iMin, int iMax, BOOL bNewGroup)
  113. {
  114.     LONG lStyle;
  115.  
  116.     if (cntStatusField >= MAXSTATUS) return (HWND)0; // No room left in our fixed array
  117.  
  118.     statusField[cntStatusField].hwnd = CreateWindow ("StatusField", "",
  119.         WS_CHILD | WS_VISIBLE,
  120.         0, 0, 0, 0,
  121.         hwndStatus, (HMENU)iId, hInst, NULL);
  122.  
  123.     if (!statusField[cntStatusField].hwnd) return (HWND)0; // CreateWindow failed for some reason
  124.  
  125.     if (iMin < 0) {
  126.     statusField[cntStatusField].iMinWidth = tmStatusFont.tmAveCharWidth*abs(iMin);
  127.     } else {
  128.     statusField[cntStatusField].iMinWidth = iMin;
  129.     }
  130.  
  131.     if (iMax < 0) {
  132.     statusField[cntStatusField].iMaxWidth = tmStatusFont.tmAveCharWidth*abs(iMax);
  133.     } else {
  134.     statusField[cntStatusField].iMaxWidth = iMax;
  135.     }
  136.  
  137.     if (bNewGroup) {
  138.         lStyle = GetWindowLong (statusField[cntStatusField].hwnd, GWL_STYLE);
  139.         lStyle |= WS_GROUP;
  140.         SetWindowLong (statusField[cntStatusField].hwnd, GWL_STYLE, lStyle);
  141.     }
  142.  
  143.     return statusField[cntStatusField++].hwnd;
  144. }
  145.  
  146. BOOL DestroyStatusBar (void)
  147. {
  148.     return DeleteObject (hbrBtnFace);
  149. }
  150.  
  151. LONG APIENTRY StatusProc (HWND hwnd, UINT msg, UINT wParam, LONG lParam)
  152. {
  153.     HDC hdc;
  154.     PAINTSTRUCT ps;
  155.     int x, y, i;
  156.     int wAvailWidth, wFlexWidth, cntFlexWidth, wNeedWidth, cntNeedWidth;
  157.     RECT    rect, border;
  158.     HBRUSH  hBrush;
  159.     LOGFONT lfTmp;
  160.  
  161.     switch (msg) {
  162.         case WM_CREATE:
  163.             hfontStatus = CreateFont(14, 0, 0, 0, 0, 0, 0, 0,
  164.                 0, 0, 0, 0,
  165.                 VARIABLE_PITCH | FF_SWISS, "");
  166.  
  167.                         if (GetObject (hfontStatus, sizeof(LOGFONT), &lfTmp)) {
  168.                                 if ((lfTmp.lfPitchAndFamily & VARIABLE_PITCH) &&
  169.                                    (lfTmp.lfPitchAndFamily & FF_SWISS)) {
  170.                                 } else {
  171.                                         MessageBox (GetFocus(),
  172. "Unable to get an unnamed variable pitch swiss font", "Status Bar CreateFont Error",
  173.                                                 MB_OK);
  174.                 hfontStatus = CreateFont(14, 0, 0, 0, 0, 0, 0, 0,
  175.                         0, 0, 0, 0,
  176.                         VARIABLE_PITCH | FF_SWISS, "Arial");
  177.                                 }
  178.                         }
  179.  
  180.  
  181.             if (!hfontStatus) {
  182.                 MessageBox (GetFocus(), "Failed To Create Font", "StatusProc", MB_OK);
  183.             }
  184.             hdc = GetDC (hwnd);
  185.             SelectObject (hdc, hfontStatus);
  186.             GetTextMetrics (hdc, &tmStatusFont);
  187.             cxStatusBorder = GetSystemMetrics (SM_CXBORDER);
  188.             cyStatusBorder = GetSystemMetrics (SM_CYBORDER);
  189.             cxFrame = 3*cxStatusBorder;
  190.             cyFrame = 3*cyStatusBorder;
  191.             dyField = tmStatusFont.tmHeight + (2*cyStatusBorder);
  192.             dyStatus = dyField + (2*cyFrame);
  193.             ReleaseDC (hwnd, hdc);
  194.             return DefWindowProc (hwnd, msg, wParam, lParam);
  195.  
  196.         case WM_DESTROY:
  197.             if (hfontStatus) {
  198.                 DeleteObject (hfontStatus);
  199.             }
  200.             break;
  201.  
  202.         case WM_SIZE:
  203.         if (cntStatusField) {
  204.                 GetClientRect (hwnd, &rect);
  205.                 wAvailWidth = rect.right - rect.left - (cxStatusBorder*8);
  206.                 wNeedWidth = 0;
  207.                 cntNeedWidth = 0;
  208.                 cntFlexWidth = 0;
  209.  
  210.                 /* First Pass: Dole out to fields that have a minimum need */
  211.                 for (i=0; i<cntStatusField; i++) {
  212.                     statusField[i].iGiveWidth = 0; // Make sure all are initialized to 0
  213.                     if (statusField[i].iMinWidth) {
  214.                         /* (n, ?) */
  215.                         statusField[i].iGiveWidth = statusField[i].iMinWidth;
  216.                         wAvailWidth -= (statusField[i].iGiveWidth + cxStatusBorder*2);
  217.                         if (GetWindowLong(statusField[i].hwnd, GWL_STYLE) & WS_GROUP) {
  218.                             wAvailWidth -= cxStatusBorder*4;
  219.                         }
  220.                     } else {
  221.                         /* They didn't specify a minimum... don't give them anything yet */
  222.                         /* (0, ?) */
  223.                         statusField[i].iGiveWidth = 0;
  224.                     }
  225.  
  226.                     /* For those that have a minimum, but can grow to be as large as possible...*/
  227.                     /* (n, 0) */
  228.                     if ((statusField[i].iMinWidth >0) && (statusField[i].iMaxWidth ==0)) {
  229.                         ++cntFlexWidth;
  230.                     }
  231.  
  232.                     /* For those that have a max that is greater then their min... */
  233.                     /* Includes (0,n) and (n,>n) */
  234.                     if (statusField[i].iMaxWidth > statusField[i].iGiveWidth) {
  235.                         wNeedWidth += (statusField[i].iMaxWidth - statusField[i].iGiveWidth);
  236.                         ++cntNeedWidth;
  237.                     }
  238.                 }
  239.  
  240.                 /* Second Pass: Dole out to fields that have a stated maximum need */
  241.                 /* This will also hit those who had no minimum, but did have a maximum */
  242.                 /* It will still not give anything to those with no min, no max */
  243.                 if ((cntNeedWidth > 0) && (wAvailWidth > 0)) {
  244.                     if (wNeedWidth > wAvailWidth) {
  245.                         wNeedWidth = wAvailWidth;
  246.                     }
  247.                     wNeedWidth = wNeedWidth / cntNeedWidth;
  248.                     for (i=0; i<cntStatusField; i++) {
  249.                         if (statusField[i].iMaxWidth > statusField[i].iGiveWidth) {
  250.                             statusField[i].iGiveWidth += wNeedWidth;
  251.                             wAvailWidth -= (statusField[i].iGiveWidth + cxStatusBorder*2);
  252.                             if (GetWindowLong(statusField[i].hwnd, GWL_STYLE) & WS_GROUP) {
  253.                                 wAvailWidth -= cxStatusBorder*4;
  254.                             }
  255.                         }
  256.                     }
  257.                 }
  258.  
  259.                 /* Third Pass: Dole out the remaining to fields that want all they can get */
  260.                 /* This includes those who had a minimum, but no maximum */
  261.                 if ((cntFlexWidth > 0) && (wAvailWidth > 0)) {
  262.                     wFlexWidth = wAvailWidth / cntFlexWidth;
  263.                     for (i=0; i<cntStatusField; i++) {
  264.                         if (statusField[i].iMaxWidth==0) {
  265.                             statusField[i].iGiveWidth += wFlexWidth;
  266.                             wAvailWidth -= ((wFlexWidth - statusField[i].iMinWidth) + cxStatusBorder*2);
  267.                             if (GetWindowLong(statusField[i].hwnd, GWL_STYLE) & WS_GROUP) {
  268.                                 wAvailWidth -= cxStatusBorder*4;
  269.                             }
  270.                         }
  271.                     }
  272.                 }
  273.  
  274.                 x = cxStatusBorder*4;
  275.                 y = rect.top + (2*cyStatusBorder);
  276.                 for (i=0; i<cntStatusField; i++) {
  277.                     if (GetWindowLong (statusField[i].hwnd, GWL_STYLE) & WS_GROUP) {
  278.                         x += (cxStatusBorder*4);
  279.                     }
  280.                     MoveWindow (statusField[i].hwnd, x, y, statusField[i].iGiveWidth, dyField, TRUE);
  281.                     x += statusField[i].iGiveWidth + (cxStatusBorder*2);
  282.                 }
  283.             }
  284.             break;
  285.  
  286.         case WM_PAINT:
  287.             hdc = BeginPaint (hwnd, &ps);
  288.             GetClientRect (hwnd, &rect);
  289.  
  290.             hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  291.             border = rect;
  292.             border.bottom = border.top + cyStatusBorder;
  293.             FillRect (hdc, &border, hBrush);
  294.             DeleteObject (hBrush);
  295.  
  296.             hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
  297.             border = rect;
  298.             border.top = border.bottom - cyStatusBorder;
  299.             FillRect (hdc, &border, hBrush);
  300.             DeleteObject (hBrush);
  301.  
  302.             EndPaint (hwnd, &ps);
  303.  
  304.             return DefWindowProc (hwnd, msg, wParam, lParam);
  305.  
  306.         default:
  307.             return DefWindowProc (hwnd, msg, wParam, lParam);
  308.     }
  309.     return 0L;
  310. }
  311.  
  312.  
  313.  
  314. LONG APIENTRY StatusFieldProc (HWND hwnd, UINT msg, UINT wParam, LONG lParam)
  315. {
  316.     HDC     hdc;
  317.     PAINTSTRUCT ps;
  318.     RECT    rect, border;
  319.     HBRUSH  hBrush;
  320.     WORD    edge = 1;
  321.     HFONT   hTmp;
  322.     char szText[80];
  323.     int len;
  324.  
  325.     switch (msg) {
  326.         case WM_PAINT:
  327.             hdc = BeginPaint (hwnd, &ps);
  328.             GetClientRect (hwnd, &rect);
  329.  
  330.             hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
  331.             border = rect;
  332.             border.bottom = border.top + cyStatusBorder;
  333.             FillRect (hdc, &border, hBrush);
  334.             border = rect;
  335.             border.right = border.left + cxStatusBorder;
  336.             FillRect (hdc, &border, hBrush);
  337.             DeleteObject (hBrush);
  338.  
  339.             hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  340.             border = rect;
  341.             border.top = border.bottom - cyStatusBorder;
  342.             FillRect (hdc, &border, hBrush);
  343.             border = rect;
  344.             border.left = border.right - cxStatusBorder;
  345.             FillRect (hdc, &border, hBrush);
  346.             DeleteObject (hBrush);
  347.  
  348.             if (len = GetWindowText(hwnd, szText, sizeof (szText))) {
  349.                 hTmp = SelectObject(hdc, hfontStatus);
  350.  
  351.                 SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
  352.                 SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
  353.  
  354.                 InflateRect (&rect, -(cxStatusBorder*2), -cyStatusBorder);
  355.                 ExtTextOut(hdc, rect.left, rect.top,
  356.                     ETO_OPAQUE | ETO_CLIPPED,
  357.                     &rect,
  358.                     (LPSTR)szText,
  359.                     len, NULL);
  360.  
  361.                 SelectObject (hdc, hTmp);
  362.             }
  363.  
  364.             EndPaint (hwnd, &ps);
  365.             break;
  366.  
  367.         case WM_SETTEXT:
  368.             InvalidateRect (hwnd, NULL, TRUE);
  369.             return DefWindowProc (hwnd, msg, wParam, lParam);
  370.  
  371.         default:
  372.             return DefWindowProc (hwnd, msg, wParam, lParam);
  373.     }
  374.     return 0L;
  375. }
  376.