2014-02-24 11:59:34 +00:00
/*
* Shell Menu Band
*
* Copyright 2014 David Quintana
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA
*/
# include "precomp.h"
# include <windowsx.h>
2014-03-20 15:39:25 +00:00
# include <commoncontrols.h>
2014-02-24 11:59:34 +00:00
# include <shlwapi_undoc.h>
# include "CMenuBand.h"
# include "CMenuToolbars.h"
WINE_DEFAULT_DEBUG_CHANNEL ( CMenuToolbars ) ;
extern " C "
HRESULT WINAPI SHGetImageList (
_In_ int iImageList ,
_In_ REFIID riid ,
_Out_ void * * ppv
) ;
2014-03-03 11:14:04 +00:00
// FIXME: Enable if/when wine comctl supports this flag properly
2014-03-16 01:21:54 +00:00
# define USE_TBSTYLE_EX_VERTICAL 0
2014-02-24 11:59:34 +00:00
2014-04-02 17:37:37 +00:00
// User-defined timer ID used while hot-tracking around the menu
2014-02-24 11:59:34 +00:00
# define TIMERID_HOTTRACK 1
2014-03-15 21:38:15 +00:00
2014-02-26 11:13:23 +00:00
HRESULT CMenuToolbarBase : : OnWinEvent ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam , LRESULT * theResult )
{
NMHDR * hdr ;
* theResult = 0 ;
switch ( uMsg )
{
case WM_COMMAND :
return OnCommand ( wParam , lParam , theResult ) ;
case WM_NOTIFY :
hdr = reinterpret_cast < LPNMHDR > ( lParam ) ;
switch ( hdr - > code )
{
2014-03-11 10:42:25 +00:00
case TBN_DELETINGBUTTON :
return OnDeletingButton ( reinterpret_cast < LPNMTOOLBAR > ( hdr ) ) ;
2014-02-26 11:13:23 +00:00
case PGN_CALCSIZE :
2014-04-02 17:37:37 +00:00
return OnPagerCalcSize ( reinterpret_cast < LPNMPGCALCSIZE > ( hdr ) ) ;
2014-02-26 11:13:23 +00:00
case TBN_DROPDOWN :
2014-03-20 15:39:25 +00:00
return OnCommand ( reinterpret_cast < LPNMTOOLBAR > ( hdr ) - > iItem , 0 , theResult ) ;
2014-02-26 11:13:23 +00:00
case TBN_HOTITEMCHANGE :
2014-04-03 18:30:25 +00:00
//return OnHotItemChange(reinterpret_cast<LPNMTBHOTITEM>(hdr), theResult);
return S_OK ;
2014-02-26 11:13:23 +00:00
case NM_RCLICK :
2014-03-11 10:42:25 +00:00
return OnContextMenu ( reinterpret_cast < LPNMMOUSE > ( hdr ) ) ;
2014-02-26 11:13:23 +00:00
case NM_CUSTOMDRAW :
2014-03-11 10:42:25 +00:00
return OnCustomDraw ( reinterpret_cast < LPNMTBCUSTOMDRAW > ( hdr ) , theResult ) ;
2014-02-26 11:13:23 +00:00
2014-04-02 17:37:37 +00:00
case TBN_GETINFOTIP :
return OnGetInfoTip ( reinterpret_cast < LPNMTBGETINFOTIP > ( hdr ) ) ;
// Silence unhandled items so that they don't print as unknown
2014-03-11 10:42:25 +00:00
case RBN_CHILDSIZE :
return S_OK ;
2014-02-26 11:13:23 +00:00
2014-04-02 17:37:37 +00:00
case TTN_GETDISPINFO :
return S_OK ;
2014-03-20 15:39:25 +00:00
case NM_RELEASEDCAPTURE :
break ;
2014-04-02 17:37:37 +00:00
case NM_CLICK :
2014-03-20 15:39:25 +00:00
case NM_RDOWN :
case NM_LDOWN :
break ;
case TBN_GETDISPINFO :
break ;
case TBN_BEGINDRAG :
case TBN_ENDDRAG :
break ;
case NM_TOOLTIPSCREATED :
break ;
2014-04-03 18:30:25 +00:00
// Unknown
case - 714 : return S_FALSE ;
2014-03-11 10:42:25 +00:00
default :
DbgPrint ( " WM_NOTIFY unknown code %d, %d \n " , hdr - > code , hdr - > idFrom ) ;
2014-03-26 11:33:52 +00:00
return S_OK ;
2014-03-11 10:42:25 +00:00
}
2014-03-26 11:33:52 +00:00
return S_FALSE ;
2014-03-11 10:42:25 +00:00
}
2014-02-26 11:13:23 +00:00
2014-03-11 10:42:25 +00:00
return S_FALSE ;
}
2014-02-26 11:13:23 +00:00
2014-04-02 17:37:37 +00:00
LRESULT CALLBACK CMenuToolbarBase : : s_SubclassProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
CMenuToolbarBase * pthis = reinterpret_cast < CMenuToolbarBase * > ( GetWindowLongPtr ( hWnd , GWLP_USERDATA ) ) ;
return pthis - > SubclassProc ( hWnd , uMsg , wParam , lParam ) ;
}
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_SubclassOld ( hWnd , uMsg , wParam , lParam ) ;
2014-04-03 18:30:25 +00:00
return ChangeTrackedItem ( wParam , lParam ) ;
2014-04-02 17:37:37 +00:00
case WM_COMMAND :
OnWinEvent ( hWnd , uMsg , wParam , lParam , & lr ) ;
break ;
case WM_NOTIFY :
OnWinEvent ( hWnd , uMsg , wParam , lParam , & lr ) ;
break ;
case WM_TIMER :
OnPopupTimer ( wParam ) ;
}
return m_SubclassOld ( hWnd , uMsg , wParam , lParam ) ;
}
HRESULT CMenuToolbarBase : : DisableMouseTrack ( BOOL bDisable )
{
if ( m_disableMouseTrack ! = bDisable )
{
m_disableMouseTrack = bDisable ;
DbgPrint ( " DisableMouseTrack %d \n " , bDisable ) ;
}
return S_OK ;
}
HRESULT CMenuToolbarBase : : OnPagerCalcSize ( LPNMPGCALCSIZE csize )
{
SIZE tbs ;
2014-04-07 18:41:47 +00:00
GetSizes ( NULL , & tbs , NULL ) ;
2014-04-02 17:37:37 +00:00
if ( csize - > dwFlag = = PGF_CALCHEIGHT )
{
csize - > iHeight = tbs . cy ;
}
else if ( csize - > dwFlag = = PGF_CALCWIDTH )
{
csize - > iWidth = tbs . cx ;
}
return S_OK ;
}
2014-03-11 10:42:25 +00:00
HRESULT CMenuToolbarBase : : OnCustomDraw ( LPNMTBCUSTOMDRAW cdraw , LRESULT * theResult )
{
2014-04-02 17:37:37 +00:00
RECT rc ;
HDC hdc ;
2014-03-11 10:42:25 +00:00
COLORREF clrText ;
2014-04-02 17:37:37 +00:00
HBRUSH bgBrush ;
bool isHot , isPopup ;
2014-03-11 10:42:25 +00:00
TBBUTTONINFO btni ;
2014-02-27 11:56:28 +00:00
2014-03-11 10:42:25 +00:00
switch ( cdraw - > nmcd . dwDrawStage )
{
case CDDS_PREPAINT :
2014-04-02 17:37:37 +00:00
* theResult = CDRF_NOTIFYITEMDRAW ;
2014-03-11 10:42:25 +00:00
return S_OK ;
2014-02-26 11:13:23 +00:00
2014-03-11 10:42:25 +00:00
case CDDS_ITEMPREPAINT :
2014-02-26 11:13:23 +00:00
2014-03-11 10:42:25 +00:00
rc = cdraw - > nmcd . rc ;
hdc = cdraw - > nmcd . hdc ;
2014-04-02 17:37:37 +00:00
// The item with an active submenu gets the CHECKED flag.
2014-04-03 18:30:25 +00:00
isHot = m_hotBar = = this & & ( int ) cdraw - > nmcd . dwItemSpec = = m_hotItem ;
isPopup = m_popupBar = = this & & ( int ) cdraw - > nmcd . dwItemSpec = = m_popupItem ;
2014-03-11 10:42:25 +00:00
2014-04-02 17:37:37 +00:00
if ( m_initFlags & SMINIT_VERTICAL )
2014-03-11 10:42:25 +00:00
{
2014-04-02 17:37:37 +00:00
// Remove HOT and CHECKED flags (will restore HOT if necessary)
cdraw - > nmcd . uItemState & = ~ ( CDIS_HOT | CDIS_CHECKED ) ;
2014-03-11 10:42:25 +00:00
2014-04-02 17:37:37 +00:00
// Decide on the colors
if ( isHot | | ( m_hotItem < 0 & & isPopup ) )
{
cdraw - > nmcd . uItemState | = CDIS_HOT ;
clrText = GetSysColor ( COLOR_HIGHLIGHTTEXT ) ;
bgBrush = GetSysColorBrush ( m_useFlatMenus ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT ) ;
}
else
{
clrText = GetSysColor ( COLOR_MENUTEXT ) ;
bgBrush = GetSysColorBrush ( COLOR_MENU ) ;
}
// Paint the background color with the selected color
2014-03-11 10:42:25 +00:00
FillRect ( hdc , & rc , bgBrush ) ;
2014-04-02 17:37:37 +00:00
// Set the text color in advance, this color will be assigned when the ITEMPOSTPAINT triggers
2014-03-11 10:42:25 +00:00
SetTextColor ( hdc , clrText ) ;
2014-04-02 17:37:37 +00:00
// Set the text color, will be used by the internal drawing code
2014-03-11 10:42:25 +00:00
cdraw - > clrText = clrText ;
2014-04-02 17:37:37 +00:00
cdraw - > iListGap + = 4 ;
// Tell the default drawing code we don't want any fanciness, not even a background.
* theResult = CDRF_NOTIFYPOSTPAINT | TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOOFFSET | TBCDRF_NOMARK | 0x00800000 ; // FIXME: the last bit is Vista+, useful for debugging only
2014-03-11 10:42:25 +00:00
}
2014-04-02 17:37:37 +00:00
else
{
// Remove HOT and CHECKED flags (will restore HOT if necessary)
cdraw - > nmcd . uItemState & = ~ CDIS_HOT ;
2014-03-11 10:42:25 +00:00
2014-04-02 17:37:37 +00:00
// Decide on the colors
if ( isHot | | ( m_hotItem < 0 & & isPopup ) )
{
cdraw - > nmcd . uItemState | = CDIS_HOT ;
}
* theResult = 0 ;
}
2014-03-11 10:42:25 +00:00
2014-02-26 11:13:23 +00:00
return S_OK ;
2014-03-11 10:42:25 +00:00
case CDDS_ITEMPOSTPAINT :
2014-04-02 17:37:37 +00:00
// Fetch the button style
2014-03-11 10:42:25 +00:00
btni . cbSize = sizeof ( btni ) ;
btni . dwMask = TBIF_STYLE ;
SendMessage ( m_hwndToolbar , TB_GETBUTTONINFO , cdraw - > nmcd . dwItemSpec , reinterpret_cast < LPARAM > ( & btni ) ) ;
2014-04-02 17:37:37 +00:00
// Check if we need to draw a submenu arrow
2014-03-11 10:42:25 +00:00
if ( btni . fsStyle & BTNS_DROPDOWN )
{
2014-04-02 17:37:37 +00:00
// TODO: Support RTL text modes by drawing a leftwards arrow aligned to the left of the control
// "8" is the rightwards dropdown arrow in the Marlett font
WCHAR text [ ] = L " 8 " ;
// Configure the font to draw with Marlett, keeping the current background color as-is
2014-03-11 10:42:25 +00:00
SelectObject ( cdraw - > nmcd . hdc , m_marlett ) ;
SetBkMode ( cdraw - > nmcd . hdc , TRANSPARENT ) ;
2014-04-02 17:37:37 +00:00
// Tweak the alignment by 1 pixel so the menu draws like the Windows start menu.
2014-03-11 10:42:25 +00:00
RECT rc = cdraw - > nmcd . rc ;
rc . right + = 1 ;
2014-04-02 17:37:37 +00:00
// The arrow is drawn at the right of the item's rect, aligned vertically.
2014-03-11 10:42:25 +00:00
DrawTextEx ( cdraw - > nmcd . hdc , text , 1 , & rc , DT_NOCLIP | DT_VCENTER | DT_RIGHT | DT_SINGLELINE , NULL ) ;
}
* theResult = TRUE ;
return S_OK ;
}
return S_OK ;
2014-02-26 11:13:23 +00:00
}
2014-02-24 11:59:34 +00:00
CMenuToolbarBase : : CMenuToolbarBase ( CMenuBand * menuBand , BOOL usePager ) :
m_hwnd ( NULL ) ,
2014-02-26 11:13:23 +00:00
m_useFlatMenus ( FALSE ) ,
2014-03-26 11:33:52 +00:00
m_SubclassOld ( NULL ) ,
2014-03-15 21:38:15 +00:00
m_disableMouseTrack ( FALSE ) ,
2014-04-02 17:37:37 +00:00
m_timerEnabled ( FALSE ) ,
2014-02-24 11:59:34 +00:00
m_menuBand ( menuBand ) ,
m_hwndToolbar ( NULL ) ,
m_dwMenuFlags ( 0 ) ,
2014-04-07 18:41:47 +00:00
m_hasSizes ( FALSE ) ,
2014-02-27 11:56:28 +00:00
m_usePager ( usePager ) ,
m_hotItem ( - 1 ) ,
2014-03-19 15:33:41 +00:00
m_popupItem ( - 1 ) ,
2014-04-07 18:41:47 +00:00
m_isTrackingPopup ( FALSE )
2014-02-24 11:59:34 +00:00
{
2014-04-07 18:41:47 +00:00
m_idealSize . cx = 0 ;
m_idealSize . cy = 0 ;
m_itemSize . cx = 0 ;
m_itemSize . cy = 0 ;
2014-02-26 11:13:23 +00:00
m_marlett = CreateFont (
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , DEFAULT_CHARSET ,
OUT_DEFAULT_PRECIS , CLIP_DEFAULT_PRECIS ,
DEFAULT_QUALITY , FF_DONTCARE , L " Marlett " ) ;
}
CMenuToolbarBase : : ~ CMenuToolbarBase ( )
{
2014-04-02 17:37:37 +00:00
if ( m_hwndToolbar & & m_hwndToolbar ! = m_hwnd )
DestroyWindow ( m_hwndToolbar ) ;
2014-02-24 11:59:34 +00:00
2014-04-02 17:37:37 +00:00
if ( m_hwnd )
DestroyWindow ( m_hwnd ) ;
DeleteObject ( m_marlett ) ;
2014-02-24 11:59:34 +00:00
}
void CMenuToolbarBase : : InvalidateDraw ( )
{
InvalidateRect ( m_hwnd , NULL , FALSE ) ;
}
HRESULT CMenuToolbarBase : : ShowWindow ( BOOL fShow )
{
: : ShowWindow ( m_hwnd , fShow ? SW_SHOW : SW_HIDE ) ;
2014-04-02 17:37:37 +00:00
// Ensure that the right image list is assigned to the toolbar
2014-02-25 10:44:28 +00:00
UpdateImageLists ( ) ;
2014-04-02 17:37:37 +00:00
// For custom-drawing
2014-02-26 11:13:23 +00:00
SystemParametersInfo ( SPI_GETFLATMENU , 0 , & m_useFlatMenus , 0 ) ;
2014-02-25 10:44:28 +00:00
return S_OK ;
}
HRESULT CMenuToolbarBase : : UpdateImageLists ( )
{
2014-04-02 17:37:37 +00:00
if ( ( m_initFlags & ( SMINIT_TOPLEVEL | SMINIT_VERTICAL ) ) = = SMINIT_TOPLEVEL ) // not vertical.
2014-03-07 22:28:55 +00:00
{
2014-04-02 17:37:37 +00:00
// No image list, prevents the buttons from having a margin at the left side
2014-03-07 22:28:55 +00:00
SendMessageW ( m_hwnd , TB_SETIMAGELIST , 0 , 0 ) ;
return S_OK ;
}
2014-04-02 17:37:37 +00:00
// Assign the correct imagelist and padding based on the current icon size
2014-02-24 11:59:34 +00:00
int shiml ;
if ( m_menuBand - > UseBigIcons ( ) )
{
shiml = SHIL_LARGE ;
2014-02-25 18:23:02 +00:00
SendMessageW ( m_hwndToolbar , TB_SETPADDING , 0 , MAKELPARAM ( 4 , 0 ) ) ;
2014-02-24 11:59:34 +00:00
}
else
{
shiml = SHIL_SMALL ;
2014-02-25 18:23:02 +00:00
SendMessageW ( m_hwndToolbar , TB_SETPADDING , 0 , MAKELPARAM ( 4 , 4 ) ) ;
2014-02-24 11:59:34 +00:00
}
IImageList * piml ;
HRESULT hr = SHGetImageList ( shiml , IID_PPV_ARG ( IImageList , & piml ) ) ;
2014-04-02 17:37:37 +00:00
if ( FAILED_UNEXPECTEDLY ( hr ) )
2014-02-24 11:59:34 +00:00
{
2014-04-02 17:37:37 +00:00
SendMessageW ( m_hwndToolbar , TB_SETIMAGELIST , 0 , 0 ) ;
2014-02-24 11:59:34 +00:00
}
else
{
2014-04-02 17:37:37 +00:00
SendMessageW ( m_hwndToolbar , TB_SETIMAGELIST , 0 , reinterpret_cast < LPARAM > ( piml ) ) ;
2014-02-24 11:59:34 +00:00
}
return S_OK ;
}
HRESULT CMenuToolbarBase : : Close ( )
{
if ( m_hwndToolbar ! = m_hwnd )
2014-04-02 17:37:37 +00:00
DestroyWindow ( m_hwndToolbar ) ;
DestroyWindow ( m_hwnd ) ;
2014-02-24 11:59:34 +00:00
m_hwndToolbar = NULL ;
m_hwnd = NULL ;
2014-04-02 17:37:37 +00:00
2014-02-24 11:59:34 +00:00
return S_OK ;
}
HRESULT CMenuToolbarBase : : CreateToolbar ( HWND hwndParent , DWORD dwFlags )
{
LONG tbStyles = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
TBSTYLE_TOOLTIPS | TBSTYLE_TRANSPARENT | TBSTYLE_REGISTERDROP | TBSTYLE_LIST | TBSTYLE_FLAT | TBSTYLE_CUSTOMERASE |
CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE | CCS_TOP ;
2014-04-02 17:37:37 +00:00
LONG tbExStyles = TBSTYLE_EX_DOUBLEBUFFER | WS_EX_TOOLWINDOW ;
2014-02-24 11:59:34 +00:00
if ( dwFlags & SMINIT_VERTICAL )
{
2014-04-02 17:37:37 +00:00
// Activate vertical semantics
2014-02-24 11:59:34 +00:00
tbStyles | = CCS_VERT ;
2014-03-02 19:35:13 +00:00
2014-03-16 01:21:54 +00:00
# if USE_TBSTYLE_EX_VERTICAL
2014-04-02 17:37:37 +00:00
tbExStyles | = TBSTYLE_EX_VERTICAL ;
2014-03-03 11:14:04 +00:00
# endif
2014-02-24 11:59:34 +00:00
}
2014-04-02 17:37:37 +00:00
m_initFlags = dwFlags ;
2014-03-07 22:28:55 +00:00
2014-04-02 17:37:37 +00:00
// Get a temporary rect to use while creating the toolbar window.
// Ensure that it is not a null rect.
2014-02-24 11:59:34 +00:00
RECT rc ;
2014-04-02 17:37:37 +00:00
if ( ! : : GetClientRect ( hwndParent , & rc ) | |
( rc . left = = rc . right ) | |
( rc . top = = rc . bottom ) )
2014-02-24 11:59:34 +00:00
{
rc . left = 0 ;
rc . top = 0 ;
rc . right = 1 ;
rc . bottom = 1 ;
}
HWND hwndToolbar = CreateWindowEx (
tbExStyles , TOOLBARCLASSNAMEW , NULL ,
tbStyles , rc . left , rc . top , rc . right - rc . left , rc . bottom - rc . top ,
hwndParent , NULL , _AtlBaseModule . GetModuleInstance ( ) , 0 ) ;
if ( hwndToolbar = = NULL )
return E_FAIL ;
2014-04-02 17:37:37 +00:00
// If needed, create the pager.
2014-02-24 11:59:34 +00:00
if ( m_usePager )
{
LONG pgStyles = PGS_VERT | WS_CHILD | WS_VISIBLE ;
LONG pgExStyles = 0 ;
HWND hwndPager = CreateWindowEx (
pgExStyles , WC_PAGESCROLLER , NULL ,
pgStyles , rc . left , rc . top , rc . right - rc . left , rc . bottom - rc . top ,
hwndParent , NULL , _AtlBaseModule . GetModuleInstance ( ) , 0 ) ;
: : SetParent ( hwndToolbar , hwndPager ) ;
: : SetParent ( hwndPager , hwndParent ) ;
SendMessage ( hwndPager , PGM_SETCHILD , 0 , reinterpret_cast < LPARAM > ( hwndToolbar ) ) ;
m_hwndToolbar = hwndToolbar ;
m_hwnd = hwndPager ;
}
else
{
: : SetParent ( hwndToolbar , hwndParent ) ;
m_hwndToolbar = hwndToolbar ;
m_hwnd = hwndToolbar ;
}
2014-03-26 11:33:52 +00:00
2014-04-02 17:37:37 +00:00
// Identify the version of the used Common Controls DLL by sending the size of the TBBUTTON structure.
2014-02-24 11:59:34 +00:00
SendMessageW ( hwndToolbar , TB_BUTTONSTRUCTSIZE , sizeof ( TBBUTTON ) , 0 ) ;
2014-04-02 17:37:37 +00:00
// Apply subclassing
2014-02-24 11:59:34 +00:00
SetWindowLongPtr ( hwndToolbar , GWLP_USERDATA , reinterpret_cast < LONG_PTR > ( this ) ) ;
m_SubclassOld = ( WNDPROC ) SetWindowLongPtr ( hwndToolbar , GWLP_WNDPROC , reinterpret_cast < LONG_PTR > ( CMenuToolbarBase : : s_SubclassProc ) ) ;
2014-04-02 17:37:37 +00:00
// Configure the image lists
2014-02-25 10:44:28 +00:00
UpdateImageLists ( ) ;
2014-02-24 11:59:34 +00:00
return S_OK ;
}
2014-04-07 18:41:47 +00:00
HRESULT CMenuToolbarBase : : GetSizes ( SIZE * pMinSize , SIZE * pMaxSize , SIZE * pIntegralSize )
2014-02-24 11:59:34 +00:00
{
2014-04-07 18:41:47 +00:00
if ( pMinSize )
* pMinSize = m_idealSize ;
if ( pMaxSize )
* pMaxSize = m_idealSize ;
if ( pIntegralSize )
* pIntegralSize = m_itemSize ;
if ( m_hasSizes )
return S_OK ;
2014-02-24 11:59:34 +00:00
2014-04-07 18:41:47 +00:00
if ( ! m_hwndToolbar )
return S_OK ;
2014-02-24 11:59:34 +00:00
2014-04-07 18:41:47 +00:00
// Obtain the ideal size, to be used as min and max
SendMessageW ( m_hwndToolbar , TB_AUTOSIZE , 0 , 0 ) ;
SendMessageW ( m_hwndToolbar , TB_GETMAXSIZE , 0 , reinterpret_cast < LPARAM > ( & m_idealSize ) ) ;
SendMessageW ( m_hwndToolbar , TB_GETIDEALSIZE , ( m_initFlags & SMINIT_VERTICAL ) ! = 0 , reinterpret_cast < LPARAM > ( & m_idealSize ) ) ;
// Obtain the button size, to be used as the integral size
DWORD size = SendMessageW ( m_hwndToolbar , TB_GETBUTTONSIZE , 0 , 0 ) ;
m_itemSize . cx = GET_X_LPARAM ( size ) ;
m_itemSize . cy = GET_Y_LPARAM ( size ) ;
m_hasSizes = TRUE ;
if ( pMinSize )
* pMinSize = m_idealSize ;
if ( pMaxSize )
* pMaxSize = m_idealSize ;
if ( pIntegralSize )
* pIntegralSize = m_itemSize ;
2014-02-24 11:59:34 +00:00
return S_OK ;
}
HRESULT CMenuToolbarBase : : SetPosSize ( int x , int y , int cx , int cy )
{
2014-04-02 17:37:37 +00:00
// If we have a pager, set the toolbar height to the ideal height of the toolbar
2014-02-24 11:59:34 +00:00
if ( m_hwnd ! = m_hwndToolbar )
{
SetWindowPos ( m_hwndToolbar , NULL , x , y , cx , m_idealSize . cy , 0 ) ;
}
2014-04-02 17:37:37 +00:00
// Update the toolbar or pager to fit the requested rect
2014-02-24 11:59:34 +00:00
SetWindowPos ( m_hwnd , NULL , x , y , cx , cy , 0 ) ;
2014-04-02 17:37:37 +00:00
// In a vertical menu, resize the buttons to fit the width
if ( m_initFlags & SMINIT_VERTICAL )
2014-03-07 22:28:55 +00:00
{
DWORD btnSize = SendMessage ( m_hwndToolbar , TB_GETBUTTONSIZE , 0 , 0 ) ;
SendMessage ( m_hwndToolbar , TB_SETBUTTONSIZE , 0 , MAKELPARAM ( cx , HIWORD ( btnSize ) ) ) ;
}
2014-04-02 17:37:37 +00:00
2014-02-24 11:59:34 +00:00
return S_OK ;
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuToolbarBase : : IsWindowOwner ( HWND hwnd )
{
if ( m_hwnd & & m_hwnd = = hwnd ) return S_OK ;
if ( m_hwndToolbar & & m_hwndToolbar = = hwnd ) return S_OK ;
return S_FALSE ;
}
2014-02-24 11:59:34 +00:00
HRESULT CMenuToolbarBase : : GetWindow ( HWND * phwnd )
{
if ( ! phwnd )
return E_FAIL ;
* phwnd = m_hwnd ;
return S_OK ;
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuToolbarBase : : OnGetInfoTip ( NMTBGETINFOTIP * tip )
2014-02-24 11:59:34 +00:00
{
2014-04-02 17:37:37 +00:00
INT index ;
DWORD_PTR dwData ;
INT iItem = tip - > iItem ;
GetDataFromId ( iItem , & index , & dwData ) ;
return GetInfoTip ( tip - > pszText , tip - > cchTextMax , iItem , index , dwData ) ;
2014-02-24 11:59:34 +00:00
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuToolbarBase : : OnPopupTimer ( DWORD timerId )
2014-02-24 11:59:34 +00:00
{
2014-04-02 17:37:37 +00:00
if ( timerId ! = TIMERID_HOTTRACK )
return S_FALSE ;
2014-03-07 22:28:55 +00:00
2014-04-02 17:37:37 +00:00
KillTimer ( m_hwndToolbar , TIMERID_HOTTRACK ) ;
2014-03-19 15:33:41 +00:00
2014-04-02 17:37:37 +00:00
if ( ! m_timerEnabled )
return S_FALSE ;
2014-02-24 11:59:34 +00:00
2014-04-02 17:37:37 +00:00
m_timerEnabled = FALSE ;
2014-03-26 11:33:52 +00:00
2014-04-02 17:37:37 +00:00
if ( m_hotItem < 0 )
return S_FALSE ;
2014-02-24 11:59:34 +00:00
2014-04-02 17:37:37 +00:00
// Returns S_FALSE if the current item did not show a submenu
HRESULT hr = PopupItem ( m_hotItem ) ;
if ( hr ! = S_FALSE )
return hr ;
2014-03-26 11:33:52 +00:00
2014-04-02 17:37:37 +00:00
// If we didn't switch submenus, cancel the current popup regardless
if ( m_popupBar )
{
HRESULT hr = CancelCurrentPopup ( ) ;
if ( FAILED_UNEXPECTEDLY ( hr ) )
return hr ;
2014-02-24 11:59:34 +00:00
}
2014-04-02 17:37:37 +00:00
return S_OK ;
}
HRESULT CMenuToolbarBase : : KillPopupTimer ( )
{
if ( m_timerEnabled )
{
m_timerEnabled = FALSE ;
KillTimer ( m_hwndToolbar , TIMERID_HOTTRACK ) ;
return S_OK ;
}
return S_FALSE ;
2014-02-24 11:59:34 +00:00
}
2014-04-07 18:41:47 +00:00
HRESULT CMenuToolbarBase : : ChangeHotItem ( CMenuToolbarBase * toolbar , INT item , DWORD dwFlags )
2014-02-24 11:59:34 +00:00
{
2014-04-07 18:41:47 +00:00
// Ignore the change if it already matches the stored info
if ( m_hotBar = = toolbar & & m_hotItem = = item )
return S_FALSE ;
2014-04-02 17:37:37 +00:00
// Prevent a change of hot item if the change was triggered by the mouse,
// and mouse tracking is disabled.
2014-04-07 18:41:47 +00:00
if ( m_disableMouseTrack & & dwFlags & HICF_MOUSE )
2014-03-15 21:38:15 +00:00
{
2014-04-02 17:37:37 +00:00
DbgPrint ( " Hot item change prevented by DisableMouseTrack \n " ) ;
2014-03-15 21:38:15 +00:00
return S_OK ;
}
2014-04-07 18:41:47 +00:00
// Notify the toolbar if the hot-tracking left this toolbar
2014-04-02 17:37:37 +00:00
if ( m_hotBar = = this & & toolbar ! = this )
2014-03-07 22:28:55 +00:00
{
2014-04-07 10:12:41 +00:00
SendMessage ( m_hwndToolbar , TB_SETHOTITEM , ( WPARAM ) - 1 , 0 ) ;
2014-03-07 22:28:55 +00:00
}
2014-04-02 17:37:37 +00:00
2014-02-27 11:56:28 +00:00
m_hotBar = toolbar ;
m_hotItem = item ;
2014-04-02 17:37:37 +00:00
if ( m_hotBar = = this )
2014-03-07 22:28:55 +00:00
{
2014-04-02 17:37:37 +00:00
if ( dwFlags & HICF_MOUSE )
{
// Vertical menus show/hide the submenu after a delay,
// but horizontal menubars switch between items instantly,
// if they were open.
if ( m_initFlags & SMINIT_VERTICAL )
{
DWORD elapsed = 0 ;
SystemParametersInfo ( SPI_GETMENUSHOWDELAY , 0 , & elapsed , 0 ) ;
SetTimer ( m_hwndToolbar , TIMERID_HOTTRACK , elapsed , NULL ) ;
m_timerEnabled = TRUE ;
DbgPrint ( " SetTimer called with m_hotItem=%d \n " , m_hotItem ) ;
}
2014-04-07 18:41:47 +00:00
else if ( m_isTrackingPopup )
2014-04-02 17:37:37 +00:00
{
2014-04-07 18:41:47 +00:00
// If the menubar has an open submenu, switch to the new item's submenu immediately
2014-04-02 17:37:37 +00:00
PopupItem ( m_hotItem ) ;
}
}
else
{
TBBUTTONINFO info ;
info . cbSize = sizeof ( info ) ;
info . dwMask = 0 ;
int index = SendMessage ( m_hwndToolbar , TB_GETBUTTONINFO , item , reinterpret_cast < LPARAM > ( & info ) ) ;
SendMessage ( m_hwndToolbar , TB_SETHOTITEM , index , 0 ) ;
}
2014-03-07 22:28:55 +00:00
}
2014-04-02 17:37:37 +00:00
2014-02-27 11:56:28 +00:00
InvalidateDraw ( ) ;
return S_OK ;
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuToolbarBase : : ChangePopupItem ( CMenuToolbarBase * toolbar , INT item )
2014-02-27 11:56:28 +00:00
{
2014-04-07 18:41:47 +00:00
// Ignore the change if it already matches the stored info
2014-04-02 17:37:37 +00:00
if ( m_popupBar = = toolbar & & m_popupItem = = item )
return S_FALSE ;
2014-04-07 18:41:47 +00:00
// Notify the toolbar if the popup-tracking this toolbar
2014-04-02 17:37:37 +00:00
if ( m_popupBar = = this & & toolbar ! = this )
2014-03-16 09:28:51 +00:00
{
2014-03-19 15:33:41 +00:00
SendMessage ( m_hwndToolbar , TB_CHECKBUTTON , m_popupItem , FALSE ) ;
2014-04-07 18:41:47 +00:00
m_isTrackingPopup = FALSE ;
2014-03-16 09:28:51 +00:00
}
2014-04-02 17:37:37 +00:00
2014-02-27 11:56:28 +00:00
m_popupBar = toolbar ;
m_popupItem = item ;
2014-04-02 17:37:37 +00:00
if ( m_popupBar = = this )
{
SendMessage ( m_hwndToolbar , TB_CHECKBUTTON , m_popupItem , TRUE ) ;
}
2014-02-27 11:56:28 +00:00
InvalidateDraw ( ) ;
return S_OK ;
}
2014-03-19 15:33:41 +00:00
HRESULT CMenuToolbarBase : : IsTrackedItem ( INT index )
{
TBBUTTON btn ;
if ( m_hotBar ! = this )
return S_FALSE ;
2014-04-02 17:37:37 +00:00
if ( ! SendMessage ( m_hwndToolbar , TB_GETBUTTON , index , reinterpret_cast < LPARAM > ( & btn ) ) )
return E_FAIL ;
2014-03-19 15:33:41 +00:00
if ( m_hotItem = = btn . idCommand )
return S_OK ;
2014-04-02 17:37:37 +00:00
if ( m_popupItem = = btn . idCommand )
return S_OK ;
2014-03-19 15:33:41 +00:00
return S_FALSE ;
}
2014-04-03 18:30:25 +00:00
HRESULT CMenuToolbarBase : : ChangeTrackedItem ( INT index , BOOL wasTracking )
2014-03-19 15:33:41 +00:00
{
TBBUTTON btn ;
2014-04-02 17:37:37 +00:00
if ( ! SendMessage ( m_hwndToolbar , TB_GETBUTTON , index , reinterpret_cast < LPARAM > ( & btn ) ) )
return E_FAIL ;
2014-03-19 15:33:41 +00:00
2014-03-26 11:33:52 +00:00
DbgPrint ( " Changing tracked item to %d... \n " , index ) ;
2014-04-07 18:41:47 +00:00
m_isTrackingPopup = wasTracking ;
2014-04-02 17:37:37 +00:00
m_menuBand - > _ChangeHotItem ( this , btn . idCommand , HICF_MOUSE ) ;
2014-03-26 11:33:52 +00:00
2014-03-19 15:33:41 +00:00
return S_OK ;
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuToolbarBase : : PopupSubMenu ( UINT iItem , UINT index , IShellMenu * childShellMenu )
2014-02-24 11:59:34 +00:00
{
2014-04-07 18:41:47 +00:00
// Calculate the submenu position and exclude area
2014-02-24 11:59:34 +00:00
RECT rc = { 0 } ;
2014-03-07 22:28:55 +00:00
RECT rcx = { 0 } ;
2014-02-24 11:59:34 +00:00
if ( ! SendMessage ( m_hwndToolbar , TB_GETITEMRECT , index , reinterpret_cast < LPARAM > ( & rc ) ) )
return E_FAIL ;
2014-03-07 22:28:55 +00:00
GetWindowRect ( m_hwnd , & rcx ) ;
2014-02-24 11:59:34 +00:00
POINT a = { rc . left , rc . top } ;
POINT b = { rc . right , rc . bottom } ;
2014-03-07 22:28:55 +00:00
POINT c = { rcx . left , rcx . top } ;
POINT d = { rcx . right , rcx . bottom } ;
2014-02-24 11:59:34 +00:00
ClientToScreen ( m_hwndToolbar , & a ) ;
ClientToScreen ( m_hwndToolbar , & b ) ;
2014-03-07 22:28:55 +00:00
ClientToScreen ( m_hwnd , & c ) ;
ClientToScreen ( m_hwnd , & d ) ;
2014-02-24 11:59:34 +00:00
2014-03-13 16:21:56 +00:00
POINTL pt = { a . x , b . y } ;
2014-03-07 22:28:55 +00:00
RECTL rcl = { c . x , c . y , d . x , d . y } ;
2014-02-24 11:59:34 +00:00
2014-04-02 17:37:37 +00:00
if ( m_initFlags & SMINIT_VERTICAL )
2014-03-13 16:21:56 +00:00
{
pt . x = b . x - 3 ;
pt . y = a . y - 3 ;
}
2014-04-07 18:41:47 +00:00
// Display the submenu
m_isTrackingPopup = TRUE ;
2014-03-20 15:39:25 +00:00
2014-04-02 17:37:37 +00:00
m_menuBand - > _ChangePopupItem ( this , iItem ) ;
2014-04-07 18:41:47 +00:00
m_menuBand - > _OnPopupSubMenu ( childShellMenu , & pt , & rcl ) ;
2014-02-24 11:59:34 +00:00
return S_OK ;
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuToolbarBase : : PopupSubMenu ( UINT iItem , UINT index , HMENU menu )
2014-02-24 11:59:34 +00:00
{
2014-04-07 18:41:47 +00:00
// Calculate the submenu position and exclude area
2014-02-24 11:59:34 +00:00
RECT rc = { 0 } ;
if ( ! SendMessage ( m_hwndToolbar , TB_GETITEMRECT , index , reinterpret_cast < LPARAM > ( & rc ) ) )
return E_FAIL ;
2014-04-07 18:41:47 +00:00
2014-03-07 22:28:55 +00:00
POINT a = { rc . left , rc . top } ;
2014-02-24 11:59:34 +00:00
POINT b = { rc . right , rc . bottom } ;
2014-03-07 22:28:55 +00:00
ClientToScreen ( m_hwndToolbar , & a ) ;
2014-02-24 11:59:34 +00:00
ClientToScreen ( m_hwndToolbar , & b ) ;
2014-03-07 22:28:55 +00:00
POINT pt = { a . x , b . y } ;
2014-04-07 18:41:47 +00:00
RECT rcl = { a . x , a . y , b . x , b . y } ;
2014-03-07 22:28:55 +00:00
2014-04-02 17:37:37 +00:00
if ( m_initFlags & SMINIT_VERTICAL )
2014-03-07 22:28:55 +00:00
{
pt . x = b . x ;
pt . y = a . y ;
}
2014-02-24 11:59:34 +00:00
HMENU popup = GetSubMenu ( menu , index ) ;
2014-04-07 18:41:47 +00:00
// Display the submenu
m_isTrackingPopup = TRUE ;
2014-04-02 17:37:37 +00:00
m_menuBand - > _ChangePopupItem ( this , iItem ) ;
2014-04-07 18:41:47 +00:00
m_menuBand - > _TrackSubMenu ( popup , pt . x , pt . y , rcl ) ;
2014-04-02 17:37:37 +00:00
m_menuBand - > _ChangePopupItem ( NULL , - 1 ) ;
2014-04-07 18:41:47 +00:00
m_isTrackingPopup = FALSE ;
2014-02-24 11:59:34 +00:00
return S_OK ;
}
HRESULT CMenuToolbarBase : : DoContextMenu ( IContextMenu * contextMenu )
{
2014-04-07 18:41:47 +00:00
// Calculate the context menu position
2014-02-24 11:59:34 +00:00
DWORD dwPos = GetMessagePos ( ) ;
2014-04-07 18:41:47 +00:00
POINT pt = { GET_X_LPARAM ( dwPos ) , GET_Y_LPARAM ( dwPos ) } ;
2014-02-24 11:59:34 +00:00
2014-04-07 18:41:47 +00:00
// Display the submenu
return m_menuBand - > _TrackContextMenu ( contextMenu , pt . x , pt . y ) ;
2014-02-24 11:59:34 +00:00
}
HRESULT CMenuToolbarBase : : OnCommand ( WPARAM wParam , LPARAM lParam , LRESULT * theResult )
{
2014-04-02 17:37:37 +00:00
if ( m_disableMouseTrack )
{
* theResult = 1 ;
DbgPrint ( " Item click prevented by DisableMouseTrack \n " ) ;
return S_OK ;
}
2014-03-20 15:39:25 +00:00
2014-04-07 18:41:47 +00:00
// If a button is clicked while a submenu was open, cancel the submenu.
if ( ! ( m_initFlags & SMINIT_VERTICAL ) & & m_isTrackingPopup )
{
DbgPrint ( " OnCommand cancelled because it was tracking submenu. \n " ) ;
return S_FALSE ;
}
2014-04-02 17:37:37 +00:00
* theResult = 0 ;
m_menuBand - > _KillPopupTimers ( ) ;
2014-03-20 15:39:25 +00:00
if ( PopupItem ( wParam ) = = S_OK )
2014-04-02 17:37:37 +00:00
{
DbgPrint ( " PopupItem returned S_OK \n " ) ;
2014-02-24 11:59:34 +00:00
return S_FALSE ;
2014-04-02 17:37:37 +00:00
}
DbgPrint ( " Executing... \n " ) ;
2014-03-20 15:39:25 +00:00
2014-03-11 17:40:18 +00:00
HRESULT hr = m_menuBand - > _MenuItemHotTrack ( MPOS_EXECUTE ) ;
2014-03-20 15:39:25 +00:00
2014-03-11 17:40:18 +00:00
if ( FAILED_UNEXPECTEDLY ( hr ) )
return hr ;
2014-03-20 15:39:25 +00:00
2014-04-07 18:41:47 +00:00
return OnCommandInternal ( wParam , lParam , theResult ) ;
2014-02-24 11:59:34 +00:00
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuToolbarBase : : KeyboardItemChange ( DWORD dwSelectType )
2014-02-24 11:59:34 +00:00
{
int prev = m_hotItem ;
int index = - 1 ;
if ( dwSelectType ! = 0xFFFFFFFF )
{
int count = SendMessage ( m_hwndToolbar , TB_BUTTONCOUNT , 0 , 0 ) ;
if ( m_hotItem > = 0 )
{
TBBUTTONINFO info = { 0 } ;
info . cbSize = sizeof ( TBBUTTONINFO ) ;
info . dwMask = 0 ;
index = SendMessage ( m_hwndToolbar , TB_GETBUTTONINFO , m_hotItem , reinterpret_cast < LPARAM > ( & info ) ) ;
}
if ( dwSelectType = = VK_HOME )
{
index = 0 ;
dwSelectType = VK_DOWN ;
}
else if ( dwSelectType = = VK_END )
{
index = count - 1 ;
dwSelectType = VK_UP ;
}
else if ( index < 0 )
{
if ( dwSelectType = = VK_UP )
{
index = count - 1 ;
}
else if ( dwSelectType = = VK_DOWN )
{
index = 0 ;
}
}
else
{
if ( dwSelectType = = VK_UP )
{
index - - ;
}
else if ( dwSelectType = = VK_DOWN )
{
index + + ;
}
}
TBBUTTON btn = { 0 } ;
while ( index > = 0 & & index < count )
{
DWORD res = SendMessage ( m_hwndToolbar , TB_GETBUTTON , index , reinterpret_cast < LPARAM > ( & btn ) ) ;
if ( ! res )
return E_FAIL ;
if ( btn . dwData )
{
2014-03-15 21:38:15 +00:00
if ( prev ! = btn . idCommand )
2014-02-24 11:59:34 +00:00
{
2014-04-02 17:37:37 +00:00
DbgPrint ( " Setting Hot item to %d \n " , index ) ;
2014-04-07 18:41:47 +00:00
m_menuBand - > _ChangeHotItem ( this , index , 0 ) ;
2014-02-24 11:59:34 +00:00
}
return S_OK ;
}
if ( dwSelectType = = VK_UP )
{
index - - ;
}
else if ( dwSelectType = = VK_DOWN )
{
index + + ;
}
}
}
2014-03-15 21:38:15 +00:00
if ( prev ! = - 1 )
2014-02-24 11:59:34 +00:00
{
2014-04-02 17:37:37 +00:00
DbgPrint ( " Setting Hot item to null \n " ) ;
2014-04-07 18:41:47 +00:00
m_menuBand - > _ChangeHotItem ( NULL , - 1 , 0 ) ;
2014-02-24 11:59:34 +00:00
}
2014-04-07 18:41:47 +00:00
2014-02-24 11:59:34 +00:00
return S_FALSE ;
}
2014-03-03 11:14:04 +00:00
HRESULT CMenuToolbarBase : : AddButton ( DWORD commandId , LPCWSTR caption , BOOL hasSubMenu , INT iconId , DWORD_PTR buttonData , BOOL last )
2014-03-03 10:19:35 +00:00
{
TBBUTTON tbb = { 0 } ;
2014-03-03 11:14:04 +00:00
tbb . fsState = TBSTATE_ENABLED ;
2014-03-16 01:21:54 +00:00
# if !USE_TBSTYLE_EX_VERTICAL
2014-04-02 17:37:37 +00:00
if ( ! last & & ( m_initFlags & SMINIT_VERTICAL ) )
2014-03-03 11:14:04 +00:00
tbb . fsState | = TBSTATE_WRAP ;
# endif
2014-04-02 17:37:37 +00:00
tbb . fsStyle = BTNS_CHECKGROUP ;
2014-03-03 10:19:35 +00:00
2014-04-02 17:37:37 +00:00
if ( hasSubMenu & & ( m_initFlags & SMINIT_VERTICAL ) )
2014-03-03 10:19:35 +00:00
tbb . fsStyle | = BTNS_DROPDOWN ;
2014-04-02 17:37:37 +00:00
if ( ! ( m_initFlags & SMINIT_VERTICAL ) )
tbb . fsStyle | = BTNS_AUTOSIZE ;
2014-03-07 22:28:55 +00:00
2014-03-03 10:19:35 +00:00
tbb . iString = ( INT_PTR ) caption ;
tbb . idCommand = commandId ;
tbb . iBitmap = iconId ;
tbb . dwData = buttonData ;
2014-03-03 16:11:47 +00:00
if ( ! SendMessageW ( m_hwndToolbar , TB_ADDBUTTONS , 1 , reinterpret_cast < LPARAM > ( & tbb ) ) )
return HRESULT_FROM_WIN32 ( GetLastError ( ) ) ;
2014-03-03 10:19:35 +00:00
return S_OK ;
}
2014-03-03 11:14:04 +00:00
HRESULT CMenuToolbarBase : : AddSeparator ( BOOL last )
2014-03-03 10:19:35 +00:00
{
TBBUTTON tbb = { 0 } ;
2014-03-03 11:14:04 +00:00
tbb . fsState = TBSTATE_ENABLED ;
2014-03-16 01:21:54 +00:00
# if !USE_TBSTYLE_EX_VERTICAL
2014-04-02 17:37:37 +00:00
if ( ! last & & ( m_initFlags & SMINIT_VERTICAL ) )
2014-03-03 11:14:04 +00:00
tbb . fsState | = TBSTATE_WRAP ;
# endif
2014-03-03 10:19:35 +00:00
tbb . fsStyle = BTNS_SEP ;
tbb . iBitmap = 0 ;
2014-03-03 16:11:47 +00:00
if ( ! SendMessageW ( m_hwndToolbar , TB_ADDBUTTONS , 1 , reinterpret_cast < LPARAM > ( & tbb ) ) )
return HRESULT_FROM_WIN32 ( GetLastError ( ) ) ;
2014-03-03 10:19:35 +00:00
return S_OK ;
}
HRESULT CMenuToolbarBase : : AddPlaceholder ( )
{
TBBUTTON tbb = { 0 } ;
PCWSTR MenuString = L " (Empty) " ;
2014-03-03 11:14:04 +00:00
tbb . fsState = 0 ;
2014-03-03 10:19:35 +00:00
tbb . fsStyle = 0 ;
tbb . iString = ( INT_PTR ) MenuString ;
tbb . iBitmap = - 1 ;
2014-03-03 16:11:47 +00:00
if ( ! SendMessageW ( m_hwndToolbar , TB_ADDBUTTONS , 1 , reinterpret_cast < LPARAM > ( & tbb ) ) )
return HRESULT_FROM_WIN32 ( GetLastError ( ) ) ;
2014-03-03 10:19:35 +00:00
return S_OK ;
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuToolbarBase : : GetDataFromId ( INT iItem , INT * pIndex , DWORD_PTR * pData )
2014-03-03 10:19:35 +00:00
{
2014-04-02 17:37:37 +00:00
if ( pData )
* pData = NULL ;
if ( pIndex )
* pIndex = - 1 ;
if ( iItem < 0 )
return S_OK ;
2014-03-03 10:19:35 +00:00
TBBUTTONINFO info = { 0 } ;
2014-03-20 15:39:25 +00:00
2014-03-03 10:19:35 +00:00
info . cbSize = sizeof ( TBBUTTONINFO ) ;
2014-03-20 15:39:25 +00:00
info . dwMask = TBIF_COMMAND | TBIF_LPARAM ;
2014-04-02 17:37:37 +00:00
int index = SendMessage ( m_hwndToolbar , TB_GETBUTTONINFO , iItem , reinterpret_cast < LPARAM > ( & info ) ) ;
2014-03-03 10:19:35 +00:00
if ( index < 0 )
return E_FAIL ;
if ( pIndex )
* pIndex = index ;
if ( pData )
2014-03-20 15:39:25 +00:00
* pData = info . lParam ;
2014-03-03 10:19:35 +00:00
return S_OK ;
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuToolbarBase : : CancelCurrentPopup ( )
{
return m_menuBand - > _CancelCurrentPopup ( ) ;
}
HRESULT CMenuToolbarBase : : PopupItem ( INT iItem )
2014-02-24 11:59:34 +00:00
{
2014-03-03 10:19:35 +00:00
INT index ;
DWORD_PTR dwData ;
2014-02-24 11:59:34 +00:00
2014-04-02 17:37:37 +00:00
if ( iItem < 0 )
return S_OK ;
if ( m_popupBar = = this & & m_popupItem = = iItem )
return S_OK ;
2014-03-20 15:39:25 +00:00
2014-04-02 17:37:37 +00:00
GetDataFromId ( iItem , & index , & dwData ) ;
2014-03-19 15:33:41 +00:00
2014-04-02 17:37:37 +00:00
HRESULT hr = InternalHasSubMenu ( iItem , index , dwData ) ;
2014-03-20 15:39:25 +00:00
if ( hr ! = S_OK )
return hr ;
2014-02-24 11:59:34 +00:00
2014-04-02 17:37:37 +00:00
if ( m_popupBar )
{
HRESULT hr = CancelCurrentPopup ( ) ;
if ( FAILED_UNEXPECTEDLY ( hr ) )
return hr ;
}
if ( ! ( m_initFlags & SMINIT_VERTICAL ) )
{
DbgPrint ( " PopupItem non-vertical %d %d \n " , index , iItem ) ;
m_menuBand - > _ChangeHotItem ( this , iItem , 0 ) ;
}
return InternalPopupItem ( iItem , index , dwData ) ;
2014-03-03 10:19:35 +00:00
}
2014-02-24 11:59:34 +00:00
CMenuStaticToolbar : : CMenuStaticToolbar ( CMenuBand * menuBand ) :
CMenuToolbarBase ( menuBand , FALSE ) ,
m_hmenu ( NULL )
{
}
HRESULT CMenuStaticToolbar : : GetMenu (
2014-03-13 16:21:56 +00:00
_Out_opt_ HMENU * phmenu ,
_Out_opt_ HWND * phwnd ,
_Out_opt_ DWORD * pdwFlags )
2014-02-24 11:59:34 +00:00
{
2014-03-13 16:21:56 +00:00
if ( phmenu )
* phmenu = m_hmenu ;
if ( phwnd )
* phwnd = NULL ;
if ( pdwFlags )
* pdwFlags = m_dwMenuFlags ;
2014-02-24 11:59:34 +00:00
return S_OK ;
}
HRESULT CMenuStaticToolbar : : SetMenu (
HMENU hmenu ,
HWND hwnd ,
DWORD dwFlags )
{
m_hmenu = hmenu ;
m_dwMenuFlags = dwFlags ;
return S_OK ;
}
2014-03-11 10:42:25 +00:00
HRESULT CMenuStaticToolbar : : FillToolbar ( BOOL clearFirst )
2014-02-24 11:59:34 +00:00
{
int i ;
int ic = GetMenuItemCount ( m_hmenu ) ;
2014-03-11 10:42:25 +00:00
if ( clearFirst )
{
while ( SendMessage ( m_hwndToolbar , TB_DELETEBUTTON , 0 , 0 ) )
{
// empty;
}
}
2014-03-03 17:55:43 +00:00
int count = 0 ;
2014-02-24 11:59:34 +00:00
for ( i = 0 ; i < ic ; i + + )
{
2014-03-03 11:14:04 +00:00
BOOL last = i + 1 = = ic ;
2014-02-24 11:59:34 +00:00
MENUITEMINFOW info ;
info . cbSize = sizeof ( info ) ;
2014-03-03 10:19:35 +00:00
info . dwTypeData = NULL ;
2014-03-03 16:11:47 +00:00
info . fMask = MIIM_FTYPE | MIIM_STRING | MIIM_ID ;
2014-02-24 11:59:34 +00:00
2014-03-03 16:11:47 +00:00
if ( ! GetMenuItemInfoW ( m_hmenu , i , TRUE , & info ) )
{
DbgPrint ( " Error obtaining info for menu item at pos=%d \n " , i ) ;
continue ;
}
2014-03-03 17:55:43 +00:00
count + + ;
2014-03-03 16:11:47 +00:00
if ( info . fType & MFT_SEPARATOR )
{
AddSeparator ( last ) ;
}
2014-03-05 09:12:40 +00:00
else if ( ! ( info . fType & MFT_BITMAP ) )
2014-02-24 11:59:34 +00:00
{
2014-03-03 16:11:47 +00:00
2014-03-03 10:19:35 +00:00
info . cch + + ;
info . dwTypeData = ( PWSTR ) HeapAlloc ( GetProcessHeap ( ) , 0 , ( info . cch + 1 ) * sizeof ( WCHAR ) ) ;
2014-03-03 11:14:04 +00:00
info . fMask = MIIM_STRING | MIIM_SUBMENU | MIIM_ID ;
2014-03-03 10:19:35 +00:00
GetMenuItemInfoW ( m_hmenu , i , TRUE , & info ) ;
2014-02-24 11:59:34 +00:00
SMINFO * sminfo = new SMINFO ( ) ;
sminfo - > dwMask = SMIM_ICON | SMIM_FLAGS ;
2014-03-03 10:19:35 +00:00
// FIXME: remove before deleting the toolbar or it will leak
HRESULT hr = m_menuBand - > _CallCBWithItemId ( info . wID , SMC_GETINFO , 0 , reinterpret_cast < LPARAM > ( sminfo ) ) ;
2014-03-03 16:11:47 +00:00
if ( FAILED_UNEXPECTEDLY ( hr ) )
2014-03-03 10:19:35 +00:00
return hr ;
2014-03-03 11:14:04 +00:00
AddButton ( info . wID , info . dwTypeData , info . hSubMenu ! = NULL , sminfo - > iIcon , reinterpret_cast < DWORD_PTR > ( sminfo ) , last ) ;
2014-03-03 10:19:35 +00:00
HeapFree ( GetProcessHeap ( ) , 0 , info . dwTypeData ) ;
2014-02-24 11:59:34 +00:00
}
}
2014-03-11 10:42:25 +00:00
return S_OK ;
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuStaticToolbar : : GetInfoTip ( LPWSTR pszText , INT cchTextMax , INT iItem , INT index , DWORD_PTR dwData )
{
//SMINFO * info = reinterpret_cast<SMINFO*>(dwData);
UNIMPLEMENTED ;
return E_NOTIMPL ;
}
2014-03-11 10:42:25 +00:00
HRESULT CMenuStaticToolbar : : OnDeletingButton ( const NMTOOLBAR * tb )
{
delete reinterpret_cast < SMINFO * > ( tb - > tbButton . dwData ) ;
2014-02-24 11:59:34 +00:00
return S_OK ;
}
HRESULT CMenuStaticToolbar : : OnContextMenu ( NMMOUSE * rclick )
{
CComPtr < IContextMenu > contextMenu ;
HRESULT hr = m_menuBand - > _CallCBWithItemId ( rclick - > dwItemSpec , SMC_GETOBJECT , reinterpret_cast < WPARAM > ( & IID_IContextMenu ) , reinterpret_cast < LPARAM > ( & contextMenu ) ) ;
if ( hr ! = S_OK )
return hr ;
return DoContextMenu ( contextMenu ) ;
}
2014-04-07 18:41:47 +00:00
HRESULT CMenuStaticToolbar : : OnCommandInternal ( WPARAM wParam , LPARAM lParam , LRESULT * theResult )
2014-02-24 11:59:34 +00:00
{
return m_menuBand - > _CallCBWithItemId ( wParam , SMC_EXEC , 0 , 0 ) ;
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuStaticToolbar : : InternalPopupItem ( INT iItem , INT index , DWORD_PTR dwData )
2014-02-24 11:59:34 +00:00
{
2014-03-03 10:19:35 +00:00
SMINFO * nfo = reinterpret_cast < SMINFO * > ( dwData ) ;
2014-02-24 11:59:34 +00:00
if ( ! nfo )
return E_FAIL ;
if ( nfo - > dwFlags & SMIF_TRACKPOPUP )
{
2014-04-02 17:37:37 +00:00
return PopupSubMenu ( iItem , index , m_hmenu ) ;
2014-02-24 11:59:34 +00:00
}
else
{
CComPtr < IShellMenu > shellMenu ;
2014-04-02 17:37:37 +00:00
HRESULT hr = m_menuBand - > _CallCBWithItemId ( iItem , SMC_GETOBJECT , reinterpret_cast < WPARAM > ( & IID_IShellMenu ) , reinterpret_cast < LPARAM > ( & shellMenu ) ) ;
2014-03-03 16:11:47 +00:00
if ( FAILED_UNEXPECTEDLY ( hr ) )
2014-02-24 11:59:34 +00:00
return hr ;
2014-04-02 17:37:37 +00:00
return PopupSubMenu ( iItem , index , shellMenu ) ;
2014-02-24 11:59:34 +00:00
}
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuStaticToolbar : : InternalHasSubMenu ( INT iItem , INT index , DWORD_PTR dwData )
2014-02-24 11:59:34 +00:00
{
return : : GetSubMenu ( m_hmenu , index ) ? S_OK : S_FALSE ;
}
2014-03-26 11:33:52 +00:00
2014-02-24 11:59:34 +00:00
CMenuSFToolbar : : CMenuSFToolbar ( CMenuBand * menuBand ) :
CMenuToolbarBase ( menuBand , TRUE ) ,
2014-03-13 16:21:56 +00:00
m_shellFolder ( NULL ) ,
m_idList ( NULL ) ,
m_hKey ( NULL )
2014-02-24 11:59:34 +00:00
{
}
CMenuSFToolbar : : ~ CMenuSFToolbar ( )
{
}
2014-03-11 10:42:25 +00:00
HRESULT CMenuSFToolbar : : FillToolbar ( BOOL clearFirst )
2014-02-24 11:59:34 +00:00
{
HRESULT hr ;
int i = 0 ;
PWSTR MenuString ;
IEnumIDList * eidl ;
m_shellFolder - > EnumObjects ( m_hwndToolbar , SHCONTF_FOLDERS | SHCONTF_NONFOLDERS , & eidl ) ;
LPITEMIDLIST item = static_cast < LPITEMIDLIST > ( CoTaskMemAlloc ( sizeof ( ITEMIDLIST ) ) ) ;
ULONG fetched ;
2014-03-03 11:14:04 +00:00
hr = eidl - > Next ( 1 , & item , & fetched ) ;
while ( SUCCEEDED ( hr ) & & fetched > 0 )
2014-02-24 11:59:34 +00:00
{
INT index = 0 ;
INT indexOpen = 0 ;
2014-02-26 11:13:23 +00:00
STRRET sr = { STRRET_CSTR , { 0 } } ;
2014-02-24 11:59:34 +00:00
2014-02-26 11:13:23 +00:00
hr = m_shellFolder - > GetDisplayNameOf ( item , SIGDN_NORMALDISPLAY , & sr ) ;
2014-03-03 16:11:47 +00:00
if ( FAILED_UNEXPECTEDLY ( hr ) )
2014-02-24 11:59:34 +00:00
return hr ;
2014-02-26 11:13:23 +00:00
StrRetToStr ( & sr , NULL , & MenuString ) ;
2014-02-24 11:59:34 +00:00
index = SHMapPIDLToSystemImageListIndex ( m_shellFolder , item , & indexOpen ) ;
2014-02-26 11:13:23 +00:00
LPCITEMIDLIST itemc = item ;
2014-02-24 11:59:34 +00:00
2014-02-26 11:13:23 +00:00
SFGAOF attrs = SFGAO_FOLDER ;
hr = m_shellFolder - > GetAttributesOf ( 1 , & itemc , & attrs ) ;
2014-03-03 10:19:35 +00:00
DWORD_PTR dwData = reinterpret_cast < DWORD_PTR > ( ILClone ( item ) ) ;
2014-02-24 11:59:34 +00:00
2014-03-03 11:14:04 +00:00
// Fetch next item already, so we know if the current one is the last
hr = eidl - > Next ( 1 , & item , & fetched ) ;
2014-03-03 17:55:43 +00:00
AddButton ( + + i , MenuString , attrs & SFGAO_FOLDER , index , dwData , FAILED ( hr ) | | fetched = = 0 ) ;
2014-02-24 11:59:34 +00:00
2014-03-03 10:19:35 +00:00
CoTaskMemFree ( MenuString ) ;
2014-02-24 11:59:34 +00:00
}
CoTaskMemFree ( item ) ;
// If no items were added, show the "empty" placeholder
if ( i = = 0 )
{
2014-03-03 10:19:35 +00:00
return AddPlaceholder ( ) ;
2014-02-24 11:59:34 +00:00
}
return hr ;
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuSFToolbar : : GetInfoTip ( LPWSTR pszText , INT cchTextMax , INT iItem , INT index , DWORD_PTR dwData )
{
//ITEMIDLIST * pidl = reinterpret_cast<LPITEMIDLIST>(dwData);
UNIMPLEMENTED ;
return E_NOTIMPL ;
}
2014-03-11 10:42:25 +00:00
HRESULT CMenuSFToolbar : : OnDeletingButton ( const NMTOOLBAR * tb )
{
ILFree ( reinterpret_cast < LPITEMIDLIST > ( tb - > tbButton . dwData ) ) ;
return S_OK ;
}
2014-02-24 11:59:34 +00:00
HRESULT CMenuSFToolbar : : SetShellFolder ( IShellFolder * psf , LPCITEMIDLIST pidlFolder , HKEY hKey , DWORD dwFlags )
{
m_shellFolder = psf ;
2014-03-13 16:21:56 +00:00
m_idList = ILClone ( pidlFolder ) ;
2014-02-24 11:59:34 +00:00
m_hKey = hKey ;
m_dwMenuFlags = dwFlags ;
return S_OK ;
}
HRESULT CMenuSFToolbar : : GetShellFolder ( DWORD * pdwFlags , LPITEMIDLIST * ppidl , REFIID riid , void * * ppv )
{
HRESULT hr ;
hr = m_shellFolder - > QueryInterface ( riid , ppv ) ;
2014-03-03 16:11:47 +00:00
if ( FAILED_UNEXPECTEDLY ( hr ) )
2014-02-24 11:59:34 +00:00
return hr ;
if ( pdwFlags )
* pdwFlags = m_dwMenuFlags ;
if ( ppidl )
{
LPITEMIDLIST pidl = NULL ;
if ( m_idList )
{
pidl = ILClone ( m_idList ) ;
if ( ! pidl )
{
( * ( IUnknown * * ) ppv ) - > Release ( ) ;
return E_FAIL ;
}
}
* ppidl = pidl ;
}
return hr ;
}
HRESULT CMenuSFToolbar : : OnContextMenu ( NMMOUSE * rclick )
{
HRESULT hr ;
CComPtr < IContextMenu > contextMenu ;
LPCITEMIDLIST pidl = reinterpret_cast < LPCITEMIDLIST > ( rclick - > dwItemData ) ;
hr = m_shellFolder - > GetUIObjectOf ( m_hwndToolbar , 1 , & pidl , IID_IContextMenu , NULL , reinterpret_cast < VOID * * > ( & contextMenu ) ) ;
if ( hr ! = S_OK )
return hr ;
return DoContextMenu ( contextMenu ) ;
}
2014-04-07 18:41:47 +00:00
HRESULT CMenuSFToolbar : : OnCommandInternal ( WPARAM wParam , LPARAM lParam , LRESULT * theResult )
2014-02-24 11:59:34 +00:00
{
2014-03-03 10:19:35 +00:00
DWORD_PTR data ;
2014-04-07 18:41:47 +00:00
2014-03-03 10:19:35 +00:00
GetDataFromId ( wParam , NULL , & data ) ;
return m_menuBand - > _CallCBWithItemPidl ( reinterpret_cast < LPITEMIDLIST > ( data ) , SMC_SFEXEC , 0 , 0 ) ;
2014-02-24 11:59:34 +00:00
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuSFToolbar : : InternalPopupItem ( INT iItem , INT index , DWORD_PTR dwData )
2014-02-24 11:59:34 +00:00
{
HRESULT hr ;
UINT uId ;
UINT uIdAncestor ;
DWORD flags ;
CComPtr < IShellMenuCallback > psmc ;
CComPtr < IShellMenu > shellMenu ;
2014-03-03 10:19:35 +00:00
LPITEMIDLIST pidl = reinterpret_cast < LPITEMIDLIST > ( dwData ) ;
2014-02-24 11:59:34 +00:00
if ( ! pidl )
return E_FAIL ;
# if USE_SYSTEM_MENUBAND
hr = CoCreateInstance ( CLSID_MenuBand ,
NULL ,
CLSCTX_INPROC_SERVER ,
IID_PPV_ARG ( IShellMenu , & shellMenu ) ) ;
# else
hr = CMenuBand_Constructor ( IID_PPV_ARG ( IShellMenu , & shellMenu ) ) ;
# endif
2014-03-03 16:11:47 +00:00
if ( FAILED_UNEXPECTEDLY ( hr ) )
2014-02-24 11:59:34 +00:00
return hr ;
# if WRAP_MENUBAND
hr = CMenuBand_Wrapper ( shellMenu , IID_PPV_ARG ( IShellMenu , & shellMenu ) ) ;
2014-03-03 16:11:47 +00:00
if ( FAILED_UNEXPECTEDLY ( hr ) )
2014-02-24 11:59:34 +00:00
return hr ;
# endif
m_menuBand - > GetMenuInfo ( & psmc , & uId , & uIdAncestor , & flags ) ;
// FIXME: not sure what to use as uId/uIdAncestor here
hr = shellMenu - > Initialize ( psmc , 0 , uId , SMINIT_VERTICAL ) ;
2014-03-03 16:11:47 +00:00
if ( FAILED_UNEXPECTEDLY ( hr ) )
2014-02-24 11:59:34 +00:00
return hr ;
CComPtr < IShellFolder > childFolder ;
hr = m_shellFolder - > BindToObject ( pidl , NULL , IID_PPV_ARG ( IShellFolder , & childFolder ) ) ;
2014-03-03 16:11:47 +00:00
if ( FAILED_UNEXPECTEDLY ( hr ) )
2014-02-24 11:59:34 +00:00
return hr ;
hr = shellMenu - > SetShellFolder ( childFolder , NULL , NULL , 0 ) ;
2014-03-03 16:11:47 +00:00
if ( FAILED_UNEXPECTEDLY ( hr ) )
2014-02-24 11:59:34 +00:00
return hr ;
2014-04-02 17:37:37 +00:00
return PopupSubMenu ( iItem , index , shellMenu ) ;
2014-02-24 11:59:34 +00:00
}
2014-04-02 17:37:37 +00:00
HRESULT CMenuSFToolbar : : InternalHasSubMenu ( INT iItem , INT index , DWORD_PTR dwData )
2014-02-24 11:59:34 +00:00
{
HRESULT hr ;
2014-03-03 10:19:35 +00:00
LPCITEMIDLIST pidl = reinterpret_cast < LPITEMIDLIST > ( dwData ) ;
2014-02-24 11:59:34 +00:00
2014-02-26 11:13:23 +00:00
SFGAOF attrs = SFGAO_FOLDER ;
hr = m_shellFolder - > GetAttributesOf ( 1 , & pidl , & attrs ) ;
2014-03-03 16:11:47 +00:00
if ( FAILED_UNEXPECTEDLY ( hr ) )
2014-02-24 11:59:34 +00:00
return hr ;
2014-02-26 11:13:23 +00:00
return ( attrs & SFGAO_FOLDER ) ? S_OK : S_FALSE ;
2014-02-24 11:59:34 +00:00
}