Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

514 lines
19 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 2000
  4. *
  5. * TITLE: CREATETB.CPP
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ShaunIv
  10. *
  11. * DATE: 12/22/2000
  12. *
  13. * DESCRIPTION: Toolbar helpers
  14. *
  15. *******************************************************************************/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #include "createtb.h"
  19. #include <windowsx.h>
  20. #include <simstr.h>
  21. #include <psutil.h>
  22. #include <simrect.h>
  23. namespace ToolbarHelper
  24. {
  25. //
  26. // This is a replacement for CreateToolbarEx (in comctl32.dll) that uses CreateMappedBitmap
  27. // so we can get the benefit of having buttons that work ok in high contrast mode.
  28. //
  29. HWND CreateToolbar(
  30. HWND hwndParent,
  31. DWORD dwStyle,
  32. UINT_PTR nID,
  33. CToolbarBitmapInfo &ToolbarBitmapInfo,
  34. LPCTBBUTTON pButtons,
  35. int nButtonCount,
  36. int nButtonWidth,
  37. int nButtonHeight,
  38. int nBitmapWidth,
  39. int nBitmapHeight,
  40. UINT nButtonStructSize )
  41. {
  42. HWND hwndToolbar = CreateWindow( TOOLBARCLASSNAME, NULL, WS_CHILD | dwStyle, 0, 0, 100, 30, hwndParent, reinterpret_cast<HMENU>(nID), NULL, NULL );
  43. if (hwndToolbar)
  44. {
  45. ToolbarBitmapInfo.Toolbar(hwndToolbar);
  46. SendMessage( hwndToolbar, TB_BUTTONSTRUCTSIZE, nButtonStructSize, 0 );
  47. if (nBitmapWidth && nBitmapHeight)
  48. {
  49. SendMessage( hwndToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(nBitmapWidth,nBitmapHeight) );
  50. }
  51. if (nButtonWidth && nButtonHeight)
  52. {
  53. SendMessage( hwndToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(nButtonWidth,nButtonHeight) );
  54. }
  55. HBITMAP hBitmap = CreateMappedBitmap( ToolbarBitmapInfo.ToolbarInstance(), ToolbarBitmapInfo.BitmapResId(), 0, NULL, 0 );
  56. if (hBitmap)
  57. {
  58. TBADDBITMAP TbAddBitmap = {0};
  59. TbAddBitmap.hInst = NULL;
  60. TbAddBitmap.nID = reinterpret_cast<UINT_PTR>(hBitmap);
  61. if (-1 != SendMessage( hwndToolbar, TB_ADDBITMAP, ToolbarBitmapInfo.ButtonCount(), reinterpret_cast<LPARAM>(&TbAddBitmap) ) )
  62. {
  63. ToolbarBitmapInfo.Bitmap(hBitmap);
  64. }
  65. }
  66. SendMessage( hwndToolbar, TB_ADDBUTTONS, nButtonCount, reinterpret_cast<LPARAM>(pButtons) );
  67. }
  68. return hwndToolbar;
  69. }
  70. HWND CreateToolbar(
  71. HWND hWndParent,
  72. HWND hWndPrevious,
  73. HWND hWndAlign,
  74. int Alignment,
  75. UINT nToolbarId,
  76. CToolbarBitmapInfo &ToolbarBitmapInfo,
  77. CButtonDescriptor *pButtonDescriptors,
  78. UINT nDescriptorCount )
  79. {
  80. HWND hWndToolbar = NULL;
  81. //
  82. // Make sure we have valid data
  83. //
  84. if (!hWndParent || !ToolbarBitmapInfo.ToolbarInstance() || !ToolbarBitmapInfo.BitmapResId() || !pButtonDescriptors || !nDescriptorCount)
  85. {
  86. return NULL;
  87. }
  88. //
  89. // Load the bitmap, so we can figure out how many buttons are in the supplied bitmap,
  90. // and their size. We assume that the buttons are the same height and width.
  91. //
  92. HBITMAP hBitmap = reinterpret_cast<HBITMAP>(LoadImage( ToolbarBitmapInfo.ToolbarInstance(), MAKEINTRESOURCE(ToolbarBitmapInfo.BitmapResId()), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR|LR_CREATEDIBSECTION ));
  93. if (hBitmap)
  94. {
  95. //
  96. // Get the size of the bitmap
  97. //
  98. SIZE sizeBitmap = {0};
  99. PrintScanUtil::GetBitmapSize(hBitmap,sizeBitmap);
  100. //
  101. // If the sizes are valid, continue
  102. //
  103. if (sizeBitmap.cx && sizeBitmap.cy)
  104. {
  105. //
  106. // Figure out the count and dimensions of the buttons
  107. // Note the ridiculous size supplied for nButtonSizeX. This is a
  108. // workaround for a BTNS_AUTOSIZE bug
  109. //
  110. int nToolbarButtonCount = sizeBitmap.cx / sizeBitmap.cy;
  111. int nButtonBitmapSizeX = sizeBitmap.cy;
  112. int nButtonBitmapSizeY = sizeBitmap.cy;
  113. int nButtonSizeX = 1000;
  114. int nButtonSizeY = sizeBitmap.cy;
  115. //
  116. // Figure out which buttons to actually add
  117. //
  118. CSimpleDynamicArray<TBBUTTON> aActualButtons;
  119. for (UINT i=0;i<nDescriptorCount;i++)
  120. {
  121. //
  122. // If there is no controlling variable, or if it is true, add the button
  123. //
  124. if (!pButtonDescriptors[i].pbControllingVariable || *(pButtonDescriptors[i].pbControllingVariable))
  125. {
  126. TBBUTTON ToolbarButton = {0};
  127. ToolbarButton.iBitmap = pButtonDescriptors[i].iBitmap >= 0 ? pButtonDescriptors[i].iBitmap : I_IMAGENONE;
  128. ToolbarButton.idCommand = pButtonDescriptors[i].idCommand;
  129. ToolbarButton.fsState = pButtonDescriptors[i].fsState;
  130. ToolbarButton.fsStyle = pButtonDescriptors[i].fsStyle | BTNS_AUTOSIZE;
  131. aActualButtons.Append(ToolbarButton);
  132. //
  133. // Add the separator, if requested
  134. //
  135. if (pButtonDescriptors[i].bFollowingSeparator)
  136. {
  137. TBBUTTON ToolbarButtonSeparator = {0};
  138. ToolbarButton.fsStyle = BTNS_SEP;
  139. aActualButtons.Append(ToolbarButton);
  140. }
  141. }
  142. }
  143. //
  144. // Make sure we have at least one button
  145. //
  146. ToolbarBitmapInfo.ButtonCount(nToolbarButtonCount);
  147. if (aActualButtons.Size())
  148. {
  149. //
  150. // Create the toolbar
  151. //
  152. hWndToolbar = CreateToolbar(
  153. hWndParent,
  154. WS_CHILD|WS_GROUP|WS_VISIBLE|TBSTYLE_FLAT|WS_TABSTOP|CCS_NODIVIDER|TBSTYLE_LIST|CCS_NORESIZE|TBSTYLE_TOOLTIPS,
  155. nToolbarId,
  156. ToolbarBitmapInfo,
  157. aActualButtons.Array(),
  158. aActualButtons.Size(),
  159. nButtonSizeX,
  160. nButtonSizeY,
  161. nButtonBitmapSizeX,
  162. nButtonBitmapSizeY,
  163. sizeof(TBBUTTON) );
  164. if (hWndToolbar)
  165. {
  166. //
  167. // Set the font for the toolbar to be the same as the font for its parent
  168. //
  169. LRESULT lFontResult = SendMessage( hWndParent, WM_GETFONT, 0, 0 );
  170. if (lFontResult)
  171. {
  172. SendMessage( hWndToolbar, WM_SETFONT, lFontResult, 0 );
  173. }
  174. //
  175. // Loop through all of the actual buttons, to find their string resource ID
  176. //
  177. for (int i=0;i<aActualButtons.Size();i++)
  178. {
  179. //
  180. // Look for the matching record, to find the string resource ID
  181. //
  182. for (UINT j=0;j<nDescriptorCount;j++)
  183. {
  184. //
  185. // If this is the original record
  186. //
  187. if (aActualButtons[i].idCommand == pButtonDescriptors[j].idCommand)
  188. {
  189. //
  190. // If this button has a resource ID
  191. //
  192. if (pButtonDescriptors[j].nStringResId)
  193. {
  194. //
  195. // Load the string resource and check to make sure it has a length
  196. //
  197. CSimpleString strText( pButtonDescriptors[j].nStringResId, ToolbarBitmapInfo.ToolbarInstance() );
  198. if (strText.Length())
  199. {
  200. //
  201. // Add the text
  202. //
  203. TBBUTTONINFO ToolBarButtonInfo = {0};
  204. ToolBarButtonInfo.cbSize = sizeof(ToolBarButtonInfo);
  205. ToolBarButtonInfo.dwMask = TBIF_TEXT;
  206. ToolBarButtonInfo.pszText = const_cast<LPTSTR>(strText.String());
  207. SendMessage( hWndToolbar, TB_SETBUTTONINFO, pButtonDescriptors[j].idCommand, reinterpret_cast<LPARAM>(&ToolBarButtonInfo) );
  208. }
  209. }
  210. //
  211. // Exit the inner loop, since we've found a match
  212. //
  213. break;
  214. }
  215. }
  216. }
  217. //
  218. // Tell the toolbar to resize itself
  219. //
  220. SendMessage( hWndToolbar, TB_AUTOSIZE, 0, 0 );
  221. }
  222. }
  223. }
  224. //
  225. // Free the bitmap
  226. //
  227. DeleteBitmap(hBitmap);
  228. }
  229. //
  230. // Resize and place the toolbar as needed
  231. //
  232. if (hWndToolbar && hWndAlign)
  233. {
  234. //
  235. // Get the size of the toolbar
  236. //
  237. SIZE sizeToolbar = {0};
  238. if (SendMessage( hWndToolbar, TB_GETMAXSIZE, 0, reinterpret_cast<LPARAM>(&sizeToolbar)))
  239. {
  240. //
  241. // Get the size of the placement window
  242. //
  243. CSimpleRect rcFrameWnd = CSimpleRect( hWndAlign, CSimpleRect::WindowRect ).ScreenToClient(hWndParent);
  244. //
  245. // Determine how to align horizontally
  246. //
  247. int nOriginX = rcFrameWnd.left;
  248. if (Alignment & AlignHCenter)
  249. {
  250. nOriginX = rcFrameWnd.left + (rcFrameWnd.Width() - sizeToolbar.cx) / 2;
  251. }
  252. else if (Alignment & AlignRight)
  253. {
  254. nOriginX = rcFrameWnd.right - sizeToolbar.cx;
  255. }
  256. int nOriginY = rcFrameWnd.top;
  257. if (Alignment & AlignVCenter)
  258. {
  259. nOriginY = rcFrameWnd.top + (rcFrameWnd.Height() - sizeToolbar.cy) / 2;
  260. }
  261. else if (Alignment & AlignBottom)
  262. {
  263. nOriginY = rcFrameWnd.bottom - sizeToolbar.cy;
  264. }
  265. //
  266. // Move and size the toolbar
  267. //
  268. SetWindowPos( hWndToolbar, NULL, nOriginX, nOriginY, sizeToolbar.cx, sizeToolbar.cy, SWP_NOZORDER|SWP_NOACTIVATE );
  269. }
  270. }
  271. if (hWndToolbar && hWndPrevious)
  272. {
  273. SetWindowPos( hWndToolbar, hWndPrevious, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE );
  274. }
  275. return hWndToolbar;
  276. }
  277. void SetToolbarButtonState( HWND hWndToolbar, int nButtonId, int nState )
  278. {
  279. int nCurrentState = static_cast<int>(SendMessage(hWndToolbar,TB_GETSTATE,nButtonId,0));
  280. if (nCurrentState != -1)
  281. {
  282. if (nCurrentState ^ nState)
  283. {
  284. SendMessage(hWndToolbar,TB_SETSTATE,nButtonId,MAKELONG(nState,0));
  285. }
  286. }
  287. }
  288. void EnableToolbarButton( HWND hWndToolbar, int nButtonId, bool bEnable )
  289. {
  290. WIA_PUSH_FUNCTION((TEXT("EnableToolbarButton")));
  291. int nCurrentState = static_cast<int>(SendMessage(hWndToolbar,TB_GETSTATE,nButtonId,0));
  292. if (nCurrentState != -1)
  293. {
  294. if (bEnable)
  295. {
  296. nCurrentState |= TBSTATE_ENABLED;
  297. }
  298. else
  299. {
  300. nCurrentState &= ~TBSTATE_ENABLED;
  301. }
  302. SetToolbarButtonState( hWndToolbar, nButtonId, nCurrentState );
  303. }
  304. //
  305. // If there are no enabled buttons, remove the WS_TABSTOP bit. If there are,
  306. // make sure we add it back in.
  307. //
  308. //
  309. // Assume we don't need the WS_TABSTOP style
  310. //
  311. bool bTabStop = false;
  312. //
  313. // Loop through all of the buttons in the control
  314. //
  315. for (int i=0;i<SendMessage(hWndToolbar,TB_BUTTONCOUNT,0,0);++i)
  316. {
  317. //
  318. // Get the button info for each button
  319. //
  320. TBBUTTON TbButton = {0};
  321. if (SendMessage(hWndToolbar,TB_GETBUTTON,i,reinterpret_cast<LPARAM>(&TbButton)))
  322. {
  323. WIA_TRACE((TEXT("TbButton: %d, %d, %04X, %04X, %08X, %p"), TbButton.iBitmap, TbButton.idCommand, TbButton.fsState, TbButton.fsStyle, TbButton.dwData, TbButton.iString ));
  324. //
  325. // If this button is enabled, set bTabStop to true and pop out of the loop
  326. if (!(TbButton.fsStyle & BTNS_SEP) && TbButton.fsState & TBSTATE_ENABLED)
  327. {
  328. bTabStop = true;
  329. break;
  330. }
  331. }
  332. }
  333. //
  334. // Get the current window style and save a copy, so we don't
  335. // call SetWindowLong for no reason.
  336. //
  337. LONG nStyle = GetWindowLong( hWndToolbar, GWL_STYLE );
  338. LONG nCurrent = nStyle;
  339. //
  340. // Calculate the new style
  341. //
  342. if (bTabStop)
  343. {
  344. nStyle |= WS_TABSTOP;
  345. }
  346. else
  347. {
  348. nStyle &= ~WS_TABSTOP;
  349. }
  350. //
  351. // If the new style doesn't match the old one, set the style
  352. //
  353. if (nStyle != nCurrent)
  354. {
  355. SetWindowLong( hWndToolbar, GWL_STYLE, nStyle );
  356. }
  357. }
  358. bool GetAccelerator( LPCTSTR pszString, TCHAR &chAccel )
  359. {
  360. //
  361. // & marks an accelerator
  362. //
  363. const TCHAR c_chAccelFlag = TEXT('&');
  364. //
  365. // Assume we won't find an accelerator
  366. //
  367. chAccel = 0;
  368. //
  369. // Loop through the string
  370. //
  371. LPCTSTR pszCurr = pszString;
  372. while (pszString && *pszString)
  373. {
  374. //
  375. // If this is the marker character
  376. //
  377. if (c_chAccelFlag == *pszCurr)
  378. {
  379. //
  380. // Get the next character.
  381. //
  382. pszCurr = CharNext(pszCurr);
  383. //
  384. // Make sure this isn't a && situation. If it isn't, save the accelerator and break out.
  385. //
  386. if (c_chAccelFlag != *pszCurr)
  387. {
  388. chAccel = reinterpret_cast<TCHAR>(CharUpper(reinterpret_cast<LPTSTR>(*pszCurr)));
  389. break;
  390. }
  391. }
  392. //
  393. // It is OK to call this even if we are on the end of the string already
  394. //
  395. pszCurr = CharNext(pszCurr);
  396. }
  397. return (0 != chAccel);
  398. }
  399. UINT GetButtonBarAccelerators( HWND hWndToolbar, ACCEL *pAccelerators, UINT nMaxCount )
  400. {
  401. WIA_PUSH_FUNCTION((TEXT("GetButtonBarAccelerators")));
  402. //
  403. // We can't exceed the maximum number of buttons
  404. //
  405. UINT nCurrAccel=0;
  406. //
  407. // Loop through all of the buttons in the control
  408. //
  409. for (LRESULT i=0;i<SendMessage(hWndToolbar,TB_BUTTONCOUNT,0,0) && nCurrAccel < nMaxCount;++i)
  410. {
  411. //
  412. // Get the button info for each button, so we can get the ID
  413. //
  414. TBBUTTON TbButton = {0};
  415. if (SendMessage(hWndToolbar,TB_GETBUTTON,i,reinterpret_cast<LPARAM>(&TbButton)))
  416. {
  417. WIA_TRACE((TEXT("TbButton: %d, %d, %04X, %04X, %08X, %p"), TbButton.iBitmap, TbButton.idCommand, TbButton.fsState, TbButton.fsStyle, TbButton.dwData, TbButton.iString ));
  418. //
  419. // Ignore separators
  420. //
  421. if (!(TbButton.fsStyle & BTNS_SEP))
  422. {
  423. //
  424. // Get the button text.
  425. //
  426. TCHAR szButtonText[MAX_PATH]={0};
  427. if (-1 != SendMessage(hWndToolbar,TB_GETBUTTONTEXT,TbButton.idCommand,reinterpret_cast<LPARAM>(szButtonText)))
  428. {
  429. //
  430. // Get the accelerator (if any)
  431. //
  432. TCHAR chAccel = 0;
  433. if (GetAccelerator( szButtonText, chAccel ))
  434. {
  435. //
  436. // Create an ACCEL record
  437. //
  438. pAccelerators[nCurrAccel].cmd = static_cast<WORD>(TbButton.idCommand);
  439. pAccelerators[nCurrAccel].fVirt = FALT|FVIRTKEY;
  440. pAccelerators[nCurrAccel].key = chAccel;
  441. //
  442. // One more accelerator
  443. //
  444. nCurrAccel++;
  445. }
  446. }
  447. }
  448. }
  449. }
  450. #if defined(DBG)
  451. for (UINT i=0;i<nCurrAccel;i++)
  452. {
  453. WIA_TRACE((TEXT("pAccelerators[%d].fVirt = 0x%02X, 0x%04X (%c), 0x%04X"), i, pAccelerators[i].fVirt, pAccelerators[i].key, pAccelerators[i].key, pAccelerators[i].cmd ));
  454. }
  455. #endif
  456. return nCurrAccel;
  457. }
  458. void CheckToolbarButton( HWND hWndToolbar, int nButtonId, bool bChecked )
  459. {
  460. int nCurrentState = static_cast<int>(SendMessage(hWndToolbar,TB_GETSTATE,nButtonId,0));
  461. if (nCurrentState != -1)
  462. {
  463. if (bChecked)
  464. {
  465. nCurrentState |= TBSTATE_CHECKED;
  466. }
  467. else
  468. {
  469. nCurrentState &= ~TBSTATE_CHECKED;
  470. }
  471. SetToolbarButtonState( hWndToolbar, nButtonId, nCurrentState );
  472. }
  473. }
  474. }