Leaked source code of windows server 2003
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.

587 lines
17 KiB

  1. #include "precomp.h"
  2. #include "MultiStateToolbar.h"
  3. CMultiStateToolbar::CMultiStateToolbar( void )
  4. : m_cxButton( 0 ),
  5. m_cyButton( 0 ),
  6. m_cxBtnBitmaps( 0 ),
  7. m_cyBtnBitmaps( 0 ),
  8. m_himlTB(NULL),
  9. m_himlTBHot(NULL),
  10. m_himlTBDisabled(NULL)
  11. {
  12. DBGENTRY(CMultiStateToolbar::CMultiStateToolbar);
  13. DBGEXIT(CMultiStateToolbar::CMultiStateToolbar);
  14. }
  15. CMultiStateToolbar::~CMultiStateToolbar( void )
  16. {
  17. DBGENTRY(CMultiStateToolbar::~CMultiStateToolbar);
  18. _KillAllButtons();
  19. if(m_himlTB)
  20. {
  21. ImageList_Destroy(m_himlTB);
  22. m_himlTB = NULL;
  23. }
  24. if(m_himlTBHot)
  25. {
  26. ImageList_Destroy(m_himlTBHot);
  27. m_himlTBHot = NULL;
  28. }
  29. if(m_himlTBDisabled)
  30. {
  31. ImageList_Destroy(m_himlTBDisabled);
  32. m_himlTBDisabled = NULL;
  33. }
  34. if( ::IsWindow( m_hWnd ) )
  35. {
  36. DestroyWindow();
  37. }
  38. m_hWnd = NULL;
  39. DBGEXIT(CMultiStateToolbar::~CMultiStateToolbar);
  40. }
  41. HRESULT CMultiStateToolbar::Create( HWND hWndParent,
  42. DWORD dwID,
  43. int cxButton,
  44. int cyButton,
  45. int cxBtnBitmaps,
  46. int cyBtnBitmaps
  47. )
  48. {
  49. DBGENTRY(CMultiStateToolbar::Create);
  50. HRESULT hr = S_OK;
  51. m_cxButton = cxButton;
  52. m_cyButton = cyButton;
  53. m_cxBtnBitmaps = cxBtnBitmaps;
  54. m_cyBtnBitmaps = cyBtnBitmaps;
  55. DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS |
  56. TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_ALTDRAG |
  57. CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE;
  58. HWND hWndToolbar = CreateToolbarEx( hWndParent,
  59. dwStyle,
  60. dwID,
  61. 0, // nBitmaps
  62. NULL, // instance
  63. NULL, // NO bitmap ID!
  64. NULL, // buttons
  65. 0, // number of buttons
  66. m_cxButton, // button sizes
  67. m_cyButton,
  68. m_cxBtnBitmaps, // bitmap sizes
  69. m_cyBtnBitmaps,
  70. sizeof(TBBUTTON)
  71. );
  72. if( hWndToolbar )
  73. {
  74. DWORD dwStyle = ::SendMessage(hWndToolbar, TB_GETEXTENDEDSTYLE, 0, 0);
  75. dwStyle |= TBSTYLE_EX_DRAWDDARROWS;
  76. ::SendMessage(hWndToolbar, TB_SETEXTENDEDSTYLE, 0, (LPARAM) dwStyle);
  77. SubclassWindow( hWndToolbar );
  78. }
  79. else
  80. {
  81. hr = HRESULT_FROM_WIN32(GetLastError());
  82. }
  83. DBGEXIT_HR(CMultiStateToolbar::Create,hr);
  84. return hr;
  85. }
  86. HRESULT CMultiStateToolbar::Show( BOOL bShow )
  87. {
  88. DBGENTRY(CMultiStateToolbar::Show);
  89. HRESULT hr = S_OK;
  90. ShowWindow( bShow ? SW_SHOW : SW_HIDE );
  91. DBGEXIT_HR(CMultiStateToolbar::Show,hr);
  92. return hr;
  93. }
  94. HRESULT CMultiStateToolbar::InsertItem( int cStates, LPCTSTR szTitle, ItemStateInfo* pItemStates, int* pIndex )
  95. {
  96. DBGENTRY(CMultiStateToolbar::InsertItem);
  97. HRESULT hr = S_OK;
  98. if( NULL == m_himlTB )
  99. {
  100. hr = _CreateImageLists();
  101. }
  102. TBItemData* pNewItemData = new TBItemData;
  103. pNewItemData->CurrentState = 0;
  104. pNewItemData->cStates = cStates;
  105. pNewItemData->pStateData = new TBItemStateData[ pNewItemData->cStates ];
  106. int cImageListItemsBeforeInsertion = ImageList_GetImageCount( m_himlTB );
  107. // For each state
  108. for( int iState = 0; iState < cStates; iState++ )
  109. {
  110. // Insert the bitmaps
  111. if( pItemStates[iState].hItemBitmap )
  112. {
  113. if (-1 != ImageList_AddMasked(m_himlTB, pItemStates[iState].hItemBitmap, TOOLBAR_MASK_COLOR))
  114. {
  115. SendMessage(TB_SETIMAGELIST, 0, (LPARAM) m_himlTB);
  116. }
  117. else
  118. {
  119. hr = E_FAIL;
  120. }
  121. }
  122. if( SUCCEEDED( hr ) )
  123. {
  124. if( pItemStates[iState].hItemHotBitmap )
  125. {
  126. if (-1 != ImageList_AddMasked(m_himlTBHot, pItemStates[iState].hItemHotBitmap, TOOLBAR_MASK_COLOR))
  127. {
  128. SendMessage(TB_SETHOTIMAGELIST, 0, (LPARAM) m_himlTBHot);
  129. }
  130. else
  131. {
  132. hr = E_FAIL;
  133. }
  134. }
  135. }
  136. if( SUCCEEDED( hr ) )
  137. {
  138. if( pItemStates[iState].hItemDisabledBitmap )
  139. {
  140. if (-1 != ImageList_AddMasked(m_himlTBDisabled, pItemStates[iState].hItemDisabledBitmap, TOOLBAR_MASK_COLOR))
  141. {
  142. SendMessage(TB_SETDISABLEDIMAGELIST, 0, (LPARAM) m_himlTBDisabled);
  143. }
  144. else
  145. {
  146. hr = E_FAIL;
  147. }
  148. }
  149. }
  150. // save the state data
  151. pNewItemData->pStateData[iState].BitmapId = cImageListItemsBeforeInsertion + iState;
  152. pNewItemData->pStateData[iState].CommandId = pItemStates[iState].dwID;
  153. pNewItemData->pStateData[iState].TbStyle = pItemStates[iState].TbStyle;
  154. pNewItemData->pStateData[iState].StringId = SendMessage( TB_ADDSTRING, 0, reinterpret_cast<LPARAM>( szTitle ) );
  155. }
  156. int nButtons = SendMessage(TB_BUTTONCOUNT, 0, 0 );
  157. // Insert the Item
  158. TBBUTTON tbi;
  159. ClearStruct(&tbi);
  160. tbi.iBitmap = pNewItemData->pStateData[0].BitmapId;
  161. tbi.idCommand = pNewItemData->pStateData[0].CommandId;
  162. tbi.fsState = TBSTATE_ENABLED;
  163. tbi.fsStyle = pNewItemData->pStateData[0].TbStyle;
  164. tbi.dwData = reinterpret_cast<DWORD>(pNewItemData);
  165. tbi.iString = pNewItemData->pStateData[0].StringId;
  166. SendMessage(TB_INSERTBUTTON, nButtons, reinterpret_cast<LPARAM>(&tbi));
  167. if( pIndex )
  168. {
  169. *pIndex = nButtons;
  170. }
  171. DBGEXIT_HR(CMultiStateToolbar::InsertItem,hr);
  172. return hr;
  173. }
  174. HRESULT CMultiStateToolbar::InsertBlock( int nItems,
  175. CMultiStateToolbar::BlockData* pAryOfItemData,
  176. HINSTANCE hInstance,
  177. int idTBBitmap,
  178. int idTBBitmapHot,
  179. int idTBBitmapDisabled,
  180. int* pIndexFirst
  181. )
  182. {
  183. DBGENTRY(CMultiStateToolbar::InsertBlock);
  184. HRESULT hr = S_OK;
  185. if( pAryOfItemData )
  186. {
  187. if( NULL == m_himlTB )
  188. {
  189. hr = _CreateImageLists();
  190. }
  191. if( SUCCEEDED( hr ) )
  192. {
  193. HBITMAP hBmp = NULL;
  194. int cImageListItemsBeforeInsertion = ImageList_GetImageCount( m_himlTB );
  195. // Load the Normal Toolbar Bitmap
  196. hBmp = (HBITMAP) LoadImage(hInstance, MAKEINTRESOURCE(idTBBitmap), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE);
  197. if( hBmp )
  198. {
  199. if (-1 != ImageList_AddMasked(m_himlTB, hBmp, TOOLBAR_MASK_COLOR))
  200. {
  201. SendMessage(TB_SETIMAGELIST, 0, (LPARAM) m_himlTB);
  202. }
  203. else
  204. {
  205. hr = E_FAIL;
  206. }
  207. DeleteObject(hBmp);
  208. }
  209. if( SUCCEEDED( hr ) )
  210. {
  211. // Load the Hot Toolbar Bitmap
  212. hBmp = (HBITMAP) LoadImage(hInstance, MAKEINTRESOURCE(idTBBitmapHot), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE);
  213. if( hBmp )
  214. {
  215. if (-1 != ImageList_AddMasked(m_himlTBHot, hBmp, TOOLBAR_MASK_COLOR))
  216. {
  217. SendMessage(TB_SETHOTIMAGELIST, 0, (LPARAM) m_himlTBHot);
  218. }
  219. else
  220. {
  221. hr = E_FAIL;
  222. }
  223. DeleteObject(hBmp);
  224. }
  225. }
  226. if( SUCCEEDED( hr ) )
  227. {
  228. // Load the Disabled Toolbar Bitmap
  229. hBmp = (HBITMAP) LoadImage(hInstance, MAKEINTRESOURCE(idTBBitmapDisabled), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE);
  230. if( hBmp )
  231. {
  232. if (-1 != ImageList_AddMasked(m_himlTBDisabled, hBmp, TOOLBAR_MASK_COLOR))
  233. {
  234. SendMessage(TB_SETDISABLEDIMAGELIST, 0, (LPARAM) m_himlTBDisabled);
  235. }
  236. else
  237. {
  238. hr = E_FAIL;
  239. }
  240. DeleteObject(hBmp);
  241. }
  242. }
  243. int nButtons = SendMessage(TB_BUTTONCOUNT, 0, 0 );
  244. if( pIndexFirst )
  245. {
  246. *pIndexFirst = nButtons;
  247. }
  248. // For each button to be inserted...
  249. for( int iItem = 0; SUCCEEDED( hr ) && ( iItem < nItems ) ; iItem++ )
  250. {
  251. TBItemData* pNewItemData = new TBItemData;
  252. pNewItemData->CurrentState = 0;
  253. pNewItemData->cStates = pAryOfItemData[iItem].cbStates;
  254. pNewItemData->pStateData = new TBItemStateData[ pNewItemData->cStates ];
  255. int iStringID = SendMessage( TB_ADDSTRING, 0, reinterpret_cast<LPARAM>( pAryOfItemData[iItem].szTitle ) );
  256. for( int iState = 0; iState < pAryOfItemData[iItem].cbStates; iState++ )
  257. {
  258. pNewItemData->pStateData[iState].BitmapId = pAryOfItemData[iItem].pStateData[iState].dwBitmapIndex;
  259. pNewItemData->pStateData[iState].CommandId = pAryOfItemData[iItem].pStateData[iState].dwID;
  260. pNewItemData->pStateData[iState].TbStyle = pAryOfItemData[iItem].pStateData[iState].TbStyle;
  261. pNewItemData->pStateData[iState].StringId = iStringID;
  262. }
  263. TBBUTTON tbi;
  264. ClearStruct(&tbi);
  265. tbi.iBitmap = cImageListItemsBeforeInsertion + pNewItemData->pStateData[0].BitmapId;
  266. tbi.idCommand = pNewItemData->pStateData[0].CommandId;
  267. tbi.fsState = TBSTATE_ENABLED;
  268. tbi.fsStyle = pNewItemData->pStateData[0].TbStyle;
  269. tbi.dwData = reinterpret_cast<DWORD>(pNewItemData);
  270. tbi.iString = pNewItemData->pStateData[0].StringId;
  271. if( SendMessage(TB_INSERTBUTTON, nButtons, reinterpret_cast<LPARAM>(&tbi)) )
  272. {
  273. ++nButtons;
  274. }
  275. else
  276. {
  277. hr = HRESULT_FROM_WIN32(GetLastError());
  278. }
  279. }
  280. }
  281. }
  282. else
  283. {
  284. hr = E_POINTER;
  285. }
  286. DBGEXIT_HR(CMultiStateToolbar::InsertBlock,hr);
  287. return hr;
  288. }
  289. HRESULT CMultiStateToolbar::EnableItem( DWORD dwCmd, BOOL bEnable /* = TRUE */)
  290. {
  291. DBGENTRY(CMultiStateToolbar::EnableItem);
  292. HRESULT hr = S_OK;
  293. if( ::IsWindow( _GetToolbarWindow() ) )
  294. {
  295. if( !SendMessage(TB_ENABLEBUTTON, dwCmd, bEnable ) )
  296. {
  297. hr = E_FAIL;
  298. }
  299. }
  300. else
  301. {
  302. hr = E_FAIL;
  303. }
  304. DBGEXIT_HR(CMultiStateToolbar::EnableItem,hr);
  305. return hr;
  306. }
  307. HRESULT CMultiStateToolbar::SetItemState( int iIndex, int NewState )
  308. {
  309. DBGENTRY(CMultiStateToolbar::SetItemState);
  310. HRESULT hr = S_OK;
  311. if( ::IsWindow( _GetToolbarWindow() ) )
  312. {
  313. TBBUTTON tbb;
  314. ClearStruct(&tbb);
  315. SendMessage( TB_GETBUTTON, iIndex, reinterpret_cast<LPARAM>(&tbb));
  316. TBItemData* pItemData = reinterpret_cast<TBItemData*>(tbb.dwData);
  317. if( pItemData )
  318. {
  319. if( NewState < pItemData->cStates )
  320. {
  321. if( pItemData->CurrentState != NewState )
  322. {
  323. // We have to change the state
  324. TBBUTTONINFO tbbi;
  325. ClearStruct(&tbbi);
  326. tbbi.cbSize = sizeof( TBBUTTONINFO );
  327. tbbi.dwMask = TBIF_IMAGE | TBIF_COMMAND | TBIF_STYLE;
  328. tbbi.idCommand = pItemData->pStateData[NewState].CommandId;
  329. tbbi.iImage = pItemData->pStateData[NewState].BitmapId;
  330. tbbi.fsStyle = pItemData->pStateData[NewState].TbStyle;
  331. // NOTE: Changing the string stuff is not supported....
  332. if( SendMessage( TB_SETBUTTONINFO, pItemData->pStateData[pItemData->CurrentState].CommandId, reinterpret_cast<LPARAM>(&tbbi) ) )
  333. {
  334. pItemData->CurrentState = NewState;
  335. }
  336. // force the image to be redrawn
  337. RECT rc;
  338. SendMessage(TB_GETITEMRECT, iIndex, reinterpret_cast<LPARAM>(&rc));
  339. InvalidateRect(&rc);
  340. InvalidateRect(NULL, TRUE);
  341. }
  342. }
  343. else
  344. {
  345. hr = E_INVALIDARG;
  346. }
  347. }
  348. else
  349. {
  350. hr = E_FAIL;
  351. }
  352. }
  353. DBGEXIT_HR(CMultiStateToolbar::SetItemState,hr);
  354. return hr;
  355. }
  356. HRESULT CMultiStateToolbar::ShowLabels( BOOL bShowLabels)
  357. {
  358. DBGENTRY(CMultiStateToolbar::ShowLabels);
  359. HRESULT hr = S_OK;
  360. if( !bShowLabels )
  361. {
  362. SendMessage(TB_SETBUTTONSIZE, 0, MAKELPARAM( m_cxBtnBitmaps, m_cyBtnBitmaps ) );
  363. }
  364. else
  365. {
  366. SendMessage(TB_SETBUTTONSIZE, 0, MAKELPARAM( m_cxButton, m_cyButton ) );
  367. }
  368. SendMessage(TB_SETMAXTEXTROWS, bShowLabels ? 1 : 0, 0);
  369. DBGEXIT_HR(CMultiStateToolbar::ShowLabels,hr);
  370. return hr;
  371. }
  372. HRESULT CMultiStateToolbar::Resize( RECT& rc )
  373. {
  374. DBGENTRY(CMultiStateToolbar::Resize);
  375. HRESULT hr = S_OK;
  376. if( !SetWindowPos( NULL, &rc, SWP_NOACTIVATE | SWP_NOZORDER) )
  377. {
  378. hr = HRESULT_FROM_WIN32(GetLastError());
  379. }
  380. DBGEXIT_HR(CMultiStateToolbar::Resize,hr);
  381. return hr;
  382. }
  383. HRESULT CMultiStateToolbar::GetWindow( HWND* phWnd )
  384. {
  385. DBGENTRY(CMultiStateToolbar::GetWindow);
  386. HRESULT hr = S_OK;
  387. if( phWnd )
  388. {
  389. ASSERT( NULL == *phWnd );
  390. *phWnd = _GetToolbarWindow();
  391. }
  392. else
  393. {
  394. hr = E_POINTER;
  395. }
  396. DBGEXIT_HR(CMultiStateToolbar::GetWindow,hr);
  397. return hr;
  398. }
  399. LRESULT CMultiStateToolbar::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult )
  400. {
  401. DBGENTRY(CMultiStateToolbar::OnDestroy);
  402. _KillAllButtons();
  403. DBGEXIT(CMultiStateToolbar::OnDestroy);
  404. return 0;
  405. }
  406. LRESULT CMultiStateToolbar::OnNcDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult )
  407. {
  408. // There is a bug in ATL that if you don't handle WM_NCDESTROY,
  409. // ATL will call CallWindowProc will a NULL hWnd... this causes assertions
  410. // on Debug Win95 and Bounds Checker reports an error as well..
  411. DBGENTRY(CMultiStateToolbar::OnNcDestroy);
  412. DBGEXIT(CMultiStateToolbar::OnNcDestroy);
  413. return 0;
  414. }
  415. void CMultiStateToolbar::_KillAllButtons( void )
  416. {
  417. DBGENTRY(CMultiStateToolbar::_KillAllButtons);
  418. if( ::IsWindow( _GetToolbarWindow() ) )
  419. {
  420. int nButtons = SendMessage(TB_BUTTONCOUNT, 0, 0 );
  421. for( int iButton = 0; iButton < nButtons; iButton++ )
  422. {
  423. TBBUTTON tbb;
  424. ClearStruct(&tbb);
  425. if( SendMessage( TB_GETBUTTON, 0, reinterpret_cast<LPARAM>(&tbb)) )
  426. {
  427. TBItemData* pItemData = reinterpret_cast<TBItemData*>(tbb.dwData);
  428. if( pItemData )
  429. {
  430. delete [] pItemData->pStateData;
  431. }
  432. delete [] pItemData;
  433. }
  434. SendMessage( TB_DELETEBUTTON, 0, 0 );
  435. }
  436. }
  437. DBGEXIT(CMultiStateToolbar::_KillAllButtons);
  438. }
  439. HRESULT CMultiStateToolbar::_CreateImageLists( void )
  440. {
  441. DBGENTRY(CMultiStateToolbar::_CreateImageLists);
  442. HRESULT hr = S_OK;
  443. m_himlTB = ImageList_Create( m_cxBtnBitmaps,
  444. m_cyBtnBitmaps,
  445. ILC_COLOR16 | ILC_MASK,
  446. 1, // Initial size
  447. 1 // Grow By
  448. );
  449. m_himlTBHot = ImageList_Create( m_cxBtnBitmaps,
  450. m_cyBtnBitmaps,
  451. ILC_COLOR16 | ILC_MASK,
  452. 1, // Initial size
  453. 1 // Grow By
  454. );
  455. m_himlTBDisabled = ImageList_Create( m_cxBtnBitmaps,
  456. m_cyBtnBitmaps,
  457. ILC_COLOR4 | ILC_MASK,
  458. 1, // Initial size
  459. 1 // Grow By
  460. );
  461. if(! ( m_himlTB && m_himlTBHot && m_himlTBDisabled ) )
  462. { // One of the create calls failed
  463. ASSERT( 0 );
  464. // I think that this is the only reason ImageList_Create would fail...
  465. hr = E_OUTOFMEMORY;
  466. }
  467. DBGEXIT_HR(CMultiStateToolbar::_CreateImageLists,hr);
  468. return hr;
  469. }