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.

1343 lines
40 KiB

  1. #include "priv.h"
  2. #include "theater.h"
  3. #include "browbs.h"
  4. #include "resource.h"
  5. #include "legacy.h"
  6. #include "uxtheme.h" // needed for Margin.
  7. #include "mluisupp.h"
  8. #include "apithk.h"
  9. #define SUPERCLASS CBandSite
  10. TCHAR GetAccelerator(LPCTSTR psz, BOOL bUseDefault);
  11. #define ABS(x) (((x) < 0) ? -(x) : (x))
  12. #define CX_TEXTOFFSET 6
  13. #define CY_TEXTOFFSET 4
  14. #define CX_TBOFFSET 1
  15. #define CY_TBPADDING 1
  16. #define CY_ETCH 2
  17. #define CY_FLUFF 7
  18. // *** IInputObject methods ***
  19. HRESULT CBrowserBandSite::HasFocusIO()
  20. {
  21. HWND hwnd = GetFocus();
  22. if (hwnd && (hwnd == _hwndTB || hwnd == _hwndOptionsTB))
  23. return S_OK;
  24. else
  25. return SUPERCLASS::HasFocusIO();
  26. }
  27. // *** IDeskBarClient methods ***
  28. HRESULT CBrowserBandSite::SetModeDBC(DWORD dwMode)
  29. {
  30. if ((dwMode ^ _dwMode) & DBIF_VIEWMODE_VERTICAL) {
  31. // switching horizontal/vertical; need to toggle toolbar
  32. // since we hide toolbar for horizontal bars
  33. if (_hwndTBRebar) {
  34. if (dwMode & DBIF_VIEWMODE_VERTICAL) {
  35. ShowWindow(_hwndTBRebar, SW_SHOW);
  36. _fToolbar = _pCmdTarget ? TRUE : FALSE;
  37. } else {
  38. ShowWindow(_hwndTBRebar, SW_HIDE);
  39. _fToolbar = FALSE;
  40. }
  41. }
  42. }
  43. return SUPERCLASS::SetModeDBC(dwMode);
  44. }
  45. HRESULT CBrowserBandSite::TranslateAcceleratorIO(LPMSG lpMsg)
  46. {
  47. TraceMsg(TF_ACCESSIBILITY, "CBrowserBandSite::TranslateAcceleratorIO (hwnd=0x%08X) key=%d", _hwnd, lpMsg->wParam);
  48. HRESULT hr = S_FALSE;
  49. ASSERT((lpMsg->message >= WM_KEYFIRST) && (lpMsg->message <= WM_KEYLAST));
  50. #if 0 //Disabled until a better key combination can be determined
  51. // check for Control-Shift arrow keys and resize if necessary
  52. if ((GetKeyState(VK_SHIFT) < 0) && (GetKeyState(VK_CONTROL) < 0))
  53. {
  54. switch (lpMsg->wParam)
  55. {
  56. case VK_UP:
  57. case VK_DOWN:
  58. case VK_LEFT:
  59. case VK_RIGHT:
  60. IUnknown_Exec(_punkSite, &CGID_DeskBarClient, DBCID_RESIZE, (DWORD)lpMsg->wParam, NULL, NULL);
  61. return S_OK;
  62. }
  63. }
  64. #endif
  65. if (!g_fRunningOnNT && (lpMsg->message == WM_SYSCHAR))
  66. {
  67. // See AnsiWparamToUnicode for why this character tweak is needed
  68. lpMsg->wParam = AnsiWparamToUnicode(lpMsg->wParam);
  69. }
  70. // Give toolbar a crack
  71. if (hr != S_OK && _hwndTB && SendMessage(_hwndTB, TB_TRANSLATEACCELERATOR, 0, (LPARAM)lpMsg))
  72. return S_OK;
  73. else if (hr != S_OK && SendMessage(_hwndOptionsTB, TB_TRANSLATEACCELERATOR, 0, (LPARAM)lpMsg))
  74. return S_OK;
  75. // to get a mapping, forward system characters to toolbar (if any) or xBar
  76. if (WM_SYSCHAR == lpMsg->message)
  77. {
  78. if (hr == S_OK)
  79. {
  80. return S_OK;
  81. }
  82. if ((NULL != _hwndTB) && (NULL != _pCmdTarget))
  83. {
  84. UINT idBtn;
  85. if (SendMessage(_hwndTB, TB_MAPACCELERATOR, lpMsg->wParam, (LPARAM)&idBtn))
  86. {
  87. TCHAR szButtonText[MAX_PATH];
  88. // comctl says this one is the one, let's make sure we aren't getting
  89. // one of the unwanted "use the first letter" accelerators that it
  90. // will return.
  91. if ((SendMessage(_hwndTB, TB_GETBUTTONTEXT, idBtn, (LPARAM)szButtonText) > 0) &&
  92. (GetAccelerator(szButtonText, FALSE) != (TCHAR)-1))
  93. {
  94. // (tnoonan) - it feels kinda cheesy to send mouse messages, but
  95. // I don't know of a cleaner way which will accomplish what we
  96. // want (like deal with split buttons, mutually exclusive
  97. // buttons, etc.).
  98. RECT rc;
  99. SendMessage(_hwndTB, TB_GETRECT, idBtn, (LPARAM)&rc);
  100. SendMessage(_hwndTB, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(rc.left, rc.top));
  101. SendMessage(_hwndTB, WM_LBUTTONUP, 0, MAKELONG(rc.left, rc.top));
  102. hr = S_OK;
  103. }
  104. }
  105. }
  106. }
  107. if (hr != S_OK)
  108. hr = SUPERCLASS::TranslateAcceleratorIO(lpMsg);
  109. return hr;
  110. }
  111. HRESULT CBrowserBandSite::_TrySetFocusTB(int iDir)
  112. {
  113. HRESULT hres = S_FALSE;
  114. if (_hwndTB)
  115. {
  116. int cBtns = (int) SendMessage(_hwndTB, TB_BUTTONCOUNT, 0, 0);
  117. if (cBtns > 0)
  118. {
  119. // Set focus on tb. This will also set the first button to hottracked,
  120. // generating a hot item change notify, but _OnHotItemChange will ignore
  121. // the notify as neither HICF_RESELECT, HICF_ARROWKEYS nor HICF_ACCELERATOR will be set.
  122. SetFocus(_hwndTB);
  123. // If going back, make rightmost button hottracked,
  124. // else make first button hottracked.
  125. int iHotPos = (iDir == -1) ? cBtns - 1 : 0;
  126. // Pass HICF_RESELECT so that if we're reselecting the same item, another notify
  127. // is generated, and so that the filter in _OnHotItemChange will let the notification
  128. // through (and pop down the chevron menu if necessary).
  129. SendMessage(_hwndTB, TB_SETHOTITEM2, iHotPos, HICF_RESELECT);
  130. hres = S_OK;
  131. }
  132. }
  133. return hres;
  134. }
  135. HRESULT CBrowserBandSite::_CycleFocusBS(LPMSG lpMsg)
  136. {
  137. //
  138. // Tab order goes: (out)->_hwndOptionsTB->bands->(out)
  139. //
  140. // The order is reversed when shift is pressed.
  141. //
  142. // When control is pressed, and we have focus (i.e., have already been tabbed
  143. // into), we reject focus since ctl-tab is supposed to tab between contexts.
  144. //
  145. // Once _hwndOptionsTB gets focus, user can arrow over to _hwndTB. If
  146. // that happens, replace _hwndOptionsTB with _hwndTB in order above.
  147. //
  148. BOOL fHasFocus = (HasFocusIO() == S_OK);
  149. ASSERT(fHasFocus || !_ptbActive);
  150. if (fHasFocus && IsVK_CtlTABCycler(lpMsg))
  151. {
  152. // Bail on ctl-tab if one of our guys already has focus
  153. return S_FALSE;
  154. }
  155. HWND hwnd = GetFocus();
  156. BOOL fHasTBFocus = (hwnd && (hwnd == _hwndTB || hwnd == _hwndOptionsTB));
  157. BOOL fShift = (GetKeyState(VK_SHIFT) < 0);
  158. HRESULT hres = S_FALSE;
  159. // hidden options toolbar, bandsite cannot set focus to it (e.g. iBar)
  160. BOOL fStdExplorerBar = IsWindowVisible(_hwndOptionsTB);
  161. if (fHasTBFocus)
  162. {
  163. if (!fShift)
  164. hres = SUPERCLASS::_CycleFocusBS(lpMsg);
  165. }
  166. else
  167. {
  168. // Here, since !fHasTBFocus, fHasFocus => a band has focus
  169. if (fHasFocus || fShift || (!fHasFocus && !fStdExplorerBar))
  170. hres = SUPERCLASS::_CycleFocusBS(lpMsg);
  171. if (hres != S_OK && (!fHasFocus || (fHasFocus && fShift)))
  172. {
  173. // try passing focus to options toolbar if visible;
  174. if (fStdExplorerBar)
  175. {
  176. SetFocus(_hwndOptionsTB);
  177. TraceMsg(TF_ACCESSIBILITY, "CBrowserBandSite::_CycleFocusBS (hwnd=0x%08X) setting focus to optionsTB (=0x%08X)", _hwnd, _hwndOptionsTB);
  178. hres = S_OK;
  179. }
  180. }
  181. }
  182. return hres;
  183. }
  184. // this class subclasses the CBandSite class and adds functionality specific to
  185. // being hosted in the browser....
  186. //
  187. // it implements close as hide
  188. // it has its own title drawing
  189. void CBrowserBandSite::_OnCloseBand(DWORD dwBandID)
  190. {
  191. int iIndex = _BandIDToIndex(dwBandID);
  192. LPBANDITEMDATA pbid = _GetBandItem(iIndex);
  193. if (pbid)
  194. {
  195. _ShowBand(pbid, FALSE);
  196. if (_pct)
  197. {
  198. BOOL fShowing = FALSE;
  199. for (int i = _GetBandItemCount() - 1; i >= 0; i--)
  200. {
  201. LPBANDITEMDATA pbid = _GetBandItem(i);
  202. if (pbid)
  203. {
  204. fShowing |= pbid->fShow;
  205. }
  206. }
  207. if (!fShowing)
  208. {
  209. _pct->Exec(&CGID_DeskBarClient, DBCID_EMPTY, 0, NULL, NULL);
  210. }
  211. }
  212. }
  213. }
  214. // don't allow d/d of any band in here
  215. LRESULT CBrowserBandSite::_OnBeginDrag(NMREBAR* pnm)
  216. {
  217. return 1;
  218. }
  219. CBrowserBandSite::CBrowserBandSite() : CBandSite(NULL)
  220. {
  221. _dwBandIDCur = -1;
  222. }
  223. CBrowserBandSite::~CBrowserBandSite()
  224. {
  225. ATOMICRELEASE(_pCmdTarget);
  226. }
  227. HFONT CBrowserBandSite::_GetTitleFont(BOOL fForceRefresh)
  228. {
  229. if (_hfont && fForceRefresh)
  230. DeleteObject(_hfont);
  231. if (!_hfont || fForceRefresh) {
  232. // create our font to use for title & toolbar text
  233. // use A version for win9x compat
  234. NONCLIENTMETRICSA ncm;
  235. ncm.cbSize = sizeof(ncm);
  236. SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
  237. if (!(_dwMode & DBIF_VIEWMODE_VERTICAL)) {
  238. // horizontal band w/ vertical caption, so rotate the font
  239. ncm.lfMenuFont.lfEscapement = 900; // rotate by 90 degrees
  240. ncm.lfMenuFont.lfOutPrecision = OUT_TT_ONLY_PRECIS; // TT can be rotated
  241. }
  242. _hfont = CreateFontIndirectA(&ncm.lfMenuFont);
  243. }
  244. return _hfont;
  245. }
  246. void CBrowserBandSite::_InitLayout()
  247. {
  248. // force update font
  249. _GetTitleFont(TRUE);
  250. // update toolbar font
  251. _UpdateToolbarFont();
  252. // recalc title and toolbar heights
  253. _CalcHeights();
  254. _UpdateLayout();
  255. }
  256. void CBrowserBandSite::_UpdateAllBands(BOOL fBSOnly, BOOL fNoAutoSize)
  257. {
  258. if (!fBSOnly && !fNoAutoSize)
  259. _InitLayout();
  260. SUPERCLASS::_UpdateAllBands(fBSOnly, fNoAutoSize);
  261. }
  262. HRESULT CBrowserBandSite::_Initialize(HWND hwndParent)
  263. {
  264. HRESULT hres = SUPERCLASS::_Initialize(hwndParent);
  265. SendMessage(_hwnd, CCM_SETUNICODEFORMAT, DLL_IS_UNICODE, 0);
  266. _CreateOptionsTB();
  267. _InitLayout();
  268. return hres;
  269. }
  270. void CBrowserBandSite::_CalcHeights()
  271. {
  272. // calc title height
  273. // calc height of captionless bandsites, too, needed to calc toolband height
  274. // HACKHACK: use height of 'All Folders' as standard title height
  275. TCHAR szTitle[64];
  276. if (MLLoadStringW(IDS_TREETITLE, szTitle, ARRAYSIZE(szTitle))) {
  277. HDC hdc = GetDC(_hwnd);
  278. if (hdc)
  279. {
  280. HFONT hfont = _GetTitleFont(FALSE);
  281. HFONT hfontOld = (HFONT)SelectObject(hdc, hfont);
  282. int iLen = lstrlen(szTitle);
  283. SIZE size;
  284. GetTextExtentPoint32(hdc, szTitle, iLen, &size);
  285. _uTitle = size.cy;
  286. // make space for etch line + space
  287. _uTitle += CY_ETCH + CY_FLUFF;
  288. SelectObject(hdc, hfontOld);
  289. ReleaseDC(_hwnd, hdc);
  290. }
  291. } else {
  292. // no string; use a default height
  293. _uTitle = BROWSERBAR_TITLEHEIGHT;
  294. }
  295. // calc toolbar height
  296. _uToolbar = _uTitle + (2 * CY_TBPADDING) + CY_ETCH;
  297. if (_dwStyle & BSIS_NOCAPTION)
  298. {
  299. // rebar has no caption
  300. _uTitle = 0;
  301. }
  302. }
  303. void CBrowserBandSite::_UpdateToolbarFont()
  304. {
  305. if (_hwndTB && (_dwMode & DBIF_VIEWMODE_VERTICAL)) {
  306. // use same font for title and toolbar
  307. HFONT hfont = _GetTitleFont(FALSE);
  308. if (hfont)
  309. SendMessage(_hwndTB, WM_SETFONT, (WPARAM)hfont, TRUE);
  310. }
  311. }
  312. void CBrowserBandSite::_ShowBand(LPBANDITEMDATA pbid, BOOL fShow)
  313. {
  314. if (fShow && (_dwBandIDCur != pbid->dwBandID)) {
  315. _dwBandIDCur = pbid->dwBandID;
  316. _UpdateLayout();
  317. } else if (!fShow && _dwBandIDCur == pbid->dwBandID) {
  318. _dwBandIDCur = -1;
  319. }
  320. SUPERCLASS::_ShowBand(pbid, fShow);
  321. }
  322. void CBrowserBandSite::_UpdateLayout()
  323. {
  324. // update toolbar button size
  325. if (_hwndTB && SendMessage(_hwndTB, TB_BUTTONCOUNT, 0, 0) > 0)
  326. {
  327. // try to set button height to title height
  328. LONG lSize = MAKELONG(0, _uTitle);
  329. SendMessage(_hwndTB, TB_SETBUTTONSIZE, 0, lSize);
  330. // see what toolbar actually gave us
  331. RECT rc;
  332. SendMessage(_hwndTB, TB_GETITEMRECT, 0, (LPARAM)&rc);
  333. // calc toolbar height (final version)
  334. _uToolbar = RECTHEIGHT(rc) + CY_ETCH + 2 * CY_TBPADDING;
  335. }
  336. // update header height for the current band
  337. if (_dwBandIDCur != -1)
  338. {
  339. REBARBANDINFO rbbi;
  340. rbbi.cbSize = sizeof(rbbi);
  341. rbbi.fMask = RBBIM_HEADERSIZE;
  342. rbbi.cxHeader = _uTitle + (_fToolbar ? _uToolbar : 0);
  343. SendMessage(_hwnd, RB_SETBANDINFO, _BandIDToIndex(_dwBandIDCur), (LPARAM)&rbbi);
  344. }
  345. // update toolbar size
  346. _UpdateToolbarBand();
  347. // reposition toolbars
  348. _PositionToolbars(NULL);
  349. }
  350. void CBrowserBandSite::_BandInfoFromBandItem(REBARBANDINFO *prbbi, LPBANDITEMDATA pbid, BOOL fBSOnly)
  351. {
  352. SUPERCLASS::_BandInfoFromBandItem(prbbi, pbid, fBSOnly);
  353. if (prbbi)
  354. {
  355. // we override header width so we can fit browbs's fancy ui (title,
  356. // toolbar, close & autohide buttons) in the band's header area.
  357. prbbi->cxHeader = _uTitle + (_fToolbar ? _uToolbar : 0);
  358. }
  359. }
  360. void CBrowserBandSite::_DrawEtchline(HDC hdc, LPRECT prc, int iOffset, BOOL fVertEtch)
  361. {
  362. RECT rc;
  363. CopyRect(&rc, prc);
  364. if (fVertEtch) {
  365. rc.left += iOffset - CY_ETCH;
  366. rc.right = rc.left + 1;
  367. } else {
  368. rc.top += iOffset - CY_ETCH;
  369. rc.bottom = rc.top + 1;
  370. }
  371. SHFillRectClr(hdc, &rc, GetSysColor(COLOR_BTNSHADOW));
  372. if (fVertEtch) {
  373. rc.left++;
  374. rc.right++;
  375. } else {
  376. rc.bottom++;
  377. rc.top++;
  378. }
  379. SHFillRectClr(hdc, &rc, GetSysColor(COLOR_BTNHILIGHT));
  380. }
  381. LRESULT CBrowserBandSite::_OnCDNotify(LPNMCUSTOMDRAW pnm)
  382. {
  383. switch (pnm->dwDrawStage) {
  384. case CDDS_PREPAINT:
  385. return CDRF_NOTIFYITEMDRAW;
  386. case CDDS_PREERASE:
  387. return CDRF_NOTIFYITEMDRAW;
  388. case CDDS_ITEMPREPAINT:
  389. if (!(_dwStyle & BSIS_NOCAPTION))
  390. {
  391. // horz bar has vert caption and vice versa
  392. BOOL fVertCaption = (_dwMode&DBIF_VIEWMODE_VERTICAL) ? FALSE:TRUE;
  393. LPBANDITEMDATA pbid = (LPBANDITEMDATA)pnm->lItemlParam;
  394. if (pbid)
  395. {
  396. int iLen;
  397. HFONT hfont, hfontOld = NULL;
  398. LPCTSTR pszTitle;
  399. SIZE size;
  400. USES_CONVERSION;
  401. hfont = _GetTitleFont(FALSE);
  402. hfontOld = (HFONT)SelectObject(pnm->hdc, hfont);
  403. pszTitle = W2CT(pbid->szTitle);
  404. iLen = lstrlen(pszTitle);
  405. GetTextExtentPoint32(pnm->hdc, pszTitle, iLen, &size);
  406. // center text inside caption and draw edge at bottom/right.
  407. if (!fVertCaption)
  408. {
  409. // vertical bar, has horizontal text
  410. int x = pnm->rc.left + CX_TEXTOFFSET;
  411. int y = pnm->rc.top + ((_uTitle - CY_ETCH) - size.cy) / 2;
  412. ExtTextOut(pnm->hdc, x, y, NULL, NULL, pszTitle, iLen, NULL);
  413. _DrawEtchline(pnm->hdc, &pnm->rc, RECTHEIGHT(pnm->rc), fVertCaption);
  414. if (_fToolbar)
  415. _DrawEtchline(pnm->hdc, &pnm->rc, _uTitle, fVertCaption);
  416. }
  417. else
  418. {
  419. // horizontal bar, has vertical text
  420. UINT nPrevAlign = SetTextAlign(pnm->hdc, TA_BOTTOM);
  421. int x = pnm->rc.right - ((_uTitle - CY_ETCH) - size.cy) / 2;
  422. int y = pnm->rc.bottom - CY_TEXTOFFSET;
  423. ExtTextOut(pnm->hdc, x, y, NULL, NULL, pszTitle, iLen, NULL);
  424. SetTextAlign(pnm->hdc, nPrevAlign);
  425. _DrawEtchline(pnm->hdc, &pnm->rc, RECTWIDTH(pnm->rc), fVertCaption);
  426. ASSERT(!_fToolbar);
  427. }
  428. if (hfontOld)
  429. SelectObject(pnm->hdc, hfontOld);
  430. }
  431. }
  432. return CDRF_SKIPDEFAULT;
  433. }
  434. return CDRF_DODEFAULT;
  435. }
  436. LRESULT CBrowserBandSite::_OnNotify(LPNMHDR pnm)
  437. {
  438. switch (pnm->idFrom)
  439. {
  440. case FCIDM_REBAR:
  441. switch (pnm->code)
  442. {
  443. case NM_CUSTOMDRAW:
  444. return _OnCDNotify((LPNMCUSTOMDRAW)pnm);
  445. case NM_NCHITTEST:
  446. {
  447. NMMOUSE *pnmMouse = (NMMOUSE*)pnm;
  448. RECT rc;
  449. GetClientRect(_hwnd, &rc);
  450. if (pnmMouse->dwItemSpec == (DWORD)-1) {
  451. Lchktrans:
  452. //
  453. // Edges are mirrored if the window is mirrored. [samera]
  454. //
  455. if (IS_WINDOW_RTL_MIRRORED(_hwnd)) {
  456. int iTmp = rc.right;
  457. rc.right = rc.left;
  458. rc.left = iTmp;
  459. }
  460. // gotta check all 4 edges or non-left-side bars (e.g.
  461. // commbar) won't work.
  462. // (we separate this into 2 checks to give a trace,
  463. // since the old code only checked the right side)
  464. if (pnmMouse->pt.x > rc.right) {
  465. return HTTRANSPARENT;
  466. }
  467. if (pnmMouse->pt.x < rc.left ||
  468. pnmMouse->pt.y > rc.bottom || pnmMouse->pt.y < rc.top) {
  469. return HTTRANSPARENT;
  470. }
  471. } else if (pnmMouse->dwHitInfo == RBHT_CLIENT) {
  472. InflateRect(&rc, -(GetSystemMetrics(SM_CXFRAME)),
  473. -(GetSystemMetrics(SM_CYFRAME)));
  474. goto Lchktrans;
  475. }
  476. return SUPERCLASS::_OnNotify(pnm);
  477. }
  478. default:
  479. return SUPERCLASS::_OnNotify(pnm);
  480. }
  481. default:
  482. return SUPERCLASS::_OnNotify(pnm);
  483. }
  484. return 0;
  485. }
  486. IDropTarget* CBrowserBandSite::_WrapDropTargetForBand(IDropTarget* pdtBand)
  487. {
  488. pdtBand->AddRef();
  489. return pdtBand;
  490. }
  491. HRESULT CBrowserBandSite::v_InternalQueryInterface(REFIID riid, void **ppv)
  492. {
  493. static const QITAB qit[] = {
  494. QITABENT(CBrowserBandSite, IExplorerToolbar),
  495. { 0 },
  496. };
  497. HRESULT hr;
  498. if (IsEqualIID(riid, IID_IDropTarget))
  499. {
  500. *ppv = NULL;
  501. hr = E_NOINTERFACE;
  502. }
  503. else
  504. {
  505. hr = QISearch(this, qit, riid, ppv);
  506. if (FAILED(hr))
  507. hr = SUPERCLASS::v_InternalQueryInterface(riid, ppv);
  508. }
  509. return hr;
  510. }
  511. DWORD CBrowserBandSite::_GetWindowStyle(DWORD *pdwExStyle)
  512. {
  513. *pdwExStyle = 0;
  514. return RBS_REGISTERDROP |
  515. RBS_VERTICALGRIPPER |
  516. RBS_VARHEIGHT | RBS_DBLCLKTOGGLE |
  517. WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_BORDER |
  518. WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN;
  519. }
  520. // *** IOleCommandTarget ***
  521. HRESULT CBrowserBandSite::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,
  522. VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  523. {
  524. if (pguidCmdGroup == NULL)
  525. {
  526. }
  527. #ifdef UNIX
  528. // IEUNIX: Special case to handle the case where the band wants to
  529. // close itself. Used in Cache Warning pane (msgband.cpp)
  530. else if (IsEqualGUID(CGID_Explorer, *pguidCmdGroup))
  531. {
  532. switch (nCmdID)
  533. {
  534. case SBCMDID_MSGBAND:
  535. {
  536. IDockingWindow * pdw;
  537. if (SUCCEEDED(_punkSite->QueryInterface(IID_PPV_ARG(IDockingWindow, &pdw))))
  538. {
  539. pdw->ShowDW((BOOL)nCmdexecopt);
  540. pdw->Release();
  541. }
  542. }
  543. }
  544. }
  545. #endif
  546. else if (IsEqualGUID(CGID_Theater, *pguidCmdGroup))
  547. {
  548. switch (nCmdID)
  549. {
  550. case THID_ACTIVATE:
  551. _fTheater = TRUE;
  552. SHSetWindowBits(_hwnd, GWL_EXSTYLE, WS_EX_CLIENTEDGE, 0);
  553. // fall through
  554. case THID_SETBROWSERBARAUTOHIDE:
  555. if (pvarargIn && pvarargIn->vt == VT_I4)
  556. _fNoAutoHide = !(pvarargIn->lVal);
  557. SendMessage(_hwndOptionsTB, TB_CHANGEBITMAP, IDM_AB_AUTOHIDE, _fNoAutoHide ? 2 : 0);
  558. break;
  559. case THID_DEACTIVATE:
  560. _fTheater = FALSE;
  561. SHSetWindowBits(_hwnd, GWL_EXSTYLE, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE);
  562. break;
  563. }
  564. SetWindowPos(_hwnd, NULL, 0,0,0,0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
  565. _SizeOptionsTB();
  566. return S_OK;
  567. }
  568. return SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  569. }
  570. #define BBSC_REBAR 0x00000001
  571. #define BBSC_TOOLBAR 0x00000002
  572. void CBrowserBandSite::_CreateTBRebar()
  573. {
  574. ASSERT(!_hwndTBRebar);
  575. _hwndTBRebar = CreateWindowEx(WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL,
  576. WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN |
  577. WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOPARENTALIGN,
  578. 0, 0, 100, 36,
  579. _hwnd, (HMENU) BBSC_REBAR, HINST_THISDLL, NULL);
  580. if (_hwndTBRebar)
  581. SendMessage(_hwndTBRebar, CCM_SETVERSION, COMCTL32_VERSION, 0);
  582. }
  583. void CBrowserBandSite::_InsertToolbarBand()
  584. {
  585. if (_hwndTBRebar && _hwndTB)
  586. {
  587. // Assert that we haven't added the toolbar band yet
  588. ASSERT(SendMessage(_hwndTBRebar, RB_GETBANDCOUNT, 0, 0) == 0);
  589. // Assert that we've calculated toolbar height
  590. ASSERT(_uToolbar);
  591. REBARBANDINFO rbbi;
  592. rbbi.cbSize = sizeof(REBARBANDINFO);
  593. rbbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE;
  594. // RBBIM_CHILD
  595. rbbi.hwndChild = _hwndTB;
  596. // RBBIM_CHILDSIZE
  597. rbbi.cxMinChild = 0;
  598. rbbi.cyMinChild = _uToolbar - (CY_ETCH + 2 * CY_TBPADDING);
  599. // RBBIM_STYLE
  600. rbbi.fStyle = RBBS_NOGRIPPER | RBBS_USECHEVRON;
  601. SendMessage(_hwndTBRebar, RB_INSERTBAND, -1, (LPARAM)&rbbi);
  602. }
  603. }
  604. void CBrowserBandSite::_UpdateToolbarBand()
  605. {
  606. if (_hwndTBRebar && _hwndTB)
  607. {
  608. // Assert that we've added the toolbar band
  609. ASSERT(SendMessage(_hwndTBRebar, RB_GETBANDCOUNT, 0, 0) == 1);
  610. // Assert that we've calculated toolbar height
  611. ASSERT(_uToolbar);
  612. REBARBANDINFO rbbi;
  613. rbbi.cbSize = sizeof(REBARBANDINFO);
  614. rbbi.fMask = RBBIM_CHILDSIZE;
  615. SIZE size = {0, _uToolbar};
  616. if (SendMessage(_hwndTB, TB_GETIDEALSIZE, FALSE, (LPARAM)&size))
  617. {
  618. // RBBIM_IDEALSIZE
  619. rbbi.fMask |= RBBIM_IDEALSIZE;
  620. rbbi.cxIdeal = size.cx;
  621. }
  622. // RBBIM_CHILDSIZE
  623. rbbi.cxMinChild = 0;
  624. rbbi.cyMinChild = _uToolbar - (CY_ETCH + 2 * CY_TBPADDING);
  625. SendMessage(_hwndTBRebar, RB_SETBANDINFO, 0, (LPARAM)&rbbi);
  626. }
  627. }
  628. void CBrowserBandSite::_CreateTB()
  629. {
  630. ASSERT(!_hwndTB);
  631. // Create a rebar too so we get the chevron
  632. _CreateTBRebar();
  633. if (_hwndTBRebar)
  634. {
  635. _hwndTB = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
  636. WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS |
  637. TBSTYLE_FLAT | TBSTYLE_LIST | CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE,
  638. 0, 0, 0, 0,
  639. _hwndTBRebar, (HMENU) BBSC_TOOLBAR, HINST_THISDLL, NULL);
  640. }
  641. if (_hwndTB)
  642. {
  643. SendMessage(_hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
  644. SendMessage(_hwndTB, CCM_SETVERSION, COMCTL32_VERSION, 0);
  645. // FEATURE: use TBSTYLE_EX_HIDECLIPPEDBUTTONS here? looks kinda goofy so i'm leaving it out for now.
  646. SendMessage(_hwndTB, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_MIXEDBUTTONS);
  647. SendMessage(_hwndTB, TB_SETMAXTEXTROWS, 1, 0L);
  648. _UpdateToolbarFont();
  649. _InsertToolbarBand();
  650. }
  651. }
  652. void CBrowserBandSite::_RemoveAllButtons()
  653. {
  654. if (!_hwndTB || !_hwndTBRebar)
  655. return;
  656. ShowWindow(_hwndTBRebar, SW_HIDE);
  657. _fToolbar = FALSE;
  658. INT_PTR nCount = SendMessage(_hwndTB, TB_BUTTONCOUNT, 0, 0L);
  659. while (nCount-- > 0)
  660. SendMessage(_hwndTB, TB_DELETEBUTTON, nCount, 0L);
  661. _UpdateLayout();
  662. }
  663. void CBrowserBandSite::_Close()
  664. {
  665. ATOMICRELEASE(_pCmdTarget);
  666. //
  667. // Destroying _hwndTBRebar will take care of _hwndTB too
  668. //
  669. ASSERT(!_hwndTB || IsChild(_hwndTBRebar, _hwndTB));
  670. DESTROY_OBJ_WITH_HANDLE(_hwndTBRebar, DestroyWindow);
  671. DESTROY_OBJ_WITH_HANDLE(_hwndOptionsTB, DestroyWindow);
  672. DESTROY_OBJ_WITH_HANDLE(_hfont, DeleteObject);
  673. SUPERCLASS::_Close();
  674. }
  675. LRESULT CBrowserBandSite::_OnHotItemChange(LPNMTBHOTITEM pnmtb)
  676. {
  677. LRESULT lres = 0;
  678. // We might want to drop down the chevron menu if the hot item change
  679. // flags has these characteristics:
  680. //
  681. // - not HICF_LEAVING, since if HICF_LEAVING, the hot item should instead wrap to _hwndClose
  682. // - and not HICF_MOUSE, since we only drop down on keyboard hot item change
  683. // - HICF_ACCELERATOR | HICF_ARROWKEYS, since we only drop down on keyboard hot item change
  684. // - or HICF_RESELECT, since we force a reselect in _TrySetFocusTB
  685. //
  686. if (!(pnmtb->dwFlags & (HICF_LEAVING | HICF_MOUSE)) &&
  687. (pnmtb->dwFlags & (HICF_RESELECT | HICF_ACCELERATOR | HICF_ARROWKEYS)))
  688. {
  689. // Check to see if new hot button is clipped. If it is,
  690. // then we pop down the chevron menu.
  691. RECT rc;
  692. GetClientRect(_hwndTB, &rc);
  693. int iButton = (int)SendMessage(_hwndTB, TB_COMMANDTOINDEX, pnmtb->idNew, 0);
  694. if (SHIsButtonObscured(_hwndTB, &rc, iButton))
  695. {
  696. // Clear hot item
  697. SendMessage(_hwndTB, TB_SETHOTITEM, -1, 0);
  698. // Figure out whether to highlight first or last item in menu
  699. UINT uSelect;
  700. int cButtons = (int)SendMessage(_hwndTB, TB_BUTTONCOUNT, 0, 0);
  701. if (iButton == cButtons - 1)
  702. uSelect = DBPC_SELECTLAST;
  703. else
  704. uSelect = DBPC_SELECTFIRST;
  705. // Pop it down
  706. SendMessage(_hwndTBRebar, RB_PUSHCHEVRON, 0, uSelect);
  707. lres = 1;
  708. }
  709. }
  710. return lres;
  711. }
  712. LRESULT CBrowserBandSite::_OnNotifyBBS(LPNMHDR pnm)
  713. {
  714. switch (pnm->code)
  715. {
  716. case TBN_DROPDOWN:
  717. if (EVAL(_pCmdTarget))
  718. {
  719. LPNMTOOLBAR pnmtoolbar = (LPNMTOOLBAR)pnm;
  720. VARIANTARG var;
  721. RECT rc = pnmtoolbar->rcButton;
  722. var.vt = VT_I4;
  723. MapWindowPoints(_hwndTB, HWND_DESKTOP, (LPPOINT)&rc, 2);
  724. var.lVal = MAKELONG(rc.left, rc.bottom);
  725. _pCmdTarget->Exec(&_guidButtonGroup, pnmtoolbar->iItem, OLECMDEXECOPT_PROMPTUSER, &var, NULL);
  726. }
  727. break;
  728. case TBN_WRAPHOTITEM:
  729. {
  730. LPNMTBWRAPHOTITEM pnmwh = (LPNMTBWRAPHOTITEM) pnm;
  731. if (pnmwh->nReason & HICF_ARROWKEYS) {
  732. if (pnm->hwndFrom == _hwndOptionsTB) {
  733. if (_TrySetFocusTB(pnmwh->iDir) != S_OK)
  734. return 0;
  735. } else {
  736. ASSERT(pnm->hwndFrom == _hwndTB);
  737. SetFocus(_hwndOptionsTB);
  738. }
  739. return 1;
  740. }
  741. }
  742. break;
  743. case TBN_HOTITEMCHANGE:
  744. if (pnm->hwndFrom == _hwndTB)
  745. return _OnHotItemChange((LPNMTBHOTITEM)pnm);
  746. break;
  747. case TBN_GETINFOTIP:
  748. // [scotthan] We'll ask the toolbar owner for tip text via
  749. // IOleCommandTarget::QueryStatus, like we do w/ defview for itbar buttons
  750. if (_pCmdTarget && pnm->hwndFrom == _hwndTB)
  751. {
  752. NMTBGETINFOTIP* pgit = (NMTBGETINFOTIP*)pnm ;
  753. OLECMDTEXTV<MAX_TOOLTIP_STRING> cmdtv;
  754. OLECMDTEXT *pcmdText = &cmdtv;
  755. pcmdText->cwBuf = MAX_TOOLTIP_STRING;
  756. pcmdText->cmdtextf = OLECMDTEXTF_NAME;
  757. pcmdText->cwActual = 0;
  758. OLECMD rgcmd = {pgit->iItem, 0};
  759. HRESULT hr = _pCmdTarget->QueryStatus(&_guidButtonGroup, 1, &rgcmd, pcmdText);
  760. if (SUCCEEDED(hr) && (pcmdText->cwActual))
  761. {
  762. SHUnicodeToTChar(pcmdText->rgwz, pgit->pszText, pgit->cchTextMax);
  763. return 1;
  764. }
  765. }
  766. break ;
  767. case RBN_CHEVRONPUSHED:
  768. LPNMREBARCHEVRON pnmch = (LPNMREBARCHEVRON) pnm;
  769. MapWindowPoints(pnmch->hdr.hwndFrom, HWND_DESKTOP, (LPPOINT)&pnmch->rc, 2);
  770. ToolbarMenu_Popup(_hwnd, &pnmch->rc, NULL, _hwndTB, 0, (DWORD)pnmch->lParamNM);
  771. return 1;
  772. }
  773. return 0;
  774. }
  775. // *** IWinEventHandler ***
  776. HRESULT CBrowserBandSite::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  777. {
  778. switch (uMsg)
  779. {
  780. case WM_COMMAND:
  781. {
  782. HWND hwndControl = GET_WM_COMMAND_HWND(wParam, lParam);
  783. UINT idCmd = GET_WM_COMMAND_ID(wParam, lParam);
  784. if (hwndControl && hwndControl == _hwndTB)
  785. {
  786. if (EVAL(_pCmdTarget))
  787. {
  788. RECT rc;
  789. VARIANTARG var;
  790. var.vt = VT_I4;
  791. SendMessage(_hwndTB, TB_GETRECT, idCmd, (LPARAM)&rc);
  792. MapWindowPoints(_hwndTB, HWND_DESKTOP, (LPPOINT)&rc, 2);
  793. var.lVal = MAKELONG(rc.left, rc.bottom);
  794. _pCmdTarget->Exec(&_guidButtonGroup, idCmd, 0, &var, NULL);
  795. }
  796. return S_OK;
  797. }
  798. else if (hwndControl == _hwndOptionsTB) {
  799. switch (idCmd) {
  800. case IDM_AB_CLOSE:
  801. IUnknown_Exec(_punkSite, &CGID_DeskBarClient, DBCID_EMPTY, 0, NULL, NULL);
  802. break;
  803. case IDM_AB_AUTOHIDE:
  804. {
  805. VARIANTARG v = {0};
  806. v.vt = VT_I4;
  807. v.lVal = _fNoAutoHide;
  808. IUnknown_Exec(_punkSite, &CGID_Theater, THID_SETBROWSERBARAUTOHIDE, 0, &v, NULL);
  809. break;
  810. }
  811. }
  812. return S_OK;
  813. }
  814. }
  815. break;
  816. case WM_NOTIFY:
  817. {
  818. LPNMHDR pnm = (LPNMHDR)lParam;
  819. if (pnm && (pnm->hwndFrom == _hwndTB || pnm->hwndFrom == _hwndOptionsTB || pnm->hwndFrom == _hwndTBRebar)) {
  820. *plres = _OnNotifyBBS(pnm);
  821. return S_OK;
  822. }
  823. }
  824. break;
  825. case WM_SIZE:
  826. {
  827. POINT pt = {LOWORD(lParam), HIWORD(lParam)};
  828. _PositionToolbars(&pt);
  829. }
  830. break;
  831. }
  832. return SUPERCLASS::OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
  833. }
  834. HRESULT CBrowserBandSite::IsWindowOwner(HWND hwnd)
  835. {
  836. if (hwnd && (hwnd == _hwndTB) || (hwnd == _hwndOptionsTB) || (hwnd == _hwndTBRebar))
  837. return S_OK;
  838. return SUPERCLASS::IsWindowOwner(hwnd);
  839. }
  840. // *** IBandSite ***
  841. HRESULT CBrowserBandSite::SetBandSiteInfo(const BANDSITEINFO * pbsinfo)
  842. {
  843. // recompute our layout if vertical viewmode is changing
  844. BOOL fUpdate = ((pbsinfo->dwMask & BSIM_STATE) &&
  845. ((pbsinfo->dwState ^ _dwMode) & DBIF_VIEWMODE_VERTICAL));
  846. // ...or if caption is turned on or off
  847. BOOL fCaptionStyleChanged = ( (pbsinfo->dwMask & BSIM_STYLE)
  848. && ((pbsinfo->dwStyle ^ _dwStyle) & BSIS_NOCAPTION));
  849. HRESULT hres = SUPERCLASS::SetBandSiteInfo(pbsinfo);
  850. if (fCaptionStyleChanged && _hwndOptionsTB)
  851. {
  852. if (_fToolbar) {
  853. // don't know if "new" band requires buttons or not, expect band to add buttons again if needed
  854. _RemoveAllButtons();
  855. }
  856. // show or hide close/hide toolbar; is always created since bandsites get reused!
  857. ::ShowWindow(_hwndOptionsTB, (_dwStyle & BSIS_NOCAPTION) ? SW_HIDE : SW_SHOW);
  858. }
  859. if (fUpdate || fCaptionStyleChanged) {
  860. _InitLayout();
  861. }
  862. return hres;
  863. }
  864. // *** IExplorerToolbar ***
  865. HRESULT CBrowserBandSite::SetCommandTarget(IUnknown* punkCmdTarget, const GUID* pguidButtonGroup, DWORD dwFlags)
  866. {
  867. HRESULT hres = S_OK;
  868. BOOL fRemoveButtons = TRUE;
  869. // dwFlags is not used
  870. ASSERT(!(dwFlags));
  871. ATOMICRELEASE(_pCmdTarget);
  872. if (punkCmdTarget && pguidButtonGroup)
  873. {
  874. hres = punkCmdTarget->QueryInterface(IID_IOleCommandTarget, (void**)&(_pCmdTarget));
  875. if (!_hwndTB)
  876. {
  877. _CreateTB();
  878. }
  879. else if (_fToolbar && IsEqualGUID(_guidButtonGroup, *pguidButtonGroup))
  880. {
  881. fRemoveButtons = FALSE;
  882. hres = S_FALSE;
  883. }
  884. _guidButtonGroup = *pguidButtonGroup;
  885. }
  886. else
  887. ASSERT(!punkCmdTarget);
  888. if (fRemoveButtons)
  889. _RemoveAllButtons();
  890. ASSERT(SUCCEEDED(hres));
  891. return hres;
  892. }
  893. // client should have already called AddString
  894. HRESULT CBrowserBandSite::AddButtons(const GUID* pguidButtonGroup, UINT nButtons, const TBBUTTON* lpButtons)
  895. {
  896. if (!_hwndTB || !nButtons)
  897. return E_FAIL;
  898. _RemoveAllButtons();
  899. if (SendMessage(_hwndTB, TB_ADDBUTTONS, nButtons, (LPARAM)lpButtons))
  900. {
  901. ShowWindow(_hwndTBRebar, SW_SHOW);
  902. _fToolbar = TRUE;
  903. _UpdateLayout();
  904. return S_OK;
  905. }
  906. return E_FAIL;
  907. }
  908. HRESULT CBrowserBandSite::AddString(const GUID* pguidButtonGroup, HINSTANCE hInst, UINT_PTR uiResID, LRESULT* pOffset)
  909. {
  910. *pOffset = -1;
  911. if (!_hwndTB)
  912. return E_FAIL;
  913. *pOffset = SendMessage(_hwndTB, TB_ADDSTRING, (WPARAM)hInst, (LPARAM)uiResID);
  914. if (*pOffset != -1)
  915. return S_OK;
  916. return E_FAIL;
  917. }
  918. HRESULT CBrowserBandSite::GetButton(const GUID* pguidButtonGroup, UINT uiCommand, LPTBBUTTON lpButton)
  919. {
  920. if (!_hwndTB)
  921. return E_FAIL;
  922. UINT_PTR uiIndex = SendMessage(_hwndTB, TB_COMMANDTOINDEX, uiCommand, 0L);
  923. if (SendMessage(_hwndTB, TB_GETBUTTON, uiIndex, (LPARAM)lpButton))
  924. return S_OK;
  925. return E_FAIL;
  926. }
  927. HRESULT CBrowserBandSite::GetState(const GUID* pguidButtonGroup, UINT uiCommand, UINT* pfState)
  928. {
  929. if (!_hwndTB)
  930. return E_FAIL;
  931. *pfState = (UINT)SendMessage(_hwndTB, TB_GETSTATE, uiCommand, 0L);
  932. return S_OK;
  933. }
  934. HRESULT CBrowserBandSite::SetState(const GUID* pguidButtonGroup, UINT uiCommand, UINT fState)
  935. {
  936. if (!_hwndTB)
  937. return E_FAIL;
  938. UINT_PTR uiState = SendMessage(_hwndTB, TB_GETSTATE, uiCommand, NULL);
  939. uiState ^= fState;
  940. if (uiState)
  941. SendMessage(_hwndTB, TB_SETSTATE, uiCommand, (LPARAM)fState);
  942. return S_OK;
  943. }
  944. HRESULT CBrowserBandSite::SetImageList( const GUID* pguidCmdGroup, HIMAGELIST himlNormal, HIMAGELIST himlHot, HIMAGELIST himlDisabled)
  945. {
  946. if (IsEqualGUID(*pguidCmdGroup, _guidButtonGroup)) {
  947. SendMessage(_hwndTB, TB_SETIMAGELIST, 0, (LPARAM)himlNormal);
  948. SendMessage(_hwndTB, TB_SETHOTIMAGELIST, 0, (LPARAM)himlHot);
  949. SendMessage(_hwndTB, TB_SETDISABLEDIMAGELIST, 0, (LPARAM)himlDisabled);
  950. }
  951. return S_OK;
  952. };
  953. BYTE TBStateFromIndex(HWND hwnd, int iIndex)
  954. {
  955. TBBUTTONINFO tbbi;
  956. tbbi.cbSize = sizeof(TBBUTTONINFO);
  957. tbbi.dwMask = TBIF_BYINDEX | TBIF_STATE;
  958. tbbi.fsState = 0;
  959. SendMessage(hwnd, TB_GETBUTTONINFO, iIndex, (LPARAM)&tbbi);
  960. return tbbi.fsState;
  961. }
  962. int CBrowserBandSite::_ContextMenuHittest(LPARAM lParam, POINT* ppt)
  963. {
  964. if (lParam == (LPARAM)-1)
  965. {
  966. //
  967. // Keyboard activation. If one of our toolbars has
  968. // focus, and it has a hottracked button, put up the
  969. // context menu below that button.
  970. //
  971. HWND hwnd = GetFocus();
  972. if (hwnd && (hwnd == _hwndTB || hwnd == _hwndOptionsTB))
  973. {
  974. INT_PTR iHot = SendMessage(hwnd, TB_GETHOTITEM, 0, 0);
  975. if (iHot == -1)
  976. {
  977. // couldn't find a hot item, just use the first visible button
  978. iHot = 0;
  979. while (TBSTATE_HIDDEN & TBStateFromIndex(hwnd, (int)iHot))
  980. iHot++;
  981. ASSERT(iHot < SendMessage(hwnd, TB_BUTTONCOUNT, 0, 0));
  982. }
  983. RECT rc;
  984. SendMessage(hwnd, TB_GETITEMRECT, iHot, (LPARAM)&rc);
  985. ppt->x = rc.left;
  986. ppt->y = rc.bottom;
  987. MapWindowPoints(hwnd, HWND_DESKTOP, ppt, 1);
  988. return -1;
  989. }
  990. }
  991. return SUPERCLASS::_ContextMenuHittest(lParam, ppt);
  992. }
  993. HMENU CBrowserBandSite::_LoadContextMenu()
  994. {
  995. HMENU hmenu = SUPERCLASS::_LoadContextMenu();
  996. DeleteMenu(hmenu, BSIDM_SHOWTITLEBAND, MF_BYCOMMAND);
  997. return hmenu;
  998. }
  999. // create the options (close/hide) buttons
  1000. void CBrowserBandSite::_CreateOptionsTB()
  1001. {
  1002. // create toolbar for close/hide button always since band site is reused
  1003. // for captionless band sites (iBar), this toolbar is only hidden
  1004. _hwndOptionsTB = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
  1005. WS_VISIBLE |
  1006. WS_CHILD | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS |
  1007. WS_CLIPCHILDREN |
  1008. WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOMOVEY | CCS_NOPARENTALIGN |
  1009. CCS_NORESIZE,
  1010. 0, 0, 30, 18, _hwnd, 0, HINST_THISDLL, NULL);
  1011. _PrepareOptionsTB();
  1012. }
  1013. // init as toolbar and load bitmaps
  1014. void CBrowserBandSite::_PrepareOptionsTB()
  1015. {
  1016. if (_hwndOptionsTB)
  1017. {
  1018. static const TBBUTTON c_tb[] =
  1019. {
  1020. { 0, IDM_AB_AUTOHIDE, TBSTATE_ENABLED, TBSTYLE_CHECK, {0,0}, 0, 0 },
  1021. { 1, IDM_AB_CLOSE, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 1 }
  1022. };
  1023. SendMessage(_hwndOptionsTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
  1024. SendMessage(_hwndOptionsTB, CCM_SETVERSION, COMCTL32_VERSION, 0);
  1025. SendMessage(_hwndOptionsTB, TB_SETBITMAPSIZE, 0, (LPARAM) MAKELONG(13, 11));
  1026. TBADDBITMAP tbab = { HINST_THISDLL, IDB_BROWSERTOOLBAR };
  1027. SendMessage(_hwndOptionsTB, TB_ADDBITMAP, 3, (LPARAM)&tbab);
  1028. LONG_PTR cbOffset = SendMessage(_hwndOptionsTB, TB_ADDSTRING, (WPARAM)MLGetHinst(), (LPARAM)IDS_BANDSITE_CLOSE_LABELS);
  1029. TBBUTTON tb[ARRAYSIZE(c_tb)];
  1030. UpdateButtonArray(tb, c_tb, ARRAYSIZE(c_tb), cbOffset);
  1031. SendMessage(_hwndOptionsTB, TB_SETMAXTEXTROWS, 0, 0);
  1032. SendMessage(_hwndOptionsTB, TB_ADDBUTTONS, ARRAYSIZE(tb), (LPARAM)tb);
  1033. SendMessage(_hwndOptionsTB, TB_SETINDENT, (WPARAM)0, 0);
  1034. _SizeOptionsTB();
  1035. }
  1036. }
  1037. void CBrowserBandSite::_PositionToolbars(LPPOINT ppt)
  1038. {
  1039. RECT rc;
  1040. if (ppt)
  1041. {
  1042. rc.left = 0;
  1043. rc.right = ppt->x;
  1044. }
  1045. else
  1046. {
  1047. GetClientRect(_hwnd, &rc);
  1048. }
  1049. if (_hwndOptionsTB)
  1050. {
  1051. // always put the close restore at the top right of the floater window
  1052. int x;
  1053. if (_dwMode & DBIF_VIEWMODE_VERTICAL)
  1054. {
  1055. RECT rcTB;
  1056. GetWindowRect(_hwndOptionsTB, &rcTB);
  1057. x = rc.right - RECTWIDTH(rcTB) - 1;
  1058. }
  1059. else
  1060. {
  1061. x = rc.left;
  1062. }
  1063. MARGINS mBorders = {0, 1, 0, 0}; // 1 mimics old behavior downlevel.
  1064. Comctl32_GetBandMargins(_hwnd, &mBorders);
  1065. SetWindowPos(_hwndOptionsTB, HWND_TOP, x - mBorders.cxRightWidth, mBorders.cyTopHeight, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
  1066. }
  1067. if (_hwndTBRebar)
  1068. {
  1069. if (_fToolbar)
  1070. {
  1071. // toolbar goes on its own line below title
  1072. SetWindowPos(_hwndTBRebar, HWND_TOP,
  1073. rc.left + CX_TBOFFSET,
  1074. _uTitle + CX_TBOFFSET,
  1075. rc.right - 2 * CX_TBOFFSET,
  1076. _uToolbar,
  1077. SWP_SHOWWINDOW);
  1078. }
  1079. else
  1080. {
  1081. ASSERT(!IsWindowVisible(_hwndTBRebar));
  1082. }
  1083. }
  1084. }
  1085. // sets the size of the toolbar. if we're in theater mode, we need to show the pushpin.
  1086. // otherwise just show the close
  1087. void CBrowserBandSite::_SizeOptionsTB()
  1088. {
  1089. RECT rc;
  1090. GetWindowRect(_hwndOptionsTB, &rc);
  1091. LRESULT lButtonSize = SendMessage(_hwndOptionsTB, TB_GETBUTTONSIZE, 0, 0L);
  1092. SetWindowPos(_hwndOptionsTB, NULL, 0, 0, LOWORD(lButtonSize) * (_fTheater ? 2 : 1),
  1093. RECTHEIGHT(rc), SWP_NOMOVE | SWP_NOACTIVATE);
  1094. DWORD_PTR dwState = SendMessage(_hwndOptionsTB, TB_GETSTATE, IDM_AB_AUTOHIDE, 0);
  1095. dwState &= ~(TBSTATE_HIDDEN | TBSTATE_CHECKED);
  1096. if (!_fTheater)
  1097. dwState |= TBSTATE_HIDDEN;
  1098. if (_fNoAutoHide)
  1099. dwState |= TBSTATE_CHECKED;
  1100. SendMessage(_hwndOptionsTB, TB_SETSTATE, IDM_AB_AUTOHIDE, dwState);
  1101. _PositionToolbars(NULL);
  1102. }