home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 18.ddi / MFC / SRC / BARCORE.CP_ / BARCORE.CP
Encoding:
Text File  |  1993-02-08  |  24.1 KB  |  929 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and Microsoft
  7. // QuickHelp and/or WinHelp documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11.  
  12. #include "stdafx.h"
  13. #include <malloc.h>
  14.  
  15. #ifdef AFX_CORE3_SEG
  16. #pragma code_seg(AFX_CORE3_SEG)
  17. #endif
  18.  
  19. #ifdef _DEBUG
  20. #undef THIS_FILE
  21. static char BASED_CODE THIS_FILE[] = __FILE__;
  22. #define new DEBUG_NEW
  23. #endif
  24.  
  25. /////////////////////////////////////////////////////////////////////////////
  26.  
  27. // the CBRS_ style is made up of an alignment style and a draw border style
  28. //  the alignment styles are mutually exclusive
  29. //  the draw border styles may be combined
  30. #define ALIGN_ANY     0xF000
  31. #define ALIGN_LEFT     0x1000
  32. #define ALIGN_TOP      0x2000
  33. #define ALIGN_RIGHT    0x4000
  34. #define ALIGN_BOTTOM   0x8000
  35. #define BORDER_ANY    0x0F00
  36. #define BORDER_LEFT    0x0100
  37. #define BORDER_TOP     0x0200
  38. #define BORDER_RIGHT   0x0400
  39. #define BORDER_BOTTOM  0x0800
  40.  
  41. /////////////////////////////////////////////////////////////////////////////
  42. // CControlBar
  43.  
  44. IMPLEMENT_DYNAMIC(CControlBar, CWnd)
  45.  
  46. BEGIN_MESSAGE_MAP(CControlBar, CWnd)
  47.     //{{AFX_MSG_MAP(CControlBar)
  48.     ON_WM_PAINT()
  49.     ON_WM_CTLCOLOR()
  50.     ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
  51.     ON_MESSAGE_VOID(WM_INITIALUPDATE, OnInitialUpdate)
  52.     ON_MESSAGE(WM_SIZEPARENT, OnSizeParent)
  53.     ON_MESSAGE(WM_HELPHITTEST, OnHelpHitTest)
  54.     //}}AFX_MSG_MAP
  55. END_MESSAGE_MAP()
  56.  
  57. #ifdef AFX_INIT_SEG
  58. #pragma code_seg(AFX_INIT_SEG)
  59. #endif
  60.  
  61. CControlBar::CControlBar()
  62. {
  63.     m_sizeFixedLayout.cx = 32767;   // fill available space
  64.     m_sizeFixedLayout.cy = 32767;   // fill available space
  65.     m_nCount = 0;
  66.     m_pData = NULL;
  67.     // set up some default border spacings
  68.     m_cxLeftBorder = 8;
  69.     m_cxDefaultGap = 2;
  70.     m_cyTopBorder = m_cyBottomBorder = 1;
  71.     m_bAutoDelete = FALSE;
  72. }
  73.  
  74. BOOL CControlBar::AllocElements(int nElements, int cbElement)
  75. {
  76.     ASSERT_VALID(this);
  77.     ASSERT(nElements > 0 && cbElement > 0);
  78.     if (m_pData != NULL)
  79.     {
  80.         ASSERT(m_nCount != 0);
  81.         free(m_pData);      // free old data
  82.     }
  83.     else
  84.     {
  85.         // no initialized yet
  86.         ASSERT(m_nCount == 0);
  87.     }
  88.  
  89.     if ((m_pData = calloc(nElements, cbElement)) == NULL)
  90.         return FALSE;
  91.     m_nCount = nElements;
  92.     return TRUE;
  93. }
  94.  
  95. #ifdef AFX_CORE3_SEG
  96. #pragma code_seg(AFX_CORE3_SEG)
  97. #endif
  98.  
  99. CControlBar::~CControlBar()
  100. {
  101.     ASSERT_VALID(this);
  102.     DestroyWindow();    // avoid PostNcDestroy problems
  103.     // free array
  104.     if (m_pData != NULL)
  105.     {
  106.         ASSERT(m_nCount != 0);
  107.         free(m_pData);
  108.     }
  109. }
  110.  
  111. void CControlBar::PostNcDestroy()
  112. {
  113.     if (m_bAutoDelete)      // Automatic cleanup?
  114.         delete this;
  115. }
  116.  
  117.  
  118. /////////////////////////////////////////////////////////////////////////////
  119. // Default control bar processing
  120.  
  121. BOOL CControlBar::PreTranslateMessage(MSG* pMsg)
  122. {
  123.     ASSERT_VALID(this);
  124.     // act like a modeless dialog
  125.     ASSERT(m_hWnd != NULL);
  126.  
  127.     // don't translate dialog messages when in Shift+F1 help mode
  128.     if (AfxGetApp()->m_bHelpMode)
  129.         return FALSE;
  130.  
  131.     // since 'IsDialogMessage' will eat frame window accelerators,
  132.     //   we call the frame window's PreTranslateMessage first
  133.     CWnd* pFrame;
  134.     if ((pFrame = GetParentFrame()) != NULL)
  135.     {
  136.         if (pFrame->PreTranslateMessage(pMsg))
  137.             return TRUE;        // eaten by frame accelerator
  138.         // check for parent of the frame in case of MDI
  139.         if ((pFrame = pFrame->GetParentFrame()) != NULL &&
  140.           pFrame->PreTranslateMessage(pMsg))
  141.             return TRUE;        // eaten by frame accelerator
  142.     }
  143.  
  144.     // filter both messages to dialog and from children
  145.     return ::IsDialogMessage(m_hWnd, pMsg);
  146. }
  147.  
  148. LRESULT CControlBar::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
  149. {
  150.     ASSERT_VALID(this);
  151.  
  152.     // parent notification messages are just passed to parent of control bar
  153.     switch (nMsg)
  154.     {
  155.     case WM_COMMAND:
  156.     case WM_DRAWITEM:
  157.     case WM_MEASUREITEM:
  158.     case WM_DELETEITEM:
  159.     case WM_COMPAREITEM:
  160.     case WM_VKEYTOITEM:
  161.     case WM_CHARTOITEM:
  162.     case WM_VBXEVENT:
  163.         return ::SendMessage(::GetParent(m_hWnd), nMsg, wParam, lParam);
  164.     }
  165.     return CWnd::WindowProc(nMsg, wParam, lParam);
  166. }
  167.  
  168. LRESULT CControlBar::OnHelpHitTest(WPARAM, LPARAM)
  169. {
  170.     ASSERT_VALID(this);
  171.  
  172.     UINT nID = _AfxGetDlgCtrlID(m_hWnd);
  173.     if (nID != 0)
  174.         return HID_BASE_CONTROL+nID;
  175.     else
  176.         return 0;
  177. }
  178.  
  179.  
  180. void CControlBar::OnPaint()
  181. {
  182.     // background is already filled in grey
  183.     CPaintDC dc(this);
  184.     DoPaint(&dc);       // delegate to paint helper
  185. }
  186.  
  187. HBRUSH CControlBar::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
  188. {
  189.     LRESULT lResult;
  190.     if (pWnd->SendChildNotifyLastMsg(&lResult))
  191.         return (HBRUSH)lResult;     // eat it
  192.  
  193.     // force black text on grey background all the time
  194.     if (!GrayCtlColor(pDC->m_hDC, pWnd->GetSafeHwnd(), nCtlColor,
  195.        afxData.hbrBtnFace, afxData.clrBtnText))
  196.         return (HBRUSH)Default();
  197.     return afxData.hbrBtnFace;
  198. }
  199.  
  200. LRESULT CControlBar::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM)
  201. {
  202.     if (GetStyle() & WS_VISIBLE)        // ignore if child is invisible
  203.     {
  204.         CFrameWnd* pTarget = GetParentFrame();
  205.         if (pTarget != NULL)
  206.             OnUpdateCmdUI(pTarget, (BOOL)wParam);
  207.     }
  208.     return 0L;
  209. }
  210.  
  211. void CControlBar::OnInitialUpdate()
  212. {
  213.     // update the indicators before becoming visible
  214.     OnIdleUpdateCmdUI((WPARAM)TRUE, 0L);
  215. }
  216.  
  217. LRESULT CControlBar::OnSizeParent(WPARAM, LPARAM lParam)
  218. {
  219.     AFX_SIZEPARENTPARAMS FAR* lpLayout = (AFX_SIZEPARENTPARAMS FAR*)lParam;
  220.  
  221.     ASSERT(CBRS_NOALIGN == 0);
  222.     ASSERT(CBRS_LEFT == (ALIGN_LEFT | BORDER_RIGHT));
  223.     ASSERT(CBRS_RIGHT == (ALIGN_RIGHT | BORDER_LEFT));
  224.     ASSERT(CBRS_TOP == (ALIGN_TOP | BORDER_BOTTOM));
  225.     ASSERT(CBRS_BOTTOM == (ALIGN_BOTTOM | BORDER_TOP));
  226.  
  227.     // resize and reposition this control bar based on styles
  228.     DWORD dwStyle = GetStyle();
  229.  
  230.     if ((dwStyle & WS_VISIBLE) && (dwStyle & ALIGN_ANY) != 0)
  231.     {
  232.         // align the control bar
  233.         CRect rect;
  234.         rect.CopyRect(&lpLayout->rect);
  235.  
  236.         CSize sizeAvail = rect.Size();  // maximum size available
  237.         CSize size;     // maximum requested size
  238.         size.cx = min(m_sizeFixedLayout.cx, sizeAvail.cx);
  239.         size.cy = min(m_sizeFixedLayout.cy, sizeAvail.cy);
  240.  
  241.         if (dwStyle & ALIGN_LEFT)
  242.         {
  243.             // left align (stretch height)
  244.             size.cy = sizeAvail.cy;
  245.             lpLayout->rect.left += size.cx;
  246.         }
  247.         else if (dwStyle & ALIGN_TOP)
  248.         {
  249.             // top align (stretch width)
  250.             size.cx = sizeAvail.cx;
  251.             lpLayout->rect.top += size.cy;
  252.         }
  253.         else if (dwStyle & ALIGN_RIGHT)
  254.         {
  255.             // right align (stretch height)
  256.             size.cy = sizeAvail.cy;
  257.             rect.left = rect.right - size.cx;
  258.             lpLayout->rect.right -= size.cx;
  259.         }
  260.         else if (dwStyle & ALIGN_BOTTOM)
  261.         {
  262.             // bottom align (stretch width)
  263.             size.cx = sizeAvail.cx;
  264.             rect.top = rect.bottom - size.cy;
  265.             lpLayout->rect.bottom -= size.cy;
  266.         }
  267.         else
  268.         {
  269.             ASSERT(FALSE);      // can never happen
  270.         }
  271.  
  272.         rect.right = rect.left + size.cx;
  273.         rect.bottom = rect.top + size.cy;
  274.         _AfxRepositionWindow(lpLayout, m_hWnd, &rect);
  275.     }
  276.     return 0;
  277. }
  278.  
  279. void CControlBar::DoPaint(CDC* pDC)
  280. {
  281.     ASSERT_VALID(this);
  282.     ASSERT_VALID(pDC);
  283.  
  284.     DWORD dwStyle = GetStyle();
  285.     if (dwStyle & BORDER_ANY)
  286.     {
  287.         // draw border line on sides
  288.         CRect rect;
  289.         GetClientRect(&rect);
  290.         ASSERT(rect.top == 0 && rect.left == 0);
  291.         HBRUSH hbrFrame = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME));
  292.         if (hbrFrame != NULL)
  293.         {
  294.             HGDIOBJ hOldBrush = pDC->SelectObject(hbrFrame);
  295.             if (hOldBrush != NULL)
  296.             {
  297.                 if (dwStyle & BORDER_LEFT)
  298.                     pDC->PatBlt(0, 0, CX_BORDER, rect.bottom, PATCOPY);
  299.                 if (dwStyle & BORDER_TOP)
  300.                     pDC->PatBlt(0, 0, rect.right, CY_BORDER, PATCOPY);
  301.                 if (dwStyle & BORDER_RIGHT)
  302.                     pDC->PatBlt(rect.right, 0, -CX_BORDER, rect.bottom,
  303.                         PATCOPY);
  304.                 if (dwStyle & BORDER_BOTTOM)
  305.                     pDC->PatBlt(0, rect.bottom, rect.right, -CY_BORDER,
  306.                         PATCOPY);
  307.                 pDC->SelectObject(hOldBrush);
  308.             }
  309.             DeleteObject(hbrFrame);
  310.         }
  311.     }
  312. }
  313.  
  314. // input CRect should be client rectangle size
  315. void CControlBar::CalcInsideRect(CRect& rect) const
  316. {
  317.     ASSERT_VALID(this);
  318.     DWORD dwStyle = GetStyle();
  319.  
  320.     // adjust for border size
  321.     if (dwStyle & BORDER_LEFT)
  322.         rect.left += CX_BORDER;
  323.     if (dwStyle & BORDER_TOP)
  324.         rect.top += CY_BORDER;
  325.     if (dwStyle & BORDER_RIGHT)
  326.         rect.right -= CX_BORDER;
  327.     if (dwStyle & BORDER_BOTTOM)
  328.         rect.bottom -= CY_BORDER;
  329.  
  330.     // inset the top and bottom.
  331.     rect.left += m_cxLeftBorder;
  332.     rect.top += m_cyTopBorder;
  333.     rect.bottom -= m_cyBottomBorder;
  334. }
  335.  
  336.  
  337. #ifdef _DEBUG
  338. void CControlBar::AssertValid() const
  339. {
  340.     CWnd::AssertValid();
  341.     ASSERT(m_nCount == 0 || m_pData != NULL);
  342. }
  343.  
  344. void CControlBar::Dump(CDumpContext& dc) const
  345. {
  346.     CWnd::Dump(dc);
  347.     AFX_DUMP1(dc, "\nborder offset = ", m_cxLeftBorder);
  348.     AFX_DUMP1(dc, "\nm_cyTopBorder = ", m_cyTopBorder);
  349.     AFX_DUMP1(dc, "\nm_cyBottomBorder = ", m_cyBottomBorder);
  350.     AFX_DUMP1(dc, "\ndefault gap = ", m_cxDefaultGap);
  351.     AFX_DUMP1(dc, "\nfixed layout size = ", m_sizeFixedLayout);
  352.     AFX_DUMP1(dc, "\n# of non HWND elements = ", m_nCount);
  353.     AFX_DUMP1(dc, "\nm_bAutoDelete = ", m_bAutoDelete);
  354. }
  355. #endif
  356.  
  357.  
  358. /////////////////////////////////////////////////////////////////////////////
  359. // CStatusBar creation etc
  360.  
  361. struct AFX_STATUSPANE
  362. {
  363.     UINT    nID;        // IDC of indicator: 0 => normal text area
  364.     UINT    nStyle;     // style flags (SBPS_*)
  365.     int     cxText;     // width of string area in pixels
  366.                         //   on both sides there is a 1 pixel gap and
  367.                         //    a one pixel border, making a pane 4 pixels wider
  368.     LPCSTR  lpszText;   // always far strings
  369. };
  370.  
  371. inline AFX_STATUSPANE* CStatusBar::_GetPanePtr(int nIndex) const
  372. {
  373.     ASSERT(nIndex >= 0 && nIndex < m_nCount);
  374.     ASSERT(m_pData != NULL);
  375.     return ((AFX_STATUSPANE*)m_pData) + nIndex;
  376. }
  377.  
  378. IMPLEMENT_DYNAMIC(CStatusBar, CControlBar)
  379.  
  380. #ifdef AFX_INIT_SEG
  381. #pragma code_seg(AFX_INIT_SEG)
  382. #endif
  383.  
  384. CStatusBar::CStatusBar()
  385. {
  386.     m_hFont = NULL;
  387.     m_cxRightBorder = m_cxDefaultGap;
  388.  
  389.     if (afxData.hStatusFont == NULL)
  390.     {
  391.         // load status bar font
  392.         LOGFONT logfont;
  393.         memset(&logfont, 0, sizeof(logfont));
  394.  
  395.         // 10 point height Sans Serif font
  396.         logfont.lfHeight = -MulDiv(10, afxData.cyPixelsPerInch, 72);
  397.         logfont.lfWeight = FW_NORMAL;
  398.         logfont.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
  399.         static char BASED_CODE szFaceName[] = "MS Sans Serif";
  400.         lstrcpy(logfont.lfFaceName, szFaceName);
  401.         if ((afxData.hStatusFont = ::CreateFontIndirect(&logfont)) == NULL)
  402.         {
  403.             TRACE0("Warning: Using system font for status font\n");
  404.             afxData.hStatusFont = (HFONT)::GetStockObject(SYSTEM_FONT);
  405.         }
  406.     }
  407. }
  408.  
  409. CStatusBar::~CStatusBar()
  410. {
  411.     // free strings before freeing array of elements
  412.     for (int i = 0; i < m_nCount; i++)
  413.         VERIFY(SetPaneText(i, NULL, FALSE));    // no update
  414. }
  415.  
  416. BOOL CStatusBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
  417. {
  418.     ASSERT_VALID(pParentWnd);   // must have a parent
  419.  
  420.     // create the HWND
  421.     CRect rect;
  422.     rect.SetRectEmpty();
  423.     if (!CWnd::Create(_afxWndControlBar, NULL, dwStyle, rect, pParentWnd, nID))
  424.         return FALSE;
  425.         // NOTE: Parent must resize itself for control bar to be resized
  426.  
  427.     // set initial font and calculate bar height
  428.     OnSetFont((WPARAM)afxData.hStatusFont, 0);  // initialize font height etc
  429.     return TRUE;
  430. }
  431.  
  432. BOOL CStatusBar::SetIndicators(const UINT FAR* lpIDArray, int nIDCount)
  433. {
  434.     ASSERT_VALID(this);
  435.     ASSERT(nIDCount >= 1);  // must be at least one of them
  436.     ASSERT(lpIDArray == NULL ||
  437.         AfxIsValidAddress(lpIDArray, sizeof(UINT) * nIDCount, FALSE));
  438.  
  439.     // first allocate array for panes and copy initial data
  440.     if (!AllocElements(nIDCount, sizeof(AFX_STATUSPANE)))
  441.         return FALSE;
  442.     ASSERT(nIDCount == m_nCount);
  443.  
  444.     BOOL bOK = TRUE;
  445.     if (lpIDArray != NULL)
  446.     {
  447.         ASSERT(m_hFont != NULL);        // must have a font !
  448.         CString strText;
  449.         CClientDC dcScreen(NULL);
  450.         HGDIOBJ hOldFont = dcScreen.SelectObject(m_hFont);
  451.         for (int i = 0; i < nIDCount; i++)
  452.         {
  453.             AFX_STATUSPANE* pSBP = _GetPanePtr(i);
  454.             if ((pSBP->nID = *lpIDArray++) != 0)
  455.             {
  456.                 if (!strText.LoadString(pSBP->nID))
  457.                 {
  458.                     TRACE1("Warning: failed to load indicator string 0x%04X\n",
  459.                         pSBP->nID);
  460.                     bOK = FALSE;
  461.                     break;
  462.                 }
  463.                 pSBP->cxText = dcScreen.GetTextExtent(strText,
  464.                         strText.GetLength()).cx;
  465.                 ASSERT(pSBP->cxText >= 0);
  466.                 if (!SetPaneText(i, strText, FALSE))
  467.                 {
  468.                     bOK = FALSE;
  469.                     break;
  470.                 }
  471.             }
  472.             else
  473.             {
  474.                 // no indicator (must access via index)
  475.                 // default to 1/4 the screen width (first pane is stretchy)
  476.                 pSBP->cxText = ::GetSystemMetrics(SM_CXSCREEN) / 4;
  477.                 if (i == 0)
  478.                     pSBP->nStyle |= (SBPS_STRETCH | SBPS_NOBORDERS);
  479.             }
  480.         }
  481.         dcScreen.SelectObject(hOldFont);
  482.     }
  483.     return bOK;
  484. }
  485.  
  486. #ifdef AFX_CORE3_SEG
  487. #pragma code_seg(AFX_CORE3_SEG)
  488. #endif
  489.  
  490. /////////////////////////////////////////////////////////////////////////////
  491. // CStatusBar attribute access
  492.  
  493. int CStatusBar::CommandToIndex(UINT nIDFind) const
  494. {
  495.     ASSERT_VALID(this);
  496.     AFX_STATUSPANE* pSBP = _GetPanePtr(0);
  497.     for (int i = 0; i < m_nCount; i++, pSBP++)
  498.         if (pSBP->nID == nIDFind)
  499.             return i;
  500.     return -1;
  501. }
  502.  
  503. UINT CStatusBar::GetItemID(int nIndex) const
  504. {
  505.     ASSERT_VALID(this);
  506.     return _GetPanePtr(nIndex)->nID;
  507. }
  508.  
  509. void CStatusBar::GetItemRect(int nIndex, LPRECT lpRect) const
  510. {
  511.     ASSERT_VALID(this);
  512.     ASSERT(AfxIsValidAddress(lpRect, sizeof(RECT)));
  513.  
  514.     // return rectangle containing inset size
  515.     ASSERT(nIndex >= 0 && nIndex < m_nCount);
  516.     AFX_STATUSPANE* pSBP;
  517.     int i;
  518.  
  519.     CRect rect;
  520.     GetClientRect(rect);
  521.     CalcInsideRect(rect);
  522.  
  523.     int cxExtra = rect.Width() - m_cxRightBorder + m_cxDefaultGap;
  524.     // first walk through to calculate extra space
  525.     for (i = 0, pSBP = (AFX_STATUSPANE*)m_pData; i < m_nCount; i++, pSBP++)
  526.         cxExtra -= (pSBP->cxText + CX_BORDER * 4 + m_cxDefaultGap);
  527.     // if cxExtra <= 0 then we will not stretch but just clip
  528.  
  529.     for (i = 0, pSBP = (AFX_STATUSPANE*)m_pData; i < m_nCount; i++, pSBP++)
  530.     {
  531.         ASSERT(pSBP->cxText >= 0);
  532.         int cxText = pSBP->cxText;
  533.         if ((pSBP->nStyle & SBPS_STRETCH) && cxExtra > 0)
  534.         {
  535.             cxText += cxExtra;
  536.             cxExtra = 0;
  537.         }
  538.         rect.right = rect.left + cxText + CX_BORDER * 4;
  539.         if (i == nIndex)
  540.             break;  // stop with correct rectangle (includes border)
  541.         rect.left = rect.right + m_cxDefaultGap;
  542.     }
  543.     ASSERT(i == nIndex);
  544.     *lpRect = rect;
  545. }
  546.  
  547. inline UINT CStatusBar::_GetPaneStyle(int nIndex) const
  548. {
  549.     return _GetPanePtr(nIndex)->nStyle;
  550. }
  551.  
  552. void CStatusBar::_SetPaneStyle(int nIndex, UINT nStyle)
  553. {
  554.     AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
  555.     if (pSBP->nStyle != nStyle)
  556.     {
  557.         // just change the style of 1 pane, and invalidate it
  558.         pSBP->nStyle = nStyle;
  559.         CRect rect;
  560.         GetItemRect(nIndex, &rect);
  561.         InvalidateRect(rect);
  562.     }
  563. }
  564.  
  565. void CStatusBar::GetPaneInfo(int nIndex, UINT& nID, UINT& nStyle,
  566.     int& cxWidth) const
  567. {
  568.     ASSERT_VALID(this);
  569.  
  570.     AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
  571.     nID = pSBP->nID;
  572.     nStyle = pSBP->nStyle;
  573.     cxWidth = pSBP->cxText;
  574. }
  575.  
  576. void CStatusBar::SetPaneInfo(int nIndex, UINT nID, UINT nStyle, int cxWidth)
  577. {
  578.     ASSERT_VALID(this);
  579.  
  580.     AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
  581.     pSBP->nID = nID;
  582.     _SetPaneStyle(nIndex, nStyle);  // single pane invalidate
  583.     if (cxWidth != pSBP->cxText)
  584.     {
  585.         // change width of one pane -> invalidate the entire status bar
  586.         pSBP->cxText = cxWidth;
  587.         Invalidate();
  588.     }
  589. }
  590.  
  591. void CStatusBar::GetPaneText(int nIndex, CString& s) const
  592. {
  593.     ASSERT_VALID(this);
  594.  
  595.     AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
  596.     s = pSBP->lpszText;
  597. }
  598.  
  599. BOOL CStatusBar::SetPaneText(int nIndex, LPCSTR lpszNewText, BOOL bUpdate)
  600. {
  601.     ASSERT_VALID(this);
  602.  
  603.     AFX_STATUSPANE* pSBP = _GetPanePtr(nIndex);
  604.     if (pSBP == NULL)
  605.         return FALSE;
  606.  
  607.     if (pSBP->lpszText != NULL)
  608.     {
  609.         if (lpszNewText != NULL && lstrcmp(pSBP->lpszText, lpszNewText) == 0)
  610.             return TRUE;        // nothing to change
  611.         _ffree((LPVOID)pSBP->lpszText);
  612.     }
  613.  
  614.     BOOL bOK = TRUE;
  615.     if (lpszNewText == NULL || *lpszNewText == '\0')
  616.     {
  617.         pSBP->lpszText = NULL;
  618.     }
  619.     else
  620.     {
  621.         pSBP->lpszText = _fstrdup(lpszNewText);
  622.         if (pSBP->lpszText == NULL)
  623.             bOK = FALSE; // old text is lost and replaced by NULL
  624.     }
  625.         
  626.     if (bUpdate)
  627.     {
  628.         // invalidate the text of the pane - but not the border
  629.         CRect rect;
  630.         GetItemRect(nIndex, &rect);
  631.         rect.InflateRect(-CX_BORDER, -CY_BORDER);
  632.         InvalidateRect(rect);
  633.     }
  634.     return bOK;
  635. }
  636.  
  637.  
  638. /////////////////////////////////////////////////////////////////////////////
  639. // CStatusBar implementation
  640.  
  641. void CStatusBar::DoPaint(CDC* pDC)
  642. {
  643.     ASSERT_VALID(this);
  644.     ASSERT_VALID(pDC);
  645.  
  646.     CControlBar::DoPaint(pDC);      // draw border
  647.     CRect rect;
  648.     GetClientRect(rect);
  649.     CalcInsideRect(rect);
  650.  
  651.     AFX_STATUSPANE* pSBP;
  652.     int i;
  653.  
  654.     ASSERT(m_hFont != NULL);        // must have a font !
  655.     HGDIOBJ hOldFont = pDC->SelectObject(m_hFont);
  656.  
  657.     int cxExtra = rect.Width() - m_cxRightBorder + m_cxDefaultGap;
  658.     // first walk through to calculate extra space
  659.     for (i = 0, pSBP = (AFX_STATUSPANE*)m_pData; i < m_nCount; i++, pSBP++)
  660.         cxExtra -= (pSBP->cxText + CX_BORDER * 4 + m_cxDefaultGap);
  661.     // if cxExtra <= 0 then we will not stretch but just clip
  662.  
  663.     for (i = 0, pSBP = (AFX_STATUSPANE*)m_pData; i < m_nCount; i++, pSBP++)
  664.     {
  665.         ASSERT(pSBP->cxText >= 0);
  666.         int cxText = pSBP->cxText;
  667.         if ((pSBP->nStyle & SBPS_STRETCH) && cxExtra > 0)
  668.         {
  669.             cxText += cxExtra;
  670.             cxExtra = 0;
  671.         }
  672.         rect.right = rect.left + cxText + CX_BORDER * 4;
  673.         if (::RectVisible(pDC->m_hDC, &rect))
  674.             DrawStatusText(pDC->m_hDC, rect, pSBP->lpszText, pSBP->nStyle);
  675.         rect.left = rect.right + m_cxDefaultGap;
  676.     }
  677.     pDC->SelectObject(hOldFont);
  678. }
  679.  
  680. void PASCAL CStatusBar::DrawStatusText(HDC hDC, CRect const& rect,
  681.             LPCSTR lpszText, UINT nStyle)
  682. {
  683.     ASSERT(hDC != NULL);
  684.  
  685.     HBRUSH hbrHilite = NULL;
  686.     HBRUSH hbrShadow = NULL;
  687.     if (!(nStyle & SBPS_NOBORDERS))
  688.     {
  689.         if (nStyle & SBPS_POPOUT)
  690.         {
  691.             // reverse colors
  692.             hbrHilite = afxData.hbrBtnShadow;
  693.             hbrShadow = afxData.hbrBtnHilite;
  694.         }
  695.         else
  696.         {
  697.             // normal colors
  698.             hbrHilite = afxData.hbrBtnHilite;
  699.             hbrShadow = afxData.hbrBtnShadow;
  700.         }
  701.     }
  702.  
  703.     // background is already grey
  704.     UINT nOpts = ETO_CLIPPED;
  705.     int nOldMode = SetBkMode(hDC, TRANSPARENT);
  706.     COLORREF crTextColor = SetTextColor(hDC, afxData.clrBtnText);
  707.     COLORREF crBkColor = SetBkColor(hDC, afxData.clrBtnFace);
  708.  
  709.     // Draw the hilites
  710.     if (hbrHilite != NULL)
  711.     {
  712.         HGDIOBJ hOldBrush = SelectObject(hDC, hbrHilite);
  713.         if (hOldBrush)
  714.         {
  715.             PatBlt(hDC, rect.right, rect.bottom,
  716.                 -(rect.Width() - CX_BORDER),
  717.                 -CY_BORDER, PATCOPY);
  718.             PatBlt(hDC, rect.right, rect.bottom,
  719.                 -CX_BORDER,
  720.                 -(rect.Height() - CY_BORDER), PATCOPY);
  721.             SelectObject(hDC, hOldBrush);
  722.         }
  723.     }
  724.  
  725.     if (hbrShadow != NULL)
  726.     {
  727.         HGDIOBJ hOldBrush = SelectObject(hDC, hbrShadow);
  728.         if (hOldBrush)
  729.         {
  730.             PatBlt(hDC, rect.left, rect.top,
  731.                 rect.Width(), CY_BORDER, PATCOPY);
  732.             PatBlt(hDC, rect.left, rect.top,
  733.                 CX_BORDER, rect.Height(), PATCOPY);
  734.             SelectObject(hDC, hOldBrush);
  735.         }
  736.     }
  737.  
  738.     // We need to adjust the rect for the ExtTextOut, and then adjust it back
  739.  
  740.     // just support left justified text
  741.     if (lpszText != NULL && !(nStyle & SBPS_DISABLED))
  742.     {
  743.         CRect rectText(rect);
  744.         rectText.InflateRect(-2*CX_BORDER, -CY_BORDER);
  745.  
  746.         // align on bottom (since descent is more important than ascent)
  747.         SetTextAlign(hDC, TA_LEFT | TA_BOTTOM);
  748.         ExtTextOut(hDC, rectText.left, rectText.bottom,
  749.             nOpts, &rectText, lpszText, lstrlen(lpszText), NULL);
  750.     }
  751. }
  752.  
  753. /////////////////////////////////////////////////////////////////////////////
  754. // CStatusBar message handlers
  755.  
  756. BEGIN_MESSAGE_MAP(CStatusBar, CControlBar)
  757.     //{{AFX_MSG_MAP(CStatusBar)
  758.     // control messages
  759.     ON_WM_SIZE()
  760.     ON_MESSAGE(WM_SETFONT, OnSetFont)
  761.     ON_MESSAGE(WM_GETFONT, OnGetFont)
  762.     ON_MESSAGE(WM_SETTEXT, OnSetText)
  763.     ON_MESSAGE(WM_GETTEXT, OnGetText)
  764.     ON_MESSAGE(WM_GETTEXTLENGTH, OnGetTextLength)
  765.     //}}AFX_MSG_MAP
  766. END_MESSAGE_MAP()
  767.  
  768. void CStatusBar::OnSize(UINT, int, int)
  769. {
  770.     // force repaint on resize (recalculate stretchy)
  771.     Invalidate();
  772. }
  773.  
  774. LRESULT CStatusBar::OnSetFont(WPARAM wParam, LPARAM)
  775. {
  776.     m_hFont = (HFONT)wParam;
  777.     ASSERT(m_hFont != NULL);
  778.  
  779.     // recalculate based on font height + borders
  780.     TEXTMETRIC tm;
  781.     // get text metrics of font
  782.     {
  783.         CClientDC dcScreen(NULL);
  784.         HGDIOBJ hOldFont = dcScreen.SelectObject(m_hFont);
  785.         VERIFY(dcScreen.GetTextMetrics(&tm));
  786.         dcScreen.SelectObject(hOldFont);
  787.     }
  788.     CRect rectSize;
  789.     rectSize.SetRectEmpty();
  790.     CalcInsideRect(rectSize);       // will be negative size
  791.     m_sizeFixedLayout.cy = (tm.tmHeight - tm.tmInternalLeading) + 
  792.             CY_BORDER*3 /* 1 extra on top, 2 on bottom */ - rectSize.Height();
  793.     ASSERT(m_sizeFixedLayout.cx == 32767);  // max size
  794.  
  795.     return 0L;      // does not re-draw or invalidate - resize parent instead
  796. }
  797.  
  798.  
  799. LRESULT CStatusBar::OnGetFont(WPARAM, LPARAM)
  800. {
  801.     return (LRESULT)(UINT)m_hFont;
  802. }
  803.  
  804. LRESULT CStatusBar::OnSetText(WPARAM, LPARAM lParam)
  805. {
  806.     return SetPaneText(0, (LPCSTR)lParam) ? 0 : -1;
  807. }
  808.  
  809. LRESULT CStatusBar::OnGetText(WPARAM wParam, LPARAM lParam)
  810. {
  811.     int nMaxLen = (int)wParam;
  812.     if (nMaxLen == 0)
  813.         return 0;       // nothing copied
  814.     LPSTR lpszDest = (LPSTR)lParam;
  815.  
  816.     AFX_STATUSPANE* pSBP = _GetPanePtr(0);
  817.     int nLen = (pSBP != NULL && pSBP->lpszText != NULL) ?
  818.         lstrlen(pSBP->lpszText) : 0;
  819.     if (nLen > nMaxLen)
  820.         nLen = nMaxLen - 1;     // number of characters to copy (less term.)
  821.     _fmemcpy(lpszDest, pSBP->lpszText, nLen);
  822.     lpszDest[nLen] = '\0';
  823.     return nLen+1;      // number of bytes copied
  824. }
  825.  
  826. LRESULT CStatusBar::OnGetTextLength(WPARAM, LPARAM)
  827. {
  828.     AFX_STATUSPANE* pSBP = _GetPanePtr(0);
  829.     return (pSBP != NULL && pSBP->lpszText != NULL) ?
  830.         lstrlen(pSBP->lpszText) : 0;
  831. }
  832.  
  833. /////////////////////////////////////////////////////////////////////////////
  834. // CStatusBar idle update through CStatusCmdUI class
  835.  
  836. class CStatusCmdUI : public CCmdUI      // class private to this file !
  837. {
  838. public: // re-implementations only
  839.     virtual void Enable(BOOL bOn);
  840.     virtual void SetCheck(int nCheck);
  841.     virtual void SetText(LPCSTR lpszText);
  842. };
  843.  
  844. void CStatusCmdUI::Enable(BOOL bOn)
  845. {
  846.     m_bEnableChanged = TRUE;
  847.     CStatusBar* pStatusBar = (CStatusBar*)m_pOther;
  848.     ASSERT(pStatusBar != NULL);
  849.     ASSERT(pStatusBar->IsKindOf(RUNTIME_CLASS(CStatusBar)));
  850.     ASSERT(m_nIndex < m_nIndexMax);
  851.  
  852.     UINT nNewStyle = pStatusBar->_GetPaneStyle(m_nIndex) & ~SBPS_DISABLED;
  853.     if (!bOn)
  854.         nNewStyle |= SBPS_DISABLED;
  855.     pStatusBar->_SetPaneStyle(m_nIndex, nNewStyle);
  856. }
  857.  
  858. void CStatusCmdUI::SetCheck(int nCheck) // "checking" will pop out the text
  859. {
  860.     CStatusBar* pStatusBar = (CStatusBar*)m_pOther;
  861.     ASSERT(pStatusBar != NULL);
  862.     ASSERT(pStatusBar->IsKindOf(RUNTIME_CLASS(CStatusBar)));
  863.     ASSERT(m_nIndex < m_nIndexMax);
  864.  
  865.     UINT nNewStyle = pStatusBar->_GetPaneStyle(m_nIndex) & ~SBPS_POPOUT;
  866.     if (nCheck != 0)
  867.         nNewStyle |= SBPS_POPOUT;
  868.     pStatusBar->_SetPaneStyle(m_nIndex, nNewStyle);
  869. }
  870.  
  871. void CStatusCmdUI::SetText(LPCSTR lpszText)
  872. {
  873.     ASSERT(m_pOther != NULL);
  874.     ASSERT(m_pOther->IsKindOf(RUNTIME_CLASS(CStatusBar)));
  875.     ASSERT(m_nIndex < m_nIndexMax);
  876.  
  877.     ((CStatusBar*)m_pOther)->SetPaneText(m_nIndex, lpszText);
  878. }
  879.  
  880. void CStatusBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
  881. {
  882.     CStatusCmdUI state;
  883.     state.m_pOther = this;
  884.     state.m_nIndexMax = (UINT)m_nCount;
  885.     for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
  886.       state.m_nIndex++)
  887.     {
  888.         state.m_nID = _GetPanePtr(state.m_nIndex)->nID;
  889.         state.DoUpdate(pTarget, bDisableIfNoHndler);
  890.     }
  891.  
  892.     // update the dialog controls added to the status bar
  893.     UpdateDialogControls(pTarget, bDisableIfNoHndler);
  894. }
  895.  
  896. /////////////////////////////////////////////////////////////////////////////
  897. // CStatusBar diagnostics
  898.  
  899. #ifdef _DEBUG
  900. void CStatusBar::AssertValid() const
  901. {
  902.     CControlBar::AssertValid();
  903. }
  904.  
  905. void CStatusBar::Dump(CDumpContext& dc) const
  906. {
  907.     CControlBar::Dump(dc);
  908.  
  909.     AFX_DUMP1(dc, "\nm_cxRightBorder = ", m_cxRightBorder);
  910.     AFX_DUMP1(dc, "\nm_hFont = ", (UINT)m_hFont);
  911.  
  912.     if (dc.GetDepth() > 0)
  913.     {
  914.         for (int i = 0; i < m_nCount; i++)
  915.         {
  916.             AFX_DUMP1(dc, "status pane[", i); AFX_DUMP0(dc, "] = { ");
  917.             AFX_DUMP1(dc, "\n\tnID = ", _GetPanePtr(i)->nID);
  918.             AFX_DUMP1(dc, "\n\tnStyle = ", _GetPanePtr(i)->nStyle);
  919.             AFX_DUMP1(dc, "\n\tcxText = ", _GetPanePtr(i)->cxText);
  920.             AFX_DUMP1(dc, "\n\tlpszText = ", _GetPanePtr(i)->lpszText);
  921.             AFX_DUMP0(dc, "\n\t}");
  922.         }
  923.     }
  924. }
  925. #endif //_DEBUG
  926.  
  927.  
  928. /////////////////////////////////////////////////////////////////////////////
  929.