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.

326 lines
9.4 KiB

  1. #include "shellprv.h"
  2. #include "resource.h"
  3. #include "tbmenu.h"
  4. #include "isfband.h"
  5. #include "util.h"
  6. #include <uxtheme.h>
  7. #define SUPERCLASS CMenuToolbarBase
  8. CToolbarMenu::CToolbarMenu(DWORD dwFlags, HWND hwndTB) :
  9. CMenuToolbarBase(NULL, dwFlags),
  10. _hwndSubject(hwndTB) // this is the toolbar that we are customizing
  11. {
  12. }
  13. void CToolbarMenu::GetSize(SIZE* psize)
  14. {
  15. ASSERT(_hwndMB);
  16. if (SendMessage(_hwndMB, TB_GETTEXTROWS, 0, 0) == 0)
  17. {
  18. // no text labels, so set a min width to make menu look
  19. // pretty. use min width of 5 * button width.
  20. // if < 5 buttons, use button count * button width
  21. int cButtons = ToolBar_ButtonCount(_hwndMB);
  22. cButtons = min(5, cButtons);
  23. LRESULT lButtonSize = SendMessage(_hwndMB, TB_GETBUTTONSIZE, 0, 0);
  24. LONG cxMin = cButtons * LOWORD(lButtonSize);
  25. psize->cx = max(psize->cx, cxMin);
  26. }
  27. SUPERCLASS::GetSize(psize);
  28. }
  29. void CToolbarMenu::v_Show(BOOL fShow, BOOL fForceUpdate)
  30. {
  31. if (fShow)
  32. {
  33. _fClickHandled = FALSE;
  34. _FillToolbar();
  35. _pcmb->SetTracked(NULL); // Since hot item is NULL
  36. ToolBar_SetHotItem(_hwndMB, -1);
  37. if (fForceUpdate)
  38. v_UpdateButtons(TRUE);
  39. }
  40. }
  41. void CToolbarMenu::v_Close()
  42. {
  43. if (_hwndMB)
  44. _UnsubclassWindow(_hwndMB);
  45. SUPERCLASS::v_Close();
  46. }
  47. void CToolbarMenu::v_UpdateButtons(BOOL fNegotiateSize)
  48. {
  49. }
  50. HRESULT CToolbarMenu::v_CallCBItem(int idtCmd, UINT dwMsg, WPARAM wParam, LPARAM lParam)
  51. {
  52. ASSERT(_pcmb); // if you hit this assert, you haven't initialized yet.. call SetSite first
  53. if (_pcmb->_psmcb)
  54. {
  55. SMDATA smd = {0};
  56. smd.dwMask = SMDM_TOOLBAR;
  57. smd.uId = idtCmd;
  58. smd.uIdParent = _pcmb->_uId;
  59. smd.uIdAncestor = _pcmb->_uIdAncestor;
  60. smd.punk = SAFECAST(_pcmb, IShellMenu*);
  61. smd.pvUserData = _pcmb->_pvUserData;
  62. smd.hwnd = _hwndMB;
  63. return _pcmb->_psmcb->CallbackSM(&smd, dwMsg, wParam, lParam);
  64. }
  65. return S_FALSE;
  66. }
  67. HRESULT CToolbarMenu::v_GetState(int idtCmd, LPSMDATA psmd)
  68. {
  69. ASSERT(0);
  70. return E_NOTIMPL;
  71. }
  72. HRESULT CToolbarMenu::v_ExecItem(int idCmd)
  73. {
  74. HRESULT hres = E_FAIL;
  75. TraceMsg(TF_TBMENU, "CToolbarMenu::v_ExecItem \tidCmd: %d", idCmd);
  76. return hres;
  77. }
  78. HRESULT CToolbarMenu::CreateToolbar(HWND hwndParent)
  79. {
  80. HRESULT hr = S_OK;
  81. if (!_hwndMB)
  82. {
  83. DWORD dwStyle = (WS_VISIBLE | WS_CHILD | TBSTYLE_FLAT |
  84. WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER |
  85. CCS_NOPARENTALIGN | CCS_NORESIZE | TBSTYLE_REGISTERDROP | TBSTYLE_TOOLTIPS);
  86. INT_PTR nRows = SendMessage(_hwndSubject, TB_GETTEXTROWS, 0, 0);
  87. if (nRows > 0)
  88. {
  89. // We have text labels; make it TBSTYLE_LIST. The base class will
  90. // set TBSTYLE_EX_VERTICAL for us.
  91. ASSERT(_fHorizInVerticalMB == FALSE);
  92. dwStyle |= TBSTYLE_LIST;
  93. }
  94. else
  95. {
  96. // No text labels; make it horizontal and TBSTYLE_WRAPABLE. Set
  97. // _fHorizInVerticalMB so that the base class does not try and set
  98. // TBSTYLE_EX_VERTICAL.
  99. _fHorizInVerticalMB = TRUE;
  100. dwStyle |= TBSTYLE_WRAPABLE;
  101. }
  102. _hwndMB = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, TEXT("Menu"), dwStyle,
  103. 0, 0, 0, 0, hwndParent, (HMENU) FCIDM_TOOLBAR, HINST_THISDLL, NULL);
  104. if (!_hwndMB)
  105. {
  106. TraceMsg(TF_TBMENU, "CToolbarMenu::CreateToolbar: Failed to Create Toolbar");
  107. return HRESULT_FROM_WIN32(GetLastError());
  108. }
  109. HWND hwndTT = (HWND)SendMessage(_hwndMB, TB_GETTOOLTIPS, 0, 0);
  110. SHSetWindowBits(hwndTT, GWL_STYLE, TTS_ALWAYSTIP, TTS_ALWAYSTIP);
  111. SendMessage(_hwndMB, TB_BUTTONSTRUCTSIZE, SIZEOF(TBBUTTON), 0);
  112. SendMessage(_hwndMB, TB_SETMAXTEXTROWS, nRows, 0);
  113. SendMessage(_hwndMB, CCM_SETVERSION, COMCTL32_VERSION, 0);
  114. SendMessage(_hwndMB, TB_SETEXTENDEDSTYLE, TBSTYLE_EX_DRAWDDARROWS, TBSTYLE_EX_DRAWDDARROWS);
  115. int cPimgs = (int)SendMessage(_hwndSubject, TB_GETIMAGELISTCOUNT, 0, 0);
  116. for (int i = 0; i < cPimgs; i++)
  117. {
  118. HIMAGELIST himl = (HIMAGELIST)SendMessage(_hwndSubject, TB_GETIMAGELIST, i, 0);
  119. SendMessage(_hwndMB, TB_SETIMAGELIST, i, (LPARAM)himl);
  120. HIMAGELIST himlHot = (HIMAGELIST)SendMessage(_hwndSubject, TB_GETHOTIMAGELIST, i, 0);
  121. SendMessage(_hwndMB, TB_SETHOTIMAGELIST, i, (LPARAM)himlHot);
  122. }
  123. _SubclassWindow(_hwndMB);
  124. // Set the format to ANSI
  125. ToolBar_SetUnicodeFormat(_hwndMB, 0);
  126. SetWindowTheme(_hwndMB, L"", L"");
  127. hr = CMenuToolbarBase::CreateToolbar(hwndParent);
  128. }
  129. else if (GetParent(_hwndMB) != hwndParent)
  130. {
  131. ::SetParent(_hwndMB, hwndParent);
  132. }
  133. return hr;
  134. }
  135. LRESULT CToolbarMenu::_DefWindowProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  136. {
  137. LRESULT lRes = CMenuToolbarBase::_DefWindowProcMB(hwnd, uMessage, wParam, lParam);
  138. if (lRes == 0)
  139. lRes = CNotifySubclassWndProc::_DefWindowProc(hwnd, uMessage, wParam, lParam);
  140. return lRes;
  141. }
  142. #define MAXLEN 256
  143. BYTE ToolBar_GetStateByIndex(HWND hwnd, INT_PTR iIndex)
  144. {
  145. TBBUTTONINFO tbb;
  146. tbb.cbSize = sizeof(TBBUTTONINFO);
  147. tbb.dwMask = TBIF_STATE | TBIF_BYINDEX;
  148. ToolBar_GetButtonInfo(hwnd, iIndex, &tbb);
  149. return tbb.fsState;
  150. }
  151. void CToolbarMenu::_FillToolbar()
  152. {
  153. RECT rcTB;
  154. TCHAR pszBuf[MAXLEN+1];
  155. LPTSTR psz;
  156. TBBUTTON tb;
  157. INT_PTR i, iCount;
  158. iCount = SendMessage(_hwndSubject, TB_BUTTONCOUNT, 0, 0L);
  159. GetClientRect(_hwndSubject, &rcTB);
  160. for (i = 0; i < iCount; i++)
  161. {
  162. if (SHIsButtonObscured(_hwndSubject, &rcTB, i) ||
  163. ((ToolBar_GetStateByIndex(_hwndSubject, i) & (TBSTATE_HIDDEN | TBSTATE_ENABLED)) ==
  164. (TBSTATE_HIDDEN | TBSTATE_ENABLED)))
  165. {
  166. SendMessage(_hwndSubject, TB_GETBUTTON, i, (LPARAM)&tb);
  167. if (!(tb.fsStyle & BTNS_SEP))
  168. {
  169. // autosize buttons look ugly here
  170. tb.fsStyle &= ~BTNS_AUTOSIZE;
  171. // need to rip off wrap bit; new toolbar will
  172. // figure out where wrapping should happen
  173. // also rip off hidden bit
  174. tb.fsState &= ~(TBSTATE_WRAP | TBSTATE_HIDDEN);
  175. if (tb.iString == -1)
  176. {
  177. // no string
  178. psz = NULL;
  179. }
  180. else if (HIWORD(tb.iString))
  181. {
  182. // it's a string pointer
  183. psz = (LPTSTR) tb.iString;
  184. }
  185. else
  186. {
  187. // it's an index into toolbar string array
  188. SendMessage(_hwndSubject, TB_GETSTRING, MAKELONG(MAXLEN, tb.iString), (LPARAM)pszBuf);
  189. psz = pszBuf;
  190. }
  191. if (psz)
  192. tb.iString = (INT_PTR)psz;
  193. else
  194. tb.iString = -1;
  195. if (tb.iBitmap == -1)
  196. {
  197. int id = GetDlgCtrlID(_hwndSubject);
  198. NMTBDISPINFO tbgdi = {0};
  199. tbgdi.hdr.hwndFrom = _hwndSubject;
  200. tbgdi.hdr.idFrom = id;
  201. tbgdi.hdr.code = TBN_GETDISPINFO;
  202. tbgdi.dwMask = TBNF_IMAGE;
  203. tbgdi.idCommand = tb.idCommand;
  204. tbgdi.iImage = 0;
  205. tbgdi.lParam = tb.dwData;
  206. SendMessage(GetParent(_hwndSubject), WM_NOTIFY, (WPARAM)id, (LPARAM)&tbgdi);
  207. if(tbgdi.dwMask & TBNF_DI_SETITEM)
  208. tb.iBitmap = tbgdi.iImage;
  209. }
  210. SendMessage(_hwndMB, TB_ADDBUTTONS, 1, (LPARAM)&tb);
  211. }
  212. }
  213. }
  214. }
  215. STDMETHODIMP CToolbarMenu::IsWindowOwner(HWND hwnd)
  216. {
  217. if ( hwnd == _hwndMB)
  218. return S_OK;
  219. else
  220. return S_FALSE;
  221. }
  222. void CToolbarMenu::_CancelMenu()
  223. {
  224. IMenuPopup* pmp;
  225. if (EVAL(SUCCEEDED(_pcmb->QueryInterface(IID_PPV_ARG(IMenuPopup, &pmp)))))
  226. {
  227. // tell menuband it's time to die
  228. pmp->OnSelect(MPOS_FULLCANCEL);
  229. pmp->Release();
  230. }
  231. }
  232. STDMETHODIMP CToolbarMenu::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
  233. {
  234. HRESULT hres = S_FALSE;
  235. ASSERT(plres);
  236. switch (uMsg)
  237. {
  238. case WM_COMMAND:
  239. PostMessage(GetParent(_hwndSubject), WM_COMMAND, wParam, (LPARAM)_hwndSubject);
  240. _CancelMenu();
  241. hres = S_OK;
  242. break;
  243. case WM_NOTIFY:
  244. {
  245. LPNMHDR pnmh = (LPNMHDR) lParam;
  246. switch (pnmh->code)
  247. {
  248. case TBN_DROPDOWN:
  249. _fTrackingSubMenu = TRUE;
  250. pnmh->hwndFrom = _hwndSubject;
  251. MapWindowPoints(_hwndMB, _hwndSubject, (LPPOINT) &((LPNMTOOLBAR)pnmh)->rcButton, 2);
  252. *plres = SendMessage(GetParent(_hwndSubject), WM_NOTIFY, wParam, (LPARAM)pnmh);
  253. _CancelMenu();
  254. hres = S_OK;
  255. _fTrackingSubMenu = FALSE;
  256. break;
  257. default:
  258. goto DoDefault;
  259. }
  260. }
  261. break;
  262. DoDefault:
  263. default:
  264. hres = SUPERCLASS::OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
  265. }
  266. return hres;
  267. }
  268. CMenuToolbarBase* ToolbarMenu_Create(HWND hwnd)
  269. {
  270. return new CToolbarMenu(0, hwnd);
  271. }