home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / BARTOOL.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-30  |  34.9 KB  |  1,361 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 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 related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_CORE3_SEG
  14. #pragma code_seg(AFX_CORE3_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CToolBar creation etc
  26.  
  27. #ifdef AFX_CORE3_SEG
  28. #pragma code_seg(AFX_CORE3_SEG)
  29. #endif
  30.  
  31. /*
  32.     DIBs use RGBQUAD format:
  33.         0xbb 0xgg 0xrr 0x00
  34.  
  35.     Reasonably efficient code to convert a COLORREF into an
  36.     RGBQUAD is byte-order-dependent, so we need different
  37.     code depending on the byte order we're targeting.
  38. */
  39. #ifndef _MAC
  40. #define RGB_TO_RGBQUAD(r,g,b)   (RGB(b,g,r))
  41. #define CLR_TO_RGBQUAD(clr)     (RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)))
  42. #else
  43. #define RGB_TO_RGBQUAD(r,g,b)   (RGB(r,g,b) << 8)
  44. #define CLR_TO_RGBQUAD(clr)     (clr << 8)
  45. #endif
  46.  
  47. HBITMAP AFXAPI
  48. AfxLoadSysColorBitmap(HINSTANCE hInst, HRSRC hRsrc, BOOL bMono)
  49. {
  50.     struct COLORMAP
  51.     {
  52.         // use DWORD instead of RGBQUAD so we can compare two RGBQUADs easily
  53.         DWORD rgbqFrom;
  54.         int iSysColorTo;
  55.     };
  56.     static const COLORMAP sysColorMap[] =
  57.     {
  58.         // mapping from color in DIB to system color
  59.         { RGB_TO_RGBQUAD(0x00, 0x00, 0x00),  COLOR_BTNTEXT },       // black
  60.         { RGB_TO_RGBQUAD(0x80, 0x80, 0x80),  COLOR_BTNSHADOW },     // dark grey
  61.         { RGB_TO_RGBQUAD(0xC0, 0xC0, 0xC0),  COLOR_BTNFACE },       // bright grey
  62.         { RGB_TO_RGBQUAD(0xFF, 0xFF, 0xFF),  COLOR_BTNHIGHLIGHT }   // white
  63.     };
  64.     const int nMaps = 4;
  65.  
  66.     HGLOBAL hglb;
  67.     if ((hglb = LoadResource(hInst, hRsrc)) == NULL)
  68.         return NULL;
  69.  
  70.     LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglb);
  71.     if (lpBitmap == NULL)
  72.         return NULL;
  73.  
  74.     // make copy of BITMAPINFOHEADER so we can modify the color table
  75.     const int nColorTableSize = 16;
  76.     UINT nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
  77.     LPBITMAPINFOHEADER lpBitmapInfo = (LPBITMAPINFOHEADER)::malloc(nSize);
  78.     if (lpBitmapInfo == NULL)
  79.         return NULL;
  80.     memcpy(lpBitmapInfo, lpBitmap, nSize);
  81.  
  82.     // color table is in RGBQUAD DIB format
  83.     DWORD* pColorTable =
  84.         (DWORD*)(((LPBYTE)lpBitmapInfo) + (UINT)lpBitmapInfo->biSize);
  85.  
  86.     for (int iColor = 0; iColor < nColorTableSize; iColor++)
  87.     {
  88.         // look for matching RGBQUAD color in original
  89.         for (int i = 0; i < nMaps; i++)
  90.         {
  91.             if (pColorTable[iColor] == sysColorMap[i].rgbqFrom)
  92.             {
  93.                 if (bMono)
  94.                 {
  95.                     // all colors except text become white
  96.                     if (sysColorMap[i].iSysColorTo != COLOR_BTNTEXT)
  97.                         pColorTable[iColor] = RGB_TO_RGBQUAD(255, 255, 255);
  98.                 }
  99.                 else
  100.                     pColorTable[iColor] =
  101.                         CLR_TO_RGBQUAD(::GetSysColor(sysColorMap[i].iSysColorTo));
  102.                 break;
  103.             }
  104.         }
  105.     }
  106.  
  107.     int nWidth = (int)lpBitmapInfo->biWidth;
  108.     int nHeight = (int)lpBitmapInfo->biHeight;
  109.     HDC hDCScreen = ::GetDC(NULL);
  110.     HBITMAP hbm = ::CreateCompatibleBitmap(hDCScreen, nWidth, nHeight);
  111.  
  112.     if (hbm != NULL)
  113.     {
  114.         HDC hDCGlyphs = ::CreateCompatibleDC(hDCScreen);
  115.         HBITMAP hbmOld = (HBITMAP)::SelectObject(hDCGlyphs, hbm);
  116.  
  117.         LPBYTE lpBits;
  118.         lpBits = (LPBYTE)(lpBitmap + 1);
  119.         lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
  120.  
  121.         StretchDIBits(hDCGlyphs, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
  122.             lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
  123.         SelectObject(hDCGlyphs, hbmOld);
  124.  
  125. #ifdef _MAC
  126.         // We don't change this bitmap any more, so get rid of the big,
  127.         // wasteful Macintosh port
  128.         ::SetBitmapReadOnly(hbm, BRO_READONLY);
  129. #endif
  130.  
  131.         ::DeleteDC(hDCGlyphs);
  132.     }
  133.     ::ReleaseDC(NULL, hDCScreen);
  134.  
  135.     // free copy of bitmap info struct and resource itself
  136.     ::free(lpBitmapInfo);
  137.     ::FreeResource(hglb);
  138.  
  139.     return hbm;
  140. }
  141.  
  142. #ifdef AFX_INIT_SEG
  143. #pragma code_seg(AFX_INIT_SEG)
  144. #endif
  145.  
  146. CToolBar::CToolBar()
  147. {
  148.     // initialize state
  149.     m_pStringMap = NULL;
  150.     m_hRsrcImageWell = NULL;
  151.     m_hInstImageWell = NULL;
  152.     m_hbmImageWell = NULL;
  153.     m_bDelayedButtonLayout = TRUE;
  154.  
  155.     // default image sizes
  156.     m_sizeImage.cx = 16;
  157.     m_sizeImage.cy = 15;
  158.  
  159.     // default button sizes
  160.     m_sizeButton.cx = 23;
  161.     m_sizeButton.cy = 22;
  162.  
  163.     // top and bottom borders are 1 larger than default for ease of grabbing
  164.     m_cyTopBorder = 3;
  165.     m_cyBottomBorder = 3;
  166. }
  167.  
  168. CToolBar::~CToolBar()
  169. {
  170.     AfxDeleteObject((HGDIOBJ*)&m_hbmImageWell);
  171.     delete m_pStringMap;
  172.  
  173.     m_nCount = 0;
  174. }
  175.  
  176. BOOL CToolBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
  177. {
  178.     ASSERT_VALID(pParentWnd);   // must have a parent
  179.     ASSERT (!((dwStyle & CBRS_SIZE_FIXED) && (dwStyle & CBRS_SIZE_DYNAMIC)));
  180.  
  181.     // save the style
  182.     m_dwStyle = dwStyle;
  183.     if (nID == AFX_IDW_TOOLBAR)
  184.         m_dwStyle |= CBRS_HIDE_INPLACE;
  185.  
  186.     dwStyle &= ~CBRS_ALL;
  187.     dwStyle |= CCS_NOPARENTALIGN|CCS_NOMOVEY|CCS_NODIVIDER|CCS_NORESIZE;
  188.  
  189.     // initialize common controls
  190.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTLS_REG));
  191.  
  192.     // create the HWND
  193.     CRect rect; rect.SetRectEmpty();
  194.     if (!CWnd::Create(TOOLBARCLASSNAME, NULL, dwStyle, rect, pParentWnd, nID))
  195.         return FALSE;
  196.  
  197.     // Note: Parent must resize itself for control bar to be resized
  198.  
  199.     return TRUE;
  200. }
  201.  
  202. BOOL CToolBar::OnNcCreate(LPCREATESTRUCT lpCreateStruct)
  203. {
  204.     if (!CControlBar::OnNcCreate(lpCreateStruct))
  205.         return FALSE;
  206.  
  207.     // if the owner was set before the toolbar was created, set it now
  208.     if (m_hWndOwner != NULL)
  209.         DefWindowProc(TB_SETPARENT, (WPARAM)m_hWndOwner, 0);
  210.  
  211.     DefWindowProc(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
  212.     return TRUE;
  213. }
  214.  
  215. void CToolBar::SetOwner(CWnd* pOwnerWnd)
  216. {
  217.     ASSERT_VALID(this);
  218.     if (m_hWnd != NULL)
  219.     {
  220.         ASSERT(::IsWindow(m_hWnd));
  221.         DefWindowProc(TB_SETPARENT, (WPARAM)pOwnerWnd->GetSafeHwnd(), 0);
  222.     }
  223.     CControlBar::SetOwner(pOwnerWnd);
  224. }
  225.  
  226. void CToolBar::SetSizes(SIZE sizeButton, SIZE sizeImage)
  227. {
  228.     ASSERT_VALID(this);
  229.     ASSERT(::IsWindow(m_hWnd));
  230.  
  231.     // sizes must be non-zero and positive
  232.     ASSERT(sizeButton.cx > 0 && sizeButton.cy > 0);
  233.     ASSERT(sizeImage.cx > 0 && sizeImage.cy > 0);
  234.  
  235.     // button must be big enough to hold image
  236.     //   + 7 pixels on x
  237.     //   + 6 pixels on y
  238.     ASSERT(sizeButton.cx >= sizeImage.cx + 7);
  239.     ASSERT(sizeButton.cy >= sizeImage.cy + 6);
  240.  
  241.     // set the sizes via TB_SETBITMAPSIZE and TB_SETBUTTONSIZE
  242.     VERIFY(SendMessage(TB_SETBITMAPSIZE, 0, MAKELONG(sizeImage.cx, sizeImage.cy)));
  243.     VERIFY(SendMessage(TB_SETBUTTONSIZE, 0, MAKELONG(sizeButton.cx, sizeButton.cy)));
  244.  
  245.     Invalidate();   // just to be nice if called when toolbar is visible
  246. }
  247.  
  248. void CToolBar::SetHeight(int cyHeight)
  249. {
  250.     ASSERT_VALID(this);
  251.  
  252.     int nHeight = cyHeight;
  253.     if (m_dwStyle & CBRS_BORDER_TOP)
  254.         cyHeight -= afxData.cyBorder2;
  255.     if (m_dwStyle & CBRS_BORDER_BOTTOM)
  256.         cyHeight -= afxData.cyBorder2;
  257.     m_cyBottomBorder = (cyHeight - m_sizeButton.cy) / 2;
  258.     // if there is an extra pixel, m_cyTopBorder will get it
  259.     m_cyTopBorder = cyHeight - m_sizeButton.cy - m_cyBottomBorder;
  260.     if (m_cyTopBorder < 0)
  261.     {
  262.         TRACE1("Warning: CToolBar::SetHeight(%d) is smaller than button.\n",
  263.             nHeight);
  264.         m_cyBottomBorder += m_cyTopBorder;
  265.         m_cyTopBorder = 0;  // will clip at bottom
  266.     }
  267.  
  268.     // recalculate the non-client region
  269.     SetWindowPos(NULL, 0, 0, 0, 0,
  270.         SWP_DRAWFRAME|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOZORDER);
  271.     Invalidate();   // just to be nice if called when toolbar is visible
  272. }
  273.  
  274. struct CToolBarData
  275. {
  276.     WORD wVersion;
  277.     WORD wWidth;
  278.     WORD wHeight;
  279.     WORD wItemCount;
  280.     //WORD aItems[wItemCount]
  281.  
  282.     WORD* items()
  283.         { return (WORD*)(this+1); }
  284. };
  285.  
  286. BOOL CToolBar::LoadToolBar(LPCTSTR lpszResourceName)
  287. {
  288.     ASSERT_VALID(this);
  289.     ASSERT(lpszResourceName != NULL);
  290.  
  291.     // determine location of the bitmap in resource fork
  292.     HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_TOOLBAR);
  293.     HRSRC hRsrc = ::FindResource(hInst, lpszResourceName, RT_TOOLBAR);
  294.     if (hRsrc == NULL)
  295.         return FALSE;
  296.  
  297.     HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
  298.     if (hGlobal == NULL)
  299.         return FALSE;
  300.  
  301.     CToolBarData* pData = (CToolBarData*)LockResource(hGlobal);
  302.     if (pData == NULL)
  303.         return FALSE;
  304.     ASSERT(pData->wVersion == 1);
  305.  
  306.     UINT* pItems = new UINT[pData->wItemCount];
  307.     for (int i = 0; i < pData->wItemCount; i++)
  308.         pItems[i] = pData->items()[i];
  309.     BOOL bResult = SetButtons(pItems, pData->wItemCount);
  310.     delete[] pItems;
  311.  
  312.     if (bResult)
  313.     {
  314.         // set new sizes of the buttons
  315.         CSize sizeImage(pData->wWidth, pData->wHeight);
  316.         CSize sizeButton(pData->wWidth + 7, pData->wHeight + 7);
  317.         SetSizes(sizeButton, sizeImage);
  318.  
  319.         // load bitmap now that sizes are known by the toolbar control
  320.         bResult = LoadBitmap(lpszResourceName);
  321.     }
  322.  
  323.     UnlockResource(hGlobal);
  324.     FreeResource(hGlobal);
  325.  
  326.     return bResult;
  327. }
  328.  
  329. BOOL CToolBar::LoadBitmap(LPCTSTR lpszResourceName)
  330. {
  331.     ASSERT_VALID(this);
  332.     ASSERT(lpszResourceName != NULL);
  333.  
  334.     // determine location of the bitmap in resource fork
  335.     HINSTANCE hInstImageWell = AfxFindResourceHandle(lpszResourceName, RT_BITMAP);
  336.     HRSRC hRsrcImageWell = ::FindResource(hInstImageWell, lpszResourceName, RT_BITMAP);
  337.     if (hRsrcImageWell == NULL)
  338.         return FALSE;
  339.  
  340.     // load the bitmap
  341.     HBITMAP hbmImageWell;
  342. #ifndef _MAC
  343.     hbmImageWell = AfxLoadSysColorBitmap(hInstImageWell, hRsrcImageWell);
  344. #else
  345.     hbmImageWell = AfxLoadSysColorBitmap(hInstImageWell, hRsrcImageWell, m_bMonochrome);
  346. #endif
  347.  
  348.     // tell common control toolbar about the new bitmap
  349.     if (!AddReplaceBitmap(hbmImageWell))
  350.         return FALSE;
  351.  
  352.     // remember the resource handles so the bitmap can be recolored if necessary
  353.     m_hInstImageWell = hInstImageWell;
  354.     m_hRsrcImageWell = hRsrcImageWell;
  355.     return TRUE;
  356. }
  357.  
  358. BOOL CToolBar::SetBitmap(HBITMAP hbmImageWell)
  359. {
  360.     ASSERT_VALID(this);
  361.     ASSERT(hbmImageWell != NULL);
  362.  
  363.     // the caller must manage changing system colors
  364.     m_hInstImageWell = NULL;
  365.     m_hRsrcImageWell = NULL;
  366.  
  367.     // tell common control toolbar about the new bitmap
  368.     return AddReplaceBitmap(hbmImageWell);
  369. }
  370.  
  371. BOOL CToolBar::AddReplaceBitmap(HBITMAP hbmImageWell)
  372. {
  373.     // need complete bitmap size to determine number of images
  374.     BITMAP bitmap;
  375.     VERIFY(::GetObject(hbmImageWell, sizeof(BITMAP), &bitmap));
  376.  
  377.     // add the bitmap to the common control toolbar
  378.     BOOL bResult;
  379.     if (m_hbmImageWell == NULL)
  380.     {
  381.         TBADDBITMAP addBitmap;
  382.         addBitmap.hInst = NULL; // makes TBADDBITMAP::nID behave a HBITMAP
  383.         addBitmap.nID = (UINT)hbmImageWell;
  384.         bResult =  DefWindowProc(TB_ADDBITMAP,
  385.             bitmap.bmWidth / m_sizeImage.cx, (LPARAM)&addBitmap) == 0;
  386.     }
  387.     else
  388.     {
  389.         TBREPLACEBITMAP replaceBitmap;
  390.         replaceBitmap.hInstOld = NULL;
  391.         replaceBitmap.nIDOld = (UINT)m_hbmImageWell;
  392.         replaceBitmap.hInstNew = NULL;
  393.         replaceBitmap.nIDNew = (UINT)hbmImageWell;
  394.         replaceBitmap.nButtons = bitmap.bmWidth / m_sizeImage.cx;
  395.         bResult = (BOOL)DefWindowProc(TB_REPLACEBITMAP, 0,
  396.             (LPARAM)&replaceBitmap);
  397.     }
  398.     // remove old bitmap, if present
  399.     if (bResult)
  400.     {
  401.         AfxDeleteObject((HGDIOBJ*)&m_hbmImageWell);
  402.         m_hbmImageWell = hbmImageWell;
  403.     }
  404.  
  405.     return bResult;
  406. }
  407.  
  408. BOOL CToolBar::SetButtons(const UINT* lpIDArray, int nIDCount)
  409. {
  410.     ASSERT_VALID(this);
  411.     ASSERT(nIDCount >= 1);  // must be at least one of them
  412.     ASSERT(lpIDArray == NULL ||
  413.         AfxIsValidAddress(lpIDArray, sizeof(UINT) * nIDCount, FALSE));
  414.  
  415.     // delete all existing buttons
  416.     int nCount = (int)DefWindowProc(TB_BUTTONCOUNT, 0, 0);
  417.     while (nCount--)
  418.         VERIFY(DefWindowProc(TB_DELETEBUTTON, 0, 0));
  419.  
  420.     if (lpIDArray != NULL)
  421.     {
  422.         // add new buttons to the common control
  423.         TBBUTTON button; memset(&button, 0, sizeof(TBBUTTON));
  424.         int iImage = 0;
  425.         for (int i = 0; i < nIDCount; i++)
  426.         {
  427.             button.fsState = TBSTATE_ENABLED;
  428.             if ((button.idCommand = *lpIDArray++) == 0)
  429.             {
  430.                 // separator
  431.                 button.fsStyle = TBSTYLE_SEP;
  432.                 // width of separator includes 8 pixel overlap
  433.                 button.iBitmap = 8;
  434.             }
  435.             else
  436.             {
  437.                 // a command button with image
  438.                 button.fsStyle = TBSTYLE_BUTTON;
  439.                 button.iBitmap = iImage++;
  440.             }
  441.             if (!DefWindowProc(TB_ADDBUTTONS, 1, (LPARAM)&button))
  442.                 return FALSE;
  443.         }
  444.     }
  445.     else
  446.     {
  447.         // add 'blank' buttons
  448.         TBBUTTON button; memset(&button, 0, sizeof(TBBUTTON));
  449.         button.fsState = TBSTATE_ENABLED;
  450.         for (int i = 0; i < nIDCount; i++)
  451.         {
  452.             ASSERT(button.fsStyle == TBSTYLE_BUTTON);
  453.             if (!DefWindowProc(TB_ADDBUTTONS, 1, (LPARAM)&button))
  454.                 return FALSE;
  455.         }
  456.     }
  457.     m_nCount = (int)DefWindowProc(TB_BUTTONCOUNT, 0, 0);
  458.  
  459.     m_bDelayedButtonLayout = TRUE;
  460.  
  461.     return TRUE;
  462. }
  463.  
  464. #ifdef _MAC
  465. BOOL CToolBar::CheckMonochrome(void)
  466. {
  467.     BOOL bMono = CControlBar::CheckMonochrome();
  468.  
  469.     if (!bMono)
  470.     {
  471.         DWORD dw3D;
  472.  
  473.         SystemParametersInfo(SPI_GET3D, 0, (void*) &dw3D, FALSE);
  474.         bMono = (dw3D & F3D_NO3D) || !(dw3D & F3D_3DTOOLBAR);
  475.     }
  476.  
  477.     return bMono;
  478. }
  479. #endif
  480.  
  481. #ifdef AFX_CORE3_SEG
  482. #pragma code_seg(AFX_CORE3_SEG)
  483. #endif
  484.  
  485. /////////////////////////////////////////////////////////////////////////////
  486. // CToolBar attribute access
  487.  
  488. void CToolBar::_GetButton(int nIndex, TBBUTTON* pButton) const
  489. {
  490.     CToolBar* pBar = (CToolBar*)this;
  491.     VERIFY(pBar->DefWindowProc(TB_GETBUTTON, nIndex, (LPARAM)pButton));
  492.     // TBSTATE_ENABLED == TBBS_DISABLED so invert it
  493.     pButton->fsState ^= TBSTATE_ENABLED;
  494. }
  495.  
  496. void CToolBar::_SetButton(int nIndex, TBBUTTON* pButton)
  497. {
  498.     // get original button state
  499.     TBBUTTON button;
  500.     VERIFY(DefWindowProc(TB_GETBUTTON, nIndex, (LPARAM)&button));
  501.  
  502.     // prepare for old/new button comparsion
  503.     button.bReserved[0] = 0;
  504.     button.bReserved[1] = 0;
  505.     // TBSTATE_ENABLED == TBBS_DISABLED so invert it
  506.     pButton->fsState ^= TBSTATE_ENABLED;
  507.     pButton->bReserved[0] = 0;
  508.     pButton->bReserved[1] = 0;
  509.  
  510.     // nothing to do if they are the same
  511.     if (memcmp(pButton, &button, sizeof(TBBUTTON)) != 0)
  512.     {
  513.         // don't redraw everything while setting the button
  514.         DWORD dwStyle = GetStyle();
  515.         ModifyStyle(WS_VISIBLE, 0);
  516.         VERIFY(DefWindowProc(TB_DELETEBUTTON, nIndex, 0));
  517.         VERIFY(DefWindowProc(TB_INSERTBUTTON, nIndex, (LPARAM)pButton));
  518.         ModifyStyle(0, dwStyle & WS_VISIBLE);
  519.  
  520.         // invalidate appropriate parts
  521.         if (((pButton->fsStyle ^ button.fsStyle) & TBSTYLE_SEP) ||
  522.             ((pButton->fsStyle & TBSTYLE_SEP) && pButton->iBitmap != button.iBitmap))
  523.         {
  524.             // changing a separator
  525.             Invalidate(FALSE);
  526.         }
  527.         else
  528.         {
  529.             // invalidate just the button
  530.             CRect rect;
  531.             if (DefWindowProc(TB_GETITEMRECT, nIndex, (LPARAM)&rect))
  532.                 InvalidateRect(rect, FALSE);    // don't erase background
  533.         }
  534.     }
  535. }
  536.  
  537. int CToolBar::CommandToIndex(UINT nIDFind) const
  538. {
  539.     ASSERT_VALID(this);
  540.     ASSERT(::IsWindow(m_hWnd));
  541.  
  542.     CToolBar* pBar = (CToolBar*)this;
  543.     return (int)pBar->DefWindowProc(TB_COMMANDTOINDEX, nIDFind, 0);
  544. }
  545.  
  546. UINT CToolBar::GetItemID(int nIndex) const
  547. {
  548.     ASSERT_VALID(this);
  549.     ASSERT(::IsWindow(m_hWnd));
  550.  
  551.     TBBUTTON button;
  552.     _GetButton(nIndex, &button);
  553.     return button.idCommand;
  554. }
  555.  
  556. void CToolBar::GetItemRect(int nIndex, LPRECT lpRect) const
  557. {
  558.     ASSERT_VALID(this);
  559.     ASSERT(::IsWindow(m_hWnd));
  560.  
  561.     if (m_bDelayedButtonLayout)
  562.     {   // REVEW: how do I comment on casting away the const below?
  563.         // The only way m_bDelayedButtonLayout gets set to TRUE
  564.         // is in a non const function.  Since we are just delaying
  565.         // a calculation that should have occured already this function
  566.         // is still theoretically const
  567.         BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) != 0;
  568.         if ((m_dwStyle & CBRS_FLOATING) && (m_dwStyle & CBRS_SIZE_DYNAMIC))
  569.             ((CToolBar*)this)->CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH | LM_COMMIT);
  570.         else if (bHorz)
  571.             ((CToolBar*)this)->CalcDynamicLayout(0, LM_HORZ | LM_HORZDOCK | LM_COMMIT);
  572.         else
  573.             ((CToolBar*)this)->CalcDynamicLayout(0, LM_VERTDOCK | LM_COMMIT);
  574.     }
  575.  
  576.     CToolBar* pBar = (CToolBar*)this;
  577.     if (!pBar->DefWindowProc(TB_GETITEMRECT, nIndex, (LPARAM)lpRect))
  578.         SetRectEmpty(lpRect);
  579. }
  580.  
  581. UINT CToolBar::GetButtonStyle(int nIndex) const
  582. {
  583.     ASSERT_VALID(this);
  584.     ASSERT(::IsWindow(m_hWnd));
  585.  
  586.     TBBUTTON button;
  587.     _GetButton(nIndex, &button);
  588.     return MAKELONG(button.fsStyle, button.fsState);
  589. }
  590.  
  591. void CToolBar::SetButtonStyle(int nIndex, UINT nStyle)
  592. {
  593.     ASSERT_VALID(this);
  594.     ASSERT(::IsWindow(m_hWnd));
  595.  
  596.     TBBUTTON button;
  597.     _GetButton(nIndex, &button);
  598.     button.fsStyle = (BYTE)LOWORD(nStyle);
  599.     button.fsState = (BYTE)HIWORD(nStyle);
  600.     _SetButton(nIndex, &button);
  601.  
  602.     m_bDelayedButtonLayout = TRUE;
  603. }
  604.  
  605. #ifdef _MAC
  606.     #define CX_OVERLAP  1
  607. #else
  608.     #define CX_OVERLAP  0
  609. #endif
  610.  
  611. CSize CToolBar::CalcSize(TBBUTTON* pData, int nCount)
  612. {
  613.     ASSERT(pData != NULL && nCount > 0);
  614.  
  615.     CPoint cur(0,0);
  616.     CSize sizeResult(0,0);
  617.  
  618.     for (int i = 0; i < nCount; i++)
  619.     {
  620.         if (pData[i].fsState & TBSTATE_HIDDEN)
  621.             continue;
  622.  
  623.         if (pData[i].fsStyle & TBSTYLE_SEP)
  624.         {
  625.             // A separator represents either a height or width
  626.             if (pData[i].fsState & TBSTATE_WRAP)
  627.                 sizeResult.cy = max(cur.y + m_sizeButton.cy + pData[i].iBitmap * 2 / 3, sizeResult.cy);
  628.             else
  629.                 sizeResult.cx = max(cur.x + pData[i].iBitmap, sizeResult.cx);
  630.         }
  631.         else
  632.         {
  633.             sizeResult.cx = max(cur.x + m_sizeButton.cx, sizeResult.cx);
  634.             sizeResult.cy = max(cur.y + m_sizeButton.cy, sizeResult.cy);
  635.         }
  636.  
  637.         if (pData[i].fsStyle & TBSTYLE_SEP)
  638.             cur.x += pData[i].iBitmap;
  639.         else
  640.             cur.x += m_sizeButton.cx - CX_OVERLAP;
  641.  
  642.         if (pData[i].fsState & TBSTATE_WRAP)
  643.         {
  644.             cur.x = 0;
  645.             cur.y += m_sizeButton.cy;
  646.             if (pData[i].fsStyle & TBSTYLE_SEP)
  647.                 cur.y += pData[i].iBitmap * 2 / 3;
  648.         }
  649.     }
  650.     return sizeResult;
  651. }
  652.  
  653. int CToolBar::WrapToolBar(TBBUTTON* pData, int nCount, int nWidth)
  654. {
  655.     ASSERT(pData != NULL && nCount > 0);
  656.  
  657.     int nResult = 0;
  658.     int x = 0;
  659.     for (int i = 0; i < nCount; i++)
  660.     {
  661.         pData[i].fsState &= ~TBSTATE_WRAP;
  662.  
  663.         if (pData[i].fsState & TBSTATE_HIDDEN)
  664.             continue;
  665.  
  666.         int dx, dxNext;
  667.         if (pData[i].fsStyle & TBSTYLE_SEP)
  668.         {
  669.             dx = pData[i].iBitmap;
  670.             dxNext = dx;
  671.         }
  672.         else
  673.         {
  674.             dx = m_sizeButton.cx;
  675.             dxNext = dx - CX_OVERLAP;
  676.         }
  677.  
  678.         if (x + dx > nWidth)
  679.         {
  680.             BOOL bFound = FALSE;
  681.             for (int j = i; j >= 0  &&  !(pData[j].fsState & TBSTATE_WRAP); j--)
  682.             {
  683.                 // Find last separator that isn't hidden
  684.                 // a separator that has a command ID is not
  685.                 // a separator, but a custom control.
  686.                 if ((pData[j].fsStyle & TBSTYLE_SEP) &&
  687.                     (pData[j].idCommand == 0) &&
  688.                     !(pData[j].fsState & TBSTATE_HIDDEN))
  689.                 {
  690.                     bFound = TRUE; i = j; x = 0;
  691.                     pData[j].fsState |= TBSTATE_WRAP;
  692.                     nResult++;
  693.                     break;
  694.                 }
  695.             }
  696.             if (!bFound)
  697.             {
  698.                 for (int j = i - 1; j >= 0 && !(pData[j].fsState & TBSTATE_WRAP); j--)
  699.                 {
  700.                     // Never wrap anything that is hidden,
  701.                     // or any custom controls
  702.                     if ((pData[j].fsState & TBSTATE_HIDDEN) ||
  703.                         ((pData[j].fsStyle & TBSTYLE_SEP) &&
  704.                         (pData[j].idCommand != 0)))
  705.                         continue;
  706.  
  707.                     bFound = TRUE; i = j; x = 0;
  708.                     pData[j].fsState |= TBSTATE_WRAP;
  709.                     nResult++;
  710.                     break;
  711.                 }
  712.                 if (!bFound)
  713.                     x += dxNext;
  714.             }
  715.         }
  716.         else
  717.             x += dxNext;
  718.     }
  719.     return nResult + 1;
  720. }
  721.  
  722. void  CToolBar::SizeToolBar(TBBUTTON* pData, int nCount, int nLength, BOOL bVert)
  723. {
  724.     ASSERT(pData != NULL && nCount > 0);
  725.  
  726.     if (!bVert)
  727.     {
  728.         int nMin, nMax, nTarget, nCurrent, nMid;
  729.  
  730.         // Wrap ToolBar as specified
  731.         nMax = nLength;
  732.         nTarget = WrapToolBar(pData, nCount, nMax);
  733.  
  734.         // Wrap ToolBar vertically
  735.         nMin = 0;
  736.         nCurrent = WrapToolBar(pData, nCount, nMin);
  737.  
  738.         if (nCurrent != nTarget)
  739.         {
  740.             while (nMin < nMax)
  741.             {
  742.                 nMid = (nMin + nMax) / 2;
  743.                 nCurrent = WrapToolBar(pData, nCount, nMid);
  744.  
  745.                 if (nCurrent == nTarget)
  746.                     nMax = nMid;
  747.                 else
  748.                 {
  749.                     if (nMin == nMid)
  750.                     {
  751.                         WrapToolBar(pData, nCount, nMax);
  752.                         break;
  753.                     }
  754.                     nMin = nMid;
  755.                 }
  756.             }
  757.         }
  758.         CSize size = CalcSize(pData, nCount);
  759.         WrapToolBar(pData, nCount, size.cx);
  760.     }
  761.     else
  762.     {
  763.         CSize sizeMax, sizeMin, sizeMid;
  764.  
  765.         // Wrap ToolBar vertically
  766.         WrapToolBar(pData, nCount, 0);
  767.         sizeMin = CalcSize(pData, nCount);
  768.  
  769.         // Wrap ToolBar horizontally
  770.         WrapToolBar(pData, nCount, 32767);
  771.         sizeMax = CalcSize(pData, nCount);
  772.  
  773.         while (sizeMin.cx < sizeMax.cx)
  774.         {
  775.             sizeMid.cx = (sizeMin.cx + sizeMax.cx) / 2;
  776.             WrapToolBar(pData, nCount, sizeMid.cx);
  777.             sizeMid = CalcSize(pData, nCount);
  778.  
  779.             if (nLength < sizeMid.cy)
  780.             {
  781.                 if (sizeMin == sizeMid)
  782.                 {
  783.                     WrapToolBar(pData, nCount, sizeMax.cx);
  784.                     return;
  785.                 }
  786.                 sizeMin = sizeMid;
  787.             }
  788.             else if (nLength > sizeMid.cy)
  789.                 sizeMax = sizeMid;
  790.             else
  791.                 return;
  792.         }
  793.     }
  794. }
  795.  
  796. struct _AFX_CONTROLPOS
  797. {
  798.     int nIndex, nID;
  799.     CRect rectOldPos;
  800. };
  801.  
  802. CSize CToolBar::CalcLayout(DWORD dwMode, int nLength)
  803. {
  804.     ASSERT_VALID(this);
  805.     ASSERT(::IsWindow(m_hWnd));
  806.     if (dwMode & LM_HORZDOCK)
  807.         ASSERT(dwMode & LM_HORZ);
  808.  
  809.     int nCount;
  810.     TBBUTTON* pData;
  811.     CSize sizeResult(0,0);
  812.  
  813.     // Load Buttons
  814.     {
  815.         nCount = DefWindowProc(TB_BUTTONCOUNT, 0, 0);
  816.         if (nCount != 0)
  817.         {
  818.             int i;
  819.             pData = new TBBUTTON[nCount];
  820.             for (i = 0; i < nCount; i++)
  821.                 _GetButton(i, &pData[i]);
  822.         }
  823.     }
  824.  
  825.     if (nCount > 0)
  826.     {
  827.         if (!(m_dwStyle & CBRS_SIZE_FIXED))
  828.         {
  829.             BOOL bDynamic = m_dwStyle & CBRS_SIZE_DYNAMIC;
  830.  
  831.             if (bDynamic && (dwMode & LM_MRUWIDTH))
  832.                 SizeToolBar(pData, nCount, m_nMRUWidth);
  833.             else if (bDynamic && (dwMode & LM_HORZDOCK))
  834.                 SizeToolBar(pData, nCount, 32767);
  835.             else if (bDynamic && (dwMode & LM_VERTDOCK))
  836.                 SizeToolBar(pData, nCount, 0);
  837.             else if (bDynamic && (nLength != -1))
  838.             {
  839.                 CRect rect; rect.SetRectEmpty();
  840.                 CalcInsideRect(rect, (dwMode & LM_HORZ));
  841.                 BOOL bVert = (dwMode & LM_LENGTHY);
  842.                 int nLen = nLength + (bVert ? rect.Height() : rect.Width());
  843.  
  844.                 SizeToolBar(pData, nCount, nLen, bVert);
  845.             }
  846.             else if (bDynamic && (m_dwStyle & CBRS_FLOATING))
  847.                 SizeToolBar(pData, nCount, m_nMRUWidth);
  848.             else
  849.                 SizeToolBar(pData, nCount, (dwMode & LM_HORZ) ? 32767 : 0);
  850.         }
  851.  
  852.         sizeResult = CalcSize(pData, nCount);
  853.  
  854.         if (dwMode & LM_COMMIT)
  855.         {
  856.             _AFX_CONTROLPOS* pControl = NULL;
  857.             int nControlCount = 0;
  858.             BOOL bIsDelayed = m_bDelayedButtonLayout;
  859.             m_bDelayedButtonLayout = FALSE;
  860.  
  861.             for(int i = 0; i < nCount; i++)
  862.                 if ((pData[i].fsStyle & TBSTYLE_SEP) && (pData[i].idCommand != 0))
  863.                     nControlCount++;
  864.  
  865.             if (nControlCount > 0)
  866.             {
  867.                 pControl = new _AFX_CONTROLPOS[nControlCount];
  868.                 nControlCount = 0;
  869.  
  870.                 for(int i = 0; i < nCount; i++)
  871.                 {
  872.                     if ((pData[i].fsStyle & TBSTYLE_SEP) && (pData[i].idCommand != 0))
  873.                     {
  874.                         pControl[nControlCount].nIndex = i;
  875.                         pControl[nControlCount].nID = pData[i].idCommand;
  876.  
  877.                         CRect rect;
  878.                         GetItemRect(i, &rect);
  879.                         ClientToScreen(&rect);
  880.                         pControl[nControlCount].rectOldPos = rect;
  881.  
  882.                         nControlCount++;
  883.                     }
  884.                 }
  885.             }
  886.  
  887.             if ((m_dwStyle & CBRS_FLOATING) && (m_dwStyle & CBRS_SIZE_DYNAMIC))
  888.                 m_nMRUWidth = sizeResult.cx;
  889.             for (i = 0; i < nCount; i++)
  890.                 _SetButton(i, &pData[i]);
  891.  
  892.             if (nControlCount > 0)
  893.             {
  894.                 for (int i = 0; i < nControlCount; i++)
  895.                 {
  896.                     CWnd* pWnd = GetDlgItem(pControl[i].nID);
  897.                     if (pWnd != NULL)
  898.                     {
  899.                         CRect rect;
  900.                         pWnd->GetWindowRect(&rect);
  901.                         CPoint pt = rect.TopLeft() - pControl[i].rectOldPos.TopLeft();
  902.                         GetItemRect(pControl[i].nIndex, &rect);
  903.                         pt = rect.TopLeft() + pt;
  904.                         pWnd->SetWindowPos(NULL, pt.x, pt.y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
  905.                     }
  906.                 }
  907.                 delete[] pControl;
  908.             }
  909.             m_bDelayedButtonLayout = bIsDelayed;
  910.         }
  911.         delete[] pData;
  912.     }
  913.  
  914.     //BLOCK: Adjust Margins
  915.     {
  916.         CRect rect; rect.SetRectEmpty();
  917.         CalcInsideRect(rect, (dwMode & LM_HORZ));
  918.         sizeResult.cy -= rect.Height();
  919.         sizeResult.cx -= rect.Width();
  920.  
  921.         CSize size = CControlBar::CalcFixedLayout((dwMode & LM_STRETCH), (dwMode & LM_HORZ));
  922.         sizeResult.cx = max(sizeResult.cx, size.cx);
  923.         sizeResult.cy = max(sizeResult.cy, size.cy);
  924.     }
  925.     return sizeResult;
  926. }
  927.  
  928. CSize CToolBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
  929. {
  930.     DWORD dwMode = bStretch ? LM_STRETCH : 0;
  931.     dwMode |= bHorz ? LM_HORZ : 0;
  932.  
  933.     return CalcLayout(dwMode);
  934. }
  935.  
  936. CSize CToolBar::CalcDynamicLayout(int nLength, DWORD dwMode)
  937. {
  938.     if ((nLength == -1) && !(dwMode & LM_MRUWIDTH) && !(dwMode & LM_COMMIT) &&
  939.         ((dwMode & LM_HORZDOCK) || (dwMode & LM_VERTDOCK)))
  940.     {
  941.         return CalcFixedLayout(dwMode & LM_STRETCH, dwMode & LM_HORZDOCK);
  942.     }
  943.     return CalcLayout(dwMode, nLength);
  944. }
  945.  
  946. void CToolBar::GetButtonInfo(int nIndex, UINT& nID, UINT& nStyle, int& iImage) const
  947. {
  948.     ASSERT_VALID(this);
  949.     ASSERT(::IsWindow(m_hWnd));
  950.  
  951.     TBBUTTON button;
  952.     _GetButton(nIndex, &button);
  953.     nID = button.idCommand;
  954.     nStyle = MAKELONG(button.fsStyle, button.fsState);
  955.     iImage = button.iBitmap;
  956. }
  957.  
  958. void CToolBar::SetButtonInfo(int nIndex, UINT nID, UINT nStyle, int iImage)
  959. {
  960.     ASSERT_VALID(this);
  961.  
  962.     TBBUTTON button;
  963.     _GetButton(nIndex, &button);
  964.     button.idCommand = nID;
  965.     button.iBitmap = iImage;
  966.     button.fsStyle = (BYTE)LOWORD(nStyle);
  967.     button.fsState = (BYTE)HIWORD(nStyle);
  968.     _SetButton(nIndex, &button);
  969.  
  970.     m_bDelayedButtonLayout = TRUE;
  971. }
  972.  
  973. int CToolBar::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
  974. {
  975.     ASSERT_VALID(this);
  976.     ASSERT(::IsWindow(m_hWnd));
  977.  
  978.     // check child windows first by calling CControlBar
  979.     int nHit = CControlBar::OnToolHitTest(point, pTI);
  980.     if (nHit != -1)
  981.         return nHit;
  982.  
  983.     // now hit test against CToolBar buttons
  984.     CToolBar* pBar = (CToolBar*)this;
  985.     int nButtons = (int)pBar->DefWindowProc(TB_BUTTONCOUNT, 0, 0);
  986.     for (int i = 0; i < nButtons; i++)
  987.     {
  988.         CRect rect;
  989.         TBBUTTON button;
  990.         if (pBar->DefWindowProc(TB_GETITEMRECT, i, (LPARAM)&rect) &&
  991.             rect.PtInRect(point) &&
  992.             pBar->DefWindowProc(TB_GETBUTTON, i, (LPARAM)&button) &&
  993.             !(button.fsStyle & TBSTYLE_SEP))
  994.         {
  995.             int nHit = GetItemID(i);
  996.             if (pTI != NULL && pTI->cbSize >= sizeof(TOOLINFO))
  997.             {
  998.                 pTI->hwnd = m_hWnd;
  999.                 pTI->rect = rect;
  1000.                 pTI->uId = nHit;
  1001.                 pTI->lpszText = LPSTR_TEXTCALLBACK;
  1002.             }
  1003.             // found matching rect, return the ID of the button
  1004.             return nHit != 0 ? nHit : -1;
  1005.         }
  1006.     }
  1007.     return -1;
  1008. }
  1009.  
  1010. BOOL CToolBar::SetButtonText(int nIndex, LPCTSTR lpszText)
  1011. {
  1012.     // attempt to lookup string index in map
  1013.     int nString = -1;
  1014.     void* p;
  1015.     if (m_pStringMap != NULL && m_pStringMap->Lookup(lpszText, p))
  1016.         nString = (int)p;
  1017.  
  1018.     // add new string if not already in map
  1019.     if (nString == -1)
  1020.     {
  1021.         // add new string to toolbar list
  1022.         CString strTemp = lpszText;
  1023.         strTemp += '\0';
  1024.         nString = (int)DefWindowProc(TB_ADDSTRING, 0, (LPARAM)(LPCTSTR)strTemp);
  1025.     }
  1026.     if (nString == -1)
  1027.         return FALSE;
  1028.  
  1029.     // cache string away in string map
  1030.     if (m_pStringMap == NULL)
  1031.         m_pStringMap = new CMapStringToPtr;
  1032.     m_pStringMap->SetAt(lpszText, (void*)nString);
  1033.     ASSERT(m_pStringMap->Lookup(lpszText, p));
  1034.  
  1035.     // change the toolbar button description
  1036.     TBBUTTON button;
  1037.     _GetButton(nIndex, &button);
  1038.     button.iString = nString;
  1039.     _SetButton(nIndex, &button);
  1040.  
  1041.     return TRUE;
  1042. }
  1043.  
  1044. CString CToolBar::GetButtonText(int nIndex) const
  1045. {
  1046.     CString strResult;
  1047.     GetButtonText(nIndex, strResult);
  1048.     return strResult;
  1049. }
  1050.  
  1051. void CToolBar::GetButtonText(int nIndex, CString& rString) const
  1052. {
  1053.     if (m_pStringMap != NULL)
  1054.     {
  1055.         // get button information (need button.iString)
  1056.         TBBUTTON button;
  1057.         _GetButton(nIndex, &button);
  1058.  
  1059.         // look in map for matching iString
  1060.         POSITION pos = m_pStringMap->GetStartPosition();
  1061.         CString str; void* p;
  1062.         while (pos)
  1063.         {
  1064.             m_pStringMap->GetNextAssoc(pos, str, p);
  1065.             if ((int)p == button.iString)
  1066.             {
  1067.                 rString = str;
  1068.                 return;
  1069.             }
  1070.         }
  1071.     }
  1072.     rString.Empty();
  1073. }
  1074.  
  1075. /////////////////////////////////////////////////////////////////////////////
  1076. // CToolBar message handlers
  1077.  
  1078. BEGIN_MESSAGE_MAP(CToolBar, CControlBar)
  1079.     //{{AFX_MSG_MAP(CToolBar)
  1080.     ON_WM_NCHITTEST()
  1081.     ON_WM_NCPAINT()
  1082.     ON_WM_PAINT()
  1083.     ON_WM_ERASEBKGND()
  1084.     ON_WM_NCCALCSIZE()
  1085.     ON_WM_WINDOWPOSCHANGING()
  1086.     ON_WM_NCCREATE()
  1087.     ON_MESSAGE(TB_SETBITMAPSIZE, OnSetBitmapSize)
  1088.     ON_MESSAGE(TB_SETBUTTONSIZE, OnSetButtonSize)
  1089.     ON_WM_SYSCOLORCHANGE()
  1090.     //}}AFX_MSG_MAP
  1091. END_MESSAGE_MAP()
  1092.  
  1093. BOOL CToolBar::OnEraseBkgnd(CDC*)
  1094. {
  1095.     return (BOOL)Default();
  1096. }
  1097.  
  1098. UINT CToolBar::OnNcHitTest(CPoint)
  1099. {
  1100.     return HTCLIENT;
  1101. }
  1102.  
  1103. void CToolBar::OnNcCalcSize(BOOL /*bCalcValidRects*/, NCCALCSIZE_PARAMS* lpncsp)
  1104. {
  1105.     // calculate border space (will add to top/bottom, subtract from right/bottom)
  1106.     CRect rect; rect.SetRectEmpty();
  1107.     BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) != 0;
  1108.     CControlBar::CalcInsideRect(rect, bHorz);
  1109.     ASSERT(rect.top >= 2);
  1110.  
  1111.     // adjust non-client area for border space
  1112.     lpncsp->rgrc[0].left += rect.left;
  1113.     lpncsp->rgrc[0].top += rect.top - 2;
  1114.     lpncsp->rgrc[0].right += rect.right;
  1115.     lpncsp->rgrc[0].bottom += rect.bottom;
  1116. }
  1117.  
  1118. void CToolBar::OnBarStyleChange(DWORD dwOldStyle, DWORD dwNewStyle)
  1119. {
  1120.     // a dynamically resizeable toolbar can not have the CBRS_FLOAT_MULTI
  1121.     ASSERT(!((dwNewStyle & CBRS_SIZE_DYNAMIC) &&
  1122.             (m_dwDockStyle & CBRS_FLOAT_MULTI)));
  1123.  
  1124.     // a toolbar can not be both dynamic and fixed in size
  1125.     ASSERT (!((dwNewStyle & CBRS_SIZE_FIXED) &&
  1126.         (dwNewStyle & CBRS_SIZE_DYNAMIC)));
  1127.  
  1128.     // CBRS_SIZE_DYNAMIC can not be disabled once it has been enabled
  1129.     ASSERT (((dwOldStyle & CBRS_SIZE_DYNAMIC) == 0) ||
  1130.         ((dwNewStyle & CBRS_SIZE_DYNAMIC) != 0));
  1131.  
  1132.     if (m_hWnd != NULL &&
  1133.         ((dwOldStyle & CBRS_BORDER_ANY) != (dwNewStyle & CBRS_BORDER_ANY)))
  1134.     {
  1135.         // recalc non-client area when border styles change
  1136.         SetWindowPos(NULL, 0, 0, 0, 0,
  1137.             SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DRAWFRAME);
  1138.     }
  1139.     m_bDelayedButtonLayout = TRUE;
  1140. }
  1141.  
  1142. void CToolBar::OnNcPaint()
  1143. {
  1144.     EraseNonClient();
  1145. }
  1146.  
  1147. void CToolBar::OnWindowPosChanging(LPWINDOWPOS lpWndPos)
  1148. {
  1149.     // not necessary to invalidate the borders
  1150.     DWORD dwStyle = m_dwStyle;
  1151.     m_dwStyle &= ~(CBRS_BORDER_ANY);
  1152.     CControlBar::OnWindowPosChanging(lpWndPos);
  1153.     m_dwStyle = dwStyle;
  1154.  
  1155.     // If we can resize while floating
  1156.     if (dwStyle & CBRS_SIZE_DYNAMIC)
  1157.     {
  1158.         // And we are resizing
  1159.         if (lpWndPos->flags & SWP_NOSIZE)
  1160.             return;
  1161.  
  1162.         // Then redraw the buttons
  1163.         Invalidate();
  1164.     }
  1165. }
  1166.  
  1167. void CToolBar::OnPaint()
  1168. {
  1169.     if (m_bDelayedButtonLayout)
  1170.     {
  1171.         m_bDelayedButtonLayout = FALSE;
  1172.         BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) != 0;
  1173.         if ((m_dwStyle & CBRS_FLOATING) && (m_dwStyle & CBRS_SIZE_DYNAMIC))
  1174.             CalcDynamicLayout(0, LM_HORZ | LM_MRUWIDTH | LM_COMMIT);
  1175.         else if (bHorz)
  1176.             CalcDynamicLayout(0, LM_HORZ | LM_HORZDOCK | LM_COMMIT);
  1177.         else
  1178.             CalcDynamicLayout(0, LM_VERTDOCK | LM_COMMIT);
  1179.     }
  1180.     Default();
  1181. }
  1182.  
  1183. LRESULT CToolBar::OnSetButtonSize(WPARAM, LPARAM lParam)
  1184. {
  1185.     LRESULT lResult = Default();
  1186.     if (lResult)
  1187.         m_sizeButton = lParam;
  1188.     return lResult;
  1189. }
  1190.  
  1191. LRESULT CToolBar::OnSetBitmapSize(WPARAM, LPARAM lParam)
  1192. {
  1193.     LRESULT lResult = Default();
  1194.     if (lResult)
  1195.         m_sizeImage = lParam;
  1196.     return lResult;
  1197. }
  1198.  
  1199. void CToolBar::OnSysColorChange()
  1200. {
  1201. #ifdef _MAC
  1202.     CControlBar::OnSysColorChange();
  1203. #endif
  1204.  
  1205.     // re-color bitmap for toolbar
  1206.     if (m_hInstImageWell != NULL && m_hbmImageWell != NULL)
  1207.     {
  1208.         HBITMAP hbmNew;
  1209. #ifndef _MAC
  1210.         hbmNew = AfxLoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell);
  1211. #else
  1212.         hbmNew = AfxLoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell,
  1213.             m_bMonochrome);
  1214. #endif
  1215.         if (hbmNew != NULL)
  1216.             AddReplaceBitmap(hbmNew);
  1217.     }
  1218. }
  1219.  
  1220. /////////////////////////////////////////////////////////////////////////////
  1221. // CToolBar idle update through CToolCmdUI class
  1222.  
  1223. class CToolCmdUI : public CCmdUI        // class private to this file !
  1224. {
  1225. public: // re-implementations only
  1226.     virtual void Enable(BOOL bOn);
  1227.     virtual void SetCheck(int nCheck);
  1228.     virtual void SetText(LPCTSTR lpszText);
  1229. };
  1230.  
  1231. void CToolCmdUI::Enable(BOOL bOn)
  1232. {
  1233.     m_bEnableChanged = TRUE;
  1234.     CToolBar* pToolBar = (CToolBar*)m_pOther;
  1235.     ASSERT(pToolBar != NULL);
  1236.     ASSERT_KINDOF(CToolBar, pToolBar);
  1237.     ASSERT(m_nIndex < m_nIndexMax);
  1238.  
  1239.     UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) & ~TBBS_DISABLED;
  1240.     if (!bOn)
  1241.     {
  1242.         nNewStyle |= TBBS_DISABLED;
  1243.         // WINBUG: If a button is currently pressed and then is disabled
  1244.         // COMCTL32.DLL does not unpress the button, even after the mouse
  1245.         // button goes up!  We work around this bug by forcing TBBS_PRESSED
  1246.         // off when a button is disabled.
  1247.         nNewStyle &= ~TBBS_PRESSED;
  1248.     }
  1249.     ASSERT(!(nNewStyle & TBBS_SEPARATOR));
  1250.     pToolBar->SetButtonStyle(m_nIndex, nNewStyle);
  1251. }
  1252.  
  1253. void CToolCmdUI::SetCheck(int nCheck)
  1254. {
  1255.     ASSERT(nCheck >= 0 && nCheck <= 2); // 0=>off, 1=>on, 2=>indeterminate
  1256.     CToolBar* pToolBar = (CToolBar*)m_pOther;
  1257.     ASSERT(pToolBar != NULL);
  1258.     ASSERT_KINDOF(CToolBar, pToolBar);
  1259.     ASSERT(m_nIndex < m_nIndexMax);
  1260.  
  1261.     UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) &
  1262.                 ~(TBBS_CHECKED | TBBS_INDETERMINATE);
  1263.     if (nCheck == 1)
  1264.         nNewStyle |= TBBS_CHECKED;
  1265.     else if (nCheck == 2)
  1266.         nNewStyle |= TBBS_INDETERMINATE;
  1267.     ASSERT(!(nNewStyle & TBBS_SEPARATOR));
  1268.     pToolBar->SetButtonStyle(m_nIndex, nNewStyle | TBBS_CHECKBOX);
  1269. }
  1270.  
  1271. void CToolCmdUI::SetText(LPCTSTR)
  1272. {
  1273.     // ignore it
  1274. }
  1275.  
  1276. void CToolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
  1277. {
  1278.     CToolCmdUI state;
  1279.     state.m_pOther = this;
  1280.  
  1281.     state.m_nIndexMax = (UINT)DefWindowProc(TB_BUTTONCOUNT, 0, 0);
  1282.     for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++)
  1283.     {
  1284.         // get buttons state
  1285.         TBBUTTON button;
  1286.         _GetButton(state.m_nIndex, &button);
  1287.         state.m_nID = button.idCommand;
  1288.  
  1289.         // ignore separators
  1290.         if (!(button.fsStyle & TBSTYLE_SEP))
  1291.         {
  1292.             // allow the toolbar itself to have update handlers
  1293.             if (CWnd::OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL))
  1294.                 continue;
  1295.  
  1296.             // allow the owner to process the update
  1297.             state.DoUpdate(pTarget, bDisableIfNoHndler);
  1298.         }
  1299.     }
  1300.  
  1301.     // update the dialog controls added to the toolbar
  1302.     UpdateDialogControls(pTarget, bDisableIfNoHndler);
  1303. }
  1304.  
  1305. /////////////////////////////////////////////////////////////////////////////
  1306. // CToolBar diagnostics
  1307.  
  1308. #ifdef _DEBUG
  1309. void CToolBar::AssertValid() const
  1310. {
  1311.     // Note: CControlBar::AssertValid is not called because it checks for
  1312.     //  m_nCount and m_pData to be in sync, which they are not in CToolBar.
  1313.  
  1314.     ASSERT(m_hbmImageWell == NULL ||
  1315.         (afxData.bWin32s || ::GetObjectType(m_hbmImageWell) == OBJ_BITMAP));
  1316.  
  1317.     if (m_hInstImageWell != NULL && m_hbmImageWell != NULL)
  1318.         ASSERT(m_hRsrcImageWell != NULL);
  1319. }
  1320.  
  1321. void CToolBar::Dump(CDumpContext& dc) const
  1322. {
  1323.     CControlBar::Dump(dc);
  1324.  
  1325.     dc << "m_hbmImageWell = " << (UINT)m_hbmImageWell;
  1326.     dc << "\nm_hInstImageWell = " << (UINT)m_hInstImageWell;
  1327.     dc << "\nm_hRsrcImageWell = " << (UINT)m_hRsrcImageWell;
  1328.     dc << "\nm_sizeButton = " << m_sizeButton;
  1329.     dc << "\nm_sizeImage = " << m_sizeImage;
  1330.  
  1331.     if (dc.GetDepth() > 0)
  1332.     {
  1333.         CToolBar* pBar = (CToolBar*)this;
  1334.         int nCount = pBar->DefWindowProc(TB_BUTTONCOUNT, 0, 0);
  1335.         for (int i = 0; i < nCount; i++)
  1336.         {
  1337.             TBBUTTON button;
  1338.             _GetButton(i, &button);
  1339.             dc << "\ntoolbar button[" << i << "] = {";
  1340.             dc << "\n\tnID = " << button.idCommand;
  1341.             dc << "\n\tnStyle = " << MAKELONG(button.fsStyle, button.fsState);
  1342.             if (button.fsStyle & TBSTYLE_SEP)
  1343.                 dc << "\n\tiImage (separator width) = " << button.iBitmap;
  1344.             else
  1345.                 dc <<"\n\tiImage (bitmap image index) = " << button.iBitmap;
  1346.             dc << "\n}";
  1347.         }
  1348.     }
  1349.  
  1350.     dc << "\n";
  1351. }
  1352. #endif
  1353.  
  1354. #ifdef AFX_INIT_SEG
  1355. #pragma code_seg(AFX_INIT_SEG)
  1356. #endif
  1357.  
  1358. IMPLEMENT_DYNAMIC(CToolBar, CControlBar)
  1359.  
  1360. /////////////////////////////////////////////////////////////////////////////
  1361.