bartool.cpp 39 KB

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