327 lines
9.4 KiB
C++
327 lines
9.4 KiB
C++
|
#include "shellprv.h"
|
||
|
#include "resource.h"
|
||
|
#include "tbmenu.h"
|
||
|
#include "isfband.h"
|
||
|
#include "util.h"
|
||
|
#include <uxtheme.h>
|
||
|
|
||
|
#define SUPERCLASS CMenuToolbarBase
|
||
|
|
||
|
CToolbarMenu::CToolbarMenu(DWORD dwFlags, HWND hwndTB) :
|
||
|
CMenuToolbarBase(NULL, dwFlags),
|
||
|
_hwndSubject(hwndTB) // this is the toolbar that we are customizing
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void CToolbarMenu::GetSize(SIZE* psize)
|
||
|
{
|
||
|
ASSERT(_hwndMB);
|
||
|
|
||
|
if (SendMessage(_hwndMB, TB_GETTEXTROWS, 0, 0) == 0)
|
||
|
{
|
||
|
// no text labels, so set a min width to make menu look
|
||
|
// pretty. use min width of 5 * button width.
|
||
|
// if < 5 buttons, use button count * button width
|
||
|
int cButtons = ToolBar_ButtonCount(_hwndMB);
|
||
|
cButtons = min(5, cButtons);
|
||
|
LRESULT lButtonSize = SendMessage(_hwndMB, TB_GETBUTTONSIZE, 0, 0);
|
||
|
LONG cxMin = cButtons * LOWORD(lButtonSize);
|
||
|
psize->cx = max(psize->cx, cxMin);
|
||
|
}
|
||
|
SUPERCLASS::GetSize(psize);
|
||
|
}
|
||
|
|
||
|
void CToolbarMenu::v_Show(BOOL fShow, BOOL fForceUpdate)
|
||
|
{
|
||
|
if (fShow)
|
||
|
{
|
||
|
_fClickHandled = FALSE;
|
||
|
_FillToolbar();
|
||
|
_pcmb->SetTracked(NULL); // Since hot item is NULL
|
||
|
ToolBar_SetHotItem(_hwndMB, -1);
|
||
|
if (fForceUpdate)
|
||
|
v_UpdateButtons(TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CToolbarMenu::v_Close()
|
||
|
{
|
||
|
if (_hwndMB)
|
||
|
_UnsubclassWindow(_hwndMB);
|
||
|
|
||
|
SUPERCLASS::v_Close();
|
||
|
}
|
||
|
|
||
|
|
||
|
void CToolbarMenu::v_UpdateButtons(BOOL fNegotiateSize)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CToolbarMenu::v_CallCBItem(int idtCmd, UINT dwMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
ASSERT(_pcmb); // if you hit this assert, you haven't initialized yet.. call SetSite first
|
||
|
|
||
|
if (_pcmb->_psmcb)
|
||
|
{
|
||
|
SMDATA smd = {0};
|
||
|
|
||
|
smd.dwMask = SMDM_TOOLBAR;
|
||
|
smd.uId = idtCmd;
|
||
|
smd.uIdParent = _pcmb->_uId;
|
||
|
smd.uIdAncestor = _pcmb->_uIdAncestor;
|
||
|
smd.punk = SAFECAST(_pcmb, IShellMenu*);
|
||
|
smd.pvUserData = _pcmb->_pvUserData;
|
||
|
smd.hwnd = _hwndMB;
|
||
|
|
||
|
return _pcmb->_psmcb->CallbackSM(&smd, dwMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
HRESULT CToolbarMenu::v_GetState(int idtCmd, LPSMDATA psmd)
|
||
|
{
|
||
|
ASSERT(0);
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
HRESULT CToolbarMenu::v_ExecItem(int idCmd)
|
||
|
{
|
||
|
HRESULT hres = E_FAIL;
|
||
|
TraceMsg(TF_TBMENU, "CToolbarMenu::v_ExecItem \tidCmd: %d", idCmd);
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
HRESULT CToolbarMenu::CreateToolbar(HWND hwndParent)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
if (!_hwndMB)
|
||
|
{
|
||
|
DWORD dwStyle = (WS_VISIBLE | WS_CHILD | TBSTYLE_FLAT |
|
||
|
WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER |
|
||
|
CCS_NOPARENTALIGN | CCS_NORESIZE | TBSTYLE_REGISTERDROP | TBSTYLE_TOOLTIPS);
|
||
|
|
||
|
INT_PTR nRows = SendMessage(_hwndSubject, TB_GETTEXTROWS, 0, 0);
|
||
|
|
||
|
if (nRows > 0)
|
||
|
{
|
||
|
// We have text labels; make it TBSTYLE_LIST. The base class will
|
||
|
// set TBSTYLE_EX_VERTICAL for us.
|
||
|
ASSERT(_fHorizInVerticalMB == FALSE);
|
||
|
dwStyle |= TBSTYLE_LIST;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// No text labels; make it horizontal and TBSTYLE_WRAPABLE. Set
|
||
|
// _fHorizInVerticalMB so that the base class does not try and set
|
||
|
// TBSTYLE_EX_VERTICAL.
|
||
|
_fHorizInVerticalMB = TRUE;
|
||
|
dwStyle |= TBSTYLE_WRAPABLE;
|
||
|
}
|
||
|
|
||
|
_hwndMB = CreateWindowEx(WS_EX_TOOLWINDOW, TOOLBARCLASSNAME, TEXT("Menu"), dwStyle,
|
||
|
0, 0, 0, 0, hwndParent, (HMENU) FCIDM_TOOLBAR, HINST_THISDLL, NULL);
|
||
|
|
||
|
if (!_hwndMB)
|
||
|
{
|
||
|
TraceMsg(TF_TBMENU, "CToolbarMenu::CreateToolbar: Failed to Create Toolbar");
|
||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||
|
}
|
||
|
|
||
|
HWND hwndTT = (HWND)SendMessage(_hwndMB, TB_GETTOOLTIPS, 0, 0);
|
||
|
SHSetWindowBits(hwndTT, GWL_STYLE, TTS_ALWAYSTIP, TTS_ALWAYSTIP);
|
||
|
SendMessage(_hwndMB, TB_BUTTONSTRUCTSIZE, SIZEOF(TBBUTTON), 0);
|
||
|
SendMessage(_hwndMB, TB_SETMAXTEXTROWS, nRows, 0);
|
||
|
SendMessage(_hwndMB, CCM_SETVERSION, COMCTL32_VERSION, 0);
|
||
|
|
||
|
SendMessage(_hwndMB, TB_SETEXTENDEDSTYLE, TBSTYLE_EX_DRAWDDARROWS, TBSTYLE_EX_DRAWDDARROWS);
|
||
|
|
||
|
int cPimgs = (int)SendMessage(_hwndSubject, TB_GETIMAGELISTCOUNT, 0, 0);
|
||
|
for (int i = 0; i < cPimgs; i++)
|
||
|
{
|
||
|
HIMAGELIST himl = (HIMAGELIST)SendMessage(_hwndSubject, TB_GETIMAGELIST, i, 0);
|
||
|
SendMessage(_hwndMB, TB_SETIMAGELIST, i, (LPARAM)himl);
|
||
|
HIMAGELIST himlHot = (HIMAGELIST)SendMessage(_hwndSubject, TB_GETHOTIMAGELIST, i, 0);
|
||
|
SendMessage(_hwndMB, TB_SETHOTIMAGELIST, i, (LPARAM)himlHot);
|
||
|
}
|
||
|
|
||
|
_SubclassWindow(_hwndMB);
|
||
|
|
||
|
// Set the format to ANSI
|
||
|
ToolBar_SetUnicodeFormat(_hwndMB, 0);
|
||
|
|
||
|
SetWindowTheme(_hwndMB, L"", L"");
|
||
|
hr = CMenuToolbarBase::CreateToolbar(hwndParent);
|
||
|
}
|
||
|
else if (GetParent(_hwndMB) != hwndParent)
|
||
|
{
|
||
|
::SetParent(_hwndMB, hwndParent);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
LRESULT CToolbarMenu::_DefWindowProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
LRESULT lRes = CMenuToolbarBase::_DefWindowProcMB(hwnd, uMessage, wParam, lParam);
|
||
|
|
||
|
if (lRes == 0)
|
||
|
lRes = CNotifySubclassWndProc::_DefWindowProc(hwnd, uMessage, wParam, lParam);
|
||
|
|
||
|
return lRes;
|
||
|
}
|
||
|
|
||
|
#define MAXLEN 256
|
||
|
|
||
|
BYTE ToolBar_GetStateByIndex(HWND hwnd, INT_PTR iIndex)
|
||
|
{
|
||
|
TBBUTTONINFO tbb;
|
||
|
tbb.cbSize = sizeof(TBBUTTONINFO);
|
||
|
tbb.dwMask = TBIF_STATE | TBIF_BYINDEX;
|
||
|
ToolBar_GetButtonInfo(hwnd, iIndex, &tbb);
|
||
|
return tbb.fsState;
|
||
|
}
|
||
|
|
||
|
void CToolbarMenu::_FillToolbar()
|
||
|
{
|
||
|
RECT rcTB;
|
||
|
TCHAR pszBuf[MAXLEN+1];
|
||
|
LPTSTR psz;
|
||
|
TBBUTTON tb;
|
||
|
INT_PTR i, iCount;
|
||
|
|
||
|
iCount = SendMessage(_hwndSubject, TB_BUTTONCOUNT, 0, 0L);
|
||
|
GetClientRect(_hwndSubject, &rcTB);
|
||
|
|
||
|
for (i = 0; i < iCount; i++)
|
||
|
{
|
||
|
if (SHIsButtonObscured(_hwndSubject, &rcTB, i) ||
|
||
|
((ToolBar_GetStateByIndex(_hwndSubject, i) & (TBSTATE_HIDDEN | TBSTATE_ENABLED)) ==
|
||
|
(TBSTATE_HIDDEN | TBSTATE_ENABLED)))
|
||
|
{
|
||
|
SendMessage(_hwndSubject, TB_GETBUTTON, i, (LPARAM)&tb);
|
||
|
if (!(tb.fsStyle & BTNS_SEP))
|
||
|
{
|
||
|
// autosize buttons look ugly here
|
||
|
tb.fsStyle &= ~BTNS_AUTOSIZE;
|
||
|
|
||
|
// need to rip off wrap bit; new toolbar will
|
||
|
// figure out where wrapping should happen
|
||
|
// also rip off hidden bit
|
||
|
tb.fsState &= ~(TBSTATE_WRAP | TBSTATE_HIDDEN);
|
||
|
|
||
|
if (tb.iString == -1)
|
||
|
{
|
||
|
// no string
|
||
|
psz = NULL;
|
||
|
}
|
||
|
else if (HIWORD(tb.iString))
|
||
|
{
|
||
|
// it's a string pointer
|
||
|
psz = (LPTSTR) tb.iString;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// it's an index into toolbar string array
|
||
|
SendMessage(_hwndSubject, TB_GETSTRING, MAKELONG(MAXLEN, tb.iString), (LPARAM)pszBuf);
|
||
|
psz = pszBuf;
|
||
|
}
|
||
|
if (psz)
|
||
|
tb.iString = (INT_PTR)psz;
|
||
|
else
|
||
|
tb.iString = -1;
|
||
|
|
||
|
if (tb.iBitmap == -1)
|
||
|
{
|
||
|
int id = GetDlgCtrlID(_hwndSubject);
|
||
|
|
||
|
NMTBDISPINFO tbgdi = {0};
|
||
|
tbgdi.hdr.hwndFrom = _hwndSubject;
|
||
|
tbgdi.hdr.idFrom = id;
|
||
|
tbgdi.hdr.code = TBN_GETDISPINFO;
|
||
|
tbgdi.dwMask = TBNF_IMAGE;
|
||
|
tbgdi.idCommand = tb.idCommand;
|
||
|
tbgdi.iImage = 0;
|
||
|
tbgdi.lParam = tb.dwData;
|
||
|
|
||
|
SendMessage(GetParent(_hwndSubject), WM_NOTIFY, (WPARAM)id, (LPARAM)&tbgdi);
|
||
|
|
||
|
if(tbgdi.dwMask & TBNF_DI_SETITEM)
|
||
|
tb.iBitmap = tbgdi.iImage;
|
||
|
}
|
||
|
|
||
|
SendMessage(_hwndMB, TB_ADDBUTTONS, 1, (LPARAM)&tb);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CToolbarMenu::IsWindowOwner(HWND hwnd)
|
||
|
{
|
||
|
if ( hwnd == _hwndMB)
|
||
|
return S_OK;
|
||
|
else
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
void CToolbarMenu::_CancelMenu()
|
||
|
{
|
||
|
IMenuPopup* pmp;
|
||
|
if (EVAL(SUCCEEDED(_pcmb->QueryInterface(IID_PPV_ARG(IMenuPopup, &pmp)))))
|
||
|
{
|
||
|
// tell menuband it's time to die
|
||
|
pmp->OnSelect(MPOS_FULLCANCEL);
|
||
|
pmp->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CToolbarMenu::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
|
||
|
{
|
||
|
HRESULT hres = S_FALSE;
|
||
|
ASSERT(plres);
|
||
|
|
||
|
switch (uMsg)
|
||
|
{
|
||
|
case WM_COMMAND:
|
||
|
PostMessage(GetParent(_hwndSubject), WM_COMMAND, wParam, (LPARAM)_hwndSubject);
|
||
|
_CancelMenu();
|
||
|
hres = S_OK;
|
||
|
break;
|
||
|
|
||
|
case WM_NOTIFY:
|
||
|
{
|
||
|
LPNMHDR pnmh = (LPNMHDR) lParam;
|
||
|
|
||
|
switch (pnmh->code)
|
||
|
{
|
||
|
case TBN_DROPDOWN:
|
||
|
_fTrackingSubMenu = TRUE;
|
||
|
pnmh->hwndFrom = _hwndSubject;
|
||
|
MapWindowPoints(_hwndMB, _hwndSubject, (LPPOINT) &((LPNMTOOLBAR)pnmh)->rcButton, 2);
|
||
|
*plres = SendMessage(GetParent(_hwndSubject), WM_NOTIFY, wParam, (LPARAM)pnmh);
|
||
|
_CancelMenu();
|
||
|
hres = S_OK;
|
||
|
_fTrackingSubMenu = FALSE;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
goto DoDefault;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
DoDefault:
|
||
|
default:
|
||
|
hres = SUPERCLASS::OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
|
||
|
}
|
||
|
|
||
|
return hres;
|
||
|
}
|
||
|
|
||
|
CMenuToolbarBase* ToolbarMenu_Create(HWND hwnd)
|
||
|
{
|
||
|
return new CToolbarMenu(0, hwnd);
|
||
|
}
|