Author: dquintana Date: Mon Apr 7 18:41:47 2014 New Revision: 62681 URL: http://svn.reactos.org/svn/reactos?rev=62681&view=rev Log: [RSHELL] * Some code improvements, refactoring, and commenting. * Using alternative method of handling hot-tracking, which does not break in win2003. CORE-7586
Modified: branches/shell-experiments/base/shell/rshell/CMenuBand.cpp branches/shell-experiments/base/shell/rshell/CMenuBand.h branches/shell-experiments/base/shell/rshell/CMenuFocusManager.cpp branches/shell-experiments/base/shell/rshell/CMenuToolbars.cpp branches/shell-experiments/base/shell/rshell/CMenuToolbars.h Modified: branches/shell-experiments/base/shell/rshell/CMenuBand.cpp URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rshell/CMenuBand.cpp?rev=62681&r1=62680&r2=62681&view=diff ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuBand.cpp [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuBand.cpp [iso-8859-1] Mon Apr 7 18:41:47 2014 @@ -260,26 +260,26 @@ HRESULT STDMETHODCALLTYPE CMenuBand::OnPosRectChangeDB(RECT *prc) { - SIZE sizeStatic = { 0 }; - SIZE sizeShlFld = { 0 }; + SIZE maxStatic = { 0 }; + SIZE maxShlFld = { 0 }; HRESULT hr = S_OK; if (m_staticToolbar != NULL) - hr = m_staticToolbar->GetIdealSize(sizeStatic); + hr = m_staticToolbar->GetSizes(NULL, &maxStatic, NULL); if (FAILED_UNEXPECTEDLY(hr)) return hr; if (m_SFToolbar != NULL) - hr = m_SFToolbar->GetIdealSize(sizeShlFld); + hr = m_SFToolbar->GetSizes(NULL, &maxShlFld, NULL); if (FAILED_UNEXPECTEDLY(hr)) return hr; if (m_staticToolbar == NULL && m_SFToolbar == NULL) return E_FAIL; - int sy = min(prc->bottom - prc->top, sizeStatic.cy + sizeShlFld.cy); - - int syStatic = sizeStatic.cy; + int sy = min(prc->bottom - prc->top, maxStatic.cy + maxShlFld.cy); + + int syStatic = maxStatic.cy; int syShlFld = sy - syStatic; if (m_SFToolbar) @@ -306,28 +306,46 @@ DWORD dwViewMode, DESKBANDINFO *pdbi) { - SIZE sizeStatic = { 0 }; - SIZE sizeShlFld = { 0 }; + SIZE minStatic = { 0 }; + SIZE minShlFld = { 0 }; + SIZE maxStatic = { 0 }; + SIZE maxShlFld = { 0 }; + SIZE intStatic = { 0 }; + SIZE intShlFld = { 0 }; HRESULT hr = S_OK; if (m_staticToolbar != NULL) - hr = m_staticToolbar->GetIdealSize(sizeStatic); + hr = m_staticToolbar->GetSizes(&minStatic, &maxStatic, &intStatic); if (FAILED_UNEXPECTEDLY(hr)) return hr; if (m_SFToolbar != NULL) - hr = m_SFToolbar->GetIdealSize(sizeShlFld); + hr = m_SFToolbar->GetSizes(&minShlFld, &maxShlFld, &intShlFld); if (FAILED_UNEXPECTEDLY(hr)) return hr; if (m_staticToolbar == NULL && m_SFToolbar == NULL) return E_FAIL; - pdbi->ptMinSize.x = max(sizeStatic.cx, sizeShlFld.cx) + 20; - pdbi->ptMinSize.y = sizeStatic.cy + sizeShlFld.cy; - pdbi->ptMaxSize.x = max(sizeStatic.cx, sizeShlFld.cx) + 20; - pdbi->ptMaxSize.y = sizeStatic.cy + sizeShlFld.cy; + if (m_dwFlags & SMINIT_VERTICAL) + { + pdbi->ptMinSize.x = max(minStatic.cx, minStatic.cx) + 20; + pdbi->ptMinSize.y = minStatic.cy + minStatic.cy; + pdbi->ptMaxSize.x = max(maxStatic.cx, maxShlFld.cx) + 20; + pdbi->ptMaxSize.y = maxStatic.cy + maxShlFld.cy; + pdbi->dwModeFlags = DBIMF_VARIABLEHEIGHT; + } + else + { + pdbi->ptMinSize.x = minStatic.cx + minStatic.cx; + pdbi->ptMinSize.y = max(minStatic.cy, minStatic.cy); + pdbi->ptMaxSize.x = maxStatic.cx + maxShlFld.cx; + pdbi->ptMaxSize.y = max(maxStatic.cy, maxShlFld.cy); + } + pdbi->ptIntegral.x = max(intStatic.cx, intStatic.cx); + pdbi->ptIntegral.y = max(intStatic.cy, intShlFld.cy); + pdbi->ptActual = pdbi->ptMinSize; return S_OK; } @@ -652,12 +670,10 @@ smData.uId = id; smData.uIdParent = m_uId; smData.uIdAncestor = m_uIdAncestor; + smData.pidlItem = pidl; smData.hwnd = hwnd; - smData.pidlItem = pidl; - if (m_staticToolbar) - { + if (m_hmenu) smData.hmenu = m_hmenu; - } smData.pvUserData = NULL; if (m_SFToolbar) m_SFToolbar->GetShellFolder(NULL, &smData.pidlFolder, IID_PPV_ARG(IShellFolder, &smData.psf)); @@ -668,7 +684,7 @@ return hr; } -HRESULT CMenuBand::_TrackSubMenuUsingTrackPopupMenu(HMENU popup, INT x, INT y, RECT& rcExclude) +HRESULT CMenuBand::_TrackSubMenu(HMENU popup, INT x, INT y, RECT& rcExclude) { TPMPARAMS params = { sizeof(TPMPARAMS), rcExclude }; @@ -688,6 +704,41 @@ _DisableMouseTrack(FALSE); return S_OK; +} + +HRESULT CMenuBand::_TrackContextMenu(IContextMenu * contextMenu, INT x, INT y) +{ + HRESULT hr; + UINT uCommand; + HMENU popup = CreatePopupMenu(); + + if (popup == NULL) + return E_FAIL; + + hr = contextMenu->QueryContextMenu(popup, 0, 0, UINT_MAX, CMF_NORMAL); + if (FAILED_UNEXPECTEDLY(hr)) + { + DestroyMenu(popup); + return hr; + } + + HWND hwnd = m_menuOwner ? m_menuOwner : m_topLevelWindow; + + m_focusManager->PushTrackedPopup(popup); + uCommand = ::TrackPopupMenuEx(popup, TPM_RETURNCMD, x, y, m_menuOwner, NULL); + m_focusManager->PopTrackedPopup(popup); + + if (uCommand == 0) + return S_FALSE; + + CMINVOKECOMMANDINFO cmi = { 0 }; + cmi.cbSize = sizeof(cmi); + cmi.lpVerb = MAKEINTRESOURCEA(uCommand); + cmi.hwnd = hwnd; + hr = contextMenu->InvokeCommand(&cmi); + + DestroyMenu(popup); + return hr; } HRESULT CMenuBand::_GetTopLevelWindow(HWND*topLevel) @@ -728,119 +779,91 @@ return S_OK; } +HRESULT CMenuBand::_KeyboardItemChange(DWORD change) +{ + HRESULT hr; + CMenuToolbarBase *tb = m_hotBar; + + if (!tb) + { + // If no hot item was selected + // choose the first toolbar (prefer shell-folder, which will be positionedat the top) + + if (m_SFToolbar) + tb = m_SFToolbar; + else + tb = m_staticToolbar; + } + + // Ask the first toolbar to change + hr = tb->KeyboardItemChange(change); + + if (hr != S_FALSE) + return hr; + + // Select the second toolbar based on the first + if (tb == m_SFToolbar) + tb = m_staticToolbar; + else + tb = m_SFToolbar; + + if (!tb) + return hr; + + // Ask the second toolbar to change + return tb->KeyboardItemChange(change == VK_DOWN ? VK_END : VK_HOME); +} + HRESULT CMenuBand::_MenuItemHotTrack(DWORD changeType) { HRESULT hr; - if (!(m_dwFlags & SMINIT_VERTICAL)) - { - if (changeType == MPOS_SELECTRIGHT) + + if (m_dwFlags & SMINIT_VERTICAL) + { + switch (changeType) { - SendMessageW(m_menuOwner, WM_CANCELMODE, 0, 0); - if (m_SFToolbar && (m_hotBar == m_SFToolbar || m_hotBar == NULL)) - { - DbgPrint("SF Toolbars in Horizontal menus is not implemented.\n"); - return S_FALSE; - } - else if (m_staticToolbar && m_hotBar == m_staticToolbar) - { - hr = m_staticToolbar->KeyboardItemChange(VK_DOWN); - if (hr == S_FALSE) - { - if (m_SFToolbar) - return m_SFToolbar->KeyboardItemChange(VK_HOME); - else - return m_staticToolbar->KeyboardItemChange(VK_HOME); - } + case VK_UP: + case VK_DOWN: + return _KeyboardItemChange(changeType); + + // TODO: Left/Right across multi-column menus, if they ever work. + case VK_LEFT: + changeType = MPOS_SELECTLEFT; + break; + case VK_RIGHT: + changeType = MPOS_SELECTRIGHT; + break; + } + } + else + { + // In horizontal menubars, left/right are equivalent to vertical's up/down + switch(changeType) + { + case VK_LEFT: + hr = _KeyboardItemChange(VK_UP); + if (hr != S_FALSE) return hr; - } + case VK_RIGHT: + hr = _KeyboardItemChange(VK_DOWN); + if (hr != S_FALSE) + return hr; } - else if (changeType == MPOS_SELECTLEFT) + } + + switch (changeType) + { + case MPOS_SELECTLEFT: + if (!m_subMenuParent) { - SendMessageW(m_menuOwner, WM_CANCELMODE, 0, 0); - if (m_staticToolbar && (m_hotBar == m_staticToolbar || m_hotBar == NULL)) - { - hr = m_staticToolbar->KeyboardItemChange(VK_UP); - if (hr == S_FALSE) - { - if (m_SFToolbar) - return m_SFToolbar->KeyboardItemChange(VK_END); - else - return m_staticToolbar->KeyboardItemChange(VK_END); - } - return hr; - } - else if (m_SFToolbar && m_hotBar == m_SFToolbar) - { - DbgPrint("SF Toolbars in Horizontal menus is not implemented.\n"); - return S_FALSE; - } + if (m_subMenuChild) + return m_subMenuChild->OnSelect(MPOS_CANCELLEVEL); + return S_OK; } - } - else if (changeType == VK_DOWN) - { - if (m_SFToolbar && (m_hotBar == m_SFToolbar || m_hotBar == NULL)) - { - hr = m_SFToolbar->KeyboardItemChange(VK_DOWN); - if (hr == S_FALSE) - { - if (m_staticToolbar) - return m_staticToolbar->KeyboardItemChange(VK_HOME); - else - return m_SFToolbar->KeyboardItemChange(VK_HOME); - } - return hr; - } - else if (m_staticToolbar && m_hotBar == m_staticToolbar) - { - hr = m_staticToolbar->KeyboardItemChange(VK_DOWN); - if (hr == S_FALSE) - { - if (m_SFToolbar) - return m_SFToolbar->KeyboardItemChange(VK_HOME); - else - return m_staticToolbar->KeyboardItemChange(VK_HOME); - } - return hr; - } - } - else if (changeType == VK_UP) - { - if (m_staticToolbar && (m_hotBar == m_staticToolbar || m_hotBar == NULL)) - { - hr = m_staticToolbar->KeyboardItemChange(VK_UP); - if (hr == S_FALSE) - { - if (m_SFToolbar) - return m_SFToolbar->KeyboardItemChange(VK_END); - else - return m_staticToolbar->KeyboardItemChange(VK_END); - } - return hr; - } - else if (m_SFToolbar && m_hotBar == m_SFToolbar) - { - hr = m_SFToolbar->KeyboardItemChange(VK_UP); - if (hr == S_FALSE) - { - if (m_staticToolbar) - return m_staticToolbar->KeyboardItemChange(VK_END); - else - return m_SFToolbar->KeyboardItemChange(VK_END); - } - return hr; - } - } - else if (changeType == MPOS_SELECTLEFT) - { - if (m_subMenuChild) - m_subMenuChild->OnSelect(MPOS_CANCELLEVEL); - if (!m_subMenuParent) - return S_OK; return m_subMenuParent->OnSelect(MPOS_CANCELLEVEL); - } - else if (changeType == MPOS_SELECTRIGHT) - { + + case MPOS_SELECTRIGHT: if (m_hotBar && m_hotItem >= 0) { if (m_hotBar->PopupItem(m_hotItem) == S_OK) @@ -848,14 +871,14 @@ } if (!m_subMenuParent) return S_OK; - return m_subMenuParent->OnSelect(changeType); - } - else - { + return m_subMenuParent->OnSelect(MPOS_SELECTRIGHT); + + default: if (!m_subMenuParent) return S_OK; return m_subMenuParent->OnSelect(changeType); } + return S_OK; } @@ -868,8 +891,60 @@ return hr; } -HRESULT CMenuBand::_OnPopupSubMenu(IMenuPopup * popup, POINTL * pAt, RECTL * pExclude) -{ +HRESULT CMenuBand::_OnPopupSubMenu(IShellMenu * childShellMenu, POINTL * pAt, RECTL * pExclude) +{ + HRESULT hr = 0; + IBandSite* pBandSite; + IDeskBar* pDeskBar; + + // Create the necessary objects + +#if USE_SYSTEM_MENUSITE + hr = CoCreateInstance(CLSID_MenuBandSite, + NULL, + CLSCTX_INPROC_SERVER, + IID_PPV_ARG(IBandSite, &pBandSite)); +#else + hr = CMenuSite_Constructor(IID_PPV_ARG(IBandSite, &pBandSite)); +#endif + if (FAILED_UNEXPECTEDLY(hr)) + return hr; +#if WRAP_MENUSITE + hr = CMenuSite_Wrapper(pBandSite, IID_PPV_ARG(IBandSite, &pBandSite)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; +#endif + +#if USE_SYSTEM_MENUDESKBAR + hr = CoCreateInstance(CLSID_MenuDeskBar, + NULL, + CLSCTX_INPROC_SERVER, + IID_PPV_ARG(IDeskBar, &pDeskBar)); +#else + hr = CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar, &pDeskBar)); +#endif + if (FAILED_UNEXPECTEDLY(hr)) + return hr; +#if WRAP_MENUDESKBAR + hr = CMenuDeskBar_Wrapper(pDeskBar, IID_PPV_ARG(IDeskBar, &pDeskBar)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; +#endif + + hr = pDeskBar->SetClient(pBandSite); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + hr = pBandSite->AddBand(childShellMenu); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + // + CComPtr<IMenuPopup> popup; + hr = pDeskBar->QueryInterface(IID_PPV_ARG(IMenuPopup, &popup)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + m_subMenuChild = popup; if (m_subMenuParent) Modified: branches/shell-experiments/base/shell/rshell/CMenuBand.h URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rshell/CMenuBand.h?rev=62681&r1=62680&r2=62681&view=diff ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuBand.h [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuBand.h [iso-8859-1] Mon Apr 7 18:41:47 2014 @@ -175,13 +175,14 @@ HRESULT _CallCBWithItemId(UINT Id, UINT uMsg, WPARAM wParam, LPARAM lParam); HRESULT _CallCBWithItemPidl(LPITEMIDLIST pidl, UINT uMsg, WPARAM wParam, LPARAM lParam); - HRESULT _TrackSubMenuUsingTrackPopupMenu(HMENU popup, INT x, INT y, RECT& rcExclude); + HRESULT _TrackSubMenu(HMENU popup, INT x, INT y, RECT& rcExclude); + HRESULT _TrackContextMenu(IContextMenu * popup, INT x, INT y); HRESULT _GetTopLevelWindow(HWND*topLevel); HRESULT _ChangeHotItem(CMenuToolbarBase * tb, INT id, DWORD dwFlags); HRESULT _ChangePopupItem(CMenuToolbarBase * tb, INT id); HRESULT _MenuItemHotTrack(DWORD changeType); HRESULT _CancelCurrentPopup(); - HRESULT _OnPopupSubMenu(IMenuPopup * popup, POINTL * pAt, RECTL * pExclude); + HRESULT _OnPopupSubMenu(IShellMenu * childShellMenu, POINTL * pAt, RECTL * pExclude); HRESULT _DisableMouseTrack(BOOL bDisable); HRESULT _SetChildBand(CMenuBand * child); HRESULT _SetParentBand(CMenuBand * parent); @@ -195,5 +196,6 @@ } private: + HRESULT _KeyboardItemChange(DWORD change); HRESULT _CallCB(UINT uMsg, WPARAM wParam, LPARAM lParam, UINT id = 0, LPITEMIDLIST pidl = NULL); }; Modified: branches/shell-experiments/base/shell/rshell/CMenuFocusManager.cpp URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rshell/CMenuFocusManager.cpp?rev=62681&r1=62680&r2=62681&view=diff ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuFocusManager.cpp [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuFocusManager.cpp [iso-8859-1] Mon Apr 7 18:41:47 2014 @@ -261,7 +261,7 @@ // Don't do anything if another window is capturing the mouse. HWND cCapture = ::GetCapture(); - if (cCapture && cCapture != m_captureHwnd) + if (cCapture && cCapture != m_captureHwnd && m_current->type != TrackedMenuEntry) return TRUE; m_ptPrev = pt; @@ -283,7 +283,8 @@ { m_entryUnderMouse->mb->_ChangeHotItem(NULL, -1, HICF_MOUSE); } - SetCapture(NULL); + if (cCapture == m_captureHwnd) + SetCapture(NULL); } } @@ -303,7 +304,8 @@ if (m_current->type == TrackedMenuEntry) SendMessage(entry->hwnd, WM_CANCELMODE, 0, 0); PostMessage(child, WM_USER_CHANGETRACKEDITEM, iHitTestResult, isTracking); - return FALSE; + if (m_current->type == TrackedMenuEntry) + return FALSE; } } @@ -311,10 +313,10 @@ { if (entry) { - SetCapture(child); - if (m_current->type == MenuPopupEntry) { + //SetCapture(child); + ScreenToClient(child, &pt2); SendMessage(child, WM_MOUSEMOVE, msg->wParam, MAKELPARAM(pt2.x, pt2.y)); } @@ -399,6 +401,10 @@ case WM_MOUSEMOVE: callNext = ProcessMouseMove(msg); break; + case WM_MOUSELEAVE: + callNext = ProcessMouseMove(msg); + //callNext = ProcessMouseLeave(msg); + break; case WM_SYSKEYDOWN: case WM_KEYDOWN: if (m_current->type == MenuPopupEntry) @@ -406,16 +412,17 @@ DisableMouseTrack(m_current->hwnd, TRUE); switch (msg->wParam) { + case VK_ESCAPE: case VK_MENU: case VK_LMENU: case VK_RMENU: m_current->mb->_MenuItemHotTrack(MPOS_FULLCANCEL); break; case VK_LEFT: - m_current->mb->_MenuItemHotTrack(MPOS_SELECTLEFT); + m_current->mb->_MenuItemHotTrack(VK_LEFT); break; case VK_RIGHT: - m_current->mb->_MenuItemHotTrack(MPOS_SELECTRIGHT); + m_current->mb->_MenuItemHotTrack(VK_RIGHT); break; case VK_UP: m_current->mb->_MenuItemHotTrack(VK_UP); Modified: branches/shell-experiments/base/shell/rshell/CMenuToolbars.cpp URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rshell/CMenuToolbars.cpp?rev=62681&r1=62680&r2=62681&view=diff ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuToolbars.cpp [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuToolbars.cpp [iso-8859-1] Mon Apr 7 18:41:47 2014 @@ -159,7 +159,7 @@ HRESULT CMenuToolbarBase::OnPagerCalcSize(LPNMPGCALCSIZE csize) { SIZE tbs; - GetIdealSize(tbs); + GetSizes(NULL, &tbs, NULL); if (csize->dwFlag == PGF_CALCHEIGHT) { csize->iHeight = tbs.cy; @@ -284,12 +284,16 @@ m_menuBand(menuBand), m_hwndToolbar(NULL), m_dwMenuFlags(0), - m_hasIdealSize(FALSE), + m_hasSizes(FALSE), m_usePager(usePager), m_hotItem(-1), m_popupItem(-1), - m_isTracking(FALSE) -{ + m_isTrackingPopup(FALSE) +{ + m_idealSize.cx = 0; + m_idealSize.cy = 0; + m_itemSize.cx = 0; + m_itemSize.cy = 0; m_marlett = CreateFont( 0, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, @@ -452,18 +456,38 @@ return S_OK; } -HRESULT CMenuToolbarBase::GetIdealSize(SIZE& size) -{ - size.cx = size.cy = 0; - - if (m_hwndToolbar && !m_hasIdealSize) - { - SendMessageW(m_hwndToolbar, TB_AUTOSIZE, 0, 0); - SendMessageW(m_hwndToolbar, TB_GETMAXSIZE, 0, reinterpret_cast<LPARAM>(&m_idealSize)); - m_hasIdealSize = TRUE; - } - - size = m_idealSize; +HRESULT CMenuToolbarBase::GetSizes(SIZE* pMinSize, SIZE* pMaxSize, SIZE* pIntegralSize) +{ + if (pMinSize) + *pMinSize = m_idealSize; + if (pMaxSize) + *pMaxSize = m_idealSize; + if (pIntegralSize) + *pIntegralSize = m_itemSize; + + if (m_hasSizes) + return S_OK; + + if (!m_hwndToolbar) + return S_OK; + + // 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; return S_OK; } @@ -560,46 +584,21 @@ return S_FALSE; } -HRESULT CMenuToolbarBase::OnHotItemChange(const NMTBHOTITEM * hot, LRESULT * theResult) -{ +HRESULT CMenuToolbarBase::ChangeHotItem(CMenuToolbarBase * toolbar, INT item, DWORD dwFlags) +{ + // Ignore the change if it already matches the stored info + if (m_hotBar == toolbar && m_hotItem == item) + return S_FALSE; + // Prevent a change of hot item if the change was triggered by the mouse, // and mouse tracking is disabled. - if (m_disableMouseTrack && hot->dwFlags & HICF_MOUSE) - { - *theResult = 1; + if (m_disableMouseTrack && dwFlags & HICF_MOUSE) + { DbgPrint("Hot item change prevented by DisableMouseTrack\n"); return S_OK; } - HRESULT hr = S_OK; - if (hot->dwFlags & HICF_LEAVING) - { - // Only notify of LEAVING if this was the hot toolbar. - if (m_hotBar == this) - { - DbgPrint("The hot bar is now cold.\n"); - hr = m_menuBand->_ChangeHotItem(NULL, -1, hot->dwFlags); - } - } - else - { - hr = m_menuBand->_ChangeHotItem(this, hot->idNew, hot->dwFlags); - } - - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - // Reuse S_OK/S_FALSE as Continue/Cancel - *theResult = hr; - - return S_OK; -} - -HRESULT CMenuToolbarBase::ChangeHotItem(CMenuToolbarBase * toolbar, INT item, DWORD dwFlags) -{ - if (m_hotBar == toolbar && m_hotItem == item) - return S_FALSE; - + // Notify the toolbar if the hot-tracking left this toolbar if (m_hotBar == this && toolbar != this) { SendMessage(m_hwndToolbar, TB_SETHOTITEM, (WPARAM)-1, 0); @@ -623,8 +622,9 @@ m_timerEnabled = TRUE; DbgPrint("SetTimer called with m_hotItem=%d\n", m_hotItem); } - else if (m_isTracking) + else if (m_isTrackingPopup) { + // If the menubar has an open submenu, switch to the new item's submenu immediately PopupItem(m_hotItem); } } @@ -646,13 +646,15 @@ HRESULT CMenuToolbarBase::ChangePopupItem(CMenuToolbarBase * toolbar, INT item) { + // Ignore the change if it already matches the stored info if (m_popupBar == toolbar && m_popupItem == item) return S_FALSE; + // Notify the toolbar if the popup-tracking this toolbar if (m_popupBar == this && toolbar != this) { SendMessage(m_hwndToolbar, TB_CHECKBUTTON, m_popupItem, FALSE); - m_isTracking = FALSE; + m_isTrackingPopup = FALSE; } m_popupBar = toolbar; @@ -693,7 +695,7 @@ return E_FAIL; DbgPrint("Changing tracked item to %d...\n", index); - m_isTracking = wasTracking; + m_isTrackingPopup = wasTracking; m_menuBand->_ChangeHotItem(this, btn.idCommand, HICF_MOUSE); return S_OK; @@ -701,10 +703,7 @@ HRESULT CMenuToolbarBase::PopupSubMenu(UINT iItem, UINT index, IShellMenu* childShellMenu) { - IBandSite* pBandSite; - IDeskBar* pDeskBar; - - HRESULT hr = 0; + // Calculate the submenu position and exclude area RECT rc = { 0 }; RECT rcx = { 0 }; @@ -732,81 +731,31 @@ pt.y = a.y - 3; } -#if USE_SYSTEM_MENUSITE - hr = CoCreateInstance(CLSID_MenuBandSite, - NULL, - CLSCTX_INPROC_SERVER, - IID_PPV_ARG(IBandSite, &pBandSite)); -#else - hr = CMenuSite_Constructor(IID_PPV_ARG(IBandSite, &pBandSite)); -#endif - if (FAILED_UNEXPECTEDLY(hr)) - return hr; -#if WRAP_MENUSITE - hr = CMenuSite_Wrapper(pBandSite, IID_PPV_ARG(IBandSite, &pBandSite)); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; -#endif - -#if USE_SYSTEM_MENUDESKBAR - hr = CoCreateInstance(CLSID_MenuDeskBar, - NULL, - CLSCTX_INPROC_SERVER, - IID_PPV_ARG(IDeskBar, &pDeskBar)); -#else - hr = CMenuDeskBar_Constructor(IID_PPV_ARG(IDeskBar, &pDeskBar)); -#endif - if (FAILED_UNEXPECTEDLY(hr)) - return hr; -#if WRAP_MENUDESKBAR - hr = CMenuDeskBar_Wrapper(pDeskBar, IID_PPV_ARG(IDeskBar, &pDeskBar)); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; -#endif - - hr = pDeskBar->SetClient(pBandSite); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - hr = pBandSite->AddBand(childShellMenu); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - CComPtr<IMenuPopup> popup; - hr = pDeskBar->QueryInterface(IID_PPV_ARG(IMenuPopup, &popup)); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - m_isTracking = TRUE; + // Display the submenu + m_isTrackingPopup = TRUE; m_menuBand->_ChangePopupItem(this, iItem); - m_menuBand->_OnPopupSubMenu(popup, &pt, &rcl); + m_menuBand->_OnPopupSubMenu(childShellMenu, &pt, &rcl); return S_OK; } HRESULT CMenuToolbarBase::PopupSubMenu(UINT iItem, UINT index, HMENU menu) { + // Calculate the submenu position and exclude area 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 }; + RECT rcl = { a.x, a.y, b.x, b.y }; if (m_initFlags & SMINIT_VERTICAL) { @@ -816,45 +765,24 @@ HMENU popup = GetSubMenu(menu, index); - m_isTracking = TRUE; - + // Display the submenu + m_isTrackingPopup = TRUE; m_menuBand->_ChangePopupItem(this, iItem); - m_menuBand->_TrackSubMenuUsingTrackPopupMenu(popup, pt.x, pt.y, rcl); + m_menuBand->_TrackSubMenu(popup, pt.x, pt.y, rcl); m_menuBand->_ChangePopupItem(NULL, -1); - - m_isTracking = FALSE; + m_isTrackingPopup = FALSE; return S_OK; } HRESULT CMenuToolbarBase::DoContextMenu(IContextMenu* contextMenu) { - HRESULT hr; - HMENU hPopup = CreatePopupMenu(); - - if (hPopup == NULL) - return E_FAIL; - - hr = contextMenu->QueryContextMenu(hPopup, 0, 0, UINT_MAX, CMF_NORMAL); - if (FAILED_UNEXPECTEDLY(hr)) - { - DestroyMenu(hPopup); - return hr; - } - + // Calculate the context menu position DWORD dwPos = GetMessagePos(); - UINT uCommand = ::TrackPopupMenu(hPopup, TPM_RETURNCMD, GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos), 0, m_hwnd, NULL); - if (uCommand == 0) - return S_FALSE; - - CMINVOKECOMMANDINFO cmi = { 0 }; - cmi.cbSize = sizeof(cmi); - cmi.lpVerb = MAKEINTRESOURCEA(uCommand); - cmi.hwnd = m_hwnd; - hr = contextMenu->InvokeCommand(&cmi); - - DestroyMenu(hPopup); - return hr; + POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) }; + + // Display the submenu + return m_menuBand->_TrackContextMenu(contextMenu, pt.x, pt.y); } HRESULT CMenuToolbarBase::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) @@ -866,6 +794,13 @@ return S_OK; } + // 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; + } + *theResult = 0; m_menuBand->_KillPopupTimers(); @@ -883,7 +818,7 @@ if (FAILED_UNEXPECTEDLY(hr)) return hr; - return S_OK; // filter out a possible S_FALSE from here. + return OnCommandInternal(wParam, lParam, theResult); } HRESULT CMenuToolbarBase::KeyboardItemChange(DWORD dwSelectType) @@ -948,7 +883,7 @@ if (prev != btn.idCommand) { DbgPrint("Setting Hot item to %d\n", index); - SendMessage(m_hwndToolbar, TB_SETHOTITEM, index, 0); + m_menuBand->_ChangeHotItem(this, index, 0); } return S_OK; } @@ -967,8 +902,9 @@ if (prev != -1) { DbgPrint("Setting Hot item to null\n"); - SendMessage(m_hwndToolbar, TB_SETHOTITEM, (WPARAM) -1, 0); - } + m_menuBand->_ChangeHotItem(NULL, -1, 0); + } + return S_FALSE; } @@ -1219,25 +1155,8 @@ return DoContextMenu(contextMenu); } -HRESULT CMenuStaticToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) -{ - HRESULT hr; - - if (m_isTracking) - { - return S_FALSE; - } - - hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult); - 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) - { - return hr; - } - +HRESULT CMenuStaticToolbar::OnCommandInternal(WPARAM wParam, LPARAM lParam, LRESULT *theResult) +{ return m_menuBand->_CallCBWithItemId(wParam, SMC_EXEC, 0, 0); } @@ -1313,7 +1232,6 @@ hr = m_shellFolder->GetAttributesOf(1, &itemc, &attrs); DWORD_PTR dwData = reinterpret_cast<DWORD_PTR>(ILClone(item)); - // FIXME: remove before deleting the toolbar or it will leak // Fetch next item already, so we know if the current one is the last hr = eidl->Next(1, &item, &fetched); @@ -1399,21 +1317,10 @@ return DoContextMenu(contextMenu); } -HRESULT CMenuSFToolbar::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult) -{ - HRESULT hr; - hr = CMenuToolbarBase::OnCommand(wParam, lParam, theResult); - 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; - } - +HRESULT CMenuSFToolbar::OnCommandInternal(WPARAM wParam, LPARAM lParam, LRESULT *theResult) +{ DWORD_PTR data; + GetDataFromId(wParam, NULL, &data); return m_menuBand->_CallCBWithItemPidl(reinterpret_cast<LPITEMIDLIST>(data), SMC_SFEXEC, 0, 0); Modified: branches/shell-experiments/base/shell/rshell/CMenuToolbars.h URL: http://svn.reactos.org/svn/reactos/branches/shell-experiments/base/shell/rshell/CMenuToolbars.h?rev=62681&r1=62680&r2=62681&view=diff ============================================================================== --- branches/shell-experiments/base/shell/rshell/CMenuToolbars.h [iso-8859-1] (original) +++ branches/shell-experiments/base/shell/rshell/CMenuToolbars.h [iso-8859-1] Mon Apr 7 18:41:47 2014 @@ -40,8 +40,9 @@ CMenuBand * m_menuBand; HWND m_hwndToolbar; DWORD m_dwMenuFlags; - BOOL m_hasIdealSize; + BOOL m_hasSizes; SIZE m_idealSize; + SIZE m_itemSize; BOOL m_usePager; CMenuToolbarBase * m_hotBar; INT m_hotItem; @@ -49,7 +50,7 @@ INT m_popupItem; DWORD m_initFlags; - BOOL m_isTracking; + BOOL m_isTrackingPopup; private: static LRESULT CALLBACK s_SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -74,12 +75,11 @@ HRESULT DoContextMenu(IContextMenu* contextMenu); HRESULT KeyboardItemChange(DWORD changeType); - HRESULT OnHotItemChange(const NMTBHOTITEM * hot, LRESULT * theResult); HRESULT IsTrackedItem(INT index); HRESULT ChangeTrackedItem(INT index, BOOL wasTracking); - HRESULT GetIdealSize(SIZE& size); + HRESULT GetSizes(SIZE* pMinSize, SIZE* pMaxSize, SIZE* pIntegralSize); HRESULT SetPosSize(int x, int y, int cx, int cy); void InvalidateDraw(); @@ -96,7 +96,7 @@ HRESULT KillPopupTimer(); protected: - virtual HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult); + virtual HRESULT OnCommandInternal(WPARAM wParam, LPARAM lParam, LRESULT *theResult) = 0; virtual HRESULT OnDeletingButton(const NMTOOLBAR * tb) = 0; virtual HRESULT InternalPopupItem(INT iItem, INT index, DWORD_PTR dwData) = 0; @@ -113,6 +113,7 @@ HRESULT UpdateImageLists(); private: + HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult); HRESULT OnPagerCalcSize(LPNMPGCALCSIZE csize); HRESULT OnPopupTimer(DWORD timerId); HRESULT OnCustomDraw(LPNMTBCUSTOMDRAW cdraw, LRESULT * theResult); @@ -133,7 +134,7 @@ HRESULT GetMenu(HMENU *phmenu, HWND *phwnd, DWORD *pdwFlags); virtual HRESULT FillToolbar(BOOL clearFirst=FALSE); - virtual HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult); + virtual HRESULT OnCommandInternal(WPARAM wParam, LPARAM lParam, LRESULT *theResult); virtual HRESULT OnContextMenu(NMMOUSE * rclick); protected: @@ -161,7 +162,7 @@ HRESULT GetShellFolder(DWORD *pdwFlags, LPITEMIDLIST *ppidl, REFIID riid, void **ppv); virtual HRESULT FillToolbar(BOOL clearFirst=FALSE); - virtual HRESULT OnCommand(WPARAM wParam, LPARAM lParam, LRESULT *theResult); + virtual HRESULT OnCommandInternal(WPARAM wParam, LPARAM lParam, LRESULT *theResult); virtual HRESULT OnContextMenu(NMMOUSE * rclick); protected: