browbs.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 38k
Category:

Windows Kernel

Development Platform:

Visual C++

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