home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / advanced / oldbars / statbar.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-27  |  20.1 KB  |  765 lines

  1. // statbar.cpp : definition of old backward compatible CStatusBar
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14. #define _AFX_NO_OLE_SUPPORT
  15. #include <afxpriv.h>
  16. #include "statbar.h"
  17. #include "globals.h"
  18.  
  19. #ifdef _DEBUG
  20. #undef THIS_FILE
  21. static char THIS_FILE[] = __FILE__;
  22. #endif
  23.  
  24. #define new DEBUG_NEW
  25.  
  26. /////////////////////////////////////////////////////////////////////////////
  27. // CStatusBar creation etc
  28.  
  29. struct AFX_STATUSPANE
  30. {
  31.     UINT    nID;        // IDC of indicator: 0 => normal text area
  32.     UINT    nStyle;     // style flags (SBPS_*)
  33.     int     cxText;     // width of string area in pixels
  34.                         //   on both sides there is a 1 pixel gap and
  35.                         //    a one pixel border, making a pane 4 pixels wider
  36.     LPCTSTR  lpszText;  // text in the pane
  37. };
  38.  
  39. inline AFX_STATUSPANE* CStatusBar::_GetPanePtr(int nIndex) const
  40. {
  41.     ASSERT(nIndex >= 0 && nIndex < m_nCount);
  42.     ASSERT(m_pData != NULL);
  43.     return ((AFX_STATUSPANE*)m_pData) + nIndex;
  44. }
  45.  
  46. #ifdef AFX_INIT_SEG
  47. #pragma code_seg(AFX_INIT_SEG)
  48. #endif
  49.  
  50. CStatusBar::CStatusBar()
  51. {
  52.     m_hFont = NULL;
  53.  
  54.     // setup correct margins
  55.     m_cxRightBorder = m_cxDefaultGap;
  56.     m_cxSizeBox = 0;
  57.     m_bHideSizeBox = FALSE;
  58.     if (globalData.bWin4)
  59.     {
  60.         m_cxLeftBorder = 4;
  61.         m_cyTopBorder = 2;
  62.         m_cyBottomBorder = 0;
  63.         m_cxRightBorder = 0;
  64.     }
  65.  
  66.     if (globalData.hStatusFont == NULL)
  67.     {
  68.         // load status bar font
  69.         CClientDC dc(NULL);
  70.         LOGFONT logfont;
  71.         memset(&logfont, 0, sizeof(logfont));
  72.         logfont.lfWeight = FW_NORMAL;
  73.         logfont.lfHeight = -MulDiv(globalData.bWin4 ? 8 : 10,
  74.             globalData.cyPixelsPerInch, 72);
  75.         lstrcpy(logfont.lfFaceName, _T("MS Sans Serif"));
  76.         BOOL bCustom = AfxCustomLogFont(AFX_IDS_STATUS_FONT, &logfont);
  77.         if (bCustom || !GetSystemMetrics(SM_DBCSENABLED))
  78.         {
  79.             // only set pitch & family if not a custom font
  80.             if (!bCustom)
  81.                 logfont.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
  82.             // 10 point height Sans Serif font (8 point for Win4)
  83.             globalData.hStatusFont = ::CreateFontIndirect(&logfont);
  84.         }
  85.         if (globalData.hStatusFont == NULL)
  86.         {
  87.             if (!GetSystemMetrics(SM_DBCSENABLED))
  88.                 TRACE0("Warning: Using system font for status font.\n");
  89.             globalData.hStatusFont = (HFONT)::GetStockObject(SYSTEM_FONT);
  90.         }
  91.     }
  92. }
  93.  
  94. void CStatusBar::OnSettingChange(UINT /*uFlags*/, LPCTSTR /* lpszSection */)
  95. {
  96.     if (globalData.bWin4)
  97.     {
  98.         // get the drawing area for the status bar
  99.         CRect rect;
  100.         GetClientRect(rect);
  101.         CalcInsideRect(rect, TRUE);
  102.  
  103.         // the size box is based off the size of a scrollbar
  104.         m_cxSizeBox = min(GetSystemMetrics(SM_CXVSCROLL)+1, rect.Height());
  105.     }
  106. }
  107.  
  108. CStatusBar::~CStatusBar()
  109. {
  110.     // free strings before freeing array of elements
  111.     for (int i = 0; i < m_nCount; i++)
  112.         VERIFY(SetPaneText(i, NULL, FALSE));    // no update
  113. }
  114.  
  115. BOOL CStatusBar::PreCreateWindow(CREATESTRUCT& cs)
  116. {
  117.     // in Win4, status bars do not have a border at all, since it is
  118.     //  provided by the client area.
  119.     if (globalData.bWin4 &&
  120.         (m_dwStyle & (CBRS_ALIGN_ANY|CBRS_BORDER_ANY)) == CBRS_BOTTOM)
  121.     {
  122.         m_dwStyle &= ~(CBRS_BORDER_ANY|CBRS_BORDER_3D);
  123.     }
  124.  
  125.     return CControlBar::PreCreateWindow(cs);
  126. }
  127.  
  128. BOOL CStatusBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
  129. {
  130.     ASSERT_VALID(pParentWnd);   // must have a parent
  131.  
  132.     // save the style
  133.     m_dwStyle = (dwStyle & CBRS_ALL);
  134.  
  135.     // create the HWND
  136.     CRect rect;
  137.     rect.SetRectEmpty();
  138.     LPCTSTR lpszClass = AfxRegisterWndClass(0, ::LoadCursor(NULL, IDC_ARROW),
  139.         (HBRUSH)(COLOR_BTNFACE+1), NULL);
  140.     if (!CWnd::Create(lpszClass, NULL, dwStyle, rect, pParentWnd, nID))
  141.         return FALSE;
  142.  
  143.     // Note: Parent must resize itself for control bar to be resized
  144.  
  145.     // set initial font and calculate bar height
  146.     SendMessage(WM_SETFONT, (WPARAM)globalData.hStatusFont);
  147.     return TRUE;
  148. }
  149.  
  150. BOOL CStatusBar::SetIndicators(const UINT* lpIDArray, int nIDCount)
  151. {
  152.     ASSERT_VALID(this);
  153.     ASSERT(nIDCount >= 1);  // must be at least one of them
  154.     ASSERT(lpIDArray == NULL ||
  155.         AfxIsValidAddress(lpIDArray, sizeof(UINT) * nIDCount, FALSE));
  156.  
  157.     // free strings before freeing array of elements
  158.     for (int i = 0; i < m_nCount; i++)
  159.         VERIFY(SetPaneText(i, NULL, FALSE));    // no update
  160.  
  161.     // first allocate array for panes and copy initial data
  162.     if (!AllocElements(nIDCount, sizeof(AFX_STATUSPANE)))
  163.         return FALSE;
  164.     ASSERT(nIDCount == m_nCount);
  165.  
  166.     BOOL bOK = TRUE;
  167.     if (lpIDArray != NULL)
  168.     {
  169.         ASSERT(m_hFont != NULL);        // must have a font !
  170.         CString strText;
  171.         CClientDC dcScreen(NULL);
  172.         HGDIOBJ hOldFont = dcScreen.SelectObject(m_hFont);
  173.         for (int i = 0; i < nIDCount; i++)
  174.         {
  175.             AFX_STATUSPANE* pSBP = _GetPanePtr(i);
  176.             pSBP->nID = *lpIDArray++;
  177.             if (pSBP->nID != 0)
  178.             {
  179.                 if (!strText.LoadString(pSBP->nID))
  180.                 {
  181.                     TRACE1("Warning: failed to load indicator string 0x%04X.\n",
  182.                         pSBP->nID);
  183.                     bOK = FALSE;
  184.                     break;
  185.                 }
  186.                 pSBP->cxText = dcScreen.GetTextExtent(strText,
  187.                         strText.GetLength()).cx;
  188.                 ASSERT(pSBP->cxText >= 0);
  189.                 if (!SetPaneText(i, strText, FALSE))
  190.                 {
  191.                     bOK = FALSE;
  192.                     break;
  193.                 }
  194.             }
  195.             else
  196.             {
  197.                 // no indicator (must access via index)
  198.                 // default to 1/4 the screen width (first pane is stretchy)
  199.                 pSBP->cxText = ::GetSystemMetrics(SM_CXSCREEN) / 4;
  200.                 if (i == 0)
  201.                     pSBP->nStyle |= (SBPS_STRETCH | SBPS_NOBORDERS);
  202.             }
  203.         }
  204.         dcScreen.SelectObject(hOldFont);
  205.     }
  206.     return bOK;
  207. }
  208.  
  209. #ifdef AFX_CORE3_SEG
  210. #pragma code_seg(AFX_CORE3_SEG)
  211. #endif
  212.  
  213. /////////////////////////////////////////////////////////////////////////////
  214. // CStatusBar attribute access
  215.  
  216. int CStatusBar::CommandToIndex(UINT nIDFind) const
  217. {
  218.     ASSERT_VALID(this);
  219.  
  220.     if (m_nCount <= 0)
  221.         return -1;
  222.  
  223.     AFX_STATUSPANE* pSBP = _GetPanePtr(0);
  224.     for (int i = 0; i < m_nCount; i++, pSBP++)
  225.         if (pSBP->nID == nIDFind)
  226.             return i;
  227.  
  228.     return -1;
  229. }
  230.  
  231. UINT CStatusBar::GetItemID(int nIndex) const
  232. {
  233.     ASSERT_VALID(this);
  234.     return _GetPanePtr(nIndex)->nID;
  235. }
  236.  
  237. void CStatusBar::GetItemRect(int nIndex, LPRECT lpRect) const
  238. {
  239.     ASSERT_VALID(this);
  240.     ASSERT(AfxIsValidAddress(lpRect, sizeof(RECT)));
  241.  
  242.     // return rectangle containing inset size
  243.     ASSERT(nIndex >= 0 && nIndex < m_nCount);
  244.  
  245.     CRect rect;
  246.     GetClientRect(rect);
  247.     CalcInsideRect(rect, TRUE);
  248.  
  249.     // protect space for size box
  250.     int cxSizeBox = m_bHideSizeBox ? 0 : m_cxSizeBox;
  251.     int xMax = (rect.right -= cxSizeBox);
  252.     if (cxSizeBox == 0)
  253.         xMax += m_cxRightBorder + 1;
  254.  
  255.     // walk through to calculate extra space
  256.     int cxExtra = rect.Width() + m_cxDefaultGap;
  257.     AFX_STATUSPANE* pSBP = (AFX_STATUSPANE*)m_pData;
  258.     for (int i = 0; i < m_nCount; i++, pSBP++)
  259.         cxExtra -= (pSBP->cxText + CX_BORDER * 4 + m_cxDefaultGap);
  260.     // if cxExtra <= 0 then we will not stretch but just clip
  261.  
  262.     for (i = 0, pSBP = (AFX_STATUSPANE*)m_pData; i < m_nCount; i++, pSBP++)
  263.     {
  264.         ASSERT(pSBP->cxText >= 0);
  265.         int cxText = pSBP->cxText;
  266.         if ((pSBP->nStyle & SBPS_STRETCH) && cxExtra > 0)
  267.         {
  268.             cxText += cxExtra;
  269.             cxExtra = 0;
  270.         }
  271.         rect.right = rect.left + cxText + CX_BORDER * 4;
  272.         rect.right = min(rect.right, xMax);
  273.         if (i == nIndex)
  274.             break;  // stop with correct rectangle (includes border)
  275.         rect.left = rect.right + m_cxDefaultGap;
  276.         rect.left = min(rect.left, xMax);
  277.     }
  278.     ASSERT(i == nIndex);
  279.     *lpRect = rect;
  280. }
  281.  
  282. UINT CStatusBar::GetPaneStyle(int nIndex) const
  283. {
  284.     return _GetPanePtr(nIndex)->nStyle;
  285. }
  286.  
  287. void CStatusBar::SetPaneStyle(int nIndex, UINT nStyle)
  288. {
  289.     AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
  290.     if (pSBP->nStyle != nStyle)
  291.     {
  292.         // just change the style of 1 pane, and invalidate it
  293.         pSBP->nStyle = nStyle;
  294.         CRect rect;
  295.         GetItemRect(nIndex, &rect);
  296.         InvalidateRect(rect);
  297.     }
  298. }
  299.  
  300. void CStatusBar::GetPaneInfo(int nIndex, UINT& nID, UINT& nStyle,
  301.     int& cxWidth) const
  302. {
  303.     ASSERT_VALID(this);
  304.  
  305.     AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
  306.     nID = pSBP->nID;
  307.     nStyle = pSBP->nStyle;
  308.     cxWidth = pSBP->cxText;
  309. }
  310.  
  311. void CStatusBar::SetPaneInfo(int nIndex, UINT nID, UINT nStyle, int cxWidth)
  312. {
  313.     ASSERT_VALID(this);
  314.  
  315.     AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
  316.     pSBP->nID = nID;
  317.     SetPaneStyle(nIndex, nStyle);  // single pane invalidate
  318.     if (cxWidth != pSBP->cxText)
  319.     {
  320.         // change width of one pane -> invalidate the entire status bar
  321.         pSBP->cxText = cxWidth;
  322.         Invalidate();
  323.     }
  324. }
  325.  
  326. void CStatusBar::GetPaneText(int nIndex, CString& s) const
  327. {
  328.     ASSERT_VALID(this);
  329.  
  330.     AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
  331.     s = pSBP->lpszText;
  332. }
  333.  
  334. BOOL CStatusBar::SetPaneText(int nIndex, LPCTSTR lpszNewText, BOOL bUpdate)
  335. {
  336.     ASSERT_VALID(this);
  337.  
  338.     AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
  339.     if (pSBP->lpszText != NULL)
  340.     {
  341.         if (lpszNewText != NULL && lstrcmp(pSBP->lpszText, lpszNewText) == 0)
  342.             return TRUE;        // nothing to change
  343.         free((LPVOID)pSBP->lpszText);
  344.     }
  345.  
  346.     BOOL bOK = TRUE;
  347.     if (lpszNewText == NULL || *lpszNewText == '\0')
  348.     {
  349.         pSBP->lpszText = NULL;
  350.     }
  351.     else
  352.     {
  353.         pSBP->lpszText = _tcsdup(lpszNewText);
  354.         if (pSBP->lpszText == NULL)
  355.             bOK = FALSE; // old text is lost and replaced by NULL
  356.     }
  357.  
  358.     if (bUpdate)
  359.     {
  360.         // invalidate the text of the pane - not including the border
  361.         CRect rect;
  362.         GetItemRect(nIndex, &rect);
  363.         if (!(pSBP->nStyle & SBPS_NOBORDERS))
  364.             rect.InflateRect(-CX_BORDER, -CY_BORDER);
  365.         else
  366.             rect.top -= CY_BORDER;  // base line adjustment
  367.         InvalidateRect(rect);
  368.     }
  369.     return bOK;
  370. }
  371.  
  372. /////////////////////////////////////////////////////////////////////////////
  373. // CStatusBar implementation
  374.  
  375. CSize CStatusBar::CalcFixedLayout(BOOL, BOOL bHorz)
  376. {
  377.     ASSERT_VALID(this);
  378.  
  379.     // recalculate based on font height + borders
  380.     TEXTMETRIC tm;
  381.     {
  382.         CClientDC dcScreen(NULL);
  383.         HGDIOBJ hOldFont = dcScreen.SelectObject(m_hFont);
  384.         VERIFY(dcScreen.GetTextMetrics(&tm));
  385.         dcScreen.SelectObject(hOldFont);
  386.     }
  387.  
  388.     CRect rectSize;
  389.     rectSize.SetRectEmpty();
  390.     CalcInsideRect(rectSize, bHorz);    // will be negative size
  391.  
  392.     // sizeof text + 1 or 2 extra on top, 2 on bottom + borders
  393.     return CSize(32767, tm.tmHeight - tm.tmInternalLeading +
  394.         CY_BORDER * (globalData.bWin4 ? 4 : 3) - rectSize.Height());
  395. }
  396.  
  397. void CStatusBar::DoPaint(CDC* pDC)
  398. {
  399.     ASSERT_VALID(this);
  400.     ASSERT_VALID(pDC);
  401.  
  402.     CControlBar::DoPaint(pDC);      // draw border
  403.  
  404.     CRect rect;
  405.     GetClientRect(rect);
  406.     CalcInsideRect(rect, TRUE);
  407.  
  408.     ASSERT(m_hFont != NULL);        // must have a font!
  409.     HGDIOBJ hOldFont = pDC->SelectObject(m_hFont);
  410.  
  411.     // protect space for size box
  412.     int cxSizeBox = m_bHideSizeBox ? 0 : m_cxSizeBox;
  413.     int xMax = (rect.right -= cxSizeBox);
  414.     if (cxSizeBox == 0)
  415.         xMax += m_cxRightBorder + 1;
  416.  
  417.     // walk through to calculate extra space
  418.     int cxExtra = rect.Width() + m_cxDefaultGap;
  419.     AFX_STATUSPANE* pSBP = (AFX_STATUSPANE*)m_pData;
  420.     for (int i = 0; i < m_nCount; i++, pSBP++)
  421.         cxExtra -= (pSBP->cxText + CX_BORDER * 4 + m_cxDefaultGap);
  422.     // if cxExtra <= 0 then we will not stretch but just clip
  423.  
  424.     for (i = 0, pSBP = (AFX_STATUSPANE*)m_pData; i < m_nCount; i++, pSBP++)
  425.     {
  426.         ASSERT(pSBP->cxText >= 0);
  427.         int cxText = pSBP->cxText;
  428.         if ((pSBP->nStyle & SBPS_STRETCH) && cxExtra > 0)
  429.         {
  430.             cxText += cxExtra;
  431.             cxExtra = 0;
  432.         }
  433.         rect.right = rect.left + cxText + CX_BORDER * 4;
  434.         rect.right = min(rect.right, xMax);
  435.         if (!globalData.bWin32s || pDC->RectVisible(&rect))
  436.             DrawStatusText(pDC, rect, pSBP->lpszText, pSBP->nStyle);
  437.         rect.left = rect.right + m_cxDefaultGap;
  438.         if (rect.left >= xMax)
  439.             break;
  440.     }
  441.     pDC->SelectObject(hOldFont);
  442.  
  443.     // draw the size box in the bottom right corner
  444.     if (cxSizeBox != 0)
  445.     {
  446.         int cxMax = min(cxSizeBox, rect.Height()+m_cyTopBorder);
  447.         rect.left = xMax + (cxSizeBox - cxMax) + CX_BORDER;
  448.         rect.bottom -= CX_BORDER;
  449.         HPEN hPenOld = (HPEN)pDC->SelectObject(globalData.hpenBtnHilite);
  450.         for (int i = 0; i < cxMax; i += 4)
  451.         {
  452.             pDC->MoveTo(rect.left+i, rect.bottom);
  453.             pDC->LineTo(rect.left+cxMax, rect.bottom-cxMax+i);
  454.         }
  455.         pDC->SelectObject(globalData.hpenBtnShadow);
  456.         for (i = 1; i < cxMax; i += 4)
  457.         {
  458.             pDC->MoveTo(rect.left+i, rect.bottom);
  459.             pDC->LineTo(rect.left+cxMax, rect.bottom-cxMax+i);
  460.         }
  461.         for (i = 2; i < cxMax; i += 4)
  462.         {
  463.             pDC->MoveTo(rect.left+i, rect.bottom);
  464.             pDC->LineTo(rect.left+cxMax, rect.bottom-cxMax+i);
  465.         }
  466.         pDC->SelectObject(hPenOld);
  467.     }
  468. }
  469.  
  470. void CStatusBar::DrawStatusText(CDC* pDC, const CRect& rect,
  471.     LPCTSTR lpszText, UINT nStyle)
  472. {
  473.     ASSERT_VALID(pDC);
  474.  
  475.     if (!(nStyle & SBPS_NOBORDERS))
  476.     {
  477.         // draw the borders
  478.         COLORREF clrHilite;
  479.         COLORREF clrShadow;
  480.  
  481.         if (nStyle & SBPS_POPOUT)
  482.         {
  483.             // reverse colors
  484.             clrHilite = globalData.clrBtnShadow;
  485.             clrShadow = globalData.clrBtnHilite;
  486.         }
  487.         else
  488.         {
  489.             // normal colors
  490.             clrHilite = globalData.clrBtnHilite;
  491.             clrShadow = globalData.clrBtnShadow;
  492.         }
  493.         pDC->Draw3dRect(rect, clrShadow, clrHilite);
  494.     }
  495.  
  496.     // just support left justified text
  497.     if (lpszText != NULL && !(nStyle & SBPS_DISABLED))
  498.     {
  499.         CRect rectText(rect);
  500.         if (!(nStyle & SBPS_NOBORDERS)) // only adjust if there are borders
  501.             rectText.InflateRect(-2*CX_BORDER, -CY_BORDER);
  502.         else
  503.             rectText.OffsetRect(0, -CY_BORDER); // baselines line up
  504.  
  505.         // background is already grey
  506.         int nOldMode = pDC->SetBkMode(TRANSPARENT);
  507.         COLORREF crTextColor = pDC->SetTextColor(globalData.clrBtnText);
  508.         COLORREF crBkColor = pDC->SetBkColor(globalData.clrBtnFace);
  509.  
  510.         // align on bottom (since descent is more important than ascent)
  511.         pDC->SetTextAlign(TA_LEFT | TA_BOTTOM);
  512.         pDC->ExtTextOut(rectText.left, rectText.bottom,
  513.             ETO_CLIPPED, &rectText, lpszText, lstrlen(lpszText), NULL);
  514.     }
  515. }
  516.  
  517. /////////////////////////////////////////////////////////////////////////////
  518. // CStatusBar message handlers
  519.  
  520. BEGIN_MESSAGE_MAP(CStatusBar, CControlBar)
  521.     //{{AFX_MSG_MAP(CStatusBar)
  522.     ON_WM_NCHITTEST()
  523.     ON_WM_SYSCOMMAND()
  524.     ON_WM_SIZE()
  525.     ON_MESSAGE(WM_SETFONT, OnSetFont)
  526.     ON_MESSAGE(WM_GETFONT, OnGetFont)
  527.     ON_MESSAGE(WM_SETTEXT, OnSetText)
  528.     ON_MESSAGE(WM_GETTEXT, OnGetText)
  529.     ON_MESSAGE(WM_GETTEXTLENGTH, OnGetTextLength)
  530.     ON_MESSAGE(WM_SIZEPARENT, OnSizeParent)
  531.     ON_WM_SETTINGCHANGE()
  532.     //}}AFX_MSG_MAP
  533. END_MESSAGE_MAP()
  534.  
  535. UINT CStatusBar::OnNcHitTest(CPoint point)
  536. {
  537.     // hit test the size box - convert to HTCAPTION if so
  538.     if (!m_bHideSizeBox && m_cxSizeBox != 0)
  539.     {
  540.         CRect rect;
  541.         GetClientRect(rect);
  542.         CalcInsideRect(rect, TRUE);
  543.         int cxMax = min(m_cxSizeBox-1, rect.Height());
  544.         rect.left = rect.right - cxMax;
  545.         ClientToScreen(&rect);
  546.         if (rect.PtInRect(point))
  547.             return HTBOTTOMRIGHT;
  548.     }
  549.     return CControlBar::OnNcHitTest(point);
  550. }
  551.  
  552. void CStatusBar::OnSysCommand(UINT nID, LPARAM lParam)
  553. {
  554.     if (!m_bHideSizeBox && m_cxSizeBox != 0 && (nID & 0xFFF0) == SC_SIZE)
  555.     {
  556.         CFrameWnd* pFrameWnd = GetParentFrame();
  557.         if (pFrameWnd != NULL)
  558.         {
  559.             pFrameWnd->SendMessage(WM_SYSCOMMAND, (WPARAM)nID, lParam);
  560.             return;
  561.         }
  562.     }
  563.     CControlBar::OnSysCommand(nID, lParam);
  564. }
  565.  
  566. void CStatusBar::OnSize(UINT nType, int cx, int cy)
  567. {
  568.     CControlBar::OnSize(nType, cx, cy);
  569.  
  570.     // adjust m_cxSizeBox if necessary
  571.     OnSettingChange(0, NULL);
  572.  
  573.     // force repaint on resize (recalculate stretchy)
  574.     Invalidate();
  575. }
  576.  
  577. LRESULT CStatusBar::OnSetFont(WPARAM wParam, LPARAM)
  578. {
  579.     m_hFont = (HFONT)wParam;
  580.     ASSERT(m_hFont != NULL);
  581.  
  582.     return 0L;      // does not re-draw or invalidate - resize parent instead
  583. }
  584.  
  585. LRESULT CStatusBar::OnGetFont(WPARAM, LPARAM)
  586. {
  587.     return (LRESULT)(UINT)m_hFont;
  588. }
  589.  
  590. LRESULT CStatusBar::OnSetText(WPARAM, LPARAM lParam)
  591. {
  592.     int nIndex = CommandToIndex(0);
  593.     if (nIndex < 0)
  594.         return -1;
  595.     return SetPaneText(nIndex, (LPCTSTR)lParam) ? 0 : -1;
  596. }
  597.  
  598. LRESULT CStatusBar::OnGetText(WPARAM wParam, LPARAM lParam)
  599. {
  600.     int nMaxLen = (int)wParam;
  601.     if (nMaxLen == 0)
  602.         return 0;       // nothing copied
  603.     LPTSTR lpszDest = (LPTSTR)lParam;
  604.  
  605.     int nLen = 0;
  606.     int nIndex = CommandToIndex(0); // use pane with ID zero
  607.     if (nIndex >= 0)
  608.     {
  609.         AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
  610.         nLen = pSBP->lpszText != NULL ? lstrlen(pSBP->lpszText) : 0;
  611.         if (nLen > nMaxLen)
  612.             nLen = nMaxLen - 1; // number of characters to copy (less term.)
  613.         memcpy(lpszDest, pSBP->lpszText, nLen*sizeof(TCHAR));
  614.     }
  615.     lpszDest[nLen] = '\0';
  616.     return nLen+1;      // number of bytes copied
  617. }
  618.  
  619. LRESULT CStatusBar::OnGetTextLength(WPARAM, LPARAM)
  620. {
  621.     int nLen = 0;
  622.     int nIndex = CommandToIndex(0); // use pane with ID zero
  623.     if (nIndex >= 0)
  624.     {
  625.         AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
  626.         if (pSBP->lpszText != NULL)
  627.             nLen = lstrlen(pSBP->lpszText);
  628.     }
  629.     return nLen;
  630. }
  631.  
  632. LRESULT CStatusBar::OnSizeParent(WPARAM wParam, LPARAM lParam)
  633. {
  634.     AFX_SIZEPARENTPARAMS* lpLayout = (AFX_SIZEPARENTPARAMS*)lParam;
  635.     if (lpLayout->hDWP != NULL)
  636.     {
  637.         // hide size box if parent is maximized
  638.         CFrameWnd* pFrameWnd = GetParentFrame();
  639.         if (pFrameWnd != NULL)
  640.         {
  641.             // the size box only appears when status bar is on the bottom
  642.             //  of a non-maximized, sizeable frame window.
  643.             CRect rectFrame;
  644.             pFrameWnd->GetClientRect(rectFrame);
  645.             BOOL bHideSizeBox = pFrameWnd->IsZoomed() ||
  646.                 !(pFrameWnd->GetStyle() & WS_THICKFRAME) ||
  647.                 rectFrame.bottom != lpLayout->rect.bottom ||
  648.                 rectFrame.right != lpLayout->rect.right;
  649.  
  650.             // update the size box hidden status, if changed
  651.             if (bHideSizeBox != m_bHideSizeBox)
  652.             {
  653.                 m_bHideSizeBox = bHideSizeBox;
  654.                 Invalidate();
  655.             }
  656.         }
  657.     }
  658.  
  659.     return CControlBar::OnSizeParent(wParam, lParam);
  660. }
  661.  
  662. /////////////////////////////////////////////////////////////////////////////
  663. // CStatusBar idle update through CStatusCmdUI class
  664.  
  665. #define CStatusCmdUI COldStatusCmdUI
  666.  
  667. class CStatusCmdUI : public CCmdUI      // class private to this file!
  668. {
  669. public: // re-implementations only
  670.     virtual void Enable(BOOL bOn);
  671.     virtual void SetCheck(int nCheck);
  672.     virtual void SetText(LPCTSTR lpszText);
  673. };
  674.  
  675. void CStatusCmdUI::Enable(BOOL bOn)
  676. {
  677.     m_bEnableChanged = TRUE;
  678.     CStatusBar* pStatusBar = (CStatusBar*)m_pOther;
  679.     ASSERT(pStatusBar != NULL);
  680.     ASSERT_KINDOF(CStatusBar, pStatusBar);
  681.     ASSERT(m_nIndex < m_nIndexMax);
  682.  
  683.     UINT nNewStyle = pStatusBar->GetPaneStyle(m_nIndex) & ~SBPS_DISABLED;
  684.     if (!bOn)
  685.         nNewStyle |= SBPS_DISABLED;
  686.     pStatusBar->SetPaneStyle(m_nIndex, nNewStyle);
  687. }
  688.  
  689. void CStatusCmdUI::SetCheck(int nCheck) // "checking" will pop out the text
  690. {
  691.     CStatusBar* pStatusBar = (CStatusBar*)m_pOther;
  692.     ASSERT(pStatusBar != NULL);
  693.     ASSERT_KINDOF(CStatusBar, pStatusBar);
  694.     ASSERT(m_nIndex < m_nIndexMax);
  695.  
  696.     UINT nNewStyle = pStatusBar->GetPaneStyle(m_nIndex) & ~SBPS_POPOUT;
  697.     if (nCheck != 0)
  698.         nNewStyle |= SBPS_POPOUT;
  699.     pStatusBar->SetPaneStyle(m_nIndex, nNewStyle);
  700. }
  701.  
  702. void CStatusCmdUI::SetText(LPCTSTR lpszText)
  703. {
  704.     ASSERT(m_pOther != NULL);
  705.     ASSERT_KINDOF(CStatusBar, m_pOther);
  706.     ASSERT(m_nIndex < m_nIndexMax);
  707.  
  708.     ((CStatusBar*)m_pOther)->SetPaneText(m_nIndex, lpszText);
  709. }
  710.  
  711. void CStatusBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
  712. {
  713.     CStatusCmdUI state;
  714.     state.m_pOther = this;
  715.     state.m_nIndexMax = (UINT)m_nCount;
  716.     for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
  717.         state.m_nIndex++)
  718.     {
  719.         state.m_nID = _GetPanePtr(state.m_nIndex)->nID;
  720.         state.DoUpdate(pTarget, bDisableIfNoHndler);
  721.     }
  722.  
  723.     // update the dialog controls added to the status bar
  724.     UpdateDialogControls(pTarget, bDisableIfNoHndler);
  725. }
  726.  
  727. /////////////////////////////////////////////////////////////////////////////
  728. // CStatusBar diagnostics
  729.  
  730. #ifdef _DEBUG
  731. void CStatusBar::AssertValid() const
  732. {
  733.     CControlBar::AssertValid();
  734. }
  735.  
  736. void CStatusBar::Dump(CDumpContext& dc) const
  737. {
  738.     CControlBar::Dump(dc);
  739.  
  740.     dc << "\nm_hFont = " << (UINT)m_hFont;
  741.  
  742.     if (dc.GetDepth() > 0)
  743.     {
  744.         for (int i = 0; i < m_nCount; i++)
  745.         {
  746.             dc << "\nstatus pane[" << i << "] = {";
  747.             dc << "\n\tnID = " << _GetPanePtr(i)->nID;
  748.             dc << "\n\tnStyle = " << _GetPanePtr(i)->nStyle;
  749.             dc << "\n\tcxText = " << _GetPanePtr(i)->cxText;
  750.             dc << "\n\tlpszText = " << _GetPanePtr(i)->lpszText;
  751.             dc << "\n\t}";
  752.         }
  753.     }
  754.  
  755.     dc << "\n";
  756. }
  757. #endif //_DEBUG
  758.  
  759. #undef new
  760. #ifdef AFX_INIT_SEG
  761. #pragma code_seg(AFX_INIT_SEG)
  762. #endif
  763.  
  764. IMPLEMENT_DYNAMIC(CStatusBar, CControlBar)
  765.