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 / toolbar.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-27  |  30.9 KB  |  1,172 lines

  1. // toolbar.cpp : definition of old backward compatible CToolBar
  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 "toolbar.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. // globals for fast drawing (shared globals)
  27. static HDC hDCGlyphs = NULL;
  28. static HDC hDCMono = NULL;
  29. static HBRUSH hbrDither = NULL;
  30.  
  31. /////////////////////////////////////////////////////////////////////////////
  32. // Init / Term
  33.  
  34. static HBITMAP AFXAPI CreateDitherBitmap();
  35.  
  36. #ifdef AFX_INIT_SEG
  37. #pragma code_seg(AFX_INIT_SEG)
  38. #endif
  39.  
  40.  
  41. // a special struct that will cleanup automatically
  42. struct _AFX_TOOLBAR_TERM
  43. {
  44.     ~_AFX_TOOLBAR_TERM()
  45.     {
  46.         AfxDeleteObject((HGDIOBJ*)&hDCMono);
  47.         AfxDeleteObject((HGDIOBJ*)&hDCGlyphs);
  48.         AfxDeleteObject((HGDIOBJ*)&hbrDither);
  49.     }
  50. };
  51.  
  52. static const _AFX_TOOLBAR_TERM toolbarTerm;
  53.  
  54. /////////////////////////////////////////////////////////////////////////////
  55.  
  56. #ifdef AFX_CORE3_SEG
  57. #pragma code_seg(AFX_CORE3_SEG)
  58. #endif
  59.  
  60. static HBITMAP AFXAPI CreateDitherBitmap()
  61. {
  62.     struct  // BITMAPINFO with 16 colors
  63.     {
  64.         BITMAPINFOHEADER bmiHeader;
  65.         RGBQUAD      bmiColors[16];
  66.     } bmi;
  67.     memset(&bmi, 0, sizeof(bmi));
  68.  
  69.     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  70.     bmi.bmiHeader.biWidth = 8;
  71.     bmi.bmiHeader.biHeight = 8;
  72.     bmi.bmiHeader.biPlanes = 1;
  73.     bmi.bmiHeader.biBitCount = 1;
  74.     bmi.bmiHeader.biCompression = BI_RGB;
  75.  
  76.     COLORREF clr = ::GetSysColor(COLOR_BTNFACE);
  77.     bmi.bmiColors[0].rgbBlue = GetBValue(clr);
  78.     bmi.bmiColors[0].rgbGreen = GetGValue(clr);
  79.     bmi.bmiColors[0].rgbRed = GetRValue(clr);
  80.  
  81.     clr = ::GetSysColor(COLOR_BTNHIGHLIGHT);
  82.     bmi.bmiColors[1].rgbBlue = GetBValue(clr);
  83.     bmi.bmiColors[1].rgbGreen = GetGValue(clr);
  84.     bmi.bmiColors[1].rgbRed = GetRValue(clr);
  85.  
  86.     // initialize the brushes
  87.     long patGray[8];
  88.     for (int i = 0; i < 8; i++)
  89.        patGray[i] = (i & 1) ? 0xAAAA5555L : 0x5555AAAAL;
  90.  
  91.     HDC hDC = GetDC(NULL);
  92.     HBITMAP hbm = CreateDIBitmap(hDC, &bmi.bmiHeader, CBM_INIT,
  93.         (LPBYTE)patGray, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS);
  94.     ReleaseDC(NULL, hDC);
  95.  
  96.     return hbm;
  97. }
  98.  
  99. // create a mono bitmap mask:
  100. void CToolBar::CreateMask(int iImage, CPoint ptOffset,
  101.      BOOL bHilite, BOOL bHiliteShadow)
  102. {
  103.     // initalize whole area with 0's
  104.     PatBlt(hDCMono, 0, 0, m_sizeButton.cx-2, m_sizeButton.cy-2, WHITENESS);
  105.  
  106.     // create mask based on color bitmap
  107.     // convert this to 1's
  108.     SetBkColor(hDCGlyphs, globalData.clrBtnFace);
  109.     BitBlt(hDCMono, ptOffset.x, ptOffset.y, m_sizeImage.cx, m_sizeImage.cy,
  110.         hDCGlyphs, iImage * m_sizeImage.cx, 0, SRCCOPY);
  111.  
  112.     if (bHilite)
  113.     {
  114.         // convert this to 1's
  115.         SetBkColor(hDCGlyphs, globalData.clrBtnHilite);
  116.  
  117.         // OR in the new 1's
  118.         BitBlt(hDCMono, ptOffset.x, ptOffset.y, m_sizeImage.cx, m_sizeImage.cy,
  119.             hDCGlyphs, iImage * m_sizeImage.cx, 0, SRCPAINT);
  120.  
  121.         if (bHiliteShadow)
  122.             BitBlt(hDCMono, 1, 1, m_sizeButton.cx-3, m_sizeButton.cy-3,
  123.                 hDCMono, 0, 0, SRCAND);
  124.     }
  125. }
  126.  
  127. // Raster Ops
  128. #define ROP_DSPDxax  0x00E20746L
  129. #define ROP_PSDPxax  0x00B8074AL
  130.  
  131. BOOL CToolBar::DrawButton(CDC* pDC, int x, int y, int iImage, UINT nStyle)
  132. {
  133.     ASSERT_VALID(pDC);
  134.  
  135.     int dx = m_sizeButton.cx;
  136.     int dy = m_sizeButton.cy;
  137.     if (!globalData.bWin4)
  138.     {
  139.         // make the coordinates the interior of the button
  140.         x += 1;
  141.         y += 1;
  142.         dx -= 2;
  143.         dy -= 2;
  144.  
  145.         // border around button
  146.         pDC->FillSolidRect(x,    y-1,    dx, 1,  globalData.clrWindowFrame);
  147.         pDC->FillSolidRect(x,    y+dy,   dx, 1,  globalData.clrWindowFrame);
  148.         pDC->FillSolidRect(x-1,  y,  1,  dy, globalData.clrWindowFrame);
  149.         pDC->FillSolidRect(x+dx, y,  1,  dy, globalData.clrWindowFrame);
  150.     }
  151.  
  152.     // interior grey
  153.     pDC->FillSolidRect(x, y, dx, dy, globalData.clrBtnFace);
  154.  
  155.     // determine offset of bitmap (centered within button)
  156.     CPoint ptOffset;
  157.     ptOffset.x = (dx - m_sizeImage.cx - 1) / 2;
  158.     ptOffset.y = (dy - m_sizeImage.cy) / 2;
  159.  
  160.     if (nStyle & (TBBS_PRESSED | TBBS_CHECKED))
  161.     {
  162.         // pressed in or checked
  163.         pDC->Draw3dRect(x, y, dx, dy,
  164.             globalData.bWin4 ? globalData.clrWindowFrame : globalData.clrBtnShadow,
  165.             globalData.bWin4 ? globalData.clrBtnHilite : globalData.clrBtnFace);
  166.  
  167.         if (globalData.bWin4)
  168.         {
  169.             pDC->Draw3dRect(x + 1, y + 1, dx - 2, dy - 2,
  170.                 globalData.clrBtnShadow, globalData.clrBtnFace);
  171.         }
  172.  
  173.         // for any depressed button, add one to the offsets.
  174.         ptOffset.x += 1;
  175.         ptOffset.y += 1;
  176.     }
  177.     else
  178.     {
  179.         // regular button look
  180.         pDC->Draw3dRect(x, y, dx, dy, globalData.clrBtnHilite,
  181.             globalData.bWin4 ? globalData.clrWindowFrame : globalData.clrBtnShadow);
  182.         pDC->Draw3dRect(x + 1, y + 1, dx - 2, dy - 2,
  183.             globalData.clrBtnFace, globalData.clrBtnShadow);
  184.     }
  185.  
  186.     if ((nStyle & TBBS_PRESSED) || !(nStyle & TBBS_DISABLED))
  187.     {
  188.         // normal image version
  189.         BitBlt(pDC->m_hDC, x + ptOffset.x, y + ptOffset.y,
  190.             m_sizeImage.cx, m_sizeImage.cy,
  191.             hDCGlyphs, iImage * m_sizeImage.cx, 0, SRCCOPY);
  192.  
  193.         if (nStyle & TBBS_PRESSED)
  194.             return TRUE;        // nothing more to do (rest of style is ignored)
  195.     }
  196.  
  197.     if (nStyle & (TBBS_DISABLED | TBBS_INDETERMINATE))
  198.     {
  199.         // disabled or indeterminate version
  200.         CreateMask(iImage, ptOffset, TRUE, FALSE);
  201.  
  202.         pDC->SetTextColor(0L);                  // 0's in mono -> 0 (for ROP)
  203.         pDC->SetBkColor((COLORREF)0x00FFFFFFL); // 1's in mono -> 1
  204.  
  205.         if (nStyle & TBBS_DISABLED)
  206.         {
  207.             // disabled - draw the hilighted shadow
  208.             HGDIOBJ hbrOld = pDC->SelectObject(globalData.hbrBtnHilite);
  209.             if (hbrOld != NULL)
  210.             {
  211.                 // draw hilight color where we have 0's in the mask
  212.                 BitBlt(pDC->m_hDC, x + 1, y + 1,
  213.                     m_sizeButton.cx - 2, m_sizeButton.cy - 2,
  214.                     hDCMono, 0, 0, ROP_PSDPxax);
  215.                 pDC->SelectObject(hbrOld);
  216.             }
  217.         }
  218.  
  219.         //BLOCK: always draw the shadow
  220.         {
  221.             HGDIOBJ hbrOld = pDC->SelectObject(globalData.hbrBtnShadow);
  222.             if (hbrOld != NULL)
  223.             {
  224.                 // draw the shadow color where we have 0's in the mask
  225.                 BitBlt(pDC->m_hDC, x, y,
  226.                     m_sizeButton.cx - 2, m_sizeButton.cy - 2,
  227.                     hDCMono, 0, 0, ROP_PSDPxax);
  228.                 pDC->SelectObject(hbrOld);
  229.             }
  230.         }
  231.     }
  232.  
  233.     // if it is checked do the dither brush avoiding the glyph
  234.     if (nStyle & (TBBS_CHECKED | TBBS_INDETERMINATE))
  235.     {
  236.         HGDIOBJ hbrOld = pDC->SelectObject(hbrDither);
  237.         if (hbrOld != NULL)
  238.         {
  239.             ptOffset.x -= globalData.cxBorder2;
  240.             ptOffset.y -= globalData.cyBorder2;
  241.             CreateMask(iImage, ptOffset, ~(nStyle & TBBS_INDETERMINATE),
  242.                     nStyle & TBBS_DISABLED);
  243.  
  244.             pDC->SetTextColor(0L);              // 0 -> 0
  245.             pDC->SetBkColor((COLORREF)0x00FFFFFFL); // 1 -> 1
  246.  
  247.             ASSERT(globalData.cxBorder2 == globalData.cyBorder2);
  248.             int delta = (nStyle & TBBS_INDETERMINATE) ?
  249.                 globalData.bWin4 ? globalData.cxBorder2*2 : 3 : globalData.cxBorder2*2;
  250.  
  251.             // only draw the dither brush where the mask is 1's
  252.             BitBlt(pDC->m_hDC,
  253.                 x + globalData.cxBorder2, y + globalData.cyBorder2, dx-delta, dy-delta,
  254.                 hDCMono, 0, 0, ROP_DSPDxax);
  255.             pDC->SelectObject(hbrOld);
  256.         }
  257.     }
  258.  
  259.     return TRUE;
  260. }
  261.  
  262. BOOL CToolBar::PrepareDrawButton(DrawState& ds)
  263. {
  264.     ASSERT(m_hbmImageWell != NULL);
  265.     ASSERT(m_sizeButton.cx > 2 && m_sizeButton.cy > 2);
  266.  
  267.     // We need to kick-start the bitmap selection process.
  268.     ds.hbmOldGlyphs = (HBITMAP)SelectObject(hDCGlyphs, m_hbmImageWell);
  269.     ds.hbmMono = CreateBitmap(m_sizeButton.cx-2, m_sizeButton.cy-2,
  270.                     1, 1, NULL);
  271.     ds.hbmMonoOld = (HBITMAP)SelectObject(hDCMono, ds.hbmMono);
  272.     if (ds.hbmOldGlyphs == NULL || ds.hbmMono == NULL || ds.hbmMonoOld == NULL)
  273.     {
  274.         TRACE0("Error: can't draw toolbar.\n");
  275.         AfxDeleteObject((HGDIOBJ*)&ds.hbmMono);
  276.         return FALSE;
  277.     }
  278.     return TRUE;
  279. }
  280.  
  281. void CToolBar::EndDrawButton(DrawState& ds)
  282. {
  283.     SelectObject(hDCMono, ds.hbmMonoOld);
  284.     AfxDeleteObject((HGDIOBJ*)&ds.hbmMono);
  285.     SelectObject(hDCGlyphs, ds.hbmOldGlyphs);
  286. }
  287.  
  288. /////////////////////////////////////////////////////////////////////////////
  289. // CToolBar creation etc
  290.  
  291. struct AFX_TBBUTTON
  292. {
  293.     UINT nID;        // Command ID that this button sends
  294.     UINT nStyle;    // TBBS_ styles
  295.     int iImage;     // index into mondo bitmap of this button's picture
  296.                         // or size of this spacer
  297. };
  298.  
  299. inline AFX_TBBUTTON* CToolBar::_GetButtonPtr(int nIndex) const
  300. {
  301.     ASSERT(nIndex >= 0 && nIndex < m_nCount);
  302.     ASSERT(m_pData != NULL);
  303.     return ((AFX_TBBUTTON*)m_pData) + nIndex;
  304. }
  305.  
  306. /*
  307.     DIBs use RGBQUAD format:
  308.         0xbb 0xgg 0xrr 0x00
  309.  
  310.     Reasonably efficient code to convert a COLORREF into an
  311.     RGBQUAD is byte-order-dependent, so we need different
  312.     code depending on the byte order we're targeting.
  313. */
  314. #define RGB_TO_RGBQUAD(r,g,b)   (RGB(b,g,r))
  315. #define CLR_TO_RGBQUAD(clr)     (RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)))
  316.  
  317. HBITMAP AFXAPI LoadSysColorBitmap(HINSTANCE hInst, HRSRC hRsrc)
  318. {
  319.     struct COLORMAP
  320.     {
  321.         // use DWORD instead of RGBQUAD so we can compare two RGBQUADs easily
  322.         DWORD rgbqFrom;
  323.         int iSysColorTo;
  324.     };
  325.     static const COLORMAP sysColorMap[] =
  326.     {
  327.         // mapping from color in DIB to system color
  328.         { RGB_TO_RGBQUAD(0x00, 0x00, 0x00),  COLOR_BTNTEXT },       // black
  329.         { RGB_TO_RGBQUAD(0x80, 0x80, 0x80),  COLOR_BTNSHADOW },     // dark grey
  330.         { RGB_TO_RGBQUAD(0xC0, 0xC0, 0xC0),  COLOR_BTNFACE },       // bright grey
  331.         { RGB_TO_RGBQUAD(0xFF, 0xFF, 0xFF),  COLOR_BTNHIGHLIGHT }   // white
  332.     };
  333.     const int nMaps = 4;
  334.  
  335.     HGLOBAL hglb;
  336.     if ((hglb = ::LoadResource(hInst, hRsrc)) == NULL)
  337.         return NULL;
  338.  
  339.     LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglb);
  340.     if (lpBitmap == NULL)
  341.         return NULL;
  342.  
  343.     // make copy of BITMAPINFOHEADER so we can modify the color table
  344.     const int nColorTableSize = 16;
  345.     UINT nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
  346.     LPBITMAPINFOHEADER lpBitmapInfo = (LPBITMAPINFOHEADER)::malloc(nSize);
  347.     if (lpBitmapInfo == NULL)
  348.         return NULL;
  349.     memcpy(lpBitmapInfo, lpBitmap, nSize);
  350.  
  351.     // color table is in RGBQUAD DIB format
  352.     DWORD* pColorTable =
  353.         (DWORD*)(((LPBYTE)lpBitmapInfo) + (UINT)lpBitmapInfo->biSize);
  354.  
  355.     for (int iColor = 0; iColor < nColorTableSize; iColor++)
  356.     {
  357.         // look for matching RGBQUAD color in original
  358.         for (int i = 0; i < nMaps; i++)
  359.         {
  360.             if (pColorTable[iColor] == sysColorMap[i].rgbqFrom)
  361.             {
  362.                 pColorTable[iColor] =
  363.                     CLR_TO_RGBQUAD(::GetSysColor(sysColorMap[i].iSysColorTo));
  364.                 break;
  365.             }
  366.         }
  367.     }
  368.  
  369.     int nWidth = (int)lpBitmapInfo->biWidth;
  370.     int nHeight = (int)lpBitmapInfo->biHeight;
  371.     HDC hDCScreen = ::GetDC(NULL);
  372.     HBITMAP hbm = ::CreateCompatibleBitmap(hDCScreen, nWidth, nHeight);
  373.     ::ReleaseDC(NULL, hDCScreen);
  374.  
  375.     if (hbm != NULL)
  376.     {
  377.         HBITMAP hbmOld = (HBITMAP)::SelectObject(hDCGlyphs, hbm);
  378.  
  379.         LPBYTE lpBits;
  380.         lpBits = (LPBYTE)(lpBitmap + 1);
  381.         lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
  382.  
  383.         StretchDIBits(hDCGlyphs, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
  384.             lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
  385.         SelectObject(hDCGlyphs, hbmOld);
  386.     }
  387.  
  388.     // free copy of bitmap info struct and resource itself
  389.     ::free(lpBitmapInfo);
  390.     ::FreeResource(hglb);
  391.  
  392.     return hbm;
  393. }
  394.  
  395. #ifdef AFX_INIT_SEG
  396. #pragma code_seg(AFX_INIT_SEG)
  397. #endif
  398.  
  399. CToolBar::CToolBar()
  400. {
  401.     m_hbmImageWell = NULL;
  402.     m_hInstImageWell = NULL;
  403.     m_hRsrcImageWell = NULL;
  404.     m_iButtonCapture = -1;      // nothing captured
  405.  
  406.     // UISG standard sizes
  407.     m_sizeButton.cx = 24;
  408.     m_sizeButton.cy = 22;
  409.     m_sizeImage.cx = 16;
  410.     m_sizeImage.cy = 15;
  411.     m_cyTopBorder = m_cyBottomBorder = 3;   // 3 pixel for top/bottom gaps
  412.  
  413.     // adjust sizes when running on Win4
  414.     if (globalData.bWin4)
  415.     {
  416.         m_sizeButton.cx = 23;
  417.         m_cySharedBorder = m_cxSharedBorder = 0;
  418.         m_cxDefaultGap = 8;
  419.     }
  420.     else
  421.     {
  422.         m_cxDefaultGap = 6;
  423.         m_cySharedBorder = m_cxSharedBorder = 1;
  424.     }
  425.  
  426.     // initialize the toolbar drawing engine
  427.     static BOOL bInitialized;
  428.     if (!bInitialized)
  429.     {
  430.         hDCGlyphs = CreateCompatibleDC(NULL);
  431.  
  432.         // Mono DC and Bitmap for disabled image
  433.         hDCMono = ::CreateCompatibleDC(NULL);
  434.  
  435.         HBITMAP hbmGray = ::CreateDitherBitmap();
  436.         if (hbmGray != NULL)
  437.         {
  438.             ASSERT(hbrDither == NULL);
  439.             hbrDither = ::CreatePatternBrush(hbmGray);
  440.             AfxDeleteObject((HGDIOBJ*)&hbmGray);
  441.         }
  442.  
  443.         if (hDCGlyphs == NULL || hDCMono == NULL || hbrDither == NULL)
  444.             AfxThrowResourceException();
  445.         bInitialized = TRUE;
  446.     }
  447. }
  448.  
  449. CToolBar::~CToolBar()
  450. {
  451.     AfxDeleteObject((HGDIOBJ*)&m_hbmImageWell);
  452. }
  453.  
  454. BOOL CToolBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
  455. {
  456.     if (pParentWnd != NULL)
  457.         ASSERT_VALID(pParentWnd);   // must have a parent
  458.  
  459.     // save the style
  460.     m_dwStyle = (dwStyle & CBRS_ALL);
  461.     if (nID == AFX_IDW_TOOLBAR)
  462.         m_dwStyle |= CBRS_HIDE_INPLACE;
  463.  
  464.     // create the HWND
  465.     CRect rect;
  466.     rect.SetRectEmpty();
  467.     LPCTSTR lpszClass = AfxRegisterWndClass(0, ::LoadCursor(NULL, IDC_ARROW),
  468.         (HBRUSH)(COLOR_BTNFACE+1), NULL);
  469.     if (!CWnd::Create(lpszClass, NULL, dwStyle, rect, pParentWnd, nID))
  470.         return FALSE;
  471.  
  472.     // Note: Parent must resize itself for control bar to be resized
  473.  
  474.     return TRUE;
  475. }
  476.  
  477. void CToolBar::SetSizes(SIZE sizeButton, SIZE sizeImage)
  478. {
  479.     ASSERT_VALID(this);
  480.     ASSERT(sizeButton.cx > 0 && sizeButton.cy > 0);
  481.     ASSERT(sizeImage.cx > 0 && sizeImage.cy > 0);
  482.  
  483.     // button must be big enough to hold image + 3 pixels on each side
  484.     ASSERT(sizeButton.cx >= sizeImage.cx + 6);
  485.     ASSERT(sizeButton.cy >= sizeImage.cy + 6);
  486.  
  487.     m_sizeButton = sizeButton;
  488.     m_sizeImage = sizeImage;
  489.  
  490.     // set height
  491.     Invalidate();   // just to be nice if called when toolbar is visible
  492. }
  493.  
  494. void CToolBar::SetHeight(int cyHeight)
  495. {
  496.     ASSERT_VALID(this);
  497.  
  498.     int nHeight = cyHeight;
  499.     if (m_dwStyle & CBRS_BORDER_TOP)
  500.         cyHeight -= globalData.cyBorder2;
  501.     if (m_dwStyle & CBRS_BORDER_BOTTOM)
  502.         cyHeight -= globalData.cyBorder2;
  503.     m_cyBottomBorder = (cyHeight - m_sizeButton.cy) / 2;
  504.     // if there is an extra pixel, m_cyTopBorder will get it
  505.     m_cyTopBorder = cyHeight - m_sizeButton.cy - m_cyBottomBorder;
  506.     if (m_cyTopBorder < 0)
  507.     {
  508.         TRACE1("Warning: CToolBar::SetHeight(%d) is smaller than button.\n",
  509.             nHeight);
  510.         m_cyBottomBorder += m_cyTopBorder;
  511.         m_cyTopBorder = 0;  // will clip at bottom
  512.     }
  513.     // bottom border will be ignored (truncate as needed)
  514.     Invalidate();   // just to be nice if called when toolbar is visible
  515. }
  516.  
  517. BOOL CToolBar::LoadBitmap(UINT nIDBitmap)
  518. {
  519.     return LoadBitmap(MAKEINTRESOURCE(nIDBitmap));
  520. }
  521.  
  522. BOOL CToolBar::LoadBitmap(LPCTSTR lpszResourceName)
  523. {
  524.     ASSERT_VALID(this);
  525.     ASSERT(lpszResourceName != NULL);
  526.  
  527.     AfxDeleteObject((HGDIOBJ*)&m_hbmImageWell);     // get rid of old one
  528.  
  529.     m_hInstImageWell = AfxFindResourceHandle(lpszResourceName, RT_BITMAP);
  530.     if ((m_hRsrcImageWell = ::FindResource(m_hInstImageWell,
  531.         lpszResourceName, RT_BITMAP)) == NULL)
  532.         return FALSE;
  533.  
  534.     m_hbmImageWell = LoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell);
  535.     return (m_hbmImageWell != NULL);
  536. }
  537.  
  538. BOOL CToolBar::SetButtons(const UINT* lpIDArray, int nIDCount)
  539. {
  540.     ASSERT_VALID(this);
  541.     ASSERT(nIDCount >= 1);  // must be at least one of them
  542.     ASSERT(lpIDArray == NULL ||
  543.         AfxIsValidAddress(lpIDArray, sizeof(UINT) * nIDCount, FALSE));
  544.  
  545.     // first allocate array for panes and copy initial data
  546.     if (!AllocElements(nIDCount, sizeof(AFX_TBBUTTON)))
  547.         return FALSE;
  548.     ASSERT(nIDCount == m_nCount);
  549.  
  550.     if (lpIDArray != NULL)
  551.     {
  552.         int iImage = 0;
  553.         // go through them adding buttons
  554.         AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
  555.         for (int i = 0; i < nIDCount; i++, pTBB++)
  556.         {
  557.             ASSERT(pTBB != NULL);
  558.             if ((pTBB->nID = *lpIDArray++) == 0)
  559.             {
  560.                 // separator
  561.                 pTBB->nStyle = TBBS_SEPARATOR;
  562.                 // width of separator includes 2 pixel overlap
  563.                 pTBB->iImage = m_cxDefaultGap + m_cxSharedBorder * 2;
  564.             }
  565.             else
  566.             {
  567.                 // a command button with image
  568.                 pTBB->nStyle = TBBS_BUTTON;
  569.                 pTBB->iImage = iImage++;
  570.             }
  571.         }
  572.     }
  573.     return TRUE;
  574. }
  575.  
  576. #ifdef AFX_CORE3_SEG
  577. #pragma code_seg(AFX_CORE3_SEG)
  578. #endif
  579.  
  580. /////////////////////////////////////////////////////////////////////////////
  581. // CToolBar attribute access
  582.  
  583. int CToolBar::CommandToIndex(UINT nIDFind) const
  584. {
  585.     ASSERT_VALID(this);
  586.  
  587.     AFX_TBBUTTON* pTBB = _GetButtonPtr(0);
  588.     for (int i = 0; i < m_nCount; i++, pTBB++)
  589.         if (pTBB->nID == nIDFind)
  590.             return i;
  591.     return -1;
  592. }
  593.  
  594. UINT CToolBar::GetItemID(int nIndex) const
  595. {
  596.     ASSERT_VALID(this);
  597.  
  598.     return _GetButtonPtr(nIndex)->nID;
  599. }
  600.  
  601. void CToolBar::GetItemRect(int nIndex, LPRECT lpRect) const
  602. {
  603.     ASSERT_VALID(this);
  604.     ASSERT(nIndex >= 0 && nIndex < m_nCount);
  605.     ASSERT(AfxIsValidAddress(lpRect, sizeof(RECT)));
  606.  
  607.     BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) ? TRUE : FALSE;
  608.     CRect rect;
  609.     rect.SetRectEmpty();        // only need top and left
  610.     CalcInsideRect(rect, bHorz);
  611.     AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
  612.     for (int iButton = 0; iButton < nIndex; iButton++, pTBB++)
  613.     {
  614.         ASSERT(pTBB != NULL);
  615.         // skip this button or separator
  616.         if (bHorz)
  617.         {
  618.             rect.left += (pTBB->nStyle & TBBS_SEPARATOR) ?
  619.                         pTBB->iImage : m_sizeButton.cx;
  620.             rect.left -= m_cxSharedBorder;    // go back for overlap
  621.         }
  622.         else
  623.         {
  624.             rect.top += (pTBB->nStyle & TBBS_SEPARATOR) ?
  625.                         pTBB->iImage : m_sizeButton.cy;
  626.             rect.top -= m_cySharedBorder;    // go back for overlap
  627.         }
  628.     }
  629.     ASSERT(iButton == nIndex);
  630.     ASSERT(pTBB == _GetButtonPtr(nIndex));
  631.  
  632.     // button or image width
  633.     if (bHorz)
  634.     {
  635.         int cx = (pTBB->nStyle & TBBS_SEPARATOR) ? pTBB->iImage : m_sizeButton.cx;
  636.         lpRect->right = (lpRect->left = rect.left) + cx;
  637.         lpRect->bottom = (lpRect->top = rect.top) + m_sizeButton.cy;
  638.     }
  639.     else
  640.     {
  641.         int cy = (pTBB->nStyle & TBBS_SEPARATOR) ? pTBB->iImage : m_sizeButton.cy;
  642.         lpRect->bottom = (lpRect->top = rect.top) + cy;
  643.         lpRect->right = (lpRect->left = rect.left) + m_sizeButton.cx;
  644.     }
  645. }
  646.  
  647. UINT CToolBar::GetButtonStyle(int nIndex) const
  648. {
  649.     return _GetButtonPtr(nIndex)->nStyle;
  650. }
  651.  
  652. void CToolBar::SetButtonStyle(int nIndex, UINT nStyle)
  653. {
  654.     AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
  655.     UINT nOldStyle = pTBB->nStyle;
  656.     if (nOldStyle != nStyle)
  657.     {
  658.         // update the style and invalidate
  659.         pTBB->nStyle = nStyle;
  660.  
  661.         // invalidate the button only if both styles not "pressed"
  662.         if (!(nOldStyle & nStyle & TBBS_PRESSED))
  663.             InvalidateButton(nIndex);
  664.     }
  665. }
  666.  
  667. CSize CToolBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
  668. {
  669.     ASSERT_VALID(this);
  670.  
  671.     CSize size = CControlBar::CalcFixedLayout(bStretch, bHorz);
  672.  
  673.     CRect rect;
  674.     rect.SetRectEmpty();        // only need top and left
  675.     CalcInsideRect(rect, bHorz);
  676.     AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
  677.     int nButtonDist = 0;
  678.  
  679.     if (!bStretch)
  680.     {
  681.         for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
  682.         {
  683.             ASSERT(pTBB != NULL);
  684.             // skip this button or separator
  685.             nButtonDist += (pTBB->nStyle & TBBS_SEPARATOR) ?
  686.                 pTBB->iImage : (bHorz ? m_sizeButton.cx : m_sizeButton.cy);
  687.             // go back one for overlap
  688.             nButtonDist -= bHorz ? m_cxSharedBorder : m_cySharedBorder;
  689.         }
  690.         if (bHorz)
  691.             size.cx = nButtonDist - rect.Width() + m_cxSharedBorder;
  692.         else
  693.             size.cy = nButtonDist - rect.Height() + m_cySharedBorder;
  694.     }
  695.  
  696.     if (bHorz)
  697.         size.cy = m_sizeButton.cy - rect.Height(); // rect.Height() < 0
  698.     else
  699.         size.cx = m_sizeButton.cx - rect.Width(); // rect.Width() < 0
  700.  
  701.     return size;
  702. }
  703.  
  704. void CToolBar::GetButtonInfo(int nIndex, UINT& nID, UINT& nStyle, int& iImage) const
  705. {
  706.     ASSERT_VALID(this);
  707.  
  708.     AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
  709.     nID = pTBB->nID;
  710.     nStyle = pTBB->nStyle;
  711.     iImage = pTBB->iImage;
  712. }
  713.  
  714. void CToolBar::SetButtonInfo(int nIndex, UINT nID, UINT nStyle, int iImage)
  715. {
  716.     ASSERT_VALID(this);
  717.  
  718.     AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
  719.     pTBB->nID = nID;
  720.     pTBB->iImage = iImage;
  721.     pTBB->nStyle = nStyle;
  722.     InvalidateButton(nIndex);
  723. }
  724.  
  725. void CToolBar::DoPaint(CDC* pDC)
  726. {
  727.     ASSERT_VALID(this);
  728.     ASSERT_VALID(pDC);
  729.  
  730.     CControlBar::DoPaint(pDC);      // draw border
  731.  
  732.     // if no toolbar loaded, don't draw any buttons
  733.     if (m_hbmImageWell == NULL)
  734.         return;
  735.  
  736.     BOOL bHorz = m_dwStyle & CBRS_ORIENT_HORZ ? TRUE : FALSE;
  737.     CRect rect;
  738.     GetClientRect(rect);
  739.     CalcInsideRect(rect, bHorz);
  740.  
  741.     // force the full size of the button
  742.     if (bHorz)
  743.         rect.bottom = rect.top + m_sizeButton.cy;
  744.     else
  745.         rect.right = rect.left + m_sizeButton.cx;
  746.  
  747.     DrawState ds;
  748.     if (!PrepareDrawButton(ds))
  749.         return;     // something went wrong
  750.  
  751.     AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
  752.     for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
  753.     {
  754.         ASSERT(pTBB != NULL);
  755.         if (pTBB->nStyle & TBBS_SEPARATOR)
  756.         {
  757.             // separator
  758.             if (bHorz)
  759.                 rect.right = rect.left + pTBB->iImage;
  760.             else
  761.                 rect.bottom = rect.top + pTBB->iImage;
  762.         }
  763.         else
  764.         {
  765.             if (bHorz)
  766.                 rect.right = rect.left + m_sizeButton.cx;
  767.             else
  768.                 rect.bottom = rect.top + m_sizeButton.cy;
  769.             if (!globalData.bWin32s || pDC->RectVisible(&rect))
  770.             {
  771.                 DrawButton(pDC, rect.left, rect.top,
  772.                     pTBB->iImage, pTBB->nStyle);
  773.             }
  774.         }
  775.         // adjust for overlap
  776.         if (bHorz)
  777.             rect.left = rect.right - m_cxSharedBorder;
  778.         else
  779.             rect.top = rect.bottom - m_cySharedBorder;
  780.     }
  781.     EndDrawButton(ds);
  782. }
  783.  
  784. void CToolBar::InvalidateButton(int nIndex)
  785. {
  786.     ASSERT_VALID(this);
  787.  
  788.     CRect rect;
  789.     GetItemRect(nIndex, &rect);
  790.     InvalidateRect(rect, FALSE);    // don't erase background
  791. }
  792.  
  793. int CToolBar::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
  794. {
  795.     ASSERT_VALID(this);
  796.  
  797.     // check child windows first by calling CControlBar
  798.     int nHit = CControlBar::OnToolHitTest(point, pTI);
  799.     if (nHit != -1)
  800.         return nHit;
  801.  
  802.     // now hit test against CToolBar buttons
  803.     nHit = ((CToolBar*)this)->HitTest(point);
  804.     if (nHit != -1)
  805.     {
  806.         AFX_TBBUTTON* pTBB = _GetButtonPtr(nHit);
  807.         if (pTI != NULL)
  808.         {
  809.             GetItemRect(nHit, &pTI->rect);
  810.             pTI->uId = pTBB->nID;
  811.             pTI->hwnd = m_hWnd;
  812.             pTI->lpszText = LPSTR_TEXTCALLBACK;
  813.         }
  814.         nHit = pTBB->nID;
  815.     }
  816.     return nHit;
  817. }
  818.  
  819. int CToolBar::HitTest(CPoint point) // in window relative coords
  820. {
  821.     if (m_pData == NULL)
  822.         return -1;  // no buttons
  823.  
  824.     BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) ? TRUE : FALSE;
  825.     CRect rect;
  826.     rect.SetRectEmpty();        // only need top and left
  827.     CalcInsideRect(rect, bHorz);
  828.     AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
  829.     ASSERT(pTBB != NULL);
  830.     if (bHorz)
  831.     {
  832.         if (point.y < rect.top || point.y >= rect.top + m_sizeButton.cy)
  833.             return -1;      // no Y hit
  834.         for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
  835.         {
  836.             if (point.x < rect.left)
  837.                 break;      // missed it
  838.             rect.left += (pTBB->nStyle & TBBS_SEPARATOR) ?
  839.                             pTBB->iImage : m_sizeButton.cx;
  840.             if (point.x < rect.left && !(pTBB->nStyle & TBBS_SEPARATOR))
  841.                 return iButton;     // hit !
  842.             rect.left -= m_cxSharedBorder;    // go back for overlap
  843.         }
  844.     }
  845.     else
  846.     {
  847.         if (point.x < rect.left || point.x >= rect.left + m_sizeButton.cx)
  848.             return -1;      // no X hit
  849.         for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
  850.         {
  851.             if (point.y < rect.top)
  852.                 break;      // missed it
  853.             rect.top += (pTBB->nStyle & TBBS_SEPARATOR) ?
  854.                             pTBB->iImage : m_sizeButton.cy;
  855.             if (point.y < rect.top && !(pTBB->nStyle & TBBS_SEPARATOR))
  856.                 return iButton;     // hit !
  857.             rect.top -= m_cySharedBorder;    // go back for overlap
  858.         }
  859.     }
  860.  
  861.     return -1;      // nothing hit
  862. }
  863.  
  864. /////////////////////////////////////////////////////////////////////////////
  865. // CToolBar message handlers
  866.  
  867. BEGIN_MESSAGE_MAP(CToolBar, CControlBar)
  868.     //{{AFX_MSG_MAP(CToolBar)
  869.     ON_WM_LBUTTONDOWN()
  870.     ON_WM_MOUSEMOVE()
  871.     ON_WM_LBUTTONUP()
  872.     ON_WM_CANCELMODE()
  873.     ON_WM_SYSCOLORCHANGE()
  874.     //}}AFX_MSG_MAP
  875. END_MESSAGE_MAP()
  876.  
  877. void CToolBar::OnLButtonDown(UINT nFlags, CPoint point)
  878. {
  879.     if ((m_iButtonCapture = HitTest(point)) < 0) // nothing hit
  880.     {
  881.         CControlBar::OnLButtonDown(nFlags, point);
  882.         return;
  883.     }
  884.  
  885.     AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
  886.     ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
  887.  
  888.     // update the button before checking for disabled status
  889.     UpdateButton(m_iButtonCapture);
  890.     if (pTBB->nStyle & TBBS_DISABLED)
  891.     {
  892.         m_iButtonCapture = -1;
  893.         return;     // don't press it
  894.     }
  895.  
  896.     pTBB->nStyle |= TBBS_PRESSED;
  897.     InvalidateButton(m_iButtonCapture);
  898.     UpdateWindow(); // immediate feedback
  899.     SetCapture();
  900.     GetOwner()->SendMessage(WM_SETMESSAGESTRING, (WPARAM)pTBB->nID);
  901. }
  902.  
  903. void CToolBar::OnMouseMove(UINT /*nFlags*/, CPoint point)
  904. {
  905.     if (m_iButtonCapture >= 0)
  906.     {
  907.         AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
  908.         ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
  909.  
  910.         UINT nNewStyle = (pTBB->nStyle & ~TBBS_PRESSED);
  911.         int iButtonCapture = m_iButtonCapture;
  912.         if (GetCapture() != this)
  913.         {
  914.             m_iButtonCapture = -1; // lost capture
  915.             GetOwner()->SendMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
  916.         }
  917.         else
  918.         {
  919.             // should be pressed if still hitting the captured button
  920.             if (HitTest(point) == m_iButtonCapture)
  921.                 nNewStyle |= TBBS_PRESSED;
  922.         }
  923.         SetButtonStyle(iButtonCapture, nNewStyle);
  924.         UpdateWindow(); // immediate feedback
  925.     }
  926. }
  927.  
  928. void CToolBar::OnLButtonUp(UINT nFlags, CPoint point)
  929. {
  930.     if (m_iButtonCapture < 0)
  931.     {
  932.         CControlBar::OnLButtonUp(nFlags, point);
  933.         return;     // not captured
  934.     }
  935.  
  936.     AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
  937.     ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
  938.     UINT nIDCmd = 0;
  939.  
  940.     UINT nNewStyle = (pTBB->nStyle & ~TBBS_PRESSED);
  941.     if (GetCapture() == this)
  942.     {
  943.         // we did not lose the capture
  944.         ReleaseCapture();
  945.         if (HitTest(point) == m_iButtonCapture)
  946.         {
  947.             // give button a chance to update
  948.             UpdateButton(m_iButtonCapture);
  949.  
  950.             // then check for disabled state
  951.             if (!(pTBB->nStyle & TBBS_DISABLED))
  952.             {
  953.                 // pressed, will send command notification
  954.                 nIDCmd = pTBB->nID;
  955.  
  956.                 if (pTBB->nStyle & TBBS_CHECKBOX)
  957.                 {
  958.                     // auto check: three state => down
  959.                     if (nNewStyle & TBBS_INDETERMINATE)
  960.                         nNewStyle &= ~TBBS_INDETERMINATE;
  961.  
  962.                     nNewStyle ^= TBBS_CHECKED;
  963.                 }
  964.             }
  965.         }
  966.     }
  967.  
  968.     GetOwner()->SendMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
  969.  
  970.     int iButtonCapture = m_iButtonCapture;
  971.     m_iButtonCapture = -1;
  972.     if (nIDCmd != 0)
  973.         GetOwner()->SendMessage(WM_COMMAND, nIDCmd);    // send command
  974.  
  975.     SetButtonStyle(iButtonCapture, nNewStyle);
  976.     UpdateButton(iButtonCapture);
  977.  
  978.     UpdateWindow(); // immediate feedback
  979. }
  980.  
  981. void CToolBar::OnCancelMode()
  982. {
  983.     CControlBar::OnCancelMode();
  984.  
  985.     if (m_iButtonCapture >= 0)
  986.     {
  987.         AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
  988.         ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
  989.         UINT nNewStyle = (pTBB->nStyle & ~TBBS_PRESSED);
  990.         if (GetCapture() == this)
  991.             ReleaseCapture();
  992.         SetButtonStyle(m_iButtonCapture, nNewStyle);
  993.         m_iButtonCapture = -1;
  994.         UpdateWindow();
  995.     }
  996. }
  997.  
  998. void CToolBar::OnSysColorChange()
  999. {
  1000.     // re-initialize global dither brush
  1001.     HBITMAP hbmGray = ::CreateDitherBitmap();
  1002.     if (hbmGray != NULL)
  1003.     {
  1004.         HBRUSH hbrNew = ::CreatePatternBrush(hbmGray);
  1005.         if (hbrNew != NULL)
  1006.         {
  1007.             AfxDeleteObject((HGDIOBJ*)&hbrDither);      // free old one
  1008.             hbrDither = hbrNew;
  1009.         }
  1010.         ::DeleteObject(hbmGray);
  1011.     }
  1012.  
  1013.     // re-color bitmap for toolbar
  1014.     if (m_hbmImageWell != NULL)
  1015.     {
  1016.         HBITMAP hbmNew;
  1017.         hbmNew = LoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell);
  1018.         if (hbmNew != NULL)
  1019.         {
  1020.             ::DeleteObject(m_hbmImageWell);     // free old one
  1021.             m_hbmImageWell = hbmNew;
  1022.         }
  1023.     }
  1024. }
  1025.  
  1026. /////////////////////////////////////////////////////////////////////////////
  1027. // CToolBar idle update through CToolCmdUI class
  1028.  
  1029. #define CToolCmdUI COldToolCmdUI
  1030.  
  1031. class CToolCmdUI : public CCmdUI        // class private to this file !
  1032. {
  1033. public: // re-implementations only
  1034.     virtual void Enable(BOOL bOn);
  1035.     virtual void SetCheck(int nCheck);
  1036.     virtual void SetText(LPCTSTR lpszText);
  1037. };
  1038.  
  1039. void CToolCmdUI::Enable(BOOL bOn)
  1040. {
  1041.     m_bEnableChanged = TRUE;
  1042.     CToolBar* pToolBar = (CToolBar*)m_pOther;
  1043.     ASSERT(pToolBar != NULL);
  1044.     ASSERT_KINDOF(CToolBar, pToolBar);
  1045.     ASSERT(m_nIndex < m_nIndexMax);
  1046.  
  1047.     UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) & ~TBBS_DISABLED;
  1048.     if (!bOn)
  1049.         nNewStyle |= TBBS_DISABLED;
  1050.     ASSERT(!(nNewStyle & TBBS_SEPARATOR));
  1051.     pToolBar->SetButtonStyle(m_nIndex, nNewStyle);
  1052. }
  1053.  
  1054. void CToolCmdUI::SetCheck(int nCheck)
  1055. {
  1056.     ASSERT(nCheck >= 0 && nCheck <= 2); // 0=>off, 1=>on, 2=>indeterminate
  1057.     CToolBar* pToolBar = (CToolBar*)m_pOther;
  1058.     ASSERT(pToolBar != NULL);
  1059.     ASSERT_KINDOF(CToolBar, pToolBar);
  1060.     ASSERT(m_nIndex < m_nIndexMax);
  1061.  
  1062.     UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) &
  1063.                 ~(TBBS_CHECKED | TBBS_INDETERMINATE);
  1064.     if (nCheck == 1)
  1065.         nNewStyle |= TBBS_CHECKED;
  1066.     else if (nCheck == 2)
  1067.         nNewStyle |= TBBS_INDETERMINATE;
  1068.     ASSERT(!(nNewStyle & TBBS_SEPARATOR));
  1069.     pToolBar->SetButtonStyle(m_nIndex, nNewStyle | TBBS_CHECKBOX);
  1070. }
  1071.  
  1072. void CToolCmdUI::SetText(LPCTSTR)
  1073. {
  1074.     // ignore it
  1075. }
  1076.  
  1077. void CToolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
  1078. {
  1079.     CToolCmdUI state;
  1080.     state.m_pOther = this;
  1081.  
  1082.     state.m_nIndexMax = (UINT)m_nCount;
  1083.     for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
  1084.       state.m_nIndex++)
  1085.     {
  1086.         AFX_TBBUTTON* pTBB = _GetButtonPtr(state.m_nIndex);
  1087.         state.m_nID = pTBB->nID;
  1088.  
  1089.         // ignore separators
  1090.         if (!(pTBB->nStyle & TBBS_SEPARATOR))
  1091.             state.DoUpdate(pTarget, bDisableIfNoHndler);
  1092.     }
  1093.  
  1094.     // update the dialog controls added to the toolbar
  1095.     UpdateDialogControls(pTarget, bDisableIfNoHndler);
  1096. }
  1097.  
  1098. void CToolBar::UpdateButton(int nIndex)
  1099. {
  1100.     // determine target of command update
  1101.     CFrameWnd* pTarget = (CFrameWnd*)GetOwner();
  1102.     if (pTarget == NULL || !pTarget->IsFrameWnd())
  1103.         pTarget = GetParentFrame();
  1104.  
  1105.     // send the update notification
  1106.     if (pTarget != NULL)
  1107.     {
  1108.         CToolCmdUI state;
  1109.         state.m_pOther = this;
  1110.         state.m_nIndex = nIndex;
  1111.         state.m_nIndexMax = (UINT)m_nCount;
  1112.         AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
  1113.         state.m_nID = pTBB->nID;
  1114.         state.DoUpdate(pTarget, pTarget->m_bAutoMenuEnable);
  1115.     }
  1116. }
  1117.  
  1118. /////////////////////////////////////////////////////////////////////////////
  1119. // CToolBar diagnostics
  1120.  
  1121. #ifdef _DEBUG
  1122. void CToolBar::AssertValid() const
  1123. {
  1124.     CControlBar::AssertValid();
  1125.     ASSERT(m_hbmImageWell == NULL ||
  1126.         (globalData.bWin32s || ::GetObjectType(m_hbmImageWell) == OBJ_BITMAP));
  1127.  
  1128.     if (m_hbmImageWell != NULL)
  1129.     {
  1130.         ASSERT(m_hRsrcImageWell != NULL);
  1131.         ASSERT(m_hInstImageWell != NULL);
  1132.     }
  1133. }
  1134.  
  1135. void CToolBar::Dump(CDumpContext& dc) const
  1136. {
  1137.     CControlBar::Dump(dc);
  1138.  
  1139.     dc << "m_hbmImageWell = " << (UINT)m_hbmImageWell;
  1140.     dc << "\nm_hInstImageWell = " << (UINT)m_hInstImageWell;
  1141.     dc << "\nm_hRsrcImageWell = " << (UINT)m_hRsrcImageWell;
  1142.     dc << "\nm_iButtonCapture = " << m_iButtonCapture;
  1143.     dc << "\nm_sizeButton = " << m_sizeButton;
  1144.     dc << "\nm_sizeImage = " << m_sizeImage;
  1145.  
  1146.     if (dc.GetDepth() > 0)
  1147.     {
  1148.         for (int i = 0; i < m_nCount; i++)
  1149.         {
  1150.             AFX_TBBUTTON* pTBB = _GetButtonPtr(i);
  1151.             dc << "\ntoolbar button[" << i << "] = {";
  1152.             dc << "\n\tnID = " << pTBB->nID;
  1153.             dc << "\n\tnStyle = " << pTBB->nStyle;
  1154.             if (pTBB->nStyle & TBBS_SEPARATOR)
  1155.                 dc << "\n\tiImage (separator width) = " << pTBB->iImage;
  1156.             else
  1157.                 dc <<"\n\tiImage (bitmap image index) = " << pTBB->iImage;
  1158.             dc << "\n}";
  1159.         }
  1160.     }
  1161.  
  1162.     dc << "\n";
  1163. }
  1164. #endif
  1165.  
  1166. #undef new
  1167. #ifdef AFX_INIT_SEG
  1168. #pragma code_seg(AFX_INIT_SEG)
  1169. #endif
  1170.  
  1171. IMPLEMENT_DYNAMIC(CToolBar, CControlBar)
  1172.