_Out_ void **ppv
);
-#define TBSTYLE_EX_VERTICAL 4
-
+// FIXME: Enable if/when wine comctl supports this flag properly
+#define USE_TBSTYLE_EX_VERTICAL 0
#define TIMERID_HOTTRACK 1
#define SUBCLASS_ID_MENUBAND 1
+HRESULT CMenuToolbarBase::DisableMouseTrack(BOOL bDisable)
+{
+ m_disableMouseTrack = bDisable;
+ return S_OK;
+}
+
HRESULT CMenuToolbarBase::OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
{
- RECT rc;
- HDC hdc;
- HBRUSH bgBrush;
- HBRUSH hotBrush;
NMHDR * hdr;
- NMTBCUSTOMDRAW * cdraw;
- NMTBHOTITEM * hot;
- NMMOUSE * rclick;
NMPGCALCSIZE* csize;
- TBBUTTONINFO btni;
- COLORREF clrText;
- COLORREF clrTextHighlight;
SIZE tbs;
*theResult = 0;
hdr = reinterpret_cast<LPNMHDR>(lParam);
switch (hdr->code)
{
+ case TTN_GETDISPINFOA:
+ case TTN_GETDISPINFOW:
+ return S_OK;
+
+ case TBN_DELETINGBUTTON:
+ return OnDeletingButton(reinterpret_cast<LPNMTOOLBAR>(hdr));
+
case PGN_CALCSIZE:
csize = reinterpret_cast<LPNMPGCALCSIZE>(hdr);
return OnCommand(wParam, 0, theResult);
case TBN_HOTITEMCHANGE:
- hot = reinterpret_cast<LPNMTBHOTITEM>(hdr);
- return OnHotItemChange(hot);
+ return OnHotItemChange(reinterpret_cast<LPNMTBHOTITEM>(hdr), theResult);
case NM_RCLICK:
- rclick = reinterpret_cast<LPNMMOUSE>(hdr);
-
- return OnContextMenu(rclick);
+ return OnContextMenu(reinterpret_cast<LPNMMOUSE>(hdr));
case NM_CUSTOMDRAW:
- cdraw = reinterpret_cast<LPNMTBCUSTOMDRAW>(hdr);
- switch (cdraw->nmcd.dwDrawStage)
- {
- case CDDS_PREPAINT:
- *theResult = CDRF_NOTIFYITEMDRAW;
- return S_OK;
+ return OnCustomDraw(reinterpret_cast<LPNMTBCUSTOMDRAW>(hdr), theResult);
- case CDDS_ITEMPREPAINT:
-
- clrText = GetSysColor(COLOR_MENUTEXT);
- clrTextHighlight = GetSysColor(COLOR_HIGHLIGHTTEXT);
+ case RBN_CHILDSIZE:
+ return S_OK;
- bgBrush = GetSysColorBrush(COLOR_MENU);
- hotBrush = GetSysColorBrush(m_useFlatMenus ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT);
+ default:
+ DbgPrint("WM_NOTIFY unknown code %d, %d\n", hdr->code, hdr->idFrom);
+ }
+ return S_OK;
+ }
- rc = cdraw->nmcd.rc;
- hdc = cdraw->nmcd.hdc;
+ return S_FALSE;
+}
- if (((INT) cdraw->nmcd.dwItemSpec == m_hotItem ||
- (m_hotItem < 0 && (INT) cdraw->nmcd.dwItemSpec == m_popupItem)))
- {
- cdraw->nmcd.uItemState = CDIS_HOT;
- }
+HRESULT CMenuToolbarBase::OnCustomDraw(LPNMTBCUSTOMDRAW cdraw, LRESULT * theResult)
+{
+ RECT rc;
+ HDC hdc;
+ HBRUSH bgBrush;
+ HBRUSH hotBrush;
+ COLORREF clrText;
+ COLORREF clrTextHighlight;
+ bool isHot, isPopup;
+ TBBUTTONINFO btni;
- switch (cdraw->nmcd.uItemState)
- {
- case CDIS_HOT:
- case CDIS_FOCUS:
- FillRect(hdc, &rc, hotBrush);
- SetTextColor(hdc, clrTextHighlight);
- cdraw->clrText = clrTextHighlight;
- break;
- default:
- FillRect(hdc, &rc, bgBrush);
- SetTextColor(hdc, clrText);
- cdraw->clrText = clrText;
- break;
- }
+ switch (cdraw->nmcd.dwDrawStage)
+ {
+ case CDDS_PREPAINT:
+ if (m_toolbarFlags & SMINIT_VERTICAL)
+ *theResult = CDRF_NOTIFYITEMDRAW;
+ return S_OK;
- cdraw->iListGap += 4;
+ case CDDS_ITEMPREPAINT:
- *theResult = CDRF_NOTIFYPOSTPAINT | TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOOFFSET | TBCDRF_NOMARK | 0x00800000; // FIXME: the last bit is Vista+, for debugging only
- return S_OK;
+ clrText = GetSysColor(COLOR_MENUTEXT);
+ clrTextHighlight = GetSysColor(COLOR_HIGHLIGHTTEXT);
- case CDDS_ITEMPOSTPAINT:
- btni.cbSize = sizeof(btni);
- btni.dwMask = TBIF_STYLE;
- SendMessage(hWnd, TB_GETBUTTONINFO, cdraw->nmcd.dwItemSpec, reinterpret_cast<LPARAM>(&btni));
- if (btni.fsStyle & BTNS_DROPDOWN)
- {
- SelectObject(cdraw->nmcd.hdc, m_marlett);
- WCHAR text[] = L"8";
- SetBkMode(cdraw->nmcd.hdc, TRANSPARENT);
- RECT rc = cdraw->nmcd.rc;
- rc.right += 1;
- DrawTextEx(cdraw->nmcd.hdc, text, 1, &rc, DT_NOCLIP | DT_VCENTER | DT_RIGHT | DT_SINGLELINE, NULL);
- }
- *theResult = TRUE;
- return S_OK;
- }
- return S_OK;
+ bgBrush = GetSysColorBrush(COLOR_MENU);
+ hotBrush = GetSysColorBrush(m_useFlatMenus ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT);
+
+ rc = cdraw->nmcd.rc;
+ hdc = cdraw->nmcd.hdc;
+
+ isHot = m_hotBar == this && m_hotItem == static_cast<INT>(cdraw->nmcd.dwItemSpec);
+ isPopup = m_popupBar == this && m_popupItem == static_cast<INT>(cdraw->nmcd.dwItemSpec);
+
+ if (isHot || (m_hotItem < 0 && isPopup))
+ {
+ cdraw->nmcd.uItemState |= CDIS_HOT;
+ }
+ else
+ {
+ cdraw->nmcd.uItemState &= ~CDIS_HOT;
+ }
+
+ if (cdraw->nmcd.uItemState&CDIS_HOT)
+ {
+ FillRect(hdc, &rc, hotBrush);
+ SetTextColor(hdc, clrTextHighlight);
+ cdraw->clrText = clrTextHighlight;
}
+ else
+ {
+ FillRect(hdc, &rc, bgBrush);
+ SetTextColor(hdc, clrText);
+ cdraw->clrText = clrText;
+ }
+
+ cdraw->iListGap += 4;
+
+ *theResult = CDRF_NOTIFYPOSTPAINT | TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOOFFSET | TBCDRF_NOMARK | 0x00800000; // FIXME: the last bit is Vista+, for debugging only
return S_OK;
- }
- return S_FALSE;
+ case CDDS_ITEMPOSTPAINT:
+ btni.cbSize = sizeof(btni);
+ btni.dwMask = TBIF_STYLE;
+ SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, cdraw->nmcd.dwItemSpec, reinterpret_cast<LPARAM>(&btni));
+ if (btni.fsStyle & BTNS_DROPDOWN)
+ {
+ SelectObject(cdraw->nmcd.hdc, m_marlett);
+ WCHAR text[] = L"8";
+ SetBkMode(cdraw->nmcd.hdc, TRANSPARENT);
+ RECT rc = cdraw->nmcd.rc;
+ rc.right += 1;
+ DrawTextEx(cdraw->nmcd.hdc, text, 1, &rc, DT_NOCLIP | DT_VCENTER | DT_RIGHT | DT_SINGLELINE, NULL);
+ }
+ *theResult = TRUE;
+ return S_OK;
+ }
+ return S_OK;
}
CMenuToolbarBase::CMenuToolbarBase(CMenuBand *menuBand, BOOL usePager) :
m_hwnd(NULL),
m_useFlatMenus(FALSE),
+ m_SubclassOld(NULL),
+ m_disableMouseTrack(FALSE),
m_menuBand(menuBand),
m_hwndToolbar(NULL),
m_dwMenuFlags(0),
+ m_hasIdealSize(FALSE),
+ m_usePager(usePager),
m_hotItem(-1),
m_popupItem(-1),
- m_SubclassOld(NULL),
- m_hasIdealSize(FALSE),
- m_usePager(usePager)
+ m_isTracking(FALSE)
{
m_marlett = CreateFont(
0, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET,
HRESULT CMenuToolbarBase::UpdateImageLists()
{
+ if ((m_toolbarFlags & (SMINIT_TOPLEVEL| SMINIT_VERTICAL)) == SMINIT_TOPLEVEL) // not vertical.
+ {
+ /* Hide the placeholders for the button images */
+ SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, 0);
+ return S_OK;
+ }
+
int shiml;
if (m_menuBand->UseBigIcons())
{
if (dwFlags & SMINIT_VERTICAL)
{
tbStyles |= CCS_VERT;
+
+#if USE_TBSTYLE_EX_VERTICAL
+ // FIXME: Use when it works in ros (?)
tbExStyles |= TBSTYLE_EX_VERTICAL | WS_EX_TOOLWINDOW;
+#endif
}
+ m_toolbarFlags = dwFlags;
+
RECT rc;
if (!::GetClientRect(hwndParent, &rc) || (rc.left == rc.right) || (rc.top == rc.bottom))
/* Identify the version of the used Common Controls DLL by sending the size of the TBBUTTON structure */
SendMessageW(hwndToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
- //if (dwFlags & SMINIT_TOPLEVEL)
- //{
- // /* Hide the placeholders for the button images */
- // SendMessageW(m_hwnd, TB_SETIMAGELIST, 0, 0);
- //}
- //else
-
SetWindowLongPtr(hwndToolbar, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
m_SubclassOld = (WNDPROC) SetWindowLongPtr(hwndToolbar, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(CMenuToolbarBase::s_SubclassProc));
SetWindowPos(m_hwndToolbar, NULL, x, y, cx, m_idealSize.cy, 0);
}
SetWindowPos(m_hwnd, NULL, x, y, cx, cy, 0);
- DWORD btnSize = SendMessage(m_hwndToolbar, TB_GETBUTTONSIZE, 0, 0);
- SendMessage(m_hwndToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, HIWORD(btnSize)));
+ if (m_toolbarFlags & SMINIT_VERTICAL)
+ {
+ DWORD btnSize = SendMessage(m_hwndToolbar, TB_GETBUTTONSIZE, 0, 0);
+ SendMessage(m_hwndToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(cx, HIWORD(btnSize)));
+ }
return S_OK;
}
LRESULT CMenuToolbarBase::SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
+ LRESULT lr;
+
switch (uMsg)
{
+ case WM_USER_ISTRACKEDITEM:
+ m_SubclassOld(hWnd, uMsg, wParam, lParam);
+ return IsTrackedItem(wParam);
+ case WM_USER_CHANGETRACKEDITEM:
+ m_isTracking = TRUE;
+ m_SubclassOld(hWnd, uMsg, wParam, lParam);
+ return ChangeTrackedItem(wParam);
+
+ case WM_COMMAND:
+ OnWinEvent(hWnd, uMsg, wParam, lParam, &lr);
+ break;
+ case WM_NOTIFY:
+ OnWinEvent(hWnd, uMsg, wParam, lParam, &lr);
+ break;
case WM_TIMER:
if (wParam == TIMERID_HOTTRACK)
{
KillTimer(hWnd, TIMERID_HOTTRACK);
- m_menuBand->_OnPopupSubMenu(-1, NULL, NULL, NULL);
+ m_menuBand->_OnPopupSubMenu(NULL, NULL, NULL, NULL, -1);
if (HasSubMenu(m_hotItem) == S_OK)
{
return m_SubclassOld(hWnd, uMsg, wParam, lParam);
}
-HRESULT CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM * hot)
+HRESULT CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM * hot, LRESULT * theResult)
{
+ if (m_disableMouseTrack && hot->dwFlags & HICF_MOUSE)
+ {
+ *theResult = 1;
+ return S_OK;
+ }
+
if (hot->dwFlags & HICF_LEAVING)
{
KillTimer(m_hwndToolbar, TIMERID_HOTTRACK);
- m_hotItem = -1;
- m_menuBand->_OnHotItemChanged(NULL, -1);
- m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING);
+
+ if (m_menuBand->_OnHotItemChanged(NULL, -1) == S_FALSE)
+ {
+ *theResult = 1;
+ return S_OK;
+ }
+ else
+ {
+ m_hotItem = -1;
+ m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING);
+ return S_OK;
+ }
}
else if (m_hotItem != hot->idNew)
{
- DWORD elapsed = 0;
- SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &elapsed, 0);
- SetTimer(m_hwndToolbar, TIMERID_HOTTRACK, elapsed, NULL);
+ if (hot->dwFlags & HICF_MOUSE &&
+ m_toolbarFlags & SMINIT_VERTICAL)
+ {
+ DWORD elapsed = 0;
+ SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &elapsed, 0);
+ SetTimer(m_hwndToolbar, TIMERID_HOTTRACK, elapsed, NULL);
+ }
m_hotItem = hot->idNew;
m_menuBand->_OnHotItemChanged(this, m_hotItem);
m_menuBand->_MenuItemHotTrack(MPOS_CHILDTRACKING);
+
+ if (m_isTracking && !(m_toolbarFlags & SMINIT_VERTICAL))
+ {
+ KillTimer(m_hwndToolbar, TIMERID_HOTTRACK);
+
+ m_menuBand->_OnPopupSubMenu(NULL, NULL, NULL, NULL, -1);
+
+ if (HasSubMenu(m_hotItem) == S_OK)
+ {
+ PopupItem(m_hotItem);
+ }
+ }
+ return S_OK;
}
return S_OK;
}
-HRESULT CMenuToolbarBase::PopupSubMenu(UINT itemId, UINT index, IShellMenu* childShellMenu)
+HRESULT CMenuToolbarBase::OnHotItemChanged(CMenuToolbarBase * toolbar, INT item)
+{
+ BOOL wasChecked = FALSE;
+ if (m_hotBar == this && !(m_toolbarFlags & SMINIT_VERTICAL))
+ {
+ wasChecked = SendMessage(m_hwndToolbar, TB_ISBUTTONCHECKED, m_hotItem, 0);
+ if (wasChecked)
+ {
+ SendMessage(m_hwndToolbar, TB_CHECKBUTTON, m_hotItem, FALSE);
+ }
+ }
+ m_hotBar = toolbar;
+ m_hotItem = item;
+ if (wasChecked && m_hotBar == this && !(m_toolbarFlags & SMINIT_VERTICAL))
+ {
+ SendMessage(m_hwndToolbar, TB_CHECKBUTTON, m_hotItem, TRUE);
+ }
+ InvalidateDraw();
+ return S_OK;
+}
+
+HRESULT CMenuToolbarBase::OnPopupItemChanged(CMenuToolbarBase * toolbar, INT item)
+{
+ if (toolbar == NULL && m_popupBar == this)
+ {
+ SendMessage(m_hwndToolbar, TB_CHECKBUTTON, m_popupItem, FALSE);
+ m_isTracking = FALSE;
+ }
+ m_popupBar = toolbar;
+ m_popupItem = item;
+ InvalidateDraw();
+ return S_OK;
+}
+
+HRESULT CMenuToolbarBase::IsTrackedItem(INT index)
+{
+ TBBUTTON btn;
+
+ if (m_hotBar != this)
+ return S_FALSE;
+
+ SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn));
+
+ if (m_hotItem == btn.idCommand)
+ return S_OK;
+ return S_FALSE;
+}
+
+HRESULT CMenuToolbarBase::ChangeTrackedItem(INT index)
+{
+ TBBUTTON btn;
+ SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn));
+
+ if (m_hotItem != btn.idCommand)
+ {
+ SendMessage(m_hwndToolbar, TB_SETHOTITEM, index, 0);
+ }
+ return S_OK;
+}
+
+HRESULT CMenuToolbarBase::PopupSubMenu(UINT uItem, UINT index, IShellMenu* childShellMenu)
{
IBandSite* pBandSite;
IDeskBar* pDeskBar;
HRESULT hr = 0;
RECT rc = { 0 };
+ RECT rcx = { 0 };
if (!SendMessage(m_hwndToolbar, TB_GETITEMRECT, index, reinterpret_cast<LPARAM>(&rc)))
return E_FAIL;
+ GetWindowRect(m_hwnd, &rcx);
+
POINT a = { rc.left, rc.top };
POINT b = { rc.right, rc.bottom };
+ POINT c = { rcx.left, rcx.top };
+ POINT d = { rcx.right, rcx.bottom };
ClientToScreen(m_hwndToolbar, &a);
ClientToScreen(m_hwndToolbar, &b);
+ ClientToScreen(m_hwnd, &c);
+ ClientToScreen(m_hwnd, &d);
- POINTL pt = { b.x - 3, a.y - 3 };
- RECTL rcl = { a.x, a.y, b.x, b.y }; // maybe-TODO: fetch client area of deskbar?
+ POINTL pt = { a.x, b.y };
+ RECTL rcl = { c.x, c.y, d.x, d.y };
+
+ if(m_toolbarFlags & SMINIT_VERTICAL)
+ {
+ pt.x = b.x - 3;
+ pt.y = a.y - 3;
+ }
#if USE_SYSTEM_MENUSITE
hr = CoCreateInstance(CLSID_MenuBandSite,
#else
hr = CMenuSite_Constructor(IID_PPV_ARG(IBandSite, &pBandSite));
#endif
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
#if WRAP_MENUSITE
hr = CMenuSite_Wrapper(pBandSite, IID_PPV_ARG(IBandSite, &pBandSite));
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
#endif
#else
hr = CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar, &pDeskBar));
#endif
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
#if WRAP_MENUDESKBAR
hr = CMenuDeskBar_Wrapper(pDeskBar, IID_PPV_ARG(IDeskBar, &pDeskBar));
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
#endif
hr = pDeskBar->SetClient(pBandSite);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
hr = pBandSite->AddBand(childShellMenu);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
CComPtr<IMenuPopup> popup;
hr = pDeskBar->QueryInterface(IID_PPV_ARG(IMenuPopup, &popup));
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
- m_popupItem = itemId;
- m_menuBand->_OnPopupSubMenu(itemId, popup, &pt, &rcl);
+ m_isTracking = TRUE;
+ m_menuBand->_OnPopupSubMenu(popup, &pt, &rcl, this, uItem);
return S_OK;
}
-HRESULT CMenuToolbarBase::PopupSubMenu(UINT index, HMENU menu)
+HRESULT CMenuToolbarBase::PopupSubMenu(UINT uItem, UINT index, HMENU menu)
{
RECT rc = { 0 };
+ RECT rcx = { 0 };
if (!SendMessage(m_hwndToolbar, TB_GETITEMRECT, index, reinterpret_cast<LPARAM>(&rc)))
return E_FAIL;
+ GetClientRect(m_hwndToolbar, &rcx);
+
+ POINT a = { rc.left, rc.top };
POINT b = { rc.right, rc.bottom };
+ POINT c = { rc.left, rc.top };
+ POINT d = { rc.right, rc.bottom };
+ ClientToScreen(m_hwndToolbar, &a);
ClientToScreen(m_hwndToolbar, &b);
+ ClientToScreen(m_hwndToolbar, &c);
+ ClientToScreen(m_hwndToolbar, &d);
+
+ POINT pt = { a.x, b.y };
+ RECT rcl = { c.x, c.y, d.x, d.y };
+
+ if (m_toolbarFlags & SMINIT_VERTICAL)
+ {
+ pt.x = b.x;
+ pt.y = a.y;
+ }
HMENU popup = GetSubMenu(menu, index);
- m_menuBand->_TrackSubMenuUsingTrackPopupMenu(popup, b.x, b.y);
+ m_isTracking = TRUE;
+ m_menuBand->_TrackSubMenuUsingTrackPopupMenu(popup, pt.x, pt.y, rcl);
+
+ SendMessage(m_hwndToolbar, TB_CHECKBUTTON, uItem, FALSE);
+ m_isTracking = FALSE;
return S_OK;
}
return E_FAIL;
hr = contextMenu->QueryContextMenu(hPopup, 0, 0, UINT_MAX, CMF_NORMAL);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
{
DestroyMenu(hPopup);
return hr;
PopupItem(wParam);
return S_FALSE;
}
- return m_menuBand->_MenuItemHotTrack(MPOS_EXECUTE);
+ HRESULT hr = m_menuBand->_MenuItemHotTrack(MPOS_EXECUTE);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+ return S_OK; // filter out a possible S_FALSE from here.
}
HRESULT CMenuToolbarBase::ChangeHotItem(DWORD dwSelectType)
if (btn.dwData)
{
- m_hotItem = btn.idCommand;
- if (prev != m_hotItem)
+ if (prev != btn.idCommand)
{
SendMessage(m_hwndToolbar, TB_SETHOTITEM, index, 0);
- return m_menuBand->_OnHotItemChanged(this, m_hotItem);
}
return S_OK;
}
}
}
- m_hotItem = -1;
- if (prev != m_hotItem)
+ if (prev != -1)
{
SendMessage(m_hwndToolbar, TB_SETHOTITEM, -1, 0);
- m_menuBand->_OnHotItemChanged(NULL, -1);
}
return S_FALSE;
}
-BOOL
-AllocAndGetMenuString(HMENU hMenu, UINT ItemIDByPosition, WCHAR** String)
+HRESULT CMenuToolbarBase::AddButton(DWORD commandId, LPCWSTR caption, BOOL hasSubMenu, INT iconId, DWORD_PTR buttonData, BOOL last)
+{
+ TBBUTTON tbb = { 0 };
+
+ tbb.fsState = TBSTATE_ENABLED;
+#if !USE_TBSTYLE_EX_VERTICAL
+ if (!last && (m_toolbarFlags & SMINIT_VERTICAL))
+ tbb.fsState |= TBSTATE_WRAP;
+#endif
+ tbb.fsStyle = 0;
+
+ if (hasSubMenu && (m_toolbarFlags & SMINIT_VERTICAL))
+ tbb.fsStyle |= BTNS_DROPDOWN;
+
+ if (!(m_toolbarFlags & SMINIT_VERTICAL))
+ tbb.fsStyle |= BTNS_AUTOSIZE | BTNS_CHECKGROUP;
+
+ tbb.iString = (INT_PTR) caption;
+ tbb.idCommand = commandId;
+
+ tbb.iBitmap = iconId;
+ tbb.dwData = buttonData;
+
+ if (!SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb)))
+ return HRESULT_FROM_WIN32(GetLastError());
+
+ return S_OK;
+}
+
+HRESULT CMenuToolbarBase::AddSeparator(BOOL last)
{
- int Length;
+ TBBUTTON tbb = { 0 };
+
+ tbb.fsState = TBSTATE_ENABLED;
+#if !USE_TBSTYLE_EX_VERTICAL
+ if (!last && (m_toolbarFlags & SMINIT_VERTICAL))
+ tbb.fsState |= TBSTATE_WRAP;
+#endif
+ tbb.fsStyle = BTNS_SEP;
+ tbb.iBitmap = 0;
+
+ if (!SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb)))
+ return HRESULT_FROM_WIN32(GetLastError());
- Length = GetMenuStringW(hMenu, ItemIDByPosition, NULL, 0, MF_BYPOSITION);
+ return S_OK;
+}
- if (!Length)
- return FALSE;
+HRESULT CMenuToolbarBase::AddPlaceholder()
+{
+ TBBUTTON tbb = { 0 };
+ PCWSTR MenuString = L"(Empty)";
- /* Also allocate space for the terminating NULL character */
- ++Length;
- *String = (PWSTR) HeapAlloc(GetProcessHeap(), 0, Length * sizeof(WCHAR));
+ tbb.fsState = 0;
+ tbb.fsStyle = 0;
+ tbb.iString = (INT_PTR) MenuString;
+ tbb.iBitmap = -1;
- GetMenuStringW(hMenu, ItemIDByPosition, *String, Length, MF_BYPOSITION);
+ if (!SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb)))
+ return HRESULT_FROM_WIN32(GetLastError());
- return TRUE;
+ return S_OK;
+}
+
+HRESULT CMenuToolbarBase::GetDataFromId(INT uItem, INT* pIndex, DWORD_PTR* pData)
+{
+ TBBUTTONINFO info = { 0 };
+ info.cbSize = sizeof(TBBUTTONINFO);
+ info.dwMask = 0;
+ int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
+ if (index < 0)
+ return E_FAIL;
+
+ if (pIndex)
+ *pIndex = index;
+
+ if (pData)
+ {
+ TBBUTTON btn = { 0 };
+ if (!SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn)))
+ return E_FAIL;
+ *pData = btn.dwData;
+ }
+
+ return S_OK;
+}
+
+
+HRESULT CMenuToolbarBase::PopupItem(INT uItem)
+{
+ INT index;
+ DWORD_PTR dwData;
+
+ if (!(m_toolbarFlags & SMINIT_VERTICAL))
+ {
+ SendMessage(m_hwndToolbar, TB_SETHOTITEM, uItem, 0);
+ SendMessage(m_hwndToolbar, TB_CHECKBUTTON, uItem, TRUE);
+ }
+
+ GetDataFromId(uItem, &index, &dwData);
+
+ return InternalPopupItem(uItem, index, dwData);
+}
+
+HRESULT CMenuToolbarBase::HasSubMenu(INT uItem)
+{
+ INT index;
+ DWORD_PTR dwData;
+
+ GetDataFromId(uItem, &index, &dwData);
+
+ return InternalHasSubMenu(uItem, index, dwData);
}
CMenuStaticToolbar::CMenuStaticToolbar(CMenuBand *menuBand) :
}
HRESULT CMenuStaticToolbar::GetMenu(
- HMENU *phmenu,
- HWND *phwnd,
- DWORD *pdwFlags)
+ _Out_opt_ HMENU *phmenu,
+ _Out_opt_ HWND *phwnd,
+ _Out_opt_ DWORD *pdwFlags)
{
- *phmenu = m_hmenu;
- *phwnd = NULL;
- *pdwFlags = m_dwMenuFlags;
+ if (phmenu)
+ *phmenu = m_hmenu;
+ if (phwnd)
+ *phwnd = NULL;
+ if (pdwFlags)
+ *pdwFlags = m_dwMenuFlags;
return S_OK;
}
return S_OK;
}
-HRESULT CMenuStaticToolbar::FillToolbar()
+HRESULT CMenuStaticToolbar::FillToolbar(BOOL clearFirst)
{
int i;
int ic = GetMenuItemCount(m_hmenu);
+ if (clearFirst)
+ {
+ while (SendMessage(m_hwndToolbar, TB_DELETEBUTTON, 0, 0))
+ {
+ // empty;
+ }
+ }
+
+ int count = 0;
for (i = 0; i < ic; i++)
{
- MENUITEMINFOW info;
- TBBUTTON tbb = { 0 };
- PWSTR MenuString = NULL;
+ BOOL last = i + 1 == ic;
- tbb.fsState = TBSTATE_ENABLED;
- tbb.fsStyle = 0;
+ MENUITEMINFOW info;
info.cbSize = sizeof(info);
- info.fMask = MIIM_FTYPE | MIIM_ID;
+ info.dwTypeData = NULL;
+ info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID;
- GetMenuItemInfoW(m_hmenu, i, TRUE, &info);
+ if (!GetMenuItemInfoW(m_hmenu, i, TRUE, &info))
+ {
+ DbgPrint("Error obtaining info for menu item at pos=%d\n", i);
+ continue;
+ }
- if (info.fType == MFT_STRING)
+ count++;
+
+ if (info.fType & MFT_SEPARATOR)
{
- if (!AllocAndGetMenuString(m_hmenu, i, &MenuString))
- return E_OUTOFMEMORY;
- if (::GetSubMenu(m_hmenu, i) != NULL)
- tbb.fsStyle |= BTNS_DROPDOWN;
- tbb.iString = (INT_PTR) MenuString;
- tbb.idCommand = info.wID;
+ AddSeparator(last);
+ }
+ else if (!(info.fType & MFT_BITMAP))
+ {
+
+ info.cch++;
+ info.dwTypeData = (PWSTR) HeapAlloc(GetProcessHeap(), 0, (info.cch + 1) * sizeof(WCHAR));
+
+ info.fMask = MIIM_STRING | MIIM_SUBMENU | MIIM_ID;
+ GetMenuItemInfoW(m_hmenu, i, TRUE, &info);
SMINFO * sminfo = new SMINFO();
sminfo->dwMask = SMIM_ICON | SMIM_FLAGS;
- if (SUCCEEDED(m_menuBand->_CallCBWithItemId(info.wID, SMC_GETINFO, 0, reinterpret_cast<LPARAM>(sminfo))))
- {
- tbb.iBitmap = sminfo->iIcon;
- tbb.dwData = reinterpret_cast<DWORD_PTR>(sminfo);
- // FIXME: remove before deleting the toolbar or it will leak
- }
- }
- else
- {
- tbb.fsStyle |= BTNS_SEP;
- }
+ // FIXME: remove before deleting the toolbar or it will leak
- SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb));
+ HRESULT hr = m_menuBand->_CallCBWithItemId(info.wID, SMC_GETINFO, 0, reinterpret_cast<LPARAM>(sminfo));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
- if (MenuString)
- HeapFree(GetProcessHeap(), 0, MenuString);
+ AddButton(info.wID, info.dwTypeData, info.hSubMenu != NULL, sminfo->iIcon, reinterpret_cast<DWORD_PTR>(sminfo), last);
+
+ HeapFree(GetProcessHeap(), 0, info.dwTypeData);
+ }
}
+ DbgPrint("Created toolbar with %d buttons.\n", count);
+
+ return S_OK;
+}
+
+HRESULT CMenuStaticToolbar::OnDeletingButton(const NMTOOLBAR * tb)
+{
+ delete reinterpret_cast<SMINFO*>(tb->tbButton.dwData);
return S_OK;
}
{
HRESULT hr;
hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
// in case the clicked item has a submenu, we do not need to execute the item
if (hr == S_FALSE)
+ {
+ DbgPrint("CMenuToolbarBase::OnCommand told us to cancel.\n");
return hr;
+ }
return m_menuBand->_CallCBWithItemId(wParam, SMC_EXEC, 0, 0);
}
-HRESULT CMenuStaticToolbar::PopupItem(UINT uItem)
+HRESULT CMenuStaticToolbar::InternalPopupItem(INT uItem, INT index, DWORD_PTR dwData)
{
- TBBUTTONINFO info = { 0 };
- info.cbSize = sizeof(TBBUTTONINFO);
- info.dwMask = 0;
- int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
- if (index < 0)
- return E_FAIL;
-
- TBBUTTON btn = { 0 };
- SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn));
-
- SMINFO * nfo = reinterpret_cast<SMINFO*>(btn.dwData);
+ SMINFO * nfo = reinterpret_cast<SMINFO*>(dwData);
if (!nfo)
return E_FAIL;
if (nfo->dwFlags&SMIF_TRACKPOPUP)
{
- return PopupSubMenu(index, m_hmenu);
+ return PopupSubMenu(uItem, index, m_hmenu);
}
else
{
CComPtr<IShellMenu> shellMenu;
HRESULT hr = m_menuBand->_CallCBWithItemId(uItem, SMC_GETOBJECT, reinterpret_cast<WPARAM>(&IID_IShellMenu), reinterpret_cast<LPARAM>(&shellMenu));
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
return PopupSubMenu(uItem, index, shellMenu);
}
}
-HRESULT CMenuStaticToolbar::HasSubMenu(UINT uItem)
+HRESULT CMenuStaticToolbar::InternalHasSubMenu(INT uItem, INT index, DWORD_PTR dwData)
{
- TBBUTTONINFO info = { 0 };
- info.cbSize = sizeof(TBBUTTONINFO);
- info.dwMask = 0;
- int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
- if (index < 0)
- return E_FAIL;
return ::GetSubMenu(m_hmenu, index) ? S_OK : S_FALSE;
}
CMenuSFToolbar::CMenuSFToolbar(CMenuBand * menuBand) :
CMenuToolbarBase(menuBand, TRUE),
- m_shellFolder(NULL)
+ m_shellFolder(NULL),
+ m_idList(NULL),
+ m_hKey(NULL)
{
}
{
}
-HRESULT CMenuSFToolbar::FillToolbar()
+HRESULT CMenuSFToolbar::FillToolbar(BOOL clearFirst)
{
HRESULT hr;
int i = 0;
LPITEMIDLIST item = static_cast<LPITEMIDLIST>(CoTaskMemAlloc(sizeof(ITEMIDLIST)));
ULONG fetched;
- while ((hr = eidl->Next(1, &item, &fetched)) == S_OK)
+ hr = eidl->Next(1, &item, &fetched);
+ while (SUCCEEDED(hr) && fetched > 0)
{
INT index = 0;
INT indexOpen = 0;
- TBBUTTON tbb = { 0 };
- tbb.fsState = TBSTATE_ENABLED;
- tbb.fsStyle = 0;
-
STRRET sr = { STRRET_CSTR, { 0 } };
hr = m_shellFolder->GetDisplayNameOf(item, SIGDN_NORMALDISPLAY, &sr);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
StrRetToStr(&sr, NULL, &MenuString);
SFGAOF attrs = SFGAO_FOLDER;
hr = m_shellFolder->GetAttributesOf(1, &itemc, &attrs);
- if (attrs & SFGAO_FOLDER)
- {
- tbb.fsStyle |= BTNS_DROPDOWN;
- }
-
- tbb.idCommand = ++i;
- tbb.iString = (INT_PTR) MenuString;
- tbb.iBitmap = index;
- tbb.dwData = reinterpret_cast<DWORD_PTR>(ILClone(item));
+ DWORD_PTR dwData = reinterpret_cast<DWORD_PTR>(ILClone(item));
// FIXME: remove before deleting the toolbar or it will leak
- SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb));
- CoTaskMemFree(MenuString);
+ // Fetch next item already, so we know if the current one is the last
+ hr = eidl->Next(1, &item, &fetched);
+
+ AddButton(++i, MenuString, attrs & SFGAO_FOLDER, index, dwData, FAILED(hr) || fetched == 0);
+ CoTaskMemFree(MenuString);
}
CoTaskMemFree(item);
// If no items were added, show the "empty" placeholder
if (i == 0)
{
- TBBUTTON tbb = { 0 };
- PCWSTR MenuString = L"(Empty)";
-
- tbb.fsState = 0/*TBSTATE_DISABLED*/;
- tbb.fsStyle = 0;
- tbb.iString = (INT_PTR) MenuString;
- tbb.iBitmap = -1;
-
- SendMessageW(m_hwndToolbar, TB_ADDBUTTONS, 1, reinterpret_cast<LPARAM>(&tbb));
-
- return S_OK;
+ return AddPlaceholder();
}
+ DbgPrint("Created toolbar with %d buttons.\n", i);
+
return hr;
}
+HRESULT CMenuSFToolbar::OnDeletingButton(const NMTOOLBAR * tb)
+{
+ ILFree(reinterpret_cast<LPITEMIDLIST>(tb->tbButton.dwData));
+ return S_OK;
+}
+
HRESULT CMenuSFToolbar::SetShellFolder(IShellFolder *psf, LPCITEMIDLIST pidlFolder, HKEY hKey, DWORD dwFlags)
{
m_shellFolder = psf;
- m_idList = pidlFolder;
+ m_idList = ILClone(pidlFolder);
m_hKey = hKey;
m_dwMenuFlags = dwFlags;
return S_OK;
HRESULT hr;
hr = m_shellFolder->QueryInterface(riid, ppv);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
if (pdwFlags)
return hr;
}
-LPITEMIDLIST CMenuSFToolbar::GetPidlFromId(UINT uItem, INT* pIndex)
-{
- TBBUTTONINFO info = { 0 };
- info.cbSize = sizeof(TBBUTTONINFO);
- info.dwMask = 0;
- int index = SendMessage(m_hwndToolbar, TB_GETBUTTONINFO, uItem, reinterpret_cast<LPARAM>(&info));
- if (index < 0)
- return NULL;
-
- if (pIndex)
- *pIndex = index;
-
- TBBUTTON btn = { 0 };
- if (!SendMessage(m_hwndToolbar, TB_GETBUTTON, index, reinterpret_cast<LPARAM>(&btn)))
- return NULL;
-
- return reinterpret_cast<LPITEMIDLIST>(btn.dwData);
-}
-
HRESULT CMenuSFToolbar::OnContextMenu(NMMOUSE * rclick)
{
HRESULT hr;
{
HRESULT hr;
hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
// in case the clicked item has a submenu, we do not need to execute the item
if (hr == S_FALSE)
+ {
+ DbgPrint("CMenuToolbarBase::OnCommand told us to cancel.\n");
return hr;
+ }
+
+ DWORD_PTR data;
+ GetDataFromId(wParam, NULL, &data);
- return m_menuBand->_CallCBWithItemPidl(GetPidlFromId(wParam), SMC_SFEXEC, 0, 0);
+ return m_menuBand->_CallCBWithItemPidl(reinterpret_cast<LPITEMIDLIST>(data), SMC_SFEXEC, 0, 0);
}
-HRESULT CMenuSFToolbar::PopupItem(UINT uItem)
+HRESULT CMenuSFToolbar::InternalPopupItem(INT uItem, INT index, DWORD_PTR dwData)
{
HRESULT hr;
UINT uId;
UINT uIdAncestor;
DWORD flags;
- int index;
CComPtr<IShellMenuCallback> psmc;
CComPtr<IShellMenu> shellMenu;
- LPITEMIDLIST pidl = GetPidlFromId(uItem, &index);
+ LPITEMIDLIST pidl = reinterpret_cast<LPITEMIDLIST>(dwData);
if (!pidl)
return E_FAIL;
#else
hr = CMenuBand_Constructor(IID_PPV_ARG(IShellMenu, &shellMenu));
#endif
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
#if WRAP_MENUBAND
hr = CMenuBand_Wrapper(shellMenu, IID_PPV_ARG(IShellMenu, &shellMenu));
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
#endif
// FIXME: not sure what to use as uId/uIdAncestor here
hr = shellMenu->Initialize(psmc, 0, uId, SMINIT_VERTICAL);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
CComPtr<IShellFolder> childFolder;
hr = m_shellFolder->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &childFolder));
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
hr = shellMenu->SetShellFolder(childFolder, NULL, NULL, 0);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
return PopupSubMenu(uItem, index, shellMenu);
}
-HRESULT CMenuSFToolbar::HasSubMenu(UINT uItem)
+HRESULT CMenuSFToolbar::InternalHasSubMenu(INT uItem, INT index, DWORD_PTR dwData)
{
HRESULT hr;
- LPCITEMIDLIST pidl = GetPidlFromId(uItem);
+ LPCITEMIDLIST pidl = reinterpret_cast<LPITEMIDLIST>(dwData);
SFGAOF attrs = SFGAO_FOLDER;
hr = m_shellFolder->GetAttributesOf(1, &pidl, &attrs);
- if (FAILED(hr))
+ if (FAILED_UNEXPECTEDLY(hr))
return hr;
return (attrs & SFGAO_FOLDER) ? S_OK : S_FALSE;